diff options
Diffstat (limited to 'drivers/net/phy/micrel.c')
| -rw-r--r-- | drivers/net/phy/micrel.c | 379 |
1 files changed, 347 insertions, 32 deletions
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 79ce3eb6752b..05de68b9f719 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -101,6 +101,8 @@ #define LAN8814_CABLE_DIAG_VCT_DATA_MASK GENMASK(7, 0) #define LAN8814_PAIR_BIT_SHIFT 12 +#define LAN8814_SKUS 0xB + #define LAN8814_WIRE_PAIR_MASK 0xF /* Lan8814 general Interrupt control/status reg in GPHY specific block. */ @@ -367,6 +369,9 @@ #define LAN8842_REV_8832 0x8832 +#define LAN8814_REV_LAN8814 0x8814 +#define LAN8814_REV_LAN8818 0x8818 + struct kszphy_hw_stat { const char *string; u8 reg; @@ -449,6 +454,7 @@ struct kszphy_priv { bool rmii_ref_clk_sel; bool rmii_ref_clk_sel_val; bool clk_enable; + bool is_ptp_available; u64 stats[ARRAY_SIZE(kszphy_hw_stats)]; struct kszphy_phy_stats phy_stats; }; @@ -466,6 +472,12 @@ struct lan8842_priv { u16 rev; }; +struct lanphy_reg_data { + int page; + u16 addr; + u16 val; +}; + static const struct kszphy_type lan8814_type = { .led_mode_reg = ~LAN8814_LED_CTRL_1, .cable_diag_reg = LAN8814_CABLE_DIAG, @@ -1050,7 +1062,7 @@ static int ksz9021_config_init(struct phy_device *phydev) #define TX_CLK_ID 0x1f /* set tx and tx_clk to "No delay adjustment" to keep 0ns - * dealy + * delay */ #define TX_ND 0x7 #define TX_CLK_ND 0xf @@ -1913,7 +1925,7 @@ static int ksz886x_config_aneg(struct phy_device *phydev) return ret; if (phydev->autoneg != AUTONEG_ENABLE) { - /* When autonegotation is disabled, we need to manually force + /* When autonegotiation is disabled, we need to manually force * the link state. If we don't do this, the PHY will keep * sending Fast Link Pulses (FLPs) which are part of the * autonegotiation process. This is not desired when @@ -2095,11 +2107,7 @@ static int ksz9477_phy_errata(struct phy_device *phydev) return err; } - err = genphy_restart_aneg(phydev); - if (err) - return err; - - return err; + return genphy_restart_aneg(phydev); } static int ksz9477_config_init(struct phy_device *phydev) @@ -2323,6 +2331,106 @@ static int kszphy_get_sqi_max(struct phy_device *phydev) return KSZ9477_SQI_MAX; } +static int kszphy_get_mse_capability(struct phy_device *phydev, + struct phy_mse_capability *cap) +{ + /* Capabilities depend on link mode: + * - 1000BASE-T: per-pair SQI registers exist => expose A..D + * and a WORST selector. + * - 100BASE-TX: HW provides a single MSE/SQI reading in the "channel A" + * register, but with auto MDI-X there is no MDI-X resolution bit, + * so we cannot map that register to a specific wire pair reliably. + * To avoid misleading per-channel data, advertise only LINK. + * Other speeds: no MSE exposure via this driver. + * + * Note: WORST is *not* a hardware selector on this family. + * We expose it because the driver computes it in software + * by scanning per-channel readouts (A..D) and picking the + * maximum average MSE. + */ + if (phydev->speed == SPEED_1000) + cap->supported_caps = PHY_MSE_CAP_CHANNEL_A | + PHY_MSE_CAP_CHANNEL_B | + PHY_MSE_CAP_CHANNEL_C | + PHY_MSE_CAP_CHANNEL_D | + PHY_MSE_CAP_WORST_CHANNEL; + else if (phydev->speed == SPEED_100) + cap->supported_caps = PHY_MSE_CAP_LINK; + else + return -EOPNOTSUPP; + + cap->max_average_mse = FIELD_MAX(KSZ9477_MMD_SQI_MASK); + cap->refresh_rate_ps = 2000000; /* 2 us */ + /* Estimated from link modulation (125 MBd per channel) and documented + * refresh rate of 2 us + */ + cap->num_symbols = 250; + + cap->supported_caps |= PHY_MSE_CAP_AVG; + + return 0; +} + +static int kszphy_get_mse_snapshot(struct phy_device *phydev, + enum phy_mse_channel channel, + struct phy_mse_snapshot *snapshot) +{ + u8 num_channels; + int ret; + + if (phydev->speed == SPEED_1000) + num_channels = 4; + else if (phydev->speed == SPEED_100) + num_channels = 1; + else + return -EOPNOTSUPP; + + if (channel == PHY_MSE_CHANNEL_WORST) { + u32 worst_val = 0; + int i; + + /* WORST is implemented in software: select the maximum + * average MSE across the available per-channel registers. + * Only defined when multiple channels exist (1000BASE-T). + */ + if (num_channels < 2) + return -EOPNOTSUPP; + + for (i = 0; i < num_channels; i++) { + ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, + KSZ9477_MMD_SIGNAL_QUALITY_CHAN_A + i); + if (ret < 0) + return ret; + + ret = FIELD_GET(KSZ9477_MMD_SQI_MASK, ret); + if (ret > worst_val) + worst_val = ret; + } + snapshot->average_mse = worst_val; + } else if (channel == PHY_MSE_CHANNEL_LINK && num_channels == 1) { + ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, + KSZ9477_MMD_SIGNAL_QUALITY_CHAN_A); + if (ret < 0) + return ret; + snapshot->average_mse = FIELD_GET(KSZ9477_MMD_SQI_MASK, ret); + } else if (channel >= PHY_MSE_CHANNEL_A && + channel <= PHY_MSE_CHANNEL_D) { + /* Per-channel readouts are valid only for 1000BASE-T. */ + if (phydev->speed != SPEED_1000) + return -EOPNOTSUPP; + + ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, + KSZ9477_MMD_SIGNAL_QUALITY_CHAN_A + channel); + if (ret < 0) + return ret; + snapshot->average_mse = FIELD_GET(KSZ9477_MMD_SQI_MASK, ret); + } else { + return -EOPNOTSUPP; + } + + return 0; +} + static void kszphy_enable_clk(struct phy_device *phydev) { struct kszphy_priv *priv = phydev->priv; @@ -2836,6 +2944,13 @@ static int ksz886x_cable_test_get_status(struct phy_device *phydev, #define LAN8814_PAGE_PCS_DIGITAL 2 /** + * LAN8814_PAGE_EEE - Selects Extended Page 3. + * + * This page contains EEE registers + */ +#define LAN8814_PAGE_EEE 3 + +/** * LAN8814_PAGE_COMMON_REGS - Selects Extended Page 4. * * This page contains device-common registers that affect the entire chip. @@ -2854,6 +2969,13 @@ static int ksz886x_cable_test_get_status(struct phy_device *phydev, #define LAN8814_PAGE_PORT_REGS 5 /** + * LAN8814_PAGE_POWER_REGS - Selects Extended Page 28. + * + * This page contains analog control registers and power mode registers. + */ +#define LAN8814_PAGE_POWER_REGS 28 + +/** * LAN8814_PAGE_SYSTEM_CTRL - Selects Extended Page 31. * * This page appears to hold fundamental system or global controls. In the @@ -2866,6 +2988,8 @@ static int ksz886x_cable_test_get_status(struct phy_device *phydev, #define LAN_EXT_PAGE_ACCESS_ADDRESS_DATA 0x17 #define LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC 0x4000 +#define LAN8814_QSGMII_TX_CONFIG 0x35 +#define LAN8814_QSGMII_TX_CONFIG_QSGMII BIT(3) #define LAN8814_QSGMII_SOFT_RESET 0x43 #define LAN8814_QSGMII_SOFT_RESET_BIT BIT(0) #define LAN8814_QSGMII_PCS1G_ANEG_CONFIG 0x13 @@ -3023,9 +3147,9 @@ static void lan8814_flush_fifo(struct phy_device *phydev, bool egress) lanphy_read_page_reg(phydev, LAN8814_PAGE_PORT_REGS, PTP_TSU_INT_STS); } -static int lan8814_hwtstamp(struct mii_timestamper *mii_ts, - struct kernel_hwtstamp_config *config, - struct netlink_ext_ack *extack) +static int lan8814_hwtstamp_set(struct mii_timestamper *mii_ts, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) { struct kszphy_ptp_priv *ptp_priv = container_of(mii_ts, struct kszphy_ptp_priv, mii_ts); @@ -3537,7 +3661,7 @@ static void lan8814_ptp_disable_event(struct phy_device *phydev, int event) /* Set target to too far in the future, effectively disabling it */ lan8814_ptp_set_target(phydev, event, 0xFFFFFFFF, 0); - /* And then reload once it recheas the target */ + /* And then reload once it reaches the target */ lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, LAN8814_PTP_GENERAL_CONFIG, LAN8814_PTP_GENERAL_CONFIG_RELOAD_ADD_X(event), LAN8814_PTP_GENERAL_CONFIG_RELOAD_ADD_X(event)); @@ -4130,6 +4254,17 @@ static int lan8804_config_intr(struct phy_device *phydev) return 0; } +/* Check if the PHY has 1588 support. There are multiple skus of the PHY and + * some of them support PTP while others don't support it. This function will + * return true is the sku supports it, otherwise will return false. + */ +static bool lan8814_has_ptp(struct phy_device *phydev) +{ + struct kszphy_priv *priv = phydev->priv; + + return priv->is_ptp_available; +} + static irqreturn_t lan8814_handle_interrupt(struct phy_device *phydev) { int ret = IRQ_NONE; @@ -4146,6 +4281,9 @@ static irqreturn_t lan8814_handle_interrupt(struct phy_device *phydev) ret = IRQ_HANDLED; } + if (!lan8814_has_ptp(phydev)) + return ret; + while (true) { irq_status = lanphy_read_page_reg(phydev, LAN8814_PAGE_PORT_REGS, PTP_TSU_INT_STS); @@ -4207,6 +4345,9 @@ static void lan8814_ptp_init(struct phy_device *phydev) !IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING)) return; + if (!lan8814_has_ptp(phydev)) + return; + lanphy_write_page_reg(phydev, LAN8814_PAGE_PORT_REGS, TSU_HARD_RESET, TSU_HARD_RESET_); @@ -4248,7 +4389,7 @@ static void lan8814_ptp_init(struct phy_device *phydev) ptp_priv->mii_ts.rxtstamp = lan8814_rxtstamp; ptp_priv->mii_ts.txtstamp = lan8814_txtstamp; - ptp_priv->mii_ts.hwtstamp = lan8814_hwtstamp; + ptp_priv->mii_ts.hwtstamp_set = lan8814_hwtstamp_set; ptp_priv->mii_ts.ts_info = lan8814_ts_info; phydev->mii_ts = &ptp_priv->mii_ts; @@ -4262,6 +4403,8 @@ static int __lan8814_ptp_probe_once(struct phy_device *phydev, char *pin_name, { struct lan8814_shared_priv *shared = phy_package_get_priv(phydev); + shared->phydev = phydev; + /* Initialise shared lock for clock*/ mutex_init(&shared->shared_lock); @@ -4317,8 +4460,6 @@ static int __lan8814_ptp_probe_once(struct phy_device *phydev, char *pin_name, phydev_dbg(phydev, "successfully registered ptp clock\n"); - shared->phydev = phydev; - /* The EP.4 is shared between all the PHYs in the package and also it * can be accessed by any of the PHYs */ @@ -4336,6 +4477,9 @@ static int __lan8814_ptp_probe_once(struct phy_device *phydev, char *pin_name, static int lan8814_ptp_probe_once(struct phy_device *phydev) { + if (!lan8814_has_ptp(phydev)) + return 0; + return __lan8814_ptp_probe_once(phydev, "lan8814_ptp_pin", LAN8814_PTP_GPIO_NUM); } @@ -4359,18 +4503,24 @@ static void lan8814_setup_led(struct phy_device *phydev, int val) static int lan8814_config_init(struct phy_device *phydev) { struct kszphy_priv *lan8814 = phydev->priv; + int ret; - /* Reset the PHY */ - lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, - LAN8814_QSGMII_SOFT_RESET, - LAN8814_QSGMII_SOFT_RESET_BIT, - LAN8814_QSGMII_SOFT_RESET_BIT); - - /* Disable ANEG with QSGMII PCS Host side */ - lanphy_modify_page_reg(phydev, LAN8814_PAGE_PORT_REGS, - LAN8814_QSGMII_PCS1G_ANEG_CONFIG, - LAN8814_QSGMII_PCS1G_ANEG_CONFIG_ANEG_ENA, - 0); + /* Based on the interface type select how the advertise ability is + * encoded, to set as SGMII or as USGMII. + */ + if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) + ret = lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, + LAN8814_QSGMII_TX_CONFIG, + LAN8814_QSGMII_TX_CONFIG_QSGMII, + LAN8814_QSGMII_TX_CONFIG_QSGMII); + else + ret = lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, + LAN8814_QSGMII_TX_CONFIG, + LAN8814_QSGMII_TX_CONFIG_QSGMII, + 0); + + if (ret < 0) + return ret; /* MDI-X setting for swap A,B transmit */ lanphy_modify_page_reg(phydev, LAN8814_PAGE_PCS_DIGITAL, LAN8814_ALIGN_SWAP, @@ -4407,7 +4557,7 @@ static int lan8814_release_coma_mode(struct phy_device *phydev) static void lan8814_clear_2psp_bit(struct phy_device *phydev) { /* It was noticed that when traffic is passing through the PHY and the - * cable is removed then the LED was still one even though there is no + * cable is removed then the LED was still on even though there is no * link */ lanphy_modify_page_reg(phydev, LAN8814_PAGE_PCS_DIGITAL, LAN8814_EEE_STATE, @@ -4450,7 +4600,25 @@ static int lan8814_probe(struct phy_device *phydev) devm_phy_package_join(&phydev->mdio.dev, phydev, addr, sizeof(struct lan8814_shared_priv)); + /* There are lan8814 SKUs that don't support PTP. Make sure that for + * those skus no PTP device is created. Here we check if the SKU + * supports PTP. + */ + err = lanphy_read_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, + LAN8814_SKUS); + if (err < 0) + return err; + + priv->is_ptp_available = err == LAN8814_REV_LAN8814 || + err == LAN8814_REV_LAN8818; + if (phy_package_init_once(phydev)) { + /* Reset the PHY */ + lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, + LAN8814_QSGMII_SOFT_RESET, + LAN8814_QSGMII_SOFT_RESET_BIT, + LAN8814_QSGMII_SOFT_RESET_BIT); + err = lan8814_release_coma_mode(phydev); if (err) return err; @@ -4547,7 +4715,7 @@ static int lan8841_config_init(struct phy_device *phydev) phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, LAN8841_PTP_TX_VERSION, 0xff00); - /* 100BT Clause 40 improvenent errata */ + /* 100BT Clause 40 improvement errata */ phy_write_mmd(phydev, LAN8841_MMD_ANALOG_REG, LAN8841_ANALOG_CONTROL_1, LAN8841_ANALOG_CONTROL_1_PLL_TRIM(0x2)); @@ -4874,9 +5042,9 @@ static void lan8841_ptp_enable_processing(struct kszphy_ptp_priv *ptp_priv, #define LAN8841_PTP_TX_TIMESTAMP_EN 443 #define LAN8841_PTP_TX_MOD 445 -static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, - struct kernel_hwtstamp_config *config, - struct netlink_ext_ack *extack) +static int lan8841_hwtstamp_set(struct mii_timestamper *mii_ts, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) { struct kszphy_ptp_priv *ptp_priv = container_of(mii_ts, struct kszphy_ptp_priv, mii_ts); struct phy_device *phydev = ptp_priv->phydev; @@ -5567,7 +5735,7 @@ static int lan8841_ptp_extts_on(struct kszphy_ptp_priv *ptp_priv, int pin, u16 tmp = 0; int ret; - /* Set GPIO to be intput */ + /* Set GPIO to be input */ ret = phy_set_bits_mmd(phydev, 2, LAN8841_GPIO_EN, BIT(pin)); if (ret) return ret; @@ -5756,7 +5924,7 @@ static int lan8841_probe(struct phy_device *phydev) ptp_priv->mii_ts.rxtstamp = lan8841_rxtstamp; ptp_priv->mii_ts.txtstamp = lan8814_txtstamp; - ptp_priv->mii_ts.hwtstamp = lan8841_hwtstamp; + ptp_priv->mii_ts.hwtstamp_set = lan8841_hwtstamp_set; ptp_priv->mii_ts.ts_info = lan8841_ts_info; phydev->mii_ts = &ptp_priv->mii_ts; @@ -5884,6 +6052,144 @@ static int lan8842_probe(struct phy_device *phydev) return 0; } +#define LAN8814_POWER_MGMT_MODE_3_ANEG_MDI 0x13 +#define LAN8814_POWER_MGMT_MODE_4_ANEG_MDIX 0x14 +#define LAN8814_POWER_MGMT_MODE_5_10BT_MDI 0x15 +#define LAN8814_POWER_MGMT_MODE_6_10BT_MDIX 0x16 +#define LAN8814_POWER_MGMT_MODE_7_100BT_TRAIN 0x17 +#define LAN8814_POWER_MGMT_MODE_8_100BT_MDI 0x18 +#define LAN8814_POWER_MGMT_MODE_9_100BT_EEE_MDI_TX 0x19 +#define LAN8814_POWER_MGMT_MODE_10_100BT_EEE_MDI_RX 0x1a +#define LAN8814_POWER_MGMT_MODE_11_100BT_MDIX 0x1b +#define LAN8814_POWER_MGMT_MODE_12_100BT_EEE_MDIX_TX 0x1c +#define LAN8814_POWER_MGMT_MODE_13_100BT_EEE_MDIX_RX 0x1d +#define LAN8814_POWER_MGMT_MODE_14_100BTX_EEE_TX_RX 0x1e + +#define LAN8814_POWER_MGMT_DLLPD_D BIT(0) +#define LAN8814_POWER_MGMT_ADCPD_D BIT(1) +#define LAN8814_POWER_MGMT_PGAPD_D BIT(2) +#define LAN8814_POWER_MGMT_TXPD_D BIT(3) +#define LAN8814_POWER_MGMT_DLLPD_C BIT(4) +#define LAN8814_POWER_MGMT_ADCPD_C BIT(5) +#define LAN8814_POWER_MGMT_PGAPD_C BIT(6) +#define LAN8814_POWER_MGMT_TXPD_C BIT(7) +#define LAN8814_POWER_MGMT_DLLPD_B BIT(8) +#define LAN8814_POWER_MGMT_ADCPD_B BIT(9) +#define LAN8814_POWER_MGMT_PGAPD_B BIT(10) +#define LAN8814_POWER_MGMT_TXPD_B BIT(11) +#define LAN8814_POWER_MGMT_DLLPD_A BIT(12) +#define LAN8814_POWER_MGMT_ADCPD_A BIT(13) +#define LAN8814_POWER_MGMT_PGAPD_A BIT(14) +#define LAN8814_POWER_MGMT_TXPD_A BIT(15) + +#define LAN8814_POWER_MGMT_C_D (LAN8814_POWER_MGMT_DLLPD_D | \ + LAN8814_POWER_MGMT_ADCPD_D | \ + LAN8814_POWER_MGMT_PGAPD_D | \ + LAN8814_POWER_MGMT_DLLPD_C | \ + LAN8814_POWER_MGMT_ADCPD_C | \ + LAN8814_POWER_MGMT_PGAPD_C) + +#define LAN8814_POWER_MGMT_B_C_D (LAN8814_POWER_MGMT_C_D | \ + LAN8814_POWER_MGMT_DLLPD_B | \ + LAN8814_POWER_MGMT_ADCPD_B | \ + LAN8814_POWER_MGMT_PGAPD_B) + +#define LAN8814_POWER_MGMT_VAL1 (LAN8814_POWER_MGMT_C_D | \ + LAN8814_POWER_MGMT_ADCPD_B | \ + LAN8814_POWER_MGMT_PGAPD_B | \ + LAN8814_POWER_MGMT_ADCPD_A | \ + LAN8814_POWER_MGMT_PGAPD_A) + +#define LAN8814_POWER_MGMT_VAL2 LAN8814_POWER_MGMT_C_D + +#define LAN8814_POWER_MGMT_VAL3 (LAN8814_POWER_MGMT_C_D | \ + LAN8814_POWER_MGMT_DLLPD_B | \ + LAN8814_POWER_MGMT_ADCPD_B | \ + LAN8814_POWER_MGMT_PGAPD_A) + +#define LAN8814_POWER_MGMT_VAL4 (LAN8814_POWER_MGMT_B_C_D | \ + LAN8814_POWER_MGMT_ADCPD_A | \ + LAN8814_POWER_MGMT_PGAPD_A) + +#define LAN8814_POWER_MGMT_VAL5 LAN8814_POWER_MGMT_B_C_D + +#define LAN8814_EEE_WAKE_TX_TIMER 0x0e +#define LAN8814_EEE_WAKE_TX_TIMER_MAX_VAL 0x1f + +static const struct lanphy_reg_data short_center_tap_errata[] = { + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_3_ANEG_MDI, + LAN8814_POWER_MGMT_VAL1 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_4_ANEG_MDIX, + LAN8814_POWER_MGMT_VAL1 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_5_10BT_MDI, + LAN8814_POWER_MGMT_VAL1 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_6_10BT_MDIX, + LAN8814_POWER_MGMT_VAL1 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_7_100BT_TRAIN, + LAN8814_POWER_MGMT_VAL2 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_8_100BT_MDI, + LAN8814_POWER_MGMT_VAL3 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_9_100BT_EEE_MDI_TX, + LAN8814_POWER_MGMT_VAL3 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_10_100BT_EEE_MDI_RX, + LAN8814_POWER_MGMT_VAL4 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_11_100BT_MDIX, + LAN8814_POWER_MGMT_VAL5 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_12_100BT_EEE_MDIX_TX, + LAN8814_POWER_MGMT_VAL5 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_13_100BT_EEE_MDIX_RX, + LAN8814_POWER_MGMT_VAL4 }, + { LAN8814_PAGE_POWER_REGS, + LAN8814_POWER_MGMT_MODE_14_100BTX_EEE_TX_RX, + LAN8814_POWER_MGMT_VAL4 }, +}; + +static const struct lanphy_reg_data waketx_timer_errata[] = { + { LAN8814_PAGE_EEE, + LAN8814_EEE_WAKE_TX_TIMER, + LAN8814_EEE_WAKE_TX_TIMER_MAX_VAL }, +}; + +static int lanphy_write_reg_data(struct phy_device *phydev, + const struct lanphy_reg_data *data, + size_t num) +{ + int ret = 0; + + while (num--) { + ret = lanphy_write_page_reg(phydev, data->page, data->addr, + data->val); + if (ret) + break; + } + + return ret; +} + +static int lan8842_erratas(struct phy_device *phydev) +{ + int ret; + + ret = lanphy_write_reg_data(phydev, short_center_tap_errata, + ARRAY_SIZE(short_center_tap_errata)); + if (ret) + return ret; + + return lanphy_write_reg_data(phydev, waketx_timer_errata, + ARRAY_SIZE(waketx_timer_errata)); +} + static int lan8842_config_init(struct phy_device *phydev) { int ret; @@ -5896,6 +6202,11 @@ static int lan8842_config_init(struct phy_device *phydev) if (ret < 0) return ret; + /* Apply the erratas for this device */ + ret = lan8842_erratas(phydev); + if (ret < 0) + return ret; + /* Even if the GPIOs are set to control the LEDs the behaviour of the * LEDs is wrong, they are not blinking when there is traffic. * To fix this it is required to set extended LED mode @@ -6343,6 +6654,8 @@ static struct phy_driver ksphy_driver[] = { .suspend = genphy_suspend, .resume = kszphy_resume, .config_intr = lan8814_config_intr, + .inband_caps = lan8842_inband_caps, + .config_inband = lan8842_config_inband, .handle_interrupt = lan8814_handle_interrupt, .cable_test_start = lan8814_cable_test_start, .cable_test_get_status = ksz886x_cable_test_get_status, @@ -6463,6 +6776,8 @@ static struct phy_driver ksphy_driver[] = { .cable_test_get_status = ksz9x31_cable_test_get_status, .get_sqi = kszphy_get_sqi, .get_sqi_max = kszphy_get_sqi_max, + .get_mse_capability = kszphy_get_mse_capability, + .get_mse_snapshot = kszphy_get_mse_snapshot, } }; module_phy_driver(ksphy_driver); |
