summaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/at803x.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:12 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:12 +0000
commit8665bd53f2f2e27e5511d90428cb3f60e6d0ce15 (patch)
tree8d58900dc0ebd4a3011f92c128d2fe45bc7c4bf2 /drivers/net/phy/at803x.c
parentAdding debian version 6.7.12-1. (diff)
downloadlinux-8665bd53f2f2e27e5511d90428cb3f60e6d0ce15.tar.xz
linux-8665bd53f2f2e27e5511d90428cb3f60e6d0ce15.zip
Merging upstream version 6.8.9.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/net/phy/at803x.c')
-rw-r--r--drivers/net/phy/at803x.c1090
1 files changed, 638 insertions, 452 deletions
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index ef203b0807..fdb89a505d 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -254,6 +254,7 @@
#define QCA808X_CDT_ENABLE_TEST BIT(15)
#define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
+#define QCA808X_CDT_STATUS BIT(11)
#define QCA808X_CDT_LENGTH_UNIT BIT(10)
#define QCA808X_MMD3_CDT_STATUS 0x8064
@@ -261,16 +262,44 @@
#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
-#define QCA808X_CDT_DIAG_LENGTH GENMASK(7, 0)
+#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
+#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
-#define QCA808X_CDT_STATUS_STAT_FAIL 0
-#define QCA808X_CDT_STATUS_STAT_NORMAL 1
-#define QCA808X_CDT_STATUS_STAT_OPEN 2
-#define QCA808X_CDT_STATUS_STAT_SHORT 3
+
+#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
+#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
+#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
+#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
+#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
+
+#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
+#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
+#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
+#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
+
+/* NORMAL are MDI with type set to 0 */
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
+ QCA808X_CDT_STATUS_STAT_MDI1)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
+ QCA808X_CDT_STATUS_STAT_MDI1)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
+ QCA808X_CDT_STATUS_STAT_MDI2)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
+ QCA808X_CDT_STATUS_STAT_MDI2)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
+ QCA808X_CDT_STATUS_STAT_MDI3)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
+ QCA808X_CDT_STATUS_STAT_MDI3)
+
+/* Added for reference of existence but should be handled by wait_for_completion already */
+#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
/* QCA808X 1G chip type */
#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d
@@ -295,12 +324,17 @@ struct at803x_hw_stat {
enum stat_access_type access_type;
};
-static struct at803x_hw_stat at803x_hw_stats[] = {
+static struct at803x_hw_stat qca83xx_hw_stats[] = {
{ "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
{ "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
{ "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
};
+struct at803x_ss_mask {
+ u16 speed_mask;
+ u8 speed_shift;
+};
+
struct at803x_priv {
int flags;
u16 clk_25m_reg;
@@ -311,7 +345,7 @@ struct at803x_priv {
bool is_1000basex;
struct regulator_dev *vddio_rdev;
struct regulator_dev *vddh_rdev;
- u64 stats[ARRAY_SIZE(at803x_hw_stats)];
+ u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
};
struct at803x_context {
@@ -457,7 +491,7 @@ static int at803x_set_wol(struct phy_device *phydev,
if (!ndev)
return -ENODEV;
- mac = (const u8 *) ndev->dev_addr;
+ mac = (const u8 *)ndev->dev_addr;
if (!is_valid_ether_addr(mac))
return -EINVAL;
@@ -466,27 +500,11 @@ static int at803x_set_wol(struct phy_device *phydev,
phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i],
mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
- /* Enable WOL function for 1588 */
- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
- AT803X_PHY_MMD3_WOL_CTRL,
- 0, AT803X_WOL_EN);
- if (ret)
- return ret;
- }
/* Enable WOL interrupt */
ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL);
if (ret)
return ret;
} else {
- /* Disable WoL function for 1588 */
- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
- AT803X_PHY_MMD3_WOL_CTRL,
- AT803X_WOL_EN, 0);
- if (ret)
- return ret;
- }
/* Disable WOL interrupt */
ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0);
if (ret)
@@ -529,24 +547,24 @@ static void at803x_get_wol(struct phy_device *phydev,
wol->wolopts |= WAKE_MAGIC;
}
-static int at803x_get_sset_count(struct phy_device *phydev)
+static int qca83xx_get_sset_count(struct phy_device *phydev)
{
- return ARRAY_SIZE(at803x_hw_stats);
+ return ARRAY_SIZE(qca83xx_hw_stats);
}
-static void at803x_get_strings(struct phy_device *phydev, u8 *data)
+static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
{
int i;
- for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) {
+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
strscpy(data + i * ETH_GSTRING_LEN,
- at803x_hw_stats[i].string, ETH_GSTRING_LEN);
+ qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
}
}
-static u64 at803x_get_stat(struct phy_device *phydev, int i)
+static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
{
- struct at803x_hw_stat stat = at803x_hw_stats[i];
+ struct at803x_hw_stat stat = qca83xx_hw_stats[i];
struct at803x_priv *priv = phydev->priv;
int val;
u64 ret;
@@ -567,13 +585,13 @@ static u64 at803x_get_stat(struct phy_device *phydev, int i)
return ret;
}
-static void at803x_get_stats(struct phy_device *phydev,
- struct ethtool_stats *stats, u64 *data)
+static void qca83xx_get_stats(struct phy_device *phydev,
+ struct ethtool_stats *stats, u64 *data)
{
int i;
- for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++)
- data[i] = at803x_get_stat(phydev, i);
+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
+ data[i] = qca83xx_get_stat(phydev, i);
}
static int at803x_suspend(struct phy_device *phydev)
@@ -599,139 +617,6 @@ static int at803x_resume(struct phy_device *phydev)
return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
}
-static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
- unsigned int selector)
-{
- struct phy_device *phydev = rdev_get_drvdata(rdev);
-
- if (selector)
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
- 0, AT803X_DEBUG_RGMII_1V8);
- else
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
- AT803X_DEBUG_RGMII_1V8, 0);
-}
-
-static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct phy_device *phydev = rdev_get_drvdata(rdev);
- int val;
-
- val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
- if (val < 0)
- return val;
-
- return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
-}
-
-static const struct regulator_ops vddio_regulator_ops = {
- .list_voltage = regulator_list_voltage_table,
- .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel,
- .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel,
-};
-
-static const unsigned int vddio_voltage_table[] = {
- 1500000,
- 1800000,
-};
-
-static const struct regulator_desc vddio_desc = {
- .name = "vddio",
- .of_match = of_match_ptr("vddio-regulator"),
- .n_voltages = ARRAY_SIZE(vddio_voltage_table),
- .volt_table = vddio_voltage_table,
- .ops = &vddio_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
-};
-
-static const struct regulator_ops vddh_regulator_ops = {
-};
-
-static const struct regulator_desc vddh_desc = {
- .name = "vddh",
- .of_match = of_match_ptr("vddh-regulator"),
- .n_voltages = 1,
- .fixed_uV = 2500000,
- .ops = &vddh_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
-};
-
-static int at8031_register_regulators(struct phy_device *phydev)
-{
- struct at803x_priv *priv = phydev->priv;
- struct device *dev = &phydev->mdio.dev;
- struct regulator_config config = { };
-
- config.dev = dev;
- config.driver_data = phydev;
-
- priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
- if (IS_ERR(priv->vddio_rdev)) {
- phydev_err(phydev, "failed to register VDDIO regulator\n");
- return PTR_ERR(priv->vddio_rdev);
- }
-
- priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
- if (IS_ERR(priv->vddh_rdev)) {
- phydev_err(phydev, "failed to register VDDH regulator\n");
- return PTR_ERR(priv->vddh_rdev);
- }
-
- return 0;
-}
-
-static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-{
- struct phy_device *phydev = upstream;
- __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
- __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
- DECLARE_PHY_INTERFACE_MASK(interfaces);
- phy_interface_t iface;
-
- linkmode_zero(phy_support);
- phylink_set(phy_support, 1000baseX_Full);
- phylink_set(phy_support, 1000baseT_Full);
- phylink_set(phy_support, Autoneg);
- phylink_set(phy_support, Pause);
- phylink_set(phy_support, Asym_Pause);
-
- linkmode_zero(sfp_support);
- sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
- /* Some modules support 10G modes as well as others we support.
- * Mask out non-supported modes so the correct interface is picked.
- */
- linkmode_and(sfp_support, phy_support, sfp_support);
-
- if (linkmode_empty(sfp_support)) {
- dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
- return -EINVAL;
- }
-
- iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
-
- /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes
- * interface for use with SFP modules.
- * However, some copper modules detected as having a preferred SGMII
- * interface do default to and function in 1000Base-X mode, so just
- * print a warning and allow such modules, as they may have some chance
- * of working.
- */
- if (iface == PHY_INTERFACE_MODE_SGMII)
- dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n");
- else if (iface != PHY_INTERFACE_MODE_1000BASEX)
- return -EINVAL;
-
- return 0;
-}
-
-static const struct sfp_upstream_ops at803x_sfp_ops = {
- .attach = phy_sfp_attach,
- .detach = phy_sfp_detach,
- .module_insert = at803x_sfp_insert,
-};
-
static int at803x_parse_dt(struct phy_device *phydev)
{
struct device_node *node = phydev->mdio.dev.of_node;
@@ -787,23 +672,6 @@ static int at803x_parse_dt(struct phy_device *phydev)
priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel);
priv->clk_25m_mask |= AT803X_CLK_OUT_MASK;
-
- /* Fixup for the AR8030/AR8035. This chip has another mask and
- * doesn't support the DSP reference. Eg. the lowest bit of the
- * mask. The upper two bits select the same frequencies. Mask
- * the lowest bit here.
- *
- * Warning:
- * There was no datasheet for the AR8030 available so this is
- * just a guess. But the AR8035 is listed as pin compatible
- * to the AR8030 so there might be a good chance it works on
- * the AR8030 too.
- */
- if (phydev->drv->phy_id == ATH8030_PHY_ID ||
- phydev->drv->phy_id == ATH8035_PHY_ID) {
- priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
- priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
- }
}
ret = of_property_read_u32(node, "qca,clk-out-strength", &strength);
@@ -825,30 +693,6 @@ static int at803x_parse_dt(struct phy_device *phydev)
}
}
- /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
- * options.
- */
- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
- if (of_property_read_bool(node, "qca,keep-pll-enabled"))
- priv->flags |= AT803X_KEEP_PLL_ENABLED;
-
- ret = at8031_register_regulators(phydev);
- if (ret < 0)
- return ret;
-
- ret = devm_regulator_get_enable_optional(&phydev->mdio.dev,
- "vddio");
- if (ret) {
- phydev_err(phydev, "failed to get VDDIO regulator\n");
- return ret;
- }
-
- /* Only AR8031/8033 support 1000Base-X for SFP modules */
- ret = phy_sfp_probe(phydev, &at803x_sfp_ops);
- if (ret < 0)
- return ret;
- }
-
return 0;
}
@@ -868,35 +712,6 @@ static int at803x_probe(struct phy_device *phydev)
if (ret)
return ret;
- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
- int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
- int mode_cfg;
-
- if (ccr < 0)
- return ccr;
- mode_cfg = ccr & AT803X_MODE_CFG_MASK;
-
- switch (mode_cfg) {
- case AT803X_MODE_CFG_BX1000_RGMII_50OHM:
- case AT803X_MODE_CFG_BX1000_RGMII_75OHM:
- priv->is_1000basex = true;
- fallthrough;
- case AT803X_MODE_CFG_FX100_RGMII_50OHM:
- case AT803X_MODE_CFG_FX100_RGMII_75OHM:
- priv->is_fiber = true;
- break;
- }
-
- /* Disable WoL in 1588 register which is enabled
- * by default
- */
- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
- AT803X_PHY_MMD3_WOL_CTRL,
- AT803X_WOL_EN, 0);
- if (ret)
- return ret;
- }
-
return 0;
}
@@ -1004,27 +819,8 @@ static int at803x_hibernation_mode_config(struct phy_device *phydev)
static int at803x_config_init(struct phy_device *phydev)
{
- struct at803x_priv *priv = phydev->priv;
int ret;
- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
- /* Some bootloaders leave the fiber page selected.
- * Switch to the appropriate page (fiber or copper), as otherwise we
- * read the PHY capabilities from the wrong page.
- */
- phy_lock_mdio_bus(phydev);
- ret = at803x_write_page(phydev,
- priv->is_fiber ? AT803X_PAGE_FIBER :
- AT803X_PAGE_COPPER);
- phy_unlock_mdio_bus(phydev);
- if (ret)
- return ret;
-
- ret = at8031_pll_config(phydev);
- if (ret < 0)
- return ret;
- }
-
/* The RX and TX delay default is:
* after HW reset: RX delay enabled and TX delay disabled
* after SW reset: RX delay enabled, while TX delay retains the
@@ -1078,7 +874,6 @@ static int at803x_ack_interrupt(struct phy_device *phydev)
static int at803x_config_intr(struct phy_device *phydev)
{
- struct at803x_priv *priv = phydev->priv;
int err;
int value;
@@ -1095,10 +890,6 @@ static int at803x_config_intr(struct phy_device *phydev)
value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
value |= AT803X_INTR_ENABLE_LINK_FAIL;
value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
- if (priv->is_fiber) {
- value |= AT803X_INTR_ENABLE_LINK_FAIL_BX;
- value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX;
- }
err = phy_write(phydev, AT803X_INTR_ENABLE, value);
} else {
@@ -1154,9 +945,9 @@ static void at803x_link_change_notify(struct phy_device *phydev)
at803x_context_save(phydev, &context);
phy_device_reset(phydev, 1);
- msleep(1);
+ usleep_range(1000, 2000);
phy_device_reset(phydev, 0);
- msleep(1);
+ usleep_range(1000, 2000);
at803x_context_restore(phydev, &context);
@@ -1164,7 +955,8 @@ static void at803x_link_change_notify(struct phy_device *phydev)
}
}
-static int at803x_read_specific_status(struct phy_device *phydev)
+static int at803x_read_specific_status(struct phy_device *phydev,
+ struct at803x_ss_mask ss_mask)
{
int ss;
@@ -1183,11 +975,8 @@ static int at803x_read_specific_status(struct phy_device *phydev)
if (sfc < 0)
return sfc;
- /* qca8081 takes the different bits for speed value from at803x */
- if (phydev->drv->phy_id == QCA8081_PHY_ID)
- speed = FIELD_GET(QCA808X_SS_SPEED_MASK, ss);
- else
- speed = FIELD_GET(AT803X_SS_SPEED_MASK, ss);
+ speed = ss & ss_mask.speed_mask;
+ speed >>= ss_mask.speed_shift;
switch (speed) {
case AT803X_SS_SPEED_10:
@@ -1231,12 +1020,9 @@ static int at803x_read_specific_status(struct phy_device *phydev)
static int at803x_read_status(struct phy_device *phydev)
{
- struct at803x_priv *priv = phydev->priv;
+ struct at803x_ss_mask ss_mask = { 0 };
int err, old_link = phydev->link;
- if (priv->is_1000basex)
- return genphy_c37_read_status(phydev);
-
/* Update the link, but return if there was an error */
err = genphy_update_link(phydev);
if (err)
@@ -1255,7 +1041,9 @@ static int at803x_read_status(struct phy_device *phydev)
if (err < 0)
return err;
- err = at803x_read_specific_status(phydev);
+ ss_mask.speed_mask = AT803X_SS_SPEED_MASK;
+ ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK);
+ err = at803x_read_specific_status(phydev, ss_mask);
if (err < 0)
return err;
@@ -1288,9 +1076,8 @@ static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
}
-static int at803x_config_aneg(struct phy_device *phydev)
+static int at803x_prepare_config_aneg(struct phy_device *phydev)
{
- struct at803x_priv *priv = phydev->priv;
int ret;
ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
@@ -1307,33 +1094,22 @@ static int at803x_config_aneg(struct phy_device *phydev)
return ret;
}
- if (priv->is_1000basex)
- return genphy_c37_config_aneg(phydev);
-
- /* Do not restart auto-negotiation by setting ret to 0 defautly,
- * when calling __genphy_config_aneg later.
- */
- ret = 0;
-
- if (phydev->drv->phy_id == QCA8081_PHY_ID) {
- int phy_ctrl = 0;
+ return 0;
+}
- /* The reg MII_BMCR also needs to be configured for force mode, the
- * genphy_config_aneg is also needed.
- */
- if (phydev->autoneg == AUTONEG_DISABLE)
- genphy_c45_pma_setup_forced(phydev);
+static int at803x_config_aneg(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+ int ret;
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
- phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
+ ret = at803x_prepare_config_aneg(phydev);
+ if (ret)
+ return ret;
- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
- MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
- if (ret < 0)
- return ret;
- }
+ if (priv->is_1000basex)
+ return genphy_c37_config_aneg(phydev);
- return __genphy_config_aneg(phydev, ret);
+ return genphy_config_aneg(phydev);
}
static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
@@ -1441,10 +1217,8 @@ static bool at803x_cdt_fault_length_valid(u16 status)
return false;
}
-static int at803x_cdt_fault_length(u16 status)
+static int at803x_cdt_fault_length(int dt)
{
- int dt;
-
/* According to the datasheet the distance to the fault is
* DELTA_TIME * 0.824 meters.
*
@@ -1460,36 +1234,19 @@ static int at803x_cdt_fault_length(u16 status)
* With a VF of 0.69 we get the factor 0.824 mentioned in the
* datasheet.
*/
- dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status);
-
return (dt * 824) / 10;
}
-static int at803x_cdt_start(struct phy_device *phydev, int pair)
+static int at803x_cdt_start(struct phy_device *phydev,
+ u32 cdt_start)
{
- u16 cdt;
-
- /* qca8081 takes the different bit 15 to enable CDT test */
- if (phydev->drv->phy_id == QCA8081_PHY_ID)
- cdt = QCA808X_CDT_ENABLE_TEST |
- QCA808X_CDT_LENGTH_UNIT |
- QCA808X_CDT_INTER_CHECK_DIS;
- else
- cdt = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
- AT803X_CDT_ENABLE_TEST;
-
- return phy_write(phydev, AT803X_CDT, cdt);
+ return phy_write(phydev, AT803X_CDT, cdt_start);
}
-static int at803x_cdt_wait_for_completion(struct phy_device *phydev)
+static int at803x_cdt_wait_for_completion(struct phy_device *phydev,
+ u32 cdt_en)
{
int val, ret;
- u16 cdt_en;
-
- if (phydev->drv->phy_id == QCA8081_PHY_ID)
- cdt_en = QCA808X_CDT_ENABLE_TEST;
- else
- cdt_en = AT803X_CDT_ENABLE_TEST;
/* One test run takes about 25ms */
ret = phy_read_poll_timeout(phydev, AT803X_CDT, val,
@@ -1509,11 +1266,13 @@ static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair)
};
int ret, val;
- ret = at803x_cdt_start(phydev, pair);
+ val = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
+ AT803X_CDT_ENABLE_TEST;
+ ret = at803x_cdt_start(phydev, val);
if (ret)
return ret;
- ret = at803x_cdt_wait_for_completion(phydev);
+ ret = at803x_cdt_wait_for_completion(phydev, AT803X_CDT_ENABLE_TEST);
if (ret)
return ret;
@@ -1527,27 +1286,21 @@ static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair)
ethnl_cable_test_result(phydev, ethtool_pair[pair],
at803x_cable_test_result_trans(val));
- if (at803x_cdt_fault_length_valid(val))
+ if (at803x_cdt_fault_length_valid(val)) {
+ val = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, val);
ethnl_cable_test_fault_length(phydev, ethtool_pair[pair],
at803x_cdt_fault_length(val));
+ }
return 1;
}
static int at803x_cable_test_get_status(struct phy_device *phydev,
- bool *finished)
+ bool *finished, unsigned long pair_mask)
{
- unsigned long pair_mask;
int retries = 20;
int pair, ret;
- if (phydev->phy_id == ATH9331_PHY_ID ||
- phydev->phy_id == ATH8032_PHY_ID ||
- phydev->phy_id == QCA9561_PHY_ID)
- pair_mask = 0x3;
- else
- pair_mask = 0xf;
-
*finished = false;
/* According to the datasheet the CDT can be performed when
@@ -1574,7 +1327,7 @@ static int at803x_cable_test_get_status(struct phy_device *phydev,
return 0;
}
-static int at803x_cable_test_start(struct phy_device *phydev)
+static void at803x_cable_test_autoneg(struct phy_device *phydev)
{
/* Enable auto-negotiation, but advertise no capabilities, no link
* will be established. A restart of the auto-negotiation is not
@@ -1582,15 +1335,360 @@ static int at803x_cable_test_start(struct phy_device *phydev)
*/
phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA);
- if (phydev->phy_id != ATH9331_PHY_ID &&
- phydev->phy_id != ATH8032_PHY_ID &&
- phydev->phy_id != QCA9561_PHY_ID)
- phy_write(phydev, MII_CTRL1000, 0);
+}
+
+static int at803x_cable_test_start(struct phy_device *phydev)
+{
+ at803x_cable_test_autoneg(phydev);
+ /* we do all the (time consuming) work later */
+ return 0;
+}
+
+static int at8031_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ struct phy_device *phydev = rdev_get_drvdata(rdev);
+
+ if (selector)
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
+ 0, AT803X_DEBUG_RGMII_1V8);
+ else
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
+ AT803X_DEBUG_RGMII_1V8, 0);
+}
+
+static int at8031_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct phy_device *phydev = rdev_get_drvdata(rdev);
+ int val;
+
+ val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
+ if (val < 0)
+ return val;
+
+ return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
+}
+
+static const struct regulator_ops vddio_regulator_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = at8031_rgmii_reg_set_voltage_sel,
+ .get_voltage_sel = at8031_rgmii_reg_get_voltage_sel,
+};
+
+static const unsigned int vddio_voltage_table[] = {
+ 1500000,
+ 1800000,
+};
+
+static const struct regulator_desc vddio_desc = {
+ .name = "vddio",
+ .of_match = of_match_ptr("vddio-regulator"),
+ .n_voltages = ARRAY_SIZE(vddio_voltage_table),
+ .volt_table = vddio_voltage_table,
+ .ops = &vddio_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+};
+
+static const struct regulator_ops vddh_regulator_ops = {
+};
+
+static const struct regulator_desc vddh_desc = {
+ .name = "vddh",
+ .of_match = of_match_ptr("vddh-regulator"),
+ .n_voltages = 1,
+ .fixed_uV = 2500000,
+ .ops = &vddh_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+};
+
+static int at8031_register_regulators(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+ struct device *dev = &phydev->mdio.dev;
+ struct regulator_config config = { };
+
+ config.dev = dev;
+ config.driver_data = phydev;
+
+ priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
+ if (IS_ERR(priv->vddio_rdev)) {
+ phydev_err(phydev, "failed to register VDDIO regulator\n");
+ return PTR_ERR(priv->vddio_rdev);
+ }
+
+ priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
+ if (IS_ERR(priv->vddh_rdev)) {
+ phydev_err(phydev, "failed to register VDDH regulator\n");
+ return PTR_ERR(priv->vddh_rdev);
+ }
+
+ return 0;
+}
+
+static int at8031_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
+{
+ struct phy_device *phydev = upstream;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
+ DECLARE_PHY_INTERFACE_MASK(interfaces);
+ phy_interface_t iface;
+
+ linkmode_zero(phy_support);
+ phylink_set(phy_support, 1000baseX_Full);
+ phylink_set(phy_support, 1000baseT_Full);
+ phylink_set(phy_support, Autoneg);
+ phylink_set(phy_support, Pause);
+ phylink_set(phy_support, Asym_Pause);
+
+ linkmode_zero(sfp_support);
+ sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
+ /* Some modules support 10G modes as well as others we support.
+ * Mask out non-supported modes so the correct interface is picked.
+ */
+ linkmode_and(sfp_support, phy_support, sfp_support);
+
+ if (linkmode_empty(sfp_support)) {
+ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
+ return -EINVAL;
+ }
+
+ iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
+
+ /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes
+ * interface for use with SFP modules.
+ * However, some copper modules detected as having a preferred SGMII
+ * interface do default to and function in 1000Base-X mode, so just
+ * print a warning and allow such modules, as they may have some chance
+ * of working.
+ */
+ if (iface == PHY_INTERFACE_MODE_SGMII)
+ dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n");
+ else if (iface != PHY_INTERFACE_MODE_1000BASEX)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct sfp_upstream_ops at8031_sfp_ops = {
+ .attach = phy_sfp_attach,
+ .detach = phy_sfp_detach,
+ .module_insert = at8031_sfp_insert,
+};
+
+static int at8031_parse_dt(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ struct at803x_priv *priv = phydev->priv;
+ int ret;
+
+ if (of_property_read_bool(node, "qca,keep-pll-enabled"))
+ priv->flags |= AT803X_KEEP_PLL_ENABLED;
+
+ ret = at8031_register_regulators(phydev);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_regulator_get_enable_optional(&phydev->mdio.dev,
+ "vddio");
+ if (ret) {
+ phydev_err(phydev, "failed to get VDDIO regulator\n");
+ return ret;
+ }
+
+ /* Only AR8031/8033 support 1000Base-X for SFP modules */
+ return phy_sfp_probe(phydev, &at8031_sfp_ops);
+}
+
+static int at8031_probe(struct phy_device *phydev)
+{
+ struct at803x_priv *priv;
+ int mode_cfg;
+ int ccr;
+ int ret;
+
+ ret = at803x_probe(phydev);
+ if (ret)
+ return ret;
+
+ priv = phydev->priv;
+
+ /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
+ * options.
+ */
+ ret = at8031_parse_dt(phydev);
+ if (ret)
+ return ret;
+
+ ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
+ if (ccr < 0)
+ return ccr;
+ mode_cfg = ccr & AT803X_MODE_CFG_MASK;
+
+ switch (mode_cfg) {
+ case AT803X_MODE_CFG_BX1000_RGMII_50OHM:
+ case AT803X_MODE_CFG_BX1000_RGMII_75OHM:
+ priv->is_1000basex = true;
+ fallthrough;
+ case AT803X_MODE_CFG_FX100_RGMII_50OHM:
+ case AT803X_MODE_CFG_FX100_RGMII_75OHM:
+ priv->is_fiber = true;
+ break;
+ }
+
+ /* Disable WoL in 1588 register which is enabled
+ * by default
+ */
+ return phy_modify_mmd(phydev, MDIO_MMD_PCS,
+ AT803X_PHY_MMD3_WOL_CTRL,
+ AT803X_WOL_EN, 0);
+}
+
+static int at8031_config_init(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+ int ret;
+
+ /* Some bootloaders leave the fiber page selected.
+ * Switch to the appropriate page (fiber or copper), as otherwise we
+ * read the PHY capabilities from the wrong page.
+ */
+ phy_lock_mdio_bus(phydev);
+ ret = at803x_write_page(phydev,
+ priv->is_fiber ? AT803X_PAGE_FIBER :
+ AT803X_PAGE_COPPER);
+ phy_unlock_mdio_bus(phydev);
+ if (ret)
+ return ret;
+
+ ret = at8031_pll_config(phydev);
+ if (ret < 0)
+ return ret;
+
+ return at803x_config_init(phydev);
+}
+
+static int at8031_set_wol(struct phy_device *phydev,
+ struct ethtool_wolinfo *wol)
+{
+ int ret;
+
+ /* First setup MAC address and enable WOL interrupt */
+ ret = at803x_set_wol(phydev, wol);
+ if (ret)
+ return ret;
+
+ if (wol->wolopts & WAKE_MAGIC)
+ /* Enable WOL function for 1588 */
+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
+ AT803X_PHY_MMD3_WOL_CTRL,
+ 0, AT803X_WOL_EN);
+ else
+ /* Disable WoL function for 1588 */
+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
+ AT803X_PHY_MMD3_WOL_CTRL,
+ AT803X_WOL_EN, 0);
+
+ return ret;
+}
+
+static int at8031_config_intr(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+ int err, value = 0;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED &&
+ priv->is_fiber) {
+ /* Clear any pending interrupts */
+ err = at803x_ack_interrupt(phydev);
+ if (err)
+ return err;
+
+ value |= AT803X_INTR_ENABLE_LINK_FAIL_BX;
+ value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX;
+
+ err = phy_set_bits(phydev, AT803X_INTR_ENABLE, value);
+ if (err)
+ return err;
+ }
+
+ return at803x_config_intr(phydev);
+}
+/* AR8031 and AR8033 share the same read status logic */
+static int at8031_read_status(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+
+ if (priv->is_1000basex)
+ return genphy_c37_read_status(phydev);
+
+ return at803x_read_status(phydev);
+}
+
+/* AR8031 and AR8035 share the same cable test get status reg */
+static int at8031_cable_test_get_status(struct phy_device *phydev,
+ bool *finished)
+{
+ return at803x_cable_test_get_status(phydev, finished, 0xf);
+}
+
+/* AR8031 and AR8035 share the same cable test start logic */
+static int at8031_cable_test_start(struct phy_device *phydev)
+{
+ at803x_cable_test_autoneg(phydev);
+ phy_write(phydev, MII_CTRL1000, 0);
/* we do all the (time consuming) work later */
return 0;
}
+/* AR8032, AR9331 and QCA9561 share the same cable test get status reg */
+static int at8032_cable_test_get_status(struct phy_device *phydev,
+ bool *finished)
+{
+ return at803x_cable_test_get_status(phydev, finished, 0x3);
+}
+
+static int at8035_parse_dt(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+
+ /* Mask is set by the generic at803x_parse_dt
+ * if property is set. Assume property is set
+ * with the mask not zero.
+ */
+ if (priv->clk_25m_mask) {
+ /* Fixup for the AR8030/AR8035. This chip has another mask and
+ * doesn't support the DSP reference. Eg. the lowest bit of the
+ * mask. The upper two bits select the same frequencies. Mask
+ * the lowest bit here.
+ *
+ * Warning:
+ * There was no datasheet for the AR8030 available so this is
+ * just a guess. But the AR8035 is listed as pin compatible
+ * to the AR8030 so there might be a good chance it works on
+ * the AR8030 too.
+ */
+ priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
+ priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
+ }
+
+ return 0;
+}
+
+/* AR8030 and AR8035 shared the same special mask for clk_25m */
+static int at8035_probe(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = at803x_probe(phydev);
+ if (ret)
+ return ret;
+
+ return at8035_parse_dt(phydev);
+}
+
static int qca83xx_config_init(struct phy_device *phydev)
{
u8 switch_revision;
@@ -1616,27 +1714,26 @@ static int qca83xx_config_init(struct phy_device *phydev)
break;
}
+ /* Following original QCA sourcecode set port to prefer master */
+ phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
+
+ return 0;
+}
+
+static int qca8327_config_init(struct phy_device *phydev)
+{
/* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
* Disable on init and enable only with 100m speed following
* qca original source code.
*/
- if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
- phydev->drv->phy_id == QCA8327_B_PHY_ID)
- at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
- QCA8327_DEBUG_MANU_CTRL_EN, 0);
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
- /* Following original QCA sourcecode set port to prefer master */
- phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
-
- return 0;
+ return qca83xx_config_init(phydev);
}
static void qca83xx_link_change_notify(struct phy_device *phydev)
{
- /* QCA8337 doesn't require DAC Amplitude adjustement */
- if (phydev->drv->phy_id == QCA8337_PHY_ID)
- return;
-
/* Set DAC Amplitude adjustment to +6% for 100m on link running */
if (phydev->state == PHY_RUNNING) {
if (phydev->speed == SPEED_100)
@@ -1672,26 +1769,13 @@ static int qca83xx_resume(struct phy_device *phydev)
if (ret)
return ret;
- msleep(1);
+ usleep_range(1000, 2000);
return 0;
}
static int qca83xx_suspend(struct phy_device *phydev)
{
- u16 mask = 0;
-
- /* Only QCA8337 support actual suspend.
- * QCA8327 cause port unreliability when phy suspend
- * is set.
- */
- if (phydev->drv->phy_id == QCA8337_PHY_ID) {
- genphy_suspend(phydev);
- } else {
- mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
- phy_modify(phydev, MII_BMCR, mask, 0);
- }
-
at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
AT803X_DEBUG_GATE_CLK_IN1000, 0);
@@ -1702,6 +1786,27 @@ static int qca83xx_suspend(struct phy_device *phydev)
return 0;
}
+static int qca8337_suspend(struct phy_device *phydev)
+{
+ /* Only QCA8337 support actual suspend. */
+ genphy_suspend(phydev);
+
+ return qca83xx_suspend(phydev);
+}
+
+static int qca8327_suspend(struct phy_device *phydev)
+{
+ u16 mask = 0;
+
+ /* QCA8327 cause port unreliability when phy suspend
+ * is set.
+ */
+ mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
+ phy_modify(phydev, MII_BMCR, mask, 0);
+
+ return qca83xx_suspend(phydev);
+}
+
static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
{
int ret;
@@ -1712,27 +1817,27 @@ static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
return ret;
phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1,
- QCA808X_TOP_OPTION1_DATA);
+ QCA808X_TOP_OPTION1_DATA);
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,
- QCA808X_MSE_THRESHOLD_20DB_VALUE);
+ QCA808X_MSE_THRESHOLD_20DB_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,
- QCA808X_MSE_THRESHOLD_17DB_VALUE);
+ QCA808X_MSE_THRESHOLD_17DB_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,
- QCA808X_MSE_THRESHOLD_27DB_VALUE);
+ QCA808X_MSE_THRESHOLD_27DB_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,
- QCA808X_MSE_THRESHOLD_28DB_VALUE);
+ QCA808X_MSE_THRESHOLD_28DB_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1,
- QCA808X_MMD3_DEBUG_1_VALUE);
+ QCA808X_MMD3_DEBUG_1_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4,
- QCA808X_MMD3_DEBUG_4_VALUE);
+ QCA808X_MMD3_DEBUG_4_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5,
- QCA808X_MMD3_DEBUG_5_VALUE);
+ QCA808X_MMD3_DEBUG_5_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3,
- QCA808X_MMD3_DEBUG_3_VALUE);
+ QCA808X_MMD3_DEBUG_3_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6,
- QCA808X_MMD3_DEBUG_6_VALUE);
+ QCA808X_MMD3_DEBUG_6_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2,
- QCA808X_MMD3_DEBUG_2_VALUE);
+ QCA808X_MMD3_DEBUG_2_VALUE);
return 0;
}
@@ -1769,13 +1874,14 @@ static int qca808x_config_init(struct phy_device *phydev)
/* Active adc&vga on 802.3az for the link 1000M and 100M */
ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
- QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
+ QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
if (ret)
return ret;
/* Adjust the threshold on 802.3az for the link 1000M */
ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
- QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, QCA808X_MMD3_AZ_TRAINING_VAL);
+ QCA808X_PHY_MMD3_AZ_TRAINING_CTRL,
+ QCA808X_MMD3_AZ_TRAINING_VAL);
if (ret)
return ret;
@@ -1801,11 +1907,13 @@ static int qca808x_config_init(struct phy_device *phydev)
/* Configure adc threshold as 100mv for the link 10M */
return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
- QCA808X_ADC_THRESHOLD_MASK, QCA808X_ADC_THRESHOLD_100MV);
+ QCA808X_ADC_THRESHOLD_MASK,
+ QCA808X_ADC_THRESHOLD_100MV);
}
static int qca808x_read_status(struct phy_device *phydev)
{
+ struct at803x_ss_mask ss_mask = { 0 };
int ret;
ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
@@ -1813,13 +1921,16 @@ static int qca808x_read_status(struct phy_device *phydev)
return ret;
linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
- ret & MDIO_AN_10GBT_STAT_LP2_5G);
+ ret & MDIO_AN_10GBT_STAT_LP2_5G);
ret = genphy_read_status(phydev);
if (ret)
return ret;
- ret = at803x_read_specific_status(phydev);
+ /* qca8081 takes the different bits for speed value from at803x */
+ ss_mask.speed_mask = QCA808X_SS_SPEED_MASK;
+ ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK);
+ ret = at803x_read_specific_status(phydev, ss_mask);
if (ret < 0)
return ret;
@@ -1840,7 +1951,7 @@ static int qca808x_read_status(struct phy_device *phydev)
*/
if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||
- qca808x_is_prefer_master(phydev)) {
+ qca808x_is_prefer_master(phydev)) {
qca808x_phy_ms_seed_enable(phydev, false);
} else {
qca808x_phy_ms_seed_enable(phydev, true);
@@ -1868,8 +1979,17 @@ static int qca808x_soft_reset(struct phy_device *phydev)
static bool qca808x_cdt_fault_length_valid(int cdt_code)
{
switch (cdt_code) {
- case QCA808X_CDT_STATUS_STAT_SHORT:
- case QCA808X_CDT_STATUS_STAT_OPEN:
+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
return true;
default:
return false;
@@ -1881,17 +2001,28 @@ static int qca808x_cable_test_result_trans(int cdt_code)
switch (cdt_code) {
case QCA808X_CDT_STATUS_STAT_NORMAL:
return ETHTOOL_A_CABLE_RESULT_CODE_OK;
- case QCA808X_CDT_STATUS_STAT_SHORT:
+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
- case QCA808X_CDT_STATUS_STAT_OPEN:
+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
+ return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
case QCA808X_CDT_STATUS_STAT_FAIL:
default:
return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
}
}
-static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair)
+static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
+ int result)
{
int val;
u32 cdt_length_reg = 0;
@@ -1917,7 +2048,12 @@ static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair)
if (val < 0)
return val;
- return (FIELD_GET(QCA808X_CDT_DIAG_LENGTH, val) * 824) / 10;
+ if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
+ else
+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
+
+ return at803x_cdt_fault_length(val);
}
static int qca808x_cable_test_start(struct phy_device *phydev)
@@ -1961,18 +2097,53 @@ static int qca808x_cable_test_start(struct phy_device *phydev)
return 0;
}
+static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
+ u16 status)
+{
+ int length, result;
+ u16 pair_code;
+
+ switch (pair) {
+ case ETHTOOL_A_CABLE_PAIR_A:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
+ break;
+ case ETHTOOL_A_CABLE_PAIR_B:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
+ break;
+ case ETHTOOL_A_CABLE_PAIR_C:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
+ break;
+ case ETHTOOL_A_CABLE_PAIR_D:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ result = qca808x_cable_test_result_trans(pair_code);
+ ethnl_cable_test_result(phydev, pair, result);
+
+ if (qca808x_cdt_fault_length_valid(pair_code)) {
+ length = qca808x_cdt_fault_length(phydev, pair, result);
+ ethnl_cable_test_fault_length(phydev, pair, length);
+ }
+
+ return 0;
+}
+
static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
{
int ret, val;
- int pair_a, pair_b, pair_c, pair_d;
*finished = false;
- ret = at803x_cdt_start(phydev, 0);
+ val = QCA808X_CDT_ENABLE_TEST |
+ QCA808X_CDT_LENGTH_UNIT;
+ ret = at803x_cdt_start(phydev, val);
if (ret)
return ret;
- ret = at803x_cdt_wait_for_completion(phydev);
+ ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
if (ret)
return ret;
@@ -1980,32 +2151,21 @@ static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finish
if (val < 0)
return val;
- pair_a = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, val);
- pair_b = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, val);
- pair_c = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, val);
- pair_d = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, val);
-
- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
- qca808x_cable_test_result_trans(pair_a));
- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,
- qca808x_cable_test_result_trans(pair_b));
- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C,
- qca808x_cable_test_result_trans(pair_c));
- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,
- qca808x_cable_test_result_trans(pair_d));
-
- if (qca808x_cdt_fault_length_valid(pair_a))
- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A,
- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A));
- if (qca808x_cdt_fault_length_valid(pair_b))
- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B,
- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B));
- if (qca808x_cdt_fault_length_valid(pair_c))
- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C,
- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C));
- if (qca808x_cdt_fault_length_valid(pair_d))
- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D,
- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D));
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
+ if (ret)
+ return ret;
+
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
+ if (ret)
+ return ret;
+
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
+ if (ret)
+ return ret;
+
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
+ if (ret)
+ return ret;
*finished = true;
@@ -2040,14 +2200,41 @@ static int qca808x_get_features(struct phy_device *phydev)
return 0;
}
+static int qca808x_config_aneg(struct phy_device *phydev)
+{
+ int phy_ctrl = 0;
+ int ret;
+
+ ret = at803x_prepare_config_aneg(phydev);
+ if (ret)
+ return ret;
+
+ /* The reg MII_BMCR also needs to be configured for force mode, the
+ * genphy_config_aneg is also needed.
+ */
+ if (phydev->autoneg == AUTONEG_DISABLE)
+ genphy_c45_pma_setup_forced(phydev);
+
+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
+ phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
+
+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
+ MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
+ if (ret < 0)
+ return ret;
+
+ return __genphy_config_aneg(phydev, ret);
+}
+
static void qca808x_link_change_notify(struct phy_device *phydev)
{
/* Assert interface sgmii fifo on link down, deassert it on link up,
* the interface device address is always phy address added by 1.
*/
mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,
- MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
- QCA8081_PHY_FIFO_RSTN, phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
+ MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
+ QCA8081_PHY_FIFO_RSTN,
+ phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
}
static struct phy_driver at803x_driver[] = {
@@ -2056,7 +2243,7 @@ static struct phy_driver at803x_driver[] = {
PHY_ID_MATCH_EXACT(ATH8035_PHY_ID),
.name = "Qualcomm Atheros AR8035",
.flags = PHY_POLL_CABLE_TEST,
- .probe = at803x_probe,
+ .probe = at8035_probe,
.config_aneg = at803x_config_aneg,
.config_init = at803x_config_init,
.soft_reset = genphy_soft_reset,
@@ -2070,14 +2257,14 @@ static struct phy_driver at803x_driver[] = {
.handle_interrupt = at803x_handle_interrupt,
.get_tunable = at803x_get_tunable,
.set_tunable = at803x_set_tunable,
- .cable_test_start = at803x_cable_test_start,
- .cable_test_get_status = at803x_cable_test_get_status,
+ .cable_test_start = at8031_cable_test_start,
+ .cable_test_get_status = at8031_cable_test_get_status,
}, {
/* Qualcomm Atheros AR8030 */
.phy_id = ATH8030_PHY_ID,
.name = "Qualcomm Atheros AR8030",
.phy_id_mask = AT8030_PHY_ID_MASK,
- .probe = at803x_probe,
+ .probe = at8035_probe,
.config_init = at803x_config_init,
.link_change_notify = at803x_link_change_notify,
.set_wol = at803x_set_wol,
@@ -2092,24 +2279,24 @@ static struct phy_driver at803x_driver[] = {
PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
.name = "Qualcomm Atheros AR8031/AR8033",
.flags = PHY_POLL_CABLE_TEST,
- .probe = at803x_probe,
- .config_init = at803x_config_init,
+ .probe = at8031_probe,
+ .config_init = at8031_config_init,
.config_aneg = at803x_config_aneg,
.soft_reset = genphy_soft_reset,
- .set_wol = at803x_set_wol,
+ .set_wol = at8031_set_wol,
.get_wol = at803x_get_wol,
.suspend = at803x_suspend,
.resume = at803x_resume,
.read_page = at803x_read_page,
.write_page = at803x_write_page,
.get_features = at803x_get_features,
- .read_status = at803x_read_status,
- .config_intr = at803x_config_intr,
+ .read_status = at8031_read_status,
+ .config_intr = at8031_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.get_tunable = at803x_get_tunable,
.set_tunable = at803x_set_tunable,
- .cable_test_start = at803x_cable_test_start,
- .cable_test_get_status = at803x_cable_test_get_status,
+ .cable_test_start = at8031_cable_test_start,
+ .cable_test_get_status = at8031_cable_test_get_status,
}, {
/* Qualcomm Atheros AR8032 */
PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),
@@ -2124,7 +2311,7 @@ static struct phy_driver at803x_driver[] = {
.config_intr = at803x_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.cable_test_start = at803x_cable_test_start,
- .cable_test_get_status = at803x_cable_test_get_status,
+ .cable_test_get_status = at8032_cable_test_get_status,
}, {
/* ATHEROS AR9331 */
PHY_ID_MATCH_EXACT(ATH9331_PHY_ID),
@@ -2137,7 +2324,7 @@ static struct phy_driver at803x_driver[] = {
.config_intr = at803x_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.cable_test_start = at803x_cable_test_start,
- .cable_test_get_status = at803x_cable_test_get_status,
+ .cable_test_get_status = at8032_cable_test_get_status,
.read_status = at803x_read_status,
.soft_reset = genphy_soft_reset,
.config_aneg = at803x_config_aneg,
@@ -2153,7 +2340,7 @@ static struct phy_driver at803x_driver[] = {
.config_intr = at803x_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.cable_test_start = at803x_cable_test_start,
- .cable_test_get_status = at803x_cable_test_get_status,
+ .cable_test_get_status = at8032_cable_test_get_status,
.read_status = at803x_read_status,
.soft_reset = genphy_soft_reset,
.config_aneg = at803x_config_aneg,
@@ -2163,15 +2350,14 @@ static struct phy_driver at803x_driver[] = {
.phy_id_mask = QCA8K_PHY_ID_MASK,
.name = "Qualcomm Atheros 8337 internal PHY",
/* PHY_GBIT_FEATURES */
- .link_change_notify = qca83xx_link_change_notify,
.probe = at803x_probe,
.flags = PHY_IS_INTERNAL,
.config_init = qca83xx_config_init,
.soft_reset = genphy_soft_reset,
- .get_sset_count = at803x_get_sset_count,
- .get_strings = at803x_get_strings,
- .get_stats = at803x_get_stats,
- .suspend = qca83xx_suspend,
+ .get_sset_count = qca83xx_get_sset_count,
+ .get_strings = qca83xx_get_strings,
+ .get_stats = qca83xx_get_stats,
+ .suspend = qca8337_suspend,
.resume = qca83xx_resume,
}, {
/* QCA8327-A from switch QCA8327-AL1A */
@@ -2182,12 +2368,12 @@ static struct phy_driver at803x_driver[] = {
.link_change_notify = qca83xx_link_change_notify,
.probe = at803x_probe,
.flags = PHY_IS_INTERNAL,
- .config_init = qca83xx_config_init,
+ .config_init = qca8327_config_init,
.soft_reset = genphy_soft_reset,
- .get_sset_count = at803x_get_sset_count,
- .get_strings = at803x_get_strings,
- .get_stats = at803x_get_stats,
- .suspend = qca83xx_suspend,
+ .get_sset_count = qca83xx_get_sset_count,
+ .get_strings = qca83xx_get_strings,
+ .get_stats = qca83xx_get_stats,
+ .suspend = qca8327_suspend,
.resume = qca83xx_resume,
}, {
/* QCA8327-B from switch QCA8327-BL1A */
@@ -2198,12 +2384,12 @@ static struct phy_driver at803x_driver[] = {
.link_change_notify = qca83xx_link_change_notify,
.probe = at803x_probe,
.flags = PHY_IS_INTERNAL,
- .config_init = qca83xx_config_init,
+ .config_init = qca8327_config_init,
.soft_reset = genphy_soft_reset,
- .get_sset_count = at803x_get_sset_count,
- .get_strings = at803x_get_strings,
- .get_stats = at803x_get_stats,
- .suspend = qca83xx_suspend,
+ .get_sset_count = qca83xx_get_sset_count,
+ .get_strings = qca83xx_get_strings,
+ .get_stats = qca83xx_get_stats,
+ .suspend = qca8327_suspend,
.resume = qca83xx_resume,
}, {
/* Qualcomm QCA8081 */
@@ -2218,7 +2404,7 @@ static struct phy_driver at803x_driver[] = {
.set_wol = at803x_set_wol,
.get_wol = at803x_get_wol,
.get_features = qca808x_get_features,
- .config_aneg = at803x_config_aneg,
+ .config_aneg = qca808x_config_aneg,
.suspend = genphy_suspend,
.resume = genphy_resume,
.read_status = qca808x_read_status,