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
-
-#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
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
>
--
Ansuel
© 2016 - 2025 Red Hat, Inc.