Message ID | 20240127144252.24767-5-ansuelsmth@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | net: phy: split at803x | expand |
On Sat, Jan 27, 2024 at 03:42:44PM +0100, Christian Marangi wrote: > Move additional functions to shared library in preparation for qca808x > PHY Family to be detached from at803x driver. > > Only the shared defines are moved to the shared qcom.h header. > > Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> > --- > drivers/net/phy/qcom/at803x.c | 428 +--------------------------- > drivers/net/phy/qcom/qcom-phy-lib.c | 376 ++++++++++++++++++++++++ > drivers/net/phy/qcom/qcom.h | 84 ++++++ > 3 files changed, 463 insertions(+), 425 deletions(-) > > diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c > index 638babc50df1..442060793854 100644 > --- a/drivers/net/phy/qcom/at803x.c > +++ b/drivers/net/phy/qcom/at803x.c > @@ -24,65 +24,11 @@ > > #include "qcom.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 GENMASK(15, 14) > -#define AT803X_SS_SPEED_1000 2 > -#define AT803X_SS_SPEED_100 1 > -#define AT803X_SS_SPEED_10 0 > -#define AT803X_SS_DUPLEX BIT(13) > -#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) > -#define AT803X_SS_MDIX BIT(6) > - > -#define QCA808X_SS_SPEED_MASK GENMASK(9, 7) > -#define QCA808X_SS_SPEED_2500 4 This was an intended remove and should be removed in patch 5 instead and cause build fail on testing this single patch. Will fix in v3, sorry for the noise! > - > -#define AT803X_INTR_ENABLE 0x12 > -#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) > -#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) > -#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) > -#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) > -#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) > -#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) > -#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) > -#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) > -#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) > -#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) > -#define AT803X_INTR_ENABLE_WOL BIT(0) > - > -#define AT803X_INTR_STATUS 0x13 > - > -#define AT803X_SMART_SPEED 0x14 > -#define AT803X_SMART_SPEED_ENABLE BIT(5) > -#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) > -#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) > -#define AT803X_CDT 0x16 > -#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) > -#define AT803X_CDT_ENABLE_TEST BIT(0) > -#define AT803X_CDT_STATUS 0x1c > -#define AT803X_CDT_STATUS_STAT_NORMAL 0 > -#define AT803X_CDT_STATUS_STAT_SHORT 1 > -#define AT803X_CDT_STATUS_STAT_OPEN 2 > -#define AT803X_CDT_STATUS_STAT_FAIL 3 > -#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) > -#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) > #define AT803X_LED_CONTROL 0x18 > > #define AT803X_PHY_MMD3_WOL_CTRL 0x8012 > #define AT803X_WOL_EN BIT(5) > -#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C > -#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B > -#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A > + > #define AT803X_REG_CHIP_CONFIG 0x1f > #define AT803X_BT_BX_REG_SEL 0x8000 > > @@ -138,10 +84,6 @@ > #define AT803X_CLK_OUT_STRENGTH_HALF 1 > #define AT803X_CLK_OUT_STRENGTH_QUARTER 2 > > -#define AT803X_DEFAULT_DOWNSHIFT 5 > -#define AT803X_MIN_DOWNSHIFT 2 > -#define AT803X_MAX_DOWNSHIFT 9 > - > #define AT803X_MMD3_SMARTEEE_CTL1 0x805b > #define AT803X_MMD3_SMARTEEE_CTL2 0x805c > #define AT803X_MMD3_SMARTEEE_CTL3 0x805d > @@ -158,6 +100,8 @@ > > #define QCA9561_PHY_ID 0x004dd042 > > +#define AT803X_SS_SPEED_MASK GENMASK(15, 14) > + > #define AT803X_PAGE_FIBER 0 > #define AT803X_PAGE_COPPER 1 > > @@ -366,11 +310,6 @@ MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); > MODULE_AUTHOR("Matus Ujhelyi"); > MODULE_LICENSE("GPL"); > > -struct at803x_ss_mask { > - u16 speed_mask; > - u8 speed_shift; > -}; > - > struct at803x_priv { > int flags; > u16 clk_25m_reg; > @@ -470,80 +409,6 @@ static void at803x_context_restore(struct phy_device *phydev, > phy_write(phydev, AT803X_LED_CONTROL, context->led_control); > } > > -static int at803x_set_wol(struct phy_device *phydev, > - struct ethtool_wolinfo *wol) > -{ > - int ret, irq_enabled; > - > - if (wol->wolopts & WAKE_MAGIC) { > - struct net_device *ndev = phydev->attached_dev; > - const u8 *mac; > - unsigned int i; > - static const unsigned int offsets[] = { > - AT803X_LOC_MAC_ADDR_32_47_OFFSET, > - AT803X_LOC_MAC_ADDR_16_31_OFFSET, > - AT803X_LOC_MAC_ADDR_0_15_OFFSET, > - }; > - > - if (!ndev) > - return -ENODEV; > - > - mac = (const u8 *)ndev->dev_addr; > - > - if (!is_valid_ether_addr(mac)) > - return -EINVAL; > - > - for (i = 0; i < 3; i++) > - phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], > - mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); > - > - /* Enable WOL interrupt */ > - ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); > - if (ret) > - return ret; > - } else { > - /* Disable WOL interrupt */ > - ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); > - if (ret) > - return ret; > - } > - > - /* Clear WOL status */ > - ret = phy_read(phydev, AT803X_INTR_STATUS); > - if (ret < 0) > - return ret; > - > - /* Check if there are other interrupts except for WOL triggered when PHY is > - * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can > - * be passed up to the interrupt PIN. > - */ > - irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); > - if (irq_enabled < 0) > - return irq_enabled; > - > - irq_enabled &= ~AT803X_INTR_ENABLE_WOL; > - if (ret & irq_enabled && !phy_polling_mode(phydev)) > - phy_trigger_machine(phydev); > - > - return 0; > -} > - > -static void at803x_get_wol(struct phy_device *phydev, > - struct ethtool_wolinfo *wol) > -{ > - int value; > - > - wol->supported = WAKE_MAGIC; > - wol->wolopts = 0; > - > - value = phy_read(phydev, AT803X_INTR_ENABLE); > - if (value < 0) > - return; > - > - if (value & AT803X_INTR_ENABLE_WOL) > - wol->wolopts |= WAKE_MAGIC; > -} > - > static int at803x_suspend(struct phy_device *phydev) > { > int value; > @@ -816,73 +681,6 @@ static int at803x_config_init(struct phy_device *phydev) > return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); > } > > -static int at803x_ack_interrupt(struct phy_device *phydev) > -{ > - int err; > - > - err = phy_read(phydev, AT803X_INTR_STATUS); > - > - return (err < 0) ? err : 0; > -} > - > -static int at803x_config_intr(struct phy_device *phydev) > -{ > - int err; > - int value; > - > - value = phy_read(phydev, AT803X_INTR_ENABLE); > - > - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { > - /* Clear any pending interrupts */ > - err = at803x_ack_interrupt(phydev); > - if (err) > - return err; > - > - value |= AT803X_INTR_ENABLE_AUTONEG_ERR; > - value |= AT803X_INTR_ENABLE_SPEED_CHANGED; > - value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; > - value |= AT803X_INTR_ENABLE_LINK_FAIL; > - value |= AT803X_INTR_ENABLE_LINK_SUCCESS; > - > - err = phy_write(phydev, AT803X_INTR_ENABLE, value); > - } else { > - err = phy_write(phydev, AT803X_INTR_ENABLE, 0); > - if (err) > - return err; > - > - /* Clear any pending interrupts */ > - err = at803x_ack_interrupt(phydev); > - } > - > - return err; > -} > - > -static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) > -{ > - int irq_status, int_enabled; > - > - irq_status = phy_read(phydev, AT803X_INTR_STATUS); > - if (irq_status < 0) { > - phy_error(phydev); > - return IRQ_NONE; > - } > - > - /* Read the current enabled interrupts */ > - int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); > - if (int_enabled < 0) { > - phy_error(phydev); > - return IRQ_NONE; > - } > - > - /* See if this was one of our enabled interrupts */ > - if (!(irq_status & int_enabled)) > - return IRQ_NONE; > - > - phy_trigger_machine(phydev); > - > - return IRQ_HANDLED; > -} > - > static void at803x_link_change_notify(struct phy_device *phydev) > { > /* > @@ -908,69 +706,6 @@ static void at803x_link_change_notify(struct phy_device *phydev) > } > } > > -static int at803x_read_specific_status(struct phy_device *phydev, > - struct at803x_ss_mask ss_mask) > -{ > - int ss; > - > - /* Read the AT8035 PHY-Specific Status register, which indicates the > - * speed and duplex that the PHY is actually using, irrespective of > - * whether we are in autoneg mode or not. > - */ > - ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); > - if (ss < 0) > - return ss; > - > - if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { > - int sfc, speed; > - > - sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); > - if (sfc < 0) > - return sfc; > - > - speed = ss & ss_mask.speed_mask; > - speed >>= ss_mask.speed_shift; > - > - switch (speed) { > - case AT803X_SS_SPEED_10: > - phydev->speed = SPEED_10; > - break; > - case AT803X_SS_SPEED_100: > - phydev->speed = SPEED_100; > - break; > - case AT803X_SS_SPEED_1000: > - phydev->speed = SPEED_1000; > - break; > - case QCA808X_SS_SPEED_2500: > - phydev->speed = SPEED_2500; > - break; > - } > - if (ss & AT803X_SS_DUPLEX) > - 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; > - } > - } > - > - return 0; > -} > - > static int at803x_read_status(struct phy_device *phydev) > { > struct at803x_ss_mask ss_mask = { 0 }; > @@ -1006,50 +741,6 @@ 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_prepare_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 0; > -} > - > static int at803x_config_aneg(struct phy_device *phydev) > { > struct at803x_priv *priv = phydev->priv; > @@ -1065,80 +756,6 @@ static int at803x_config_aneg(struct phy_device *phydev) > return genphy_config_aneg(phydev); > } > > -static int at803x_get_downshift(struct phy_device *phydev, u8 *d) > -{ > - int val; > - > - val = phy_read(phydev, AT803X_SMART_SPEED); > - if (val < 0) > - return val; > - > - if (val & AT803X_SMART_SPEED_ENABLE) > - *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; > - else > - *d = DOWNSHIFT_DEV_DISABLE; > - > - return 0; > -} > - > -static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) > -{ > - u16 mask, set; > - int ret; > - > - switch (cnt) { > - case DOWNSHIFT_DEV_DEFAULT_COUNT: > - cnt = AT803X_DEFAULT_DOWNSHIFT; > - fallthrough; > - case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: > - set = AT803X_SMART_SPEED_ENABLE | > - AT803X_SMART_SPEED_BYPASS_TIMER | > - FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); > - mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; > - break; > - case DOWNSHIFT_DEV_DISABLE: > - set = 0; > - mask = AT803X_SMART_SPEED_ENABLE | > - AT803X_SMART_SPEED_BYPASS_TIMER; > - break; > - default: > - return -EINVAL; > - } > - > - ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); > - > - /* After changing the smart speed settings, we need to perform a > - * software reset, use phy_init_hw() to make sure we set the > - * reapply any values which might got lost during software reset. > - */ > - if (ret == 1) > - ret = phy_init_hw(phydev); > - > - return ret; > -} > - > -static int at803x_get_tunable(struct phy_device *phydev, > - struct ethtool_tunable *tuna, void *data) > -{ > - switch (tuna->id) { > - case ETHTOOL_PHY_DOWNSHIFT: > - return at803x_get_downshift(phydev, data); > - default: > - return -EOPNOTSUPP; > - } > -} > - > -static int at803x_set_tunable(struct phy_device *phydev, > - struct ethtool_tunable *tuna, const void *data) > -{ > - switch (tuna->id) { > - case ETHTOOL_PHY_DOWNSHIFT: > - return at803x_set_downshift(phydev, *(const u8 *)data); > - default: > - return -EOPNOTSUPP; > - } > -} > - > static int at803x_cable_test_result_trans(u16 status) > { > switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { > @@ -1170,45 +787,6 @@ static bool at803x_cdt_fault_length_valid(u16 status) > return false; > } > > -static int at803x_cdt_fault_length(int dt) > -{ > - /* According to the datasheet the distance to the fault is > - * DELTA_TIME * 0.824 meters. > - * > - * The author suspect the correct formula is: > - * > - * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 > - * > - * where c is the speed of light, VF is the velocity factor of > - * the twisted pair cable, 125MHz the counter frequency and > - * we need to divide by 2 because the hardware will measure the > - * round trip time to the fault and back to the PHY. > - * > - * With a VF of 0.69 we get the factor 0.824 mentioned in the > - * datasheet. > - */ > - return (dt * 824) / 10; > -} > - > -static int at803x_cdt_start(struct phy_device *phydev, > - u32 cdt_start) > -{ > - return phy_write(phydev, AT803X_CDT, cdt_start); > -} > - > -static int at803x_cdt_wait_for_completion(struct phy_device *phydev, > - u32 cdt_en) > -{ > - int val, ret; > - > - /* One test run takes about 25ms */ > - ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, > - !(val & cdt_en), > - 30000, 100000, true); > - > - return ret < 0 ? ret : 0; > -} > - > static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair) > { > static const int ethtool_pair[] = { > diff --git a/drivers/net/phy/qcom/qcom-phy-lib.c b/drivers/net/phy/qcom/qcom-phy-lib.c > index 7192184429b7..e0295d4b4a51 100644 > --- a/drivers/net/phy/qcom/qcom-phy-lib.c > +++ b/drivers/net/phy/qcom/qcom-phy-lib.c > @@ -3,6 +3,9 @@ > #include <linux/phy.h> > #include <linux/module.h> > > +#include <linux/netdevice.h> > +#include <linux/etherdevice.h> > + > #include "qcom.h" > > MODULE_DESCRIPTION("Qualcomm PHY driver Common Functions"); > @@ -51,3 +54,376 @@ int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data) > return phy_write(phydev, AT803X_DEBUG_DATA, data); > } > EXPORT_SYMBOL_GPL(at803x_debug_reg_write); > + > +int at803x_set_wol(struct phy_device *phydev, > + struct ethtool_wolinfo *wol) > +{ > + int ret, irq_enabled; > + > + if (wol->wolopts & WAKE_MAGIC) { > + struct net_device *ndev = phydev->attached_dev; > + const u8 *mac; > + unsigned int i; > + static const unsigned int offsets[] = { > + AT803X_LOC_MAC_ADDR_32_47_OFFSET, > + AT803X_LOC_MAC_ADDR_16_31_OFFSET, > + AT803X_LOC_MAC_ADDR_0_15_OFFSET, > + }; > + > + if (!ndev) > + return -ENODEV; > + > + mac = (const u8 *)ndev->dev_addr; > + > + if (!is_valid_ether_addr(mac)) > + return -EINVAL; > + > + for (i = 0; i < 3; i++) > + phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], > + mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); > + > + /* Enable WOL interrupt */ > + ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); > + if (ret) > + return ret; > + } else { > + /* Disable WOL interrupt */ > + ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); > + if (ret) > + return ret; > + } > + > + /* Clear WOL status */ > + ret = phy_read(phydev, AT803X_INTR_STATUS); > + if (ret < 0) > + return ret; > + > + /* Check if there are other interrupts except for WOL triggered when PHY is > + * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can > + * be passed up to the interrupt PIN. > + */ > + irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); > + if (irq_enabled < 0) > + return irq_enabled; > + > + irq_enabled &= ~AT803X_INTR_ENABLE_WOL; > + if (ret & irq_enabled && !phy_polling_mode(phydev)) > + phy_trigger_machine(phydev); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(at803x_set_wol); > + > +void at803x_get_wol(struct phy_device *phydev, > + struct ethtool_wolinfo *wol) > +{ > + int value; > + > + wol->supported = WAKE_MAGIC; > + wol->wolopts = 0; > + > + value = phy_read(phydev, AT803X_INTR_ENABLE); > + if (value < 0) > + return; > + > + if (value & AT803X_INTR_ENABLE_WOL) > + wol->wolopts |= WAKE_MAGIC; > +} > +EXPORT_SYMBOL_GPL(at803x_get_wol); > + > +int at803x_ack_interrupt(struct phy_device *phydev) > +{ > + int err; > + > + err = phy_read(phydev, AT803X_INTR_STATUS); > + > + return (err < 0) ? err : 0; > +} > +EXPORT_SYMBOL_GPL(at803x_ack_interrupt); > + > +int at803x_config_intr(struct phy_device *phydev) > +{ > + int err; > + int value; > + > + value = phy_read(phydev, AT803X_INTR_ENABLE); > + > + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { > + /* Clear any pending interrupts */ > + err = at803x_ack_interrupt(phydev); > + if (err) > + return err; > + > + value |= AT803X_INTR_ENABLE_AUTONEG_ERR; > + value |= AT803X_INTR_ENABLE_SPEED_CHANGED; > + value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; > + value |= AT803X_INTR_ENABLE_LINK_FAIL; > + value |= AT803X_INTR_ENABLE_LINK_SUCCESS; > + > + err = phy_write(phydev, AT803X_INTR_ENABLE, value); > + } else { > + err = phy_write(phydev, AT803X_INTR_ENABLE, 0); > + if (err) > + return err; > + > + /* Clear any pending interrupts */ > + err = at803x_ack_interrupt(phydev); > + } > + > + return err; > +} > +EXPORT_SYMBOL_GPL(at803x_config_intr); > + > +irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) > +{ > + int irq_status, int_enabled; > + > + irq_status = phy_read(phydev, AT803X_INTR_STATUS); > + if (irq_status < 0) { > + phy_error(phydev); > + return IRQ_NONE; > + } > + > + /* Read the current enabled interrupts */ > + int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); > + if (int_enabled < 0) { > + phy_error(phydev); > + return IRQ_NONE; > + } > + > + /* See if this was one of our enabled interrupts */ > + if (!(irq_status & int_enabled)) > + return IRQ_NONE; > + > + phy_trigger_machine(phydev); > + > + return IRQ_HANDLED; > +} > +EXPORT_SYMBOL_GPL(at803x_handle_interrupt); > + > +int at803x_read_specific_status(struct phy_device *phydev, > + struct at803x_ss_mask ss_mask) > +{ > + int ss; > + > + /* Read the AT8035 PHY-Specific Status register, which indicates the > + * speed and duplex that the PHY is actually using, irrespective of > + * whether we are in autoneg mode or not. > + */ > + ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); > + if (ss < 0) > + return ss; > + > + if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { > + int sfc, speed; > + > + sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); > + if (sfc < 0) > + return sfc; > + > + speed = ss & ss_mask.speed_mask; > + speed >>= ss_mask.speed_shift; > + > + switch (speed) { > + case AT803X_SS_SPEED_10: > + phydev->speed = SPEED_10; > + break; > + case AT803X_SS_SPEED_100: > + phydev->speed = SPEED_100; > + break; > + case AT803X_SS_SPEED_1000: > + phydev->speed = SPEED_1000; > + break; > + case QCA808X_SS_SPEED_2500: > + phydev->speed = SPEED_2500; > + break; > + } > + if (ss & AT803X_SS_DUPLEX) > + 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; > + } > + } > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(at803x_read_specific_status); > + > +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)); > +} > +EXPORT_SYMBOL_GPL(at803x_config_mdix); > + > +int at803x_prepare_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 0; > +} > +EXPORT_SYMBOL_GPL(at803x_prepare_config_aneg); > + > +static int at803x_get_downshift(struct phy_device *phydev, u8 *d) > +{ > + int val; > + > + val = phy_read(phydev, AT803X_SMART_SPEED); > + if (val < 0) > + return val; > + > + if (val & AT803X_SMART_SPEED_ENABLE) > + *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; > + else > + *d = DOWNSHIFT_DEV_DISABLE; > + > + return 0; > +} > + > +static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) > +{ > + u16 mask, set; > + int ret; > + > + switch (cnt) { > + case DOWNSHIFT_DEV_DEFAULT_COUNT: > + cnt = AT803X_DEFAULT_DOWNSHIFT; > + fallthrough; > + case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: > + set = AT803X_SMART_SPEED_ENABLE | > + AT803X_SMART_SPEED_BYPASS_TIMER | > + FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); > + mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; > + break; > + case DOWNSHIFT_DEV_DISABLE: > + set = 0; > + mask = AT803X_SMART_SPEED_ENABLE | > + AT803X_SMART_SPEED_BYPASS_TIMER; > + break; > + default: > + return -EINVAL; > + } > + > + ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); > + > + /* After changing the smart speed settings, we need to perform a > + * software reset, use phy_init_hw() to make sure we set the > + * reapply any values which might got lost during software reset. > + */ > + if (ret == 1) > + ret = phy_init_hw(phydev); > + > + return ret; > +} > + > +int at803x_get_tunable(struct phy_device *phydev, > + struct ethtool_tunable *tuna, void *data) > +{ > + switch (tuna->id) { > + case ETHTOOL_PHY_DOWNSHIFT: > + return at803x_get_downshift(phydev, data); > + default: > + return -EOPNOTSUPP; > + } > +} > +EXPORT_SYMBOL_GPL(at803x_get_tunable); > + > +int at803x_set_tunable(struct phy_device *phydev, > + struct ethtool_tunable *tuna, const void *data) > +{ > + switch (tuna->id) { > + case ETHTOOL_PHY_DOWNSHIFT: > + return at803x_set_downshift(phydev, *(const u8 *)data); > + default: > + return -EOPNOTSUPP; > + } > +} > +EXPORT_SYMBOL_GPL(at803x_set_tunable); > + > +int at803x_cdt_fault_length(int dt) > +{ > + /* According to the datasheet the distance to the fault is > + * DELTA_TIME * 0.824 meters. > + * > + * The author suspect the correct formula is: > + * > + * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 > + * > + * where c is the speed of light, VF is the velocity factor of > + * the twisted pair cable, 125MHz the counter frequency and > + * we need to divide by 2 because the hardware will measure the > + * round trip time to the fault and back to the PHY. > + * > + * With a VF of 0.69 we get the factor 0.824 mentioned in the > + * datasheet. > + */ > + return (dt * 824) / 10; > +} > +EXPORT_SYMBOL_GPL(at803x_cdt_fault_length); > + > +int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start) > +{ > + return phy_write(phydev, AT803X_CDT, cdt_start); > +} > +EXPORT_SYMBOL_GPL(at803x_cdt_start); > + > +int at803x_cdt_wait_for_completion(struct phy_device *phydev, > + u32 cdt_en) > +{ > + int val, ret; > + > + /* One test run takes about 25ms */ > + ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, > + !(val & cdt_en), > + 30000, 100000, true); > + > + return ret < 0 ? ret : 0; > +} > +EXPORT_SYMBOL_GPL(at803x_cdt_wait_for_completion); > diff --git a/drivers/net/phy/qcom/qcom.h b/drivers/net/phy/qcom/qcom.h > index 8eb476d7c282..344f8c01d5b8 100644 > --- a/drivers/net/phy/qcom/qcom.h > +++ b/drivers/net/phy/qcom/qcom.h > @@ -1,5 +1,61 @@ > /* SPDX-License-Identifier: GPL-2.0 */ > > +#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_1000 2 > +#define AT803X_SS_SPEED_100 1 > +#define AT803X_SS_SPEED_10 0 > +#define AT803X_SS_DUPLEX BIT(13) > +#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) > +#define AT803X_SS_MDIX BIT(6) > + > +#define QCA808X_SS_SPEED_2500 4 > + > +#define AT803X_INTR_ENABLE 0x12 > +#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) > +#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) > +#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) > +#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) > +#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) > +#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) > +#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) > +#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) > +#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) > +#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) > +#define AT803X_INTR_ENABLE_WOL BIT(0) > + > +#define AT803X_INTR_STATUS 0x13 > + > +#define AT803X_SMART_SPEED 0x14 > +#define AT803X_SMART_SPEED_ENABLE BIT(5) > +#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) > +#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) > + > +#define AT803X_CDT 0x16 > +#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) > +#define AT803X_CDT_ENABLE_TEST BIT(0) > +#define AT803X_CDT_STATUS 0x1c > +#define AT803X_CDT_STATUS_STAT_NORMAL 0 > +#define AT803X_CDT_STATUS_STAT_SHORT 1 > +#define AT803X_CDT_STATUS_STAT_OPEN 2 > +#define AT803X_CDT_STATUS_STAT_FAIL 3 > +#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) > +#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) > + > +#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C > +#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B > +#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A > + > #define AT803X_DEBUG_ADDR 0x1D > #define AT803X_DEBUG_DATA 0x1E > > @@ -16,6 +72,10 @@ > #define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) > #define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15) > > +#define AT803X_DEFAULT_DOWNSHIFT 5 > +#define AT803X_MIN_DOWNSHIFT 2 > +#define AT803X_MAX_DOWNSHIFT 9 > + > enum stat_access_type { > PHY, > MMD > @@ -28,7 +88,31 @@ struct at803x_hw_stat { > enum stat_access_type access_type; > }; > > +struct at803x_ss_mask { > + u16 speed_mask; > + u8 speed_shift; > +}; > + > int at803x_debug_reg_read(struct phy_device *phydev, u16 reg); > int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, > u16 clear, u16 set); > int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data); > +int at803x_set_wol(struct phy_device *phydev, > + struct ethtool_wolinfo *wol); > +void at803x_get_wol(struct phy_device *phydev, > + struct ethtool_wolinfo *wol); > +int at803x_ack_interrupt(struct phy_device *phydev); > +int at803x_config_intr(struct phy_device *phydev); > +irqreturn_t at803x_handle_interrupt(struct phy_device *phydev); > +int at803x_read_specific_status(struct phy_device *phydev, > + struct at803x_ss_mask ss_mask); > +int at803x_config_mdix(struct phy_device *phydev, u8 ctrl); > +int at803x_prepare_config_aneg(struct phy_device *phydev); > +int at803x_get_tunable(struct phy_device *phydev, > + struct ethtool_tunable *tuna, void *data); > +int at803x_set_tunable(struct phy_device *phydev, > + struct ethtool_tunable *tuna, const void *data); > +int at803x_cdt_fault_length(int dt); > +int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start); > +int at803x_cdt_wait_for_completion(struct phy_device *phydev, > + u32 cdt_en); > -- > 2.43.0 >
diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c index 638babc50df1..442060793854 100644 --- a/drivers/net/phy/qcom/at803x.c +++ b/drivers/net/phy/qcom/at803x.c @@ -24,65 +24,11 @@ #include "qcom.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 GENMASK(15, 14) -#define AT803X_SS_SPEED_1000 2 -#define AT803X_SS_SPEED_100 1 -#define AT803X_SS_SPEED_10 0 -#define AT803X_SS_DUPLEX BIT(13) -#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) -#define AT803X_SS_MDIX BIT(6) - -#define QCA808X_SS_SPEED_MASK GENMASK(9, 7) -#define QCA808X_SS_SPEED_2500 4 - -#define AT803X_INTR_ENABLE 0x12 -#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) -#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) -#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) -#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) -#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) -#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) -#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) -#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) -#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) -#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) -#define AT803X_INTR_ENABLE_WOL BIT(0) - -#define AT803X_INTR_STATUS 0x13 - -#define AT803X_SMART_SPEED 0x14 -#define AT803X_SMART_SPEED_ENABLE BIT(5) -#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) -#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) -#define AT803X_CDT 0x16 -#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) -#define AT803X_CDT_ENABLE_TEST BIT(0) -#define AT803X_CDT_STATUS 0x1c -#define AT803X_CDT_STATUS_STAT_NORMAL 0 -#define AT803X_CDT_STATUS_STAT_SHORT 1 -#define AT803X_CDT_STATUS_STAT_OPEN 2 -#define AT803X_CDT_STATUS_STAT_FAIL 3 -#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) -#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) #define AT803X_LED_CONTROL 0x18 #define AT803X_PHY_MMD3_WOL_CTRL 0x8012 #define AT803X_WOL_EN BIT(5) -#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C -#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B -#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A + #define AT803X_REG_CHIP_CONFIG 0x1f #define AT803X_BT_BX_REG_SEL 0x8000 @@ -138,10 +84,6 @@ #define AT803X_CLK_OUT_STRENGTH_HALF 1 #define AT803X_CLK_OUT_STRENGTH_QUARTER 2 -#define AT803X_DEFAULT_DOWNSHIFT 5 -#define AT803X_MIN_DOWNSHIFT 2 -#define AT803X_MAX_DOWNSHIFT 9 - #define AT803X_MMD3_SMARTEEE_CTL1 0x805b #define AT803X_MMD3_SMARTEEE_CTL2 0x805c #define AT803X_MMD3_SMARTEEE_CTL3 0x805d @@ -158,6 +100,8 @@ #define QCA9561_PHY_ID 0x004dd042 +#define AT803X_SS_SPEED_MASK GENMASK(15, 14) + #define AT803X_PAGE_FIBER 0 #define AT803X_PAGE_COPPER 1 @@ -366,11 +310,6 @@ MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); -struct at803x_ss_mask { - u16 speed_mask; - u8 speed_shift; -}; - struct at803x_priv { int flags; u16 clk_25m_reg; @@ -470,80 +409,6 @@ static void at803x_context_restore(struct phy_device *phydev, phy_write(phydev, AT803X_LED_CONTROL, context->led_control); } -static int at803x_set_wol(struct phy_device *phydev, - struct ethtool_wolinfo *wol) -{ - int ret, irq_enabled; - - if (wol->wolopts & WAKE_MAGIC) { - struct net_device *ndev = phydev->attached_dev; - const u8 *mac; - unsigned int i; - static const unsigned int offsets[] = { - AT803X_LOC_MAC_ADDR_32_47_OFFSET, - AT803X_LOC_MAC_ADDR_16_31_OFFSET, - AT803X_LOC_MAC_ADDR_0_15_OFFSET, - }; - - if (!ndev) - return -ENODEV; - - mac = (const u8 *)ndev->dev_addr; - - if (!is_valid_ether_addr(mac)) - return -EINVAL; - - for (i = 0; i < 3; i++) - phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], - mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); - - /* Enable WOL interrupt */ - ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); - if (ret) - return ret; - } else { - /* Disable WOL interrupt */ - ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); - if (ret) - return ret; - } - - /* Clear WOL status */ - ret = phy_read(phydev, AT803X_INTR_STATUS); - if (ret < 0) - return ret; - - /* Check if there are other interrupts except for WOL triggered when PHY is - * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can - * be passed up to the interrupt PIN. - */ - irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); - if (irq_enabled < 0) - return irq_enabled; - - irq_enabled &= ~AT803X_INTR_ENABLE_WOL; - if (ret & irq_enabled && !phy_polling_mode(phydev)) - phy_trigger_machine(phydev); - - return 0; -} - -static void at803x_get_wol(struct phy_device *phydev, - struct ethtool_wolinfo *wol) -{ - int value; - - wol->supported = WAKE_MAGIC; - wol->wolopts = 0; - - value = phy_read(phydev, AT803X_INTR_ENABLE); - if (value < 0) - return; - - if (value & AT803X_INTR_ENABLE_WOL) - wol->wolopts |= WAKE_MAGIC; -} - static int at803x_suspend(struct phy_device *phydev) { int value; @@ -816,73 +681,6 @@ static int at803x_config_init(struct phy_device *phydev) return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); } -static int at803x_ack_interrupt(struct phy_device *phydev) -{ - int err; - - err = phy_read(phydev, AT803X_INTR_STATUS); - - return (err < 0) ? err : 0; -} - -static int at803x_config_intr(struct phy_device *phydev) -{ - int err; - int value; - - value = phy_read(phydev, AT803X_INTR_ENABLE); - - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { - /* Clear any pending interrupts */ - err = at803x_ack_interrupt(phydev); - if (err) - return err; - - value |= AT803X_INTR_ENABLE_AUTONEG_ERR; - value |= AT803X_INTR_ENABLE_SPEED_CHANGED; - value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; - value |= AT803X_INTR_ENABLE_LINK_FAIL; - value |= AT803X_INTR_ENABLE_LINK_SUCCESS; - - err = phy_write(phydev, AT803X_INTR_ENABLE, value); - } else { - err = phy_write(phydev, AT803X_INTR_ENABLE, 0); - if (err) - return err; - - /* Clear any pending interrupts */ - err = at803x_ack_interrupt(phydev); - } - - return err; -} - -static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) -{ - int irq_status, int_enabled; - - irq_status = phy_read(phydev, AT803X_INTR_STATUS); - if (irq_status < 0) { - phy_error(phydev); - return IRQ_NONE; - } - - /* Read the current enabled interrupts */ - int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); - if (int_enabled < 0) { - phy_error(phydev); - return IRQ_NONE; - } - - /* See if this was one of our enabled interrupts */ - if (!(irq_status & int_enabled)) - return IRQ_NONE; - - phy_trigger_machine(phydev); - - return IRQ_HANDLED; -} - static void at803x_link_change_notify(struct phy_device *phydev) { /* @@ -908,69 +706,6 @@ static void at803x_link_change_notify(struct phy_device *phydev) } } -static int at803x_read_specific_status(struct phy_device *phydev, - struct at803x_ss_mask ss_mask) -{ - int ss; - - /* Read the AT8035 PHY-Specific Status register, which indicates the - * speed and duplex that the PHY is actually using, irrespective of - * whether we are in autoneg mode or not. - */ - ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); - if (ss < 0) - return ss; - - if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { - int sfc, speed; - - sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); - if (sfc < 0) - return sfc; - - speed = ss & ss_mask.speed_mask; - speed >>= ss_mask.speed_shift; - - switch (speed) { - case AT803X_SS_SPEED_10: - phydev->speed = SPEED_10; - break; - case AT803X_SS_SPEED_100: - phydev->speed = SPEED_100; - break; - case AT803X_SS_SPEED_1000: - phydev->speed = SPEED_1000; - break; - case QCA808X_SS_SPEED_2500: - phydev->speed = SPEED_2500; - break; - } - if (ss & AT803X_SS_DUPLEX) - 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; - } - } - - return 0; -} - static int at803x_read_status(struct phy_device *phydev) { struct at803x_ss_mask ss_mask = { 0 }; @@ -1006,50 +741,6 @@ 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_prepare_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 0; -} - static int at803x_config_aneg(struct phy_device *phydev) { struct at803x_priv *priv = phydev->priv; @@ -1065,80 +756,6 @@ static int at803x_config_aneg(struct phy_device *phydev) return genphy_config_aneg(phydev); } -static int at803x_get_downshift(struct phy_device *phydev, u8 *d) -{ - int val; - - val = phy_read(phydev, AT803X_SMART_SPEED); - if (val < 0) - return val; - - if (val & AT803X_SMART_SPEED_ENABLE) - *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; - else - *d = DOWNSHIFT_DEV_DISABLE; - - return 0; -} - -static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) -{ - u16 mask, set; - int ret; - - switch (cnt) { - case DOWNSHIFT_DEV_DEFAULT_COUNT: - cnt = AT803X_DEFAULT_DOWNSHIFT; - fallthrough; - case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: - set = AT803X_SMART_SPEED_ENABLE | - AT803X_SMART_SPEED_BYPASS_TIMER | - FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); - mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; - break; - case DOWNSHIFT_DEV_DISABLE: - set = 0; - mask = AT803X_SMART_SPEED_ENABLE | - AT803X_SMART_SPEED_BYPASS_TIMER; - break; - default: - return -EINVAL; - } - - ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); - - /* After changing the smart speed settings, we need to perform a - * software reset, use phy_init_hw() to make sure we set the - * reapply any values which might got lost during software reset. - */ - if (ret == 1) - ret = phy_init_hw(phydev); - - return ret; -} - -static int at803x_get_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, void *data) -{ - switch (tuna->id) { - case ETHTOOL_PHY_DOWNSHIFT: - return at803x_get_downshift(phydev, data); - default: - return -EOPNOTSUPP; - } -} - -static int at803x_set_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, const void *data) -{ - switch (tuna->id) { - case ETHTOOL_PHY_DOWNSHIFT: - return at803x_set_downshift(phydev, *(const u8 *)data); - default: - return -EOPNOTSUPP; - } -} - static int at803x_cable_test_result_trans(u16 status) { switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { @@ -1170,45 +787,6 @@ static bool at803x_cdt_fault_length_valid(u16 status) return false; } -static int at803x_cdt_fault_length(int dt) -{ - /* According to the datasheet the distance to the fault is - * DELTA_TIME * 0.824 meters. - * - * The author suspect the correct formula is: - * - * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 - * - * where c is the speed of light, VF is the velocity factor of - * the twisted pair cable, 125MHz the counter frequency and - * we need to divide by 2 because the hardware will measure the - * round trip time to the fault and back to the PHY. - * - * With a VF of 0.69 we get the factor 0.824 mentioned in the - * datasheet. - */ - return (dt * 824) / 10; -} - -static int at803x_cdt_start(struct phy_device *phydev, - u32 cdt_start) -{ - return phy_write(phydev, AT803X_CDT, cdt_start); -} - -static int at803x_cdt_wait_for_completion(struct phy_device *phydev, - u32 cdt_en) -{ - int val, ret; - - /* One test run takes about 25ms */ - ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, - !(val & cdt_en), - 30000, 100000, true); - - return ret < 0 ? ret : 0; -} - static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair) { static const int ethtool_pair[] = { diff --git a/drivers/net/phy/qcom/qcom-phy-lib.c b/drivers/net/phy/qcom/qcom-phy-lib.c index 7192184429b7..e0295d4b4a51 100644 --- a/drivers/net/phy/qcom/qcom-phy-lib.c +++ b/drivers/net/phy/qcom/qcom-phy-lib.c @@ -3,6 +3,9 @@ #include <linux/phy.h> #include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> + #include "qcom.h" MODULE_DESCRIPTION("Qualcomm PHY driver Common Functions"); @@ -51,3 +54,376 @@ int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data) return phy_write(phydev, AT803X_DEBUG_DATA, data); } EXPORT_SYMBOL_GPL(at803x_debug_reg_write); + +int at803x_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int ret, irq_enabled; + + if (wol->wolopts & WAKE_MAGIC) { + struct net_device *ndev = phydev->attached_dev; + const u8 *mac; + unsigned int i; + static const unsigned int offsets[] = { + AT803X_LOC_MAC_ADDR_32_47_OFFSET, + AT803X_LOC_MAC_ADDR_16_31_OFFSET, + AT803X_LOC_MAC_ADDR_0_15_OFFSET, + }; + + if (!ndev) + return -ENODEV; + + mac = (const u8 *)ndev->dev_addr; + + if (!is_valid_ether_addr(mac)) + return -EINVAL; + + for (i = 0; i < 3; i++) + phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], + mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); + + /* Enable WOL interrupt */ + ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); + if (ret) + return ret; + } else { + /* Disable WOL interrupt */ + ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); + if (ret) + return ret; + } + + /* Clear WOL status */ + ret = phy_read(phydev, AT803X_INTR_STATUS); + if (ret < 0) + return ret; + + /* Check if there are other interrupts except for WOL triggered when PHY is + * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can + * be passed up to the interrupt PIN. + */ + irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); + if (irq_enabled < 0) + return irq_enabled; + + irq_enabled &= ~AT803X_INTR_ENABLE_WOL; + if (ret & irq_enabled && !phy_polling_mode(phydev)) + phy_trigger_machine(phydev); + + return 0; +} +EXPORT_SYMBOL_GPL(at803x_set_wol); + +void at803x_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int value; + + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + + value = phy_read(phydev, AT803X_INTR_ENABLE); + if (value < 0) + return; + + if (value & AT803X_INTR_ENABLE_WOL) + wol->wolopts |= WAKE_MAGIC; +} +EXPORT_SYMBOL_GPL(at803x_get_wol); + +int at803x_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read(phydev, AT803X_INTR_STATUS); + + return (err < 0) ? err : 0; +} +EXPORT_SYMBOL_GPL(at803x_ack_interrupt); + +int at803x_config_intr(struct phy_device *phydev) +{ + int err; + int value; + + value = phy_read(phydev, AT803X_INTR_ENABLE); + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* Clear any pending interrupts */ + err = at803x_ack_interrupt(phydev); + if (err) + return err; + + value |= AT803X_INTR_ENABLE_AUTONEG_ERR; + value |= AT803X_INTR_ENABLE_SPEED_CHANGED; + value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; + value |= AT803X_INTR_ENABLE_LINK_FAIL; + value |= AT803X_INTR_ENABLE_LINK_SUCCESS; + + err = phy_write(phydev, AT803X_INTR_ENABLE, value); + } else { + err = phy_write(phydev, AT803X_INTR_ENABLE, 0); + if (err) + return err; + + /* Clear any pending interrupts */ + err = at803x_ack_interrupt(phydev); + } + + return err; +} +EXPORT_SYMBOL_GPL(at803x_config_intr); + +irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) +{ + int irq_status, int_enabled; + + irq_status = phy_read(phydev, AT803X_INTR_STATUS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* Read the current enabled interrupts */ + int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); + if (int_enabled < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* See if this was one of our enabled interrupts */ + if (!(irq_status & int_enabled)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(at803x_handle_interrupt); + +int at803x_read_specific_status(struct phy_device *phydev, + struct at803x_ss_mask ss_mask) +{ + int ss; + + /* Read the AT8035 PHY-Specific Status register, which indicates the + * speed and duplex that the PHY is actually using, irrespective of + * whether we are in autoneg mode or not. + */ + ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); + if (ss < 0) + return ss; + + if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { + int sfc, speed; + + sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); + if (sfc < 0) + return sfc; + + speed = ss & ss_mask.speed_mask; + speed >>= ss_mask.speed_shift; + + switch (speed) { + case AT803X_SS_SPEED_10: + phydev->speed = SPEED_10; + break; + case AT803X_SS_SPEED_100: + phydev->speed = SPEED_100; + break; + case AT803X_SS_SPEED_1000: + phydev->speed = SPEED_1000; + break; + case QCA808X_SS_SPEED_2500: + phydev->speed = SPEED_2500; + break; + } + if (ss & AT803X_SS_DUPLEX) + 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; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(at803x_read_specific_status); + +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)); +} +EXPORT_SYMBOL_GPL(at803x_config_mdix); + +int at803x_prepare_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 0; +} +EXPORT_SYMBOL_GPL(at803x_prepare_config_aneg); + +static int at803x_get_downshift(struct phy_device *phydev, u8 *d) +{ + int val; + + val = phy_read(phydev, AT803X_SMART_SPEED); + if (val < 0) + return val; + + if (val & AT803X_SMART_SPEED_ENABLE) + *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; + else + *d = DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) +{ + u16 mask, set; + int ret; + + switch (cnt) { + case DOWNSHIFT_DEV_DEFAULT_COUNT: + cnt = AT803X_DEFAULT_DOWNSHIFT; + fallthrough; + case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: + set = AT803X_SMART_SPEED_ENABLE | + AT803X_SMART_SPEED_BYPASS_TIMER | + FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); + mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; + break; + case DOWNSHIFT_DEV_DISABLE: + set = 0; + mask = AT803X_SMART_SPEED_ENABLE | + AT803X_SMART_SPEED_BYPASS_TIMER; + break; + default: + return -EINVAL; + } + + ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); + + /* After changing the smart speed settings, we need to perform a + * software reset, use phy_init_hw() to make sure we set the + * reapply any values which might got lost during software reset. + */ + if (ret == 1) + ret = phy_init_hw(phydev); + + return ret; +} + +int at803x_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return at803x_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(at803x_get_tunable); + +int at803x_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return at803x_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(at803x_set_tunable); + +int at803x_cdt_fault_length(int dt) +{ + /* According to the datasheet the distance to the fault is + * DELTA_TIME * 0.824 meters. + * + * The author suspect the correct formula is: + * + * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 + * + * where c is the speed of light, VF is the velocity factor of + * the twisted pair cable, 125MHz the counter frequency and + * we need to divide by 2 because the hardware will measure the + * round trip time to the fault and back to the PHY. + * + * With a VF of 0.69 we get the factor 0.824 mentioned in the + * datasheet. + */ + return (dt * 824) / 10; +} +EXPORT_SYMBOL_GPL(at803x_cdt_fault_length); + +int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start) +{ + return phy_write(phydev, AT803X_CDT, cdt_start); +} +EXPORT_SYMBOL_GPL(at803x_cdt_start); + +int at803x_cdt_wait_for_completion(struct phy_device *phydev, + u32 cdt_en) +{ + int val, ret; + + /* One test run takes about 25ms */ + ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, + !(val & cdt_en), + 30000, 100000, true); + + return ret < 0 ? ret : 0; +} +EXPORT_SYMBOL_GPL(at803x_cdt_wait_for_completion); diff --git a/drivers/net/phy/qcom/qcom.h b/drivers/net/phy/qcom/qcom.h index 8eb476d7c282..344f8c01d5b8 100644 --- a/drivers/net/phy/qcom/qcom.h +++ b/drivers/net/phy/qcom/qcom.h @@ -1,5 +1,61 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#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_1000 2 +#define AT803X_SS_SPEED_100 1 +#define AT803X_SS_SPEED_10 0 +#define AT803X_SS_DUPLEX BIT(13) +#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) +#define AT803X_SS_MDIX BIT(6) + +#define QCA808X_SS_SPEED_2500 4 + +#define AT803X_INTR_ENABLE 0x12 +#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) +#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) +#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) +#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) +#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) +#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) +#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) +#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) +#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) +#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) +#define AT803X_INTR_ENABLE_WOL BIT(0) + +#define AT803X_INTR_STATUS 0x13 + +#define AT803X_SMART_SPEED 0x14 +#define AT803X_SMART_SPEED_ENABLE BIT(5) +#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) +#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) + +#define AT803X_CDT 0x16 +#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) +#define AT803X_CDT_ENABLE_TEST BIT(0) +#define AT803X_CDT_STATUS 0x1c +#define AT803X_CDT_STATUS_STAT_NORMAL 0 +#define AT803X_CDT_STATUS_STAT_SHORT 1 +#define AT803X_CDT_STATUS_STAT_OPEN 2 +#define AT803X_CDT_STATUS_STAT_FAIL 3 +#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) +#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) + +#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C +#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B +#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A + #define AT803X_DEBUG_ADDR 0x1D #define AT803X_DEBUG_DATA 0x1E @@ -16,6 +72,10 @@ #define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) #define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15) +#define AT803X_DEFAULT_DOWNSHIFT 5 +#define AT803X_MIN_DOWNSHIFT 2 +#define AT803X_MAX_DOWNSHIFT 9 + enum stat_access_type { PHY, MMD @@ -28,7 +88,31 @@ struct at803x_hw_stat { enum stat_access_type access_type; }; +struct at803x_ss_mask { + u16 speed_mask; + u8 speed_shift; +}; + int at803x_debug_reg_read(struct phy_device *phydev, u16 reg); int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, u16 clear, u16 set); int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data); +int at803x_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol); +void at803x_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol); +int at803x_ack_interrupt(struct phy_device *phydev); +int at803x_config_intr(struct phy_device *phydev); +irqreturn_t at803x_handle_interrupt(struct phy_device *phydev); +int at803x_read_specific_status(struct phy_device *phydev, + struct at803x_ss_mask ss_mask); +int at803x_config_mdix(struct phy_device *phydev, u8 ctrl); +int at803x_prepare_config_aneg(struct phy_device *phydev); +int at803x_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data); +int at803x_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data); +int at803x_cdt_fault_length(int dt); +int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start); +int at803x_cdt_wait_for_completion(struct phy_device *phydev, + u32 cdt_en);
Move additional functions to shared library in preparation for qca808x PHY Family to be detached from at803x driver. Only the shared defines are moved to the shared qcom.h header. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> --- drivers/net/phy/qcom/at803x.c | 428 +--------------------------- drivers/net/phy/qcom/qcom-phy-lib.c | 376 ++++++++++++++++++++++++ drivers/net/phy/qcom/qcom.h | 84 ++++++ 3 files changed, 463 insertions(+), 425 deletions(-)