summaryrefslogtreecommitdiff
path: root/drivers/net/phy/marvell.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/marvell.c')
-rw-r--r--drivers/net/phy/marvell.c476
1 files changed, 465 insertions, 11 deletions
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index eba652a4c1d8..44e1927de499 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -176,6 +176,7 @@
#define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000
#define MII_M1011_PHY_STATUS_RESOLVED 0x0800
#define MII_M1011_PHY_STATUS_LINK 0x0400
+#define MII_M1011_PHY_STATUS_MDIX BIT(6)
#define MII_88E3016_PHY_SPEC_CTRL 0x10
#define MII_88E3016_DISABLE_SCRAMBLER 0x0200
@@ -279,10 +280,29 @@
#define MII_VCT7_CTRL_METERS BIT(10)
#define MII_VCT7_CTRL_CENTIMETERS 0
+#define MII_VCT_TXPINS 0x1A
+#define MII_VCT_RXPINS 0x1B
+#define MII_VCT_SR 0x1C
+#define MII_VCT_TXPINS_ENVCT BIT(15)
+#define MII_VCT_TXRXPINS_VCTTST GENMASK(14, 13)
+#define MII_VCT_TXRXPINS_VCTTST_SHIFT 13
+#define MII_VCT_TXRXPINS_VCTTST_OK 0
+#define MII_VCT_TXRXPINS_VCTTST_SHORT 1
+#define MII_VCT_TXRXPINS_VCTTST_OPEN 2
+#define MII_VCT_TXRXPINS_VCTTST_FAIL 3
+#define MII_VCT_TXRXPINS_AMPRFLN GENMASK(12, 8)
+#define MII_VCT_TXRXPINS_AMPRFLN_SHIFT 8
+#define MII_VCT_TXRXPINS_DISTRFLN GENMASK(7, 0)
+#define MII_VCT_TXRXPINS_DISTRFLN_MAX 0xff
+
+#define M88E3082_PAIR_A BIT(0)
+#define M88E3082_PAIR_B BIT(1)
+
#define LPA_PAUSE_FIBER 0x180
#define LPA_PAUSE_ASYM_FIBER 0x100
#define NB_FIBER_STATS 1
+#define NB_STAT_MAX 3
MODULE_DESCRIPTION("Marvell PHY driver");
MODULE_AUTHOR("Andy Fleming");
@@ -295,14 +315,37 @@ struct marvell_hw_stat {
u8 bits;
};
-static struct marvell_hw_stat marvell_hw_stats[] = {
+static const struct marvell_hw_stat marvell_hw_stats[] = {
{ "phy_receive_errors_copper", 0, 21, 16},
{ "phy_idle_errors", 0, 10, 8 },
{ "phy_receive_errors_fiber", 1, 21, 16},
};
+static_assert(ARRAY_SIZE(marvell_hw_stats) <= NB_STAT_MAX);
+
+/* "simple" stat list + corresponding marvell_get_*_simple functions are used
+ * on PHYs without a page register
+ */
+struct marvell_hw_stat_simple {
+ const char *string;
+ u8 reg;
+ u8 bits;
+};
+
+static const struct marvell_hw_stat_simple marvell_hw_stats_simple[] = {
+ { "phy_receive_errors", 21, 16},
+};
+
+static_assert(ARRAY_SIZE(marvell_hw_stats_simple) <= NB_STAT_MAX);
+
+enum {
+ M88E3082_VCT_OFF,
+ M88E3082_VCT_PHASE1,
+ M88E3082_VCT_PHASE2,
+};
+
struct marvell_priv {
- u64 stats[ARRAY_SIZE(marvell_hw_stats)];
+ u64 stats[NB_STAT_MAX];
char *hwmon_name;
struct device *hwmon_dev;
bool cable_test_tdr;
@@ -310,6 +353,7 @@ struct marvell_priv {
u32 last;
u32 step;
s8 pair;
+ u8 vct_phase;
};
static int marvell_read_page(struct phy_device *phydev)
@@ -673,6 +717,48 @@ static int marvell_config_aneg_fiber(struct phy_device *phydev)
return genphy_check_and_restart_aneg(phydev, changed);
}
+static unsigned int m88e1111_inband_caps(struct phy_device *phydev,
+ phy_interface_t interface)
+{
+ /* In 1000base-X and SGMII modes, the inband mode can be changed
+ * through the Fibre page BMCR ANENABLE bit.
+ */
+ if (interface == PHY_INTERFACE_MODE_1000BASEX ||
+ interface == PHY_INTERFACE_MODE_SGMII)
+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE |
+ LINK_INBAND_BYPASS;
+
+ return 0;
+}
+
+static int m88e1111_config_inband(struct phy_device *phydev, unsigned int modes)
+{
+ u16 extsr, bmcr;
+ int err;
+
+ if (phydev->interface != PHY_INTERFACE_MODE_1000BASEX &&
+ phydev->interface != PHY_INTERFACE_MODE_SGMII)
+ return -EINVAL;
+
+ if (modes == LINK_INBAND_BYPASS)
+ extsr = MII_M1111_HWCFG_SERIAL_AN_BYPASS;
+ else
+ extsr = 0;
+
+ if (modes == LINK_INBAND_DISABLE)
+ bmcr = 0;
+ else
+ bmcr = BMCR_ANENABLE;
+
+ err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,
+ MII_M1111_HWCFG_SERIAL_AN_BYPASS, extsr);
+ if (err < 0)
+ return extsr;
+
+ return phy_modify_paged(phydev, MII_MARVELL_FIBER_PAGE, MII_BMCR,
+ BMCR_ANENABLE, bmcr);
+}
+
static int m88e1111_config_aneg(struct phy_device *phydev)
{
int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
@@ -919,7 +1005,10 @@ static int m88e1111_config_init_1000basex(struct phy_device *phydev)
if (extsr < 0)
return extsr;
- /* If using copper mode, ensure 1000BaseX auto-negotiation is enabled */
+ /* If using copper mode, ensure 1000BaseX auto-negotiation is enabled.
+ * FIXME: this does not actually enable 1000BaseX auto-negotiation if
+ * it was previously disabled in the Fiber BMCR!
+ */
mode = extsr & MII_M1111_HWCFG_MODE_MASK;
if (mode == MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN) {
err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,
@@ -1461,7 +1550,6 @@ static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs)
static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs)
{
- struct ethtool_eee eee;
int val, ret;
if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
@@ -1471,8 +1559,7 @@ static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs)
/* According to the Marvell data sheet EEE must be disabled for
* Fast Link Down detection to work properly
*/
- ret = genphy_c45_ethtool_get_eee(phydev, &eee);
- if (!ret && eee.eee_enabled) {
+ if (phydev->eee_cfg.eee_enabled) {
phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n");
return -EBUSY;
}
@@ -1676,6 +1763,19 @@ static int marvell_read_status_page(struct phy_device *phydev, int page)
phydev->duplex = DUPLEX_UNKNOWN;
phydev->port = fiber ? PORT_FIBRE : PORT_TP;
+ if (fiber) {
+ phydev->mdix = ETH_TP_MDI_INVALID;
+ } else {
+ /* The MDI-X state is set regardless of Autoneg being enabled
+ * and reflects forced MDI-X state as well as auto resolution
+ */
+ if (status & MII_M1011_PHY_STATUS_RESOLVED)
+ phydev->mdix = status & MII_M1011_PHY_STATUS_MDIX ?
+ ETH_TP_MDI_X : ETH_TP_MDI;
+ else
+ phydev->mdix = ETH_TP_MDI_INVALID;
+ }
+
if (phydev->autoneg == AUTONEG_ENABLE)
err = marvell_read_status_page_an(phydev, fiber, status);
else
@@ -1950,15 +2050,27 @@ static int marvell_get_sset_count(struct phy_device *phydev)
return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS;
}
+static int marvell_get_sset_count_simple(struct phy_device *phydev)
+{
+ return ARRAY_SIZE(marvell_hw_stats_simple);
+}
+
static void marvell_get_strings(struct phy_device *phydev, u8 *data)
{
int count = marvell_get_sset_count(phydev);
int i;
- for (i = 0; i < count; i++) {
- strscpy(data + i * ETH_GSTRING_LEN,
- marvell_hw_stats[i].string, ETH_GSTRING_LEN);
- }
+ for (i = 0; i < count; i++)
+ ethtool_puts(&data, marvell_hw_stats[i].string);
+}
+
+static void marvell_get_strings_simple(struct phy_device *phydev, u8 *data)
+{
+ int count = marvell_get_sset_count_simple(phydev);
+ int i;
+
+ for (i = 0; i < count; i++)
+ ethtool_puts(&data, marvell_hw_stats_simple[i].string);
}
static u64 marvell_get_stat(struct phy_device *phydev, int i)
@@ -1980,6 +2092,25 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i)
return ret;
}
+static u64 marvell_get_stat_simple(struct phy_device *phydev, int i)
+{
+ struct marvell_hw_stat_simple stat = marvell_hw_stats_simple[i];
+ struct marvell_priv *priv = phydev->priv;
+ int val;
+ u64 ret;
+
+ val = phy_read(phydev, stat.reg);
+ if (val < 0) {
+ ret = U64_MAX;
+ } else {
+ val = val & ((1 << stat.bits) - 1);
+ priv->stats[i] += val;
+ ret = priv->stats[i];
+ }
+
+ return ret;
+}
+
static void marvell_get_stats(struct phy_device *phydev,
struct ethtool_stats *stats, u64 *data)
{
@@ -1990,6 +2121,16 @@ static void marvell_get_stats(struct phy_device *phydev,
data[i] = marvell_get_stat(phydev, i);
}
+static void marvell_get_stats_simple(struct phy_device *phydev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ int count = marvell_get_sset_count_simple(phydev);
+ int i;
+
+ for (i = 0; i < count; i++)
+ data[i] = marvell_get_stat_simple(phydev, i);
+}
+
static int m88e1510_loopback(struct phy_device *phydev, bool enable)
{
int err;
@@ -2414,6 +2555,274 @@ static int marvell_vct7_cable_test_get_status(struct phy_device *phydev,
return 0;
}
+static int m88e3082_vct_cable_test_start(struct phy_device *phydev)
+{
+ struct marvell_priv *priv = phydev->priv;
+ int ret;
+
+ /* It needs some magic workarounds described in VCT manual for this PHY.
+ */
+ ret = phy_write(phydev, 29, 0x0003);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, 30, 0x6440);
+ if (ret < 0)
+ return ret;
+
+ if (priv->vct_phase == M88E3082_VCT_PHASE1) {
+ ret = phy_write(phydev, 29, 0x000a);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, 30, 0x0002);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = phy_write(phydev, MII_BMCR,
+ BMCR_RESET | BMCR_SPEED100 | BMCR_FULLDPLX);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, MII_VCT_TXPINS, MII_VCT_TXPINS_ENVCT);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, 29, 0x0003);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, 30, 0x0);
+ if (ret < 0)
+ return ret;
+
+ if (priv->vct_phase == M88E3082_VCT_OFF) {
+ priv->vct_phase = M88E3082_VCT_PHASE1;
+ priv->pair = 0;
+
+ return 0;
+ }
+
+ ret = phy_write(phydev, 29, 0x000a);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, 30, 0x0);
+ if (ret < 0)
+ return ret;
+
+ priv->vct_phase = M88E3082_VCT_PHASE2;
+
+ return 0;
+}
+
+static int m88e3082_vct_cable_test_report_trans(int result, u8 distance)
+{
+ switch (result) {
+ case MII_VCT_TXRXPINS_VCTTST_OK:
+ if (distance == MII_VCT_TXRXPINS_DISTRFLN_MAX)
+ return ETHTOOL_A_CABLE_RESULT_CODE_OK;
+ return ETHTOOL_A_CABLE_RESULT_CODE_IMPEDANCE_MISMATCH;
+ case MII_VCT_TXRXPINS_VCTTST_SHORT:
+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
+ case MII_VCT_TXRXPINS_VCTTST_OPEN:
+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
+ default:
+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
+ }
+}
+
+static u32 m88e3082_vct_distrfln_2_cm(u8 distrfln)
+{
+ if (distrfln < 24)
+ return 0;
+
+ /* Original function for meters: y = 0.7861x - 18.862 */
+ return (7861 * distrfln - 188620) / 100;
+}
+
+static int m88e3082_vct_cable_test_get_status(struct phy_device *phydev,
+ bool *finished)
+{
+ u8 tx_vcttst_res, rx_vcttst_res, tx_distrfln, rx_distrfln;
+ struct marvell_priv *priv = phydev->priv;
+ int ret, tx_result, rx_result;
+ bool done_phase = true;
+
+ *finished = false;
+
+ ret = phy_read(phydev, MII_VCT_TXPINS);
+ if (ret < 0)
+ return ret;
+ else if (ret & MII_VCT_TXPINS_ENVCT)
+ return 0;
+
+ tx_distrfln = ret & MII_VCT_TXRXPINS_DISTRFLN;
+ tx_vcttst_res = (ret & MII_VCT_TXRXPINS_VCTTST) >>
+ MII_VCT_TXRXPINS_VCTTST_SHIFT;
+
+ ret = phy_read(phydev, MII_VCT_RXPINS);
+ if (ret < 0)
+ return ret;
+
+ rx_distrfln = ret & MII_VCT_TXRXPINS_DISTRFLN;
+ rx_vcttst_res = (ret & MII_VCT_TXRXPINS_VCTTST) >>
+ MII_VCT_TXRXPINS_VCTTST_SHIFT;
+
+ *finished = true;
+
+ switch (priv->vct_phase) {
+ case M88E3082_VCT_PHASE1:
+ tx_result = m88e3082_vct_cable_test_report_trans(tx_vcttst_res,
+ tx_distrfln);
+ rx_result = m88e3082_vct_cable_test_report_trans(rx_vcttst_res,
+ rx_distrfln);
+
+ ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
+ tx_result);
+ ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,
+ rx_result);
+
+ if (tx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN) {
+ done_phase = false;
+ priv->pair |= M88E3082_PAIR_A;
+ } else if (tx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {
+ u8 pair = ETHTOOL_A_CABLE_PAIR_A;
+ u32 cm = m88e3082_vct_distrfln_2_cm(tx_distrfln);
+
+ ethnl_cable_test_fault_length(phydev, pair, cm);
+ }
+
+ if (rx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN) {
+ done_phase = false;
+ priv->pair |= M88E3082_PAIR_B;
+ } else if (rx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {
+ u8 pair = ETHTOOL_A_CABLE_PAIR_B;
+ u32 cm = m88e3082_vct_distrfln_2_cm(rx_distrfln);
+
+ ethnl_cable_test_fault_length(phydev, pair, cm);
+ }
+
+ break;
+ case M88E3082_VCT_PHASE2:
+ if (priv->pair & M88E3082_PAIR_A &&
+ tx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN &&
+ tx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {
+ u8 pair = ETHTOOL_A_CABLE_PAIR_A;
+ u32 cm = m88e3082_vct_distrfln_2_cm(tx_distrfln);
+
+ ethnl_cable_test_fault_length(phydev, pair, cm);
+ }
+ if (priv->pair & M88E3082_PAIR_B &&
+ rx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN &&
+ rx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {
+ u8 pair = ETHTOOL_A_CABLE_PAIR_B;
+ u32 cm = m88e3082_vct_distrfln_2_cm(rx_distrfln);
+
+ ethnl_cable_test_fault_length(phydev, pair, cm);
+ }
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!done_phase) {
+ *finished = false;
+ return m88e3082_vct_cable_test_start(phydev);
+ }
+ if (*finished)
+ priv->vct_phase = M88E3082_VCT_OFF;
+ return 0;
+}
+
+static int m88e1111_vct_cable_test_start(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = marvell_cable_test_start_common(phydev);
+ if (ret)
+ return ret;
+
+ /* It needs some magic workarounds described in VCT manual for this PHY.
+ */
+ ret = phy_write(phydev, 29, 0x0018);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, 30, 0x00c2);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, 30, 0x00ca);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, 30, 0x00c2);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write_paged(phydev, MII_MARVELL_COPPER_PAGE, MII_VCT_SR,
+ MII_VCT_TXPINS_ENVCT);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, 29, 0x0018);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, 30, 0x0042);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static u32 m88e1111_vct_distrfln_2_cm(u8 distrfln)
+{
+ if (distrfln < 36)
+ return 0;
+
+ /* Original function for meters: y = 0.8018x - 28.751 */
+ return (8018 * distrfln - 287510) / 100;
+}
+
+static int m88e1111_vct_cable_test_get_status(struct phy_device *phydev,
+ bool *finished)
+{
+ u8 vcttst_res, distrfln;
+ int ret, result;
+
+ *finished = false;
+
+ /* Each pair use one page: A-0, B-1, C-2, D-3 */
+ for (u8 i = 0; i < 4; i++) {
+ ret = phy_read_paged(phydev, i, MII_VCT_SR);
+ if (ret < 0)
+ return ret;
+ else if (i == 0 && ret & MII_VCT_TXPINS_ENVCT)
+ return 0;
+
+ distrfln = ret & MII_VCT_TXRXPINS_DISTRFLN;
+ vcttst_res = (ret & MII_VCT_TXRXPINS_VCTTST) >>
+ MII_VCT_TXRXPINS_VCTTST_SHIFT;
+
+ result = m88e3082_vct_cable_test_report_trans(vcttst_res,
+ distrfln);
+ ethnl_cable_test_result(phydev, i, result);
+
+ if (distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {
+ u32 cm = m88e1111_vct_distrfln_2_cm(distrfln);
+
+ ethnl_cable_test_fault_length(phydev, i, cm);
+ }
+ }
+
+ *finished = true;
+ return 0;
+}
+
#ifdef CONFIG_HWMON
struct marvell_hwmon_ops {
int (*config)(struct phy_device *phydev);
@@ -3254,6 +3663,8 @@ static const struct sfp_upstream_ops m88e1510_sfp_ops = {
.module_remove = m88e1510_sfp_remove,
.attach = phy_sfp_attach,
.detach = phy_sfp_detach,
+ .connect_phy = phy_sfp_connect_phy,
+ .disconnect_phy = phy_sfp_disconnect_phy,
};
static int m88e1510_probe(struct phy_device *phydev)
@@ -3287,11 +3698,27 @@ static struct phy_driver marvell_drivers[] = {
.get_stats = marvell_get_stats,
},
{
+ .phy_id = MARVELL_PHY_ID_88E3082,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "Marvell 88E308X/88E609X Family",
+ /* PHY_BASIC_FEATURES */
+ .probe = marvell_probe,
+ .config_init = marvell_config_init,
+ .aneg_done = marvell_aneg_done,
+ .read_status = marvell_read_status,
+ .resume = genphy_resume,
+ .suspend = genphy_suspend,
+ .cable_test_start = m88e3082_vct_cable_test_start,
+ .cable_test_get_status = m88e3082_vct_cable_test_get_status,
+ },
+ {
.phy_id = MARVELL_PHY_ID_88E1112,
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "Marvell 88E1112",
/* PHY_GBIT_FEATURES */
.probe = marvell_probe,
+ .inband_caps = m88e1111_inband_caps,
+ .config_inband = m88e1111_config_inband,
.config_init = m88e1112_config_init,
.config_aneg = marvell_config_aneg,
.config_intr = marvell_config_intr,
@@ -3311,7 +3738,10 @@ static struct phy_driver marvell_drivers[] = {
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "Marvell 88E1111",
/* PHY_GBIT_FEATURES */
+ .flags = PHY_POLL_CABLE_TEST,
.probe = marvell_probe,
+ .inband_caps = m88e1111_inband_caps,
+ .config_inband = m88e1111_config_inband,
.config_init = m88e1111gbe_config_init,
.config_aneg = m88e1111_config_aneg,
.read_status = marvell_read_status,
@@ -3326,6 +3756,8 @@ static struct phy_driver marvell_drivers[] = {
.get_stats = marvell_get_stats,
.get_tunable = m88e1111_get_tunable,
.set_tunable = m88e1111_set_tunable,
+ .cable_test_start = m88e1111_vct_cable_test_start,
+ .cable_test_get_status = m88e1111_vct_cable_test_get_status,
},
{
.phy_id = MARVELL_PHY_ID_88E1111_FINISAR,
@@ -3333,6 +3765,8 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1111 (Finisar)",
/* PHY_GBIT_FEATURES */
.probe = marvell_probe,
+ .inband_caps = m88e1111_inband_caps,
+ .config_inband = m88e1111_config_inband,
.config_init = m88e1111gbe_config_init,
.config_aneg = m88e1111_config_aneg,
.read_status = marvell_read_status,
@@ -3419,6 +3853,7 @@ static struct phy_driver marvell_drivers[] = {
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "Marvell 88E1145",
/* PHY_GBIT_FEATURES */
+ .flags = PHY_POLL_CABLE_TEST,
.probe = marvell_probe,
.config_init = m88e1145_config_init,
.config_aneg = m88e1101_config_aneg,
@@ -3433,6 +3868,8 @@ static struct phy_driver marvell_drivers[] = {
.get_stats = marvell_get_stats,
.get_tunable = m88e1111_get_tunable,
.set_tunable = m88e1111_set_tunable,
+ .cable_test_start = m88e1111_vct_cable_test_start,
+ .cable_test_get_status = m88e1111_vct_cable_test_get_status,
},
{
.phy_id = MARVELL_PHY_ID_88E1149R,
@@ -3607,6 +4044,21 @@ static struct phy_driver marvell_drivers[] = {
.get_stats = marvell_get_stats,
},
{
+ .phy_id = MARVELL_PHY_ID_88E6250_FAMILY,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "Marvell 88E6250 Family",
+ /* PHY_BASIC_FEATURES */
+ .probe = marvell_probe,
+ .aneg_done = marvell_aneg_done,
+ .config_intr = marvell_config_intr,
+ .handle_interrupt = marvell_handle_interrupt,
+ .resume = genphy_resume,
+ .suspend = genphy_suspend,
+ .get_sset_count = marvell_get_sset_count_simple,
+ .get_strings = marvell_get_strings_simple,
+ .get_stats = marvell_get_stats_simple,
+ },
+ {
.phy_id = MARVELL_PHY_ID_88E6341_FAMILY,
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "Marvell 88E6341 Family",
@@ -3737,8 +4189,9 @@ static struct phy_driver marvell_drivers[] = {
module_phy_driver(marvell_drivers);
-static struct mdio_device_id __maybe_unused marvell_tbl[] = {
+static const struct mdio_device_id __maybe_unused marvell_tbl[] = {
{ MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E3082, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E1111_FINISAR, MARVELL_PHY_ID_MASK },
@@ -3753,6 +4206,7 @@ static struct mdio_device_id __maybe_unused marvell_tbl[] = {
{ MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E6250_FAMILY, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E6341_FAMILY, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E6390_FAMILY, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E6393_FAMILY, MARVELL_PHY_ID_MASK },