/* Represents 1ppm adjustment in 2^32 format with * each nsec contains 4 clock cycles. * The value is calculated as following: (1/1000000)/((2^-32)/4)
*/ #define LAN8814_1PPM_FORMAT 17179
/* Represents 1ppm adjustment in 2^32 format with * each nsec contains 8 clock cycles. * The value is calculated as following: (1/1000000)/((2^-32)/8)
*/ #define LAN8841_1PPM_FORMAT 34360
temp &= ~(3 << shift);
temp |= val << shift;
rc = phy_write(phydev, reg, temp);
out: if (rc < 0)
phydev_err(phydev, "failed to set led mode\n");
return rc;
}
/* Disable PHY address 0 as the broadcast address, so that it can be used as a * unique (non-broadcast) address on a shared bus.
*/ staticint kszphy_broadcast_disable(struct phy_device *phydev)
{ int ret;
ret = phy_read(phydev, MII_KSZPHY_OMSO); if (ret < 0) goto out;
ret = phy_write(phydev, MII_KSZPHY_OMSO, ret | KSZPHY_OMSO_B_CAST_OFF);
out: if (ret)
phydev_err(phydev, "failed to disable broadcast address\n");
return ret;
}
staticint kszphy_nand_tree_disable(struct phy_device *phydev)
{ int ret;
ret = phy_read(phydev, MII_KSZPHY_OMSO); if (ret < 0) goto out;
if (!(ret & KSZPHY_OMSO_NAND_TREE_ON)) return 0;
ret = phy_write(phydev, MII_KSZPHY_OMSO,
ret & ~KSZPHY_OMSO_NAND_TREE_ON);
out: if (ret)
phydev_err(phydev, "failed to disable NAND tree mode\n");
return ret;
}
/* Some config bits need to be set again on resume, handle them here. */ staticint kszphy_config_reset(struct phy_device *phydev)
{ struct kszphy_priv *priv = phydev->priv; int ret;
if (priv->rmii_ref_clk_sel) {
ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val); if (ret) {
phydev_err(phydev, "failed to set rmii reference clock\n"); return ret;
}
}
if (priv->type && priv->led_mode >= 0)
kszphy_setup_led(phydev, priv->type->led_mode_reg, priv->led_mode);
staticint ksz8051_ksz8795_match_phy_device(struct phy_device *phydev, constbool ksz_8051)
{ int ret;
if (!phy_id_compare(phydev->phy_id, PHY_ID_KSZ8051, MICREL_PHY_ID_MASK)) return 0;
ret = phy_read(phydev, MII_BMSR); if (ret < 0) return ret;
/* KSZ8051 PHY and KSZ8794/KSZ8795/KSZ8765 switch share the same * exact PHY ID. However, they can be told apart by the extended * capability registers presence. The KSZ8051 PHY has them while * the switch does not.
*/
ret &= BMSR_ERCAP; if (ksz_8051) return ret; else return !ret;
}
staticint ksz8081_config_init(struct phy_device *phydev)
{ /* KSZPHY_OMSO_FACTORY_TEST is set at de-assertion of the reset line * based on the RXER (KSZ8081RNA/RND) or TXC (KSZ8081MNX/RNB) pin. If a * pull-down is missing, the factory test mode should be cleared by * manually writing a 0.
*/
phy_clear_bits(phydev, MII_KSZPHY_OMSO, KSZPHY_OMSO_FACTORY_TEST);
switch (ctrl) { case ETH_TP_MDI:
val = KSZ8081_CTRL2_DISABLE_AUTO_MDIX; break; case ETH_TP_MDI_X:
val = KSZ8081_CTRL2_DISABLE_AUTO_MDIX |
KSZ8081_CTRL2_MDI_MDI_X_SELECT; break; case ETH_TP_MDI_AUTO:
val = 0; break; default: return 0;
}
staticint ksz8081_config_aneg(struct phy_device *phydev)
{ int ret;
ret = genphy_config_aneg(phydev); if (ret) return ret;
/* The MDI-X configuration is automatically changed by the PHY after * switching from autoneg off to on. So, take MDI-X configuration under * own control and set it after autoneg configuration was done.
*/ return ksz8081_config_mdix(phydev, phydev->mdix_ctrl);
}
staticint ksz8081_mdix_update(struct phy_device *phydev)
{ int ret;
ret = phy_read(phydev, MII_KSZPHY_CTRL_2); if (ret < 0) return ret;
staticint ksz8081_read_status(struct phy_device *phydev)
{ int ret;
ret = ksz8081_mdix_update(phydev); if (ret < 0) return ret;
return genphy_read_status(phydev);
}
staticint ksz8061_config_init(struct phy_device *phydev)
{ int ret;
/* Chip can be powered down by the bootstrap code. */
ret = phy_read(phydev, MII_BMCR); if (ret < 0) return ret; if (ret & BMCR_PDOWN) {
ret = phy_write(phydev, MII_BMCR, ret & ~BMCR_PDOWN); if (ret < 0) return ret;
usleep_range(1000, 2000);
}
ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_DEVID1, 0xB61A); if (ret) return ret;
/* The Micrel driver has a deprecated option to place phy OF * properties in the MAC node. Walk up the tree of devices to * find a device with an OF node.
*/
dev_walker = &phydev->mdio.dev; do {
of_node = dev_walker->of_node;
dev_walker = dev_walker->parent;
/* KSZ9031 has internal RGMII_IDRX = 1.2ns and RGMII_IDTX = 0ns. To * provide different RGMII options we need to configure delay offset * for each pad relative to build in delay.
*/ /* keep rx as "No delay adjustment" and set rx_clk to +0.60ns to get delays of * 1.80ns
*/ #define RX_ID 0x7 #define RX_CLK_ID 0x19
/* set rx to +0.30ns and rx_clk to -0.90ns to compensate the * internal 1.2ns delay.
*/ #define RX_ND 0xc #define RX_CLK_ND 0x0
/* set tx to -0.42ns and tx_clk to +0.96ns to get 1.38ns delay */ #define TX_ID 0x0 #define TX_CLK_ID 0x1f
/* set tx and tx_clk to "No delay adjustment" to keep 0ns * dealy
*/ #define TX_ND 0x7 #define TX_CLK_ND 0xf
result = ksz9031_enable_edpd(phydev); if (result < 0) return result;
/* The Micrel driver has a deprecated option to place phy OF * properties in the MAC node. Walk up the tree of devices to * find a device with an OF node.
*/
dev_walker = &phydev->mdio.dev; do {
of_node = dev_walker->of_node;
dev_walker = dev_walker->parent;
} while (!of_node && dev_walker);
if (of_node) { bool update = false;
if (phy_interface_is_rgmii(phydev)) {
result = ksz9031_config_rgmii_delay(phydev); if (result < 0) return result;
}
if (update && !phy_interface_is_rgmii(phydev))
phydev_warn(phydev, "*-skew-ps values should be used only with RGMII PHY modes\n");
/* Silicon Errata Sheet (DS80000691D or DS80000692D): * When the device links in the 1000BASE-T slave mode only, * the optional 125MHz reference output clock (CLK125_NDO) * has wide duty cycle variation. * * The optional CLK125_NDO clock does not meet the RGMII * 45/55 percent (min/max) duty cycle requirement and therefore * cannot be used directly by the MAC side for clocking * applications that have setup/hold time requirements on * rising and falling clock edges. * * Workaround: * Force the phy to be the master to receive a stable clock * which meets the duty cycle requirement.
*/ if (of_property_read_bool(of_node, "micrel,force-master")) {
result = phy_read(phydev, MII_CTRL1000); if (result < 0) goto err_force_master;
/* enable master mode, config & prefer master */
result |= CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER;
result = phy_write(phydev, MII_CTRL1000, result); if (result < 0) goto err_force_master;
}
}
return ksz9031_center_flp_timing(phydev);
err_force_master:
phydev_err(phydev, "failed to force the phy to master mode\n"); return result;
}
/* Silicon Errata DS80000693B * * When LEDs are configured in Individual Mode, LED1 is ON in a no-link * condition. Workaround is to set register 0x1e, bit 9, this way LED1 behaves * according to the datasheet (off if there is no link).
*/ staticint ksz9131_led_errata(struct phy_device *phydev)
{ int reg;
switch (ctrl) { case ETH_TP_MDI:
val = MII_KSZ9131_AUTO_MDIX_SWAP_OFF |
MII_KSZ9131_AUTO_MDI_SET; break; case ETH_TP_MDI_X:
val = MII_KSZ9131_AUTO_MDIX_SWAP_OFF; break; case ETH_TP_MDI_AUTO:
val = 0; break; default: return 0;
}
staticint ksz9131_read_status(struct phy_device *phydev)
{ int ret;
ret = ksz9131_mdix_update(phydev); if (ret < 0) return ret;
return genphy_read_status(phydev);
}
staticint ksz9131_config_aneg(struct phy_device *phydev)
{ int ret;
ret = ksz9131_config_mdix(phydev, phydev->mdix_ctrl); if (ret) return ret;
return genphy_config_aneg(phydev);
}
staticint ksz9477_get_features(struct phy_device *phydev)
{ int ret;
ret = genphy_read_abilities(phydev); if (ret) return ret;
/* The "EEE control and capability 1" (Register 3.20) seems to be * influenced by the "EEE advertisement 1" (Register 7.60). Changes * on the 7.60 will affect 3.20. So, we need to construct our own list * of caps. * KSZ8563R should have 100BaseTX/Full only.
*/
linkmode_and(phydev->supported_eee, phydev->supported,
PHY_EEE_CAP1_FEATURES);
staticint ksz9031_get_features(struct phy_device *phydev)
{ int ret;
ret = genphy_read_abilities(phydev); if (ret < 0) return ret;
/* Silicon Errata Sheet (DS80000691D or DS80000692D): * Whenever the device's Asymmetric Pause capability is set to 1, * link-up may fail after a link-up to link-down transition. * * The Errata Sheet is for ksz9031, but ksz9021 has the same issue * * Workaround: * Do not enable the Asymmetric Pause capability bit.
*/
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported);
/* We force setting the Pause capability as the core will force the * Asymmetric Pause capability to 1 otherwise.
*/
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
return 0;
}
staticint ksz9031_read_status(struct phy_device *phydev)
{ int err; int regval;
err = genphy_read_status(phydev); if (err) return err;
/* Make sure the PHY is not broken. Read idle error count, * and reset the PHY if it is maxed out.
*/
regval = phy_read(phydev, MII_STAT1000); if ((regval & 0xFF) == 0xFF) {
phy_init_hw(phydev);
phydev->link = 0; if (phydev->drv->config_intr && phy_interrupt_is_valid(phydev))
phydev->drv->config_intr(phydev); return genphy_config_aneg(phydev);
}
/* KSZ9131RNX, DS00002841B-page 38, 4.14 LinkMD (R) Cable Diagnostic * Prior to running the cable diagnostics, Auto-negotiation should * be disabled, full duplex set and the link speed set to 1000Mbps * via the Basic Control Register.
*/
ret = phy_modify(phydev, MII_BMCR,
BMCR_SPEED1000 | BMCR_FULLDPLX |
BMCR_ANENABLE | BMCR_SPEED100,
BMCR_SPEED1000 | BMCR_FULLDPLX); if (ret) return ret;
/* KSZ9131RNX, DS00002841B-page 38, 4.14 LinkMD (R) Cable Diagnostic * The Master-Slave configuration should be set to Slave by writing * a value of 0x1000 to the Auto-Negotiation Master Slave Control * Register.
*/
ret = phy_read(phydev, MII_CTRL1000); if (ret < 0) return ret;
/* Cache these bits, they need to be restored once LinkMD finishes. */
priv->vct_ctrl1000 = ret & (CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
ret &= ~(CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
ret |= CTL1000_ENABLE_MASTER;
return phy_write(phydev, MII_CTRL1000, ret);
}
staticint ksz9x31_cable_test_result_trans(u16 status)
{ switch (FIELD_GET(KSZ9x31_LMD_VCT_ST_MASK, status)) { case KSZ9x31_LMD_VCT_ST_NORMAL: return ETHTOOL_A_CABLE_RESULT_CODE_OK; case KSZ9x31_LMD_VCT_ST_OPEN: return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; case KSZ9x31_LMD_VCT_ST_SHORT: return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; case KSZ9x31_LMD_VCT_ST_FAIL:
fallthrough; default: return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
}
}
staticbool ksz9x31_cable_test_failed(u16 status)
{ int stat = FIELD_GET(KSZ9x31_LMD_VCT_ST_MASK, status);
return stat == KSZ9x31_LMD_VCT_ST_FAIL;
}
staticbool ksz9x31_cable_test_fault_length_valid(u16 status)
{ switch (FIELD_GET(KSZ9x31_LMD_VCT_ST_MASK, status)) { case KSZ9x31_LMD_VCT_ST_OPEN:
fallthrough; case KSZ9x31_LMD_VCT_ST_SHORT: returntrue;
} returnfalse;
}
staticint ksz9x31_cable_test_one_pair(struct phy_device *phydev, int pair)
{ int ret, val;
/* KSZ9131RNX, DS00002841B-page 38, 4.14 LinkMD (R) Cable Diagnostic * To test each individual cable pair, set the cable pair in the Cable * Diagnostics Test Pair (VCT_PAIR[1:0]) field of the LinkMD Cable * Diagnostic Register, along with setting the Cable Diagnostics Test * Enable (VCT_EN) bit. The Cable Diagnostics Test Enable (VCT_EN) bit * will self clear when the test is concluded.
*/
ret = phy_write(phydev, KSZ9x31_LMD,
KSZ9x31_LMD_VCT_EN | KSZ9x31_LMD_VCT_PAIR(pair)); if (ret) return ret;
ret = ksz9x31_cable_test_wait_for_completion(phydev); if (ret) return ret;
val = phy_read(phydev, KSZ9x31_LMD); if (val < 0) return val;
if (ksz9x31_cable_test_failed(val)) return -EAGAIN;
ret = ethnl_cable_test_result(phydev,
ksz9x31_cable_test_get_pair(pair),
ksz9x31_cable_test_result_trans(val)); if (ret) return ret;
if (!ksz9x31_cable_test_fault_length_valid(val)) return 0;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
phydev->supported) ||
linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
phydev->supported))
pair_mask = 0xf; /* All pairs */ else
pair_mask = 0x3; /* Pairs A and B only */
/* Try harder if link partner is active */ while (pair_mask && retries--) {
for_each_set_bit(pair, &pair_mask, 4) {
ret = ksz9x31_cable_test_one_pair(phydev, pair); if (ret == -EAGAIN) continue; if (ret < 0) return ret;
clear_bit(pair, &pair_mask);
} /* If link partner is in autonegotiation mode it will send 2ms * of FLPs with at least 6ms of silence. * Add 2ms sleep to have better chances to hit this silence.
*/ if (pair_mask)
usleep_range(2000, 3000);
}
/* Report remaining unfinished pair result as unknown. */
for_each_set_bit(pair, &pair_mask, 4) {
ret = ethnl_cable_test_result(phydev,
ksz9x31_cable_test_get_pair(pair),
ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC);
}
*finished = true;
/* Restore cached bits from before LinkMD got started. */
rv = phy_modify(phydev, MII_CTRL1000,
CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER,
priv->vct_ctrl1000); if (rv) return rv;
switch (ctrl) { case ETH_TP_MDI:
val = KSZ886X_BMCR_DISABLE_AUTO_MDIX; break; case ETH_TP_MDI_X: /* Note: The naming of the bit KSZ886X_BMCR_FORCE_MDI is bit * counter intuitive, the "-X" in "1 = Force MDI" in the data * sheet seems to be missing: * 1 = Force MDI (sic!) (transmit on RX+/RX- pins) * 0 = Normal operation (transmit on TX+/TX- pins)
*/
val = KSZ886X_BMCR_DISABLE_AUTO_MDIX | KSZ886X_BMCR_FORCE_MDI; break; case ETH_TP_MDI_AUTO:
val = 0; break; default: return 0;
}
staticint ksz886x_config_aneg(struct phy_device *phydev)
{ int ret;
ret = genphy_config_aneg(phydev); if (ret) return ret;
if (phydev->autoneg != AUTONEG_ENABLE) { /* When autonegotation 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 * autonegotiation is off.
*/
ret = phy_set_bits(phydev, MII_KSZPHY_CTRL,
KSZ886X_CTRL_FORCE_LINK); if (ret) return ret;
} else { /* If we had previously forced the link state, we need to * clear KSZ886X_CTRL_FORCE_LINK bit now. Otherwise, the PHY * will not perform autonegotiation.
*/
ret = phy_clear_bits(phydev, MII_KSZPHY_CTRL,
KSZ886X_CTRL_FORCE_LINK); if (ret) return ret;
}
/* The MDI-X configuration is automatically changed by the PHY after * switching from autoneg off to on. So, take MDI-X configuration under * own control and set it after autoneg configuration was done.
*/ return ksz886x_config_mdix(phydev, phydev->mdix_ctrl);
}
staticint ksz886x_mdix_update(struct phy_device *phydev)
{ int ret;
ret = phy_read(phydev, MII_BMCR); if (ret < 0) return ret;
staticint ksz9477_phy_errata(struct phy_device *phydev)
{ int err; int i;
/* Apply PHY settings to address errata listed in * KSZ9477, KSZ9897, KSZ9896, KSZ9567, KSZ8565 * Silicon Errata and Data Sheet Clarification documents. * * Document notes: Before configuring the PHY MMD registers, it is * necessary to set the PHY to 100 Mbps speed with auto-negotiation * disabled by writing to register 0xN100-0xN101. After writing the * MMD registers, and after all errata workarounds that involve PHY * register settings, write register 0xN100-0xN101 again to enable * and restart auto-negotiation.
*/
err = phy_write(phydev, MII_BMCR, BMCR_SPEED100 | BMCR_FULLDPLX); if (err) return err;
for (i = 0; i < ARRAY_SIZE(ksz9477_errata_writes); ++i) { conststruct ksz9477_errata_write *errata = &ksz9477_errata_writes[i];
for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++)
data[i] = kszphy_get_stat(phydev, i);
}
/* KSZ9477 PHY RXER Counter. Probably supported by other PHYs like KSZ9313, * etc. The counter is incremented when the PHY receives a frame with one or * more symbol errors. The counter is cleared when the register is read.
*/ #define MII_KSZ9477_PHY_RXER_COUNTER 0x15
/* Base register for Signal Quality Indicator (SQI) - Channel A * * MMD Address: MDIO_MMD_PMAPMD (0x01) * Register: 0xAC (Channel A) * Each channel (pair) has its own register: * Channel A: 0xAC * Channel B: 0xAD * Channel C: 0xAE * Channel D: 0xAF
*/ #define KSZ9477_MMD_SIGNAL_QUALITY_CHAN_A 0xac
/* SQI field mask for bits [14:8] * * SQI indicates relative quality of the signal. * A lower value indicates better signal quality.
*/ #define KSZ9477_MMD_SQI_MASK GENMASK(14, 8)
/* Number of SQI samples to average for a stable result. * * Reference: KSZ9477S Datasheet DS00002392C, Section 4.1.11 (page 26) * For noisy environments, a minimum of 30–50 readings is recommended.
*/ #define KSZ9477_SQI_SAMPLE_COUNT 40
/* The hardware SQI register provides a raw value from 0-127, where a lower * value indicates better signal quality. However, empirical testing has * shown that only the 0-7 range is relevant for a functional link. A raw * value of 8 or higher was measured directly before link drop. This aligns * with the OPEN Alliance recommendation that SQI=0 should represent the * pre-failure state. * * This table provides a non-linear mapping from the useful raw hardware * values (0-7) to the standard 0-7 SQI scale, where higher is better.
*/ staticconst u8 ksz_sqi_mapping[] = {
7, /* raw 0 -> SQI 7 */
7, /* raw 1 -> SQI 7 */
6, /* raw 2 -> SQI 6 */
5, /* raw 3 -> SQI 5 */
4, /* raw 4 -> SQI 4 */
3, /* raw 5 -> SQI 3 */
2, /* raw 6 -> SQI 2 */
1, /* raw 7 -> SQI 1 */
};
/** * kszphy_get_sqi - Read, average, and map Signal Quality Index (SQI) * @phydev: the PHY device * * This function reads and processes the raw Signal Quality Index from the * PHY. Based on empirical testing, a raw value of 8 or higher indicates a * pre-failure state and is mapped to SQI 0. Raw values from 0-7 are * mapped to the standard 0-7 SQI scale via a lookup table. * * Return: SQI value (0–7), or a negative errno on failure.
*/ staticint kszphy_get_sqi(struct phy_device *phydev)
{ int sum[KSZ9477_MAX_CHANNELS] = { 0 }; int worst_sqi = KSZ9477_SQI_MAX; int i, val, raw_sqi, ch;
u8 channels;
/* Determine applicable channels based on link speed */ if (phydev->speed == SPEED_1000)
channels = 4; elseif (phydev->speed == SPEED_100)
channels = 1; else return -EOPNOTSUPP;
/* Sample and accumulate SQI readings for each pair (currently only one). * * Reference: KSZ9477S Datasheet DS00002392C, Section 4.1.11 (page 26) * - The SQI register is updated every 2 µs. * - Values may fluctuate significantly, even in low-noise environments. * - For reliable estimation, average a minimum of 30–50 samples * (recommended for noisy environments) * - In noisy environments, individual readings are highly unreliable. * * We use 40 samples per pair with a delay of 3 µs between each * read to ensure new values are captured (2 µs update interval).
*/ for (i = 0; i < KSZ9477_SQI_SAMPLE_COUNT; i++) { for (ch = 0; ch < channels; ch++) {
val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
KSZ9477_MMD_SIGNAL_QUALITY_CHAN_A + ch); if (val < 0) return val;
/* We communicate with the PHY via MDIO via SPI or * I2C, which is relatively slow. At least slower than * the update interval of the SQI register. * So, we can skip the delay between reads.
*/
}
}
/* Calculate average for each channel and find the worst SQI */ for (ch = 0; ch < channels; ch++) { int avg_raw_sqi = sum[ch] / KSZ9477_SQI_SAMPLE_COUNT; int mapped_sqi;
/* Handle the pre-fail/failed state first. */ if (avg_raw_sqi >= ARRAY_SIZE(ksz_sqi_mapping))
mapped_sqi = 0; else /* Use the lookup table for the good signal range. */
mapped_sqi = ksz_sqi_mapping[avg_raw_sqi];
if (mapped_sqi < worst_sqi)
worst_sqi = mapped_sqi;
}
staticint kszphy_resume(struct phy_device *phydev)
{ int ret;
ret = kszphy_generic_resume(phydev); if (ret) return ret;
/* After switching from power-down to normal mode, an internal global * reset is automatically generated. Wait a minimum of 1 ms before * read/write access to the PHY registers.
*/
usleep_range(1000, 2000);
ret = kszphy_config_reset(phydev); if (ret) return ret;
/* Enable PHY Interrupts */ if (phy_interrupt_is_valid(phydev)) {
phydev->interrupts = PHY_INTERRUPT_ENABLED; if (phydev->drv->config_intr)
phydev->drv->config_intr(phydev);
}
return 0;
}
/* Because of errata DS80000700A, receiver error following software * power down. Suspend and resume callbacks only disable and enable * external rmii reference clock.
*/ staticint ksz8041_resume(struct phy_device *phydev)
{
kszphy_enable_clk(phydev);
staticint ksz9477_resume(struct phy_device *phydev)
{ int ret;
/* No need to initialize registers if not powered down. */
ret = phy_read(phydev, MII_BMCR); if (ret < 0) return ret; if (!(ret & BMCR_PDOWN)) return 0;
genphy_resume(phydev);
/* After switching from power-down to normal mode, an internal global * reset is automatically generated. Wait a minimum of 1 ms before * read/write access to the PHY registers.
*/
usleep_range(1000, 2000);
/* Only KSZ9897 family of switches needs this fix. */ if ((phydev->phy_id & 0xf) == 1) {
ret = ksz9477_phy_errata(phydev); if (ret) return ret;
}
/* Enable PHY Interrupts */ if (phy_interrupt_is_valid(phydev)) {
phydev->interrupts = PHY_INTERRUPT_ENABLED; if (phydev->drv->config_intr)
phydev->drv->config_intr(phydev);
}
return 0;
}
staticint ksz8061_resume(struct phy_device *phydev)
{ int ret;
/* This function can be called twice when the Ethernet device is on. */
ret = phy_read(phydev, MII_BMCR); if (ret < 0) return ret; if (!(ret & BMCR_PDOWN)) return 0;
ret = kszphy_generic_resume(phydev); if (ret) return ret;
usleep_range(1000, 2000);
/* Re-program the value after chip is reset. */
ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_DEVID1, 0xB61A); if (ret) return ret;
/* Enable PHY Interrupts */ if (phy_interrupt_is_valid(phydev)) {
phydev->interrupts = PHY_INTERRUPT_ENABLED; if (phydev->drv->config_intr)
phydev->drv->config_intr(phydev);
}
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
phydev->priv = priv;
priv->type = type;
kszphy_parse_led_mode(phydev);
clk = devm_clk_get_optional_enabled(&phydev->mdio.dev, "rmii-ref"); /* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */ if (!IS_ERR_OR_NULL(clk)) { unsignedlong rate = clk_get_rate(clk); bool rmii_ref_clk_sel_25_mhz;
if (type)
priv->rmii_ref_clk_sel = type->has_rmii_ref_clk_sel;
rmii_ref_clk_sel_25_mhz = of_property_read_bool(np, "micrel,rmii-reference-clock-select-25-mhz");
if (ksz8041_fiber_mode(phydev))
phydev->port = PORT_FIBRE;
/* Support legacy board-file configuration */ if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
priv->rmii_ref_clk_sel = true;
priv->rmii_ref_clk_sel_val = true;
}
return 0;
}
staticint lan8814_cable_test_start(struct phy_device *phydev)
{ /* If autoneg is enabled, we won't be able to test cross pair * short. In this case, the PHY will "detect" a link and * confuse the internal state machine - disable auto neg here. * Set the speed to 1000mbit and full duplex.
*/ return phy_modify(phydev, MII_BMCR, BMCR_ANENABLE | BMCR_SPEED100,
BMCR_SPEED1000 | BMCR_FULLDPLX);
}
/* If autoneg is enabled, we won't be able to test cross pair * short. In this case, the PHY will "detect" a link and * confuse the internal state machine - disable auto neg here. * If autoneg is disabled, we should set the speed to 10mbit.
*/ return phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE | BMCR_SPEED100);
}
static __always_inline int ksz886x_cable_test_result_trans(u16 status, u16 mask)
{ switch (FIELD_GET(mask, status)) { case KSZ8081_LMD_STAT_NORMAL: return ETHTOOL_A_CABLE_RESULT_CODE_OK; case KSZ8081_LMD_STAT_SHORT: return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; case KSZ8081_LMD_STAT_OPEN: return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; case KSZ8081_LMD_STAT_FAIL:
fallthrough; default: return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
}
}
static __always_inline int ksz886x_cable_test_fault_length(struct phy_device *phydev,
u16 status, u16 data_mask)
{ int dt;
/* According to the data sheet the distance to the fault is * DELTA_TIME * 0.4 meters for ksz phys. * (DELTA_TIME - 22) * 0.8 for lan8814 phy.
*/
dt = FIELD_GET(data_mask, status);
staticint ksz886x_cable_test_one_pair(struct phy_device *phydev, int pair)
{ staticconstint ethtool_pair[] = {
ETHTOOL_A_CABLE_PAIR_A,
ETHTOOL_A_CABLE_PAIR_B,
}; int ret, val, mdix;
u32 fault_length;
/* There is no way to choice the pair, like we do one ksz9031. * We can workaround this limitation by using the MDI-X functionality.
*/ if (pair == 0)
mdix = ETH_TP_MDI; else
mdix = ETH_TP_MDI_X;
switch (phydev->phy_id & MICREL_PHY_ID_MASK) { case PHY_ID_KSZ8081:
ret = ksz8081_config_mdix(phydev, mdix); break; case PHY_ID_KSZ886X:
ret = ksz886x_config_mdix(phydev, mdix); break; default:
ret = -ENODEV;
}
if (ret) return ret;
/* Now we are ready to fire. This command will send a 100ns pulse * to the pair.
*/
ret = phy_write(phydev, KSZ8081_LMD, KSZ8081_LMD_ENABLE_TEST); if (ret) return ret;
ret = ksz886x_cable_test_wait_for_completion(phydev); if (ret) return ret;
val = phy_read(phydev, KSZ8081_LMD); if (val < 0) return val;
if (ksz886x_cable_test_failed(val, KSZ8081_LMD_STAT_MASK)) return -EAGAIN;
ret = ethnl_cable_test_result(phydev, ethtool_pair[pair],
ksz886x_cable_test_result_trans(val, KSZ8081_LMD_STAT_MASK)); if (ret) return ret;
if (!ksz886x_cable_test_fault_length_valid(val, KSZ8081_LMD_STAT_MASK)) return 0;
staticint ksz886x_cable_test_get_status(struct phy_device *phydev, bool *finished)
{ conststruct kszphy_type *type = phydev->drv->driver_data; unsignedlong pair_mask = type->pair_mask; int retries = 20; int ret = 0; int pair;
*finished = false;
/* Try harder if link partner is active */ while (pair_mask && retries--) {
for_each_set_bit(pair, &pair_mask, 4) { if (type->cable_diag_reg == LAN8814_CABLE_DIAG)
ret = lan8814_cable_test_one_pair(phydev, pair); else
ret = ksz886x_cable_test_one_pair(phydev, pair); if (ret == -EAGAIN) continue; if (ret < 0) return ret;
clear_bit(pair, &pair_mask);
} /* If link partner is in autonegotiation mode it will send 2ms * of FLPs with at least 6ms of silence. * Add 2ms sleep to have better chances to hit this silence.
*/ if (pair_mask)
msleep(2);
}
*finished = true;
return ret;
}
/** * LAN8814_PAGE_AFE_PMA - Selects Extended Page 1. * * This page appears to control the Analog Front-End (AFE) and Physical * Medium Attachment (PMA) layers. It is used to access registers like * LAN8814_PD_CONTROLS and LAN8814_LINK_QUALITY.
*/ #define LAN8814_PAGE_AFE_PMA 1
/** * LAN8814_PAGE_PCS_DIGITAL - Selects Extended Page 2. * * This page seems dedicated to the Physical Coding Sublayer (PCS) and other * digital logic. It is used for MDI-X alignment (LAN8814_ALIGN_SWAP) and EEE * state (LAN8814_EEE_STATE) in the LAN8814, and is repurposed for statistics * and self-test counters in the LAN8842.
*/ #define LAN8814_PAGE_PCS_DIGITAL 2
/** * LAN8814_PAGE_COMMON_REGS - Selects Extended Page 4. * * This page contains device-common registers that affect the entire chip. * It includes controls for chip-level resets, strap status, GPIO, * QSGMII, the shared 1588 PTP block, and the PVT monitor.
*/ #define LAN8814_PAGE_COMMON_REGS 4
/** * LAN8814_PAGE_PORT_REGS - Selects Extended Page 5. * * This page contains port-specific registers that must be accessed * on a per-port basis. It includes controls for port LEDs, QSGMII PCS, * rate adaptation FIFOs, and the per-port 1588 TSU block.
*/ #define LAN8814_PAGE_PORT_REGS 5
/** * LAN8814_PAGE_SYSTEM_CTRL - Selects Extended Page 31. * * This page appears to hold fundamental system or global controls. In the * driver, it is used by the related LAN8804 to access the * LAN8814_CLOCK_MANAGEMENT register.
*/ #define LAN8814_PAGE_SYSTEM_CTRL 31
if (config->rx_filter != HWTSTAMP_FILTER_NONE)
lan8814_config_ts_intr(ptp_priv->phydev, true); else
lan8814_config_ts_intr(ptp_priv->phydev, false);
/* In case of multiple starts and stops, these needs to be cleared */
list_for_each_entry_safe(rx_ts, tmp, &ptp_priv->rx_ts_list, list) {
list_del(&rx_ts->list);
kfree(rx_ts);
}
skb_queue_purge(&ptp_priv->rx_queue);
skb_queue_purge(&ptp_priv->tx_queue);
if (!lan8814_get_sig_rx(skb, &skb_sig)) return ret;
/* Iterate over all RX timestamps and match it with the received skbs */
spin_lock_irqsave(&ptp_priv->rx_ts_lock, flags);
list_for_each_entry_safe(rx_ts, tmp, &ptp_priv->rx_ts_list, list) { /* Check if we found the signature we were looking for. */ if (memcmp(&skb_sig, &rx_ts->seq_id, sizeof(rx_ts->seq_id))) continue;
/* If we failed to match then add it to the queue for when the timestamp * will come
*/ if (!lan8814_match_rx_skb(ptp_priv, skb))
skb_queue_tail(&ptp_priv->rx_queue, skb);
staticvoid lan8814_ptp_enable_event(struct phy_device *phydev, int event, int pulse_width)
{ /* Set the pulse width of the event, * Make sure that the target clock will be incremented each time when * local time reaches or pass it * Set the polarity high
*/
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, LAN8814_PTP_GENERAL_CONFIG,
LAN8814_PTP_GENERAL_CONFIG_LTC_EVENT_MASK(event) |
LAN8814_PTP_GENERAL_CONFIG_LTC_EVENT_SET(event, pulse_width) |
LAN8814_PTP_GENERAL_CONFIG_RELOAD_ADD_X(event) |
LAN8814_PTP_GENERAL_CONFIG_POLARITY_X(event),
LAN8814_PTP_GENERAL_CONFIG_LTC_EVENT_SET(event, pulse_width) |
LAN8814_PTP_GENERAL_CONFIG_POLARITY_X(event));
}
staticvoid 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 */
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));
}
staticvoid lan8814_ptp_perout_off(struct phy_device *phydev, int pin)
{ /* Disable gpio alternate function, * 1: select as gpio, * 0: select alt func
*/
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
LAN8814_GPIO_EN_ADDR(pin),
LAN8814_GPIO_EN_BIT(pin),
LAN8814_GPIO_EN_BIT(pin));
/* Set buffer type to push pull */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
LAN8814_GPIO_BUF_ADDR(pin),
LAN8814_GPIO_BUF_BIT(pin),
LAN8814_GPIO_BUF_BIT(pin));
}
if (period_nsec < 200) {
pr_warn_ratelimited("%s: perout period too small, minimum is 200 nsec\n",
phydev_name(phydev));
mutex_unlock(&shared->shared_lock); return -EOPNOTSUPP;
}
if (on_nsec >= period_nsec) {
pr_warn_ratelimited("%s: pulse width must be smaller than period\n",
phydev_name(phydev));
mutex_unlock(&shared->shared_lock); return -EINVAL;
}
switch (on_nsec) { case 200000000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_200MS; break; case 100000000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100MS; break; case 50000000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_50MS; break; case 10000000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_10MS; break; case 5000000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_5MS; break; case 1000000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_1MS; break; case 500000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_500US; break; case 100000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100US; break; case 50000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_50US; break; case 10000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_10US; break; case 5000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_5US; break; case 1000:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_1US; break; case 500:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_500NS; break; case 100:
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100NS; break; default:
pr_warn_ratelimited("%s: Use default duty cycle of 100ns\n",
phydev_name(phydev));
pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100NS; break;
}
/* Configure to pulse every period */
lan8814_ptp_enable_event(phydev, event, pulse_width);
lan8814_ptp_set_target(phydev, event, rq->perout.start.sec,
rq->perout.start.nsec);
lan8814_ptp_set_reload(phydev, event, rq->perout.period.sec,
rq->perout.period.nsec);
lan8814_ptp_perout_on(phydev, pin);
mutex_unlock(&shared->shared_lock);
return 0;
}
staticvoid lan8814_ptp_extts_on(struct phy_device *phydev, int pin, u32 flags)
{ /* Set as gpio input */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
LAN8814_GPIO_DIR_ADDR(pin),
LAN8814_GPIO_DIR_BIT(pin),
0);
/* Map the pin to ltc pin 0 of the capture map registers */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
PTP_GPIO_CAP_MAP_LO, pin, pin);
/* Enable capture on the edges of the ltc pin */ if (flags & PTP_RISING_EDGE)
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
PTP_GPIO_CAP_EN,
PTP_GPIO_CAP_EN_GPIO_RE_CAPTURE_ENABLE(0),
PTP_GPIO_CAP_EN_GPIO_RE_CAPTURE_ENABLE(0)); if (flags & PTP_FALLING_EDGE)
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
PTP_GPIO_CAP_EN,
PTP_GPIO_CAP_EN_GPIO_FE_CAPTURE_ENABLE(0),
PTP_GPIO_CAP_EN_GPIO_FE_CAPTURE_ENABLE(0));
staticvoid lan8814_ptp_extts_off(struct phy_device *phydev, int pin)
{ /* Set as gpio out */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
LAN8814_GPIO_DIR_ADDR(pin),
LAN8814_GPIO_DIR_BIT(pin),
LAN8814_GPIO_DIR_BIT(pin));
/* Clear the mapping of pin to registers 0 of the capture registers */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
PTP_GPIO_CAP_MAP_LO,
GENMASK(3, 0),
0);
/* Disable capture on both of the edges */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, PTP_GPIO_CAP_EN,
PTP_GPIO_CAP_EN_GPIO_RE_CAPTURE_ENABLE(pin) |
PTP_GPIO_CAP_EN_GPIO_FE_CAPTURE_ENABLE(pin),
0);
mutex_lock(&shared->shared_lock); if (on)
lan8814_ptp_extts_on(phydev, pin, rq->extts.flags); else
lan8814_ptp_extts_off(phydev, pin);
mutex_unlock(&shared->shared_lock);
return 0;
}
staticint lan8814_ptpci_enable(struct ptp_clock_info *ptpci, struct ptp_clock_request *rq, int on)
{ switch (rq->type) { case PTP_CLK_REQ_PEROUT: return lan8814_ptp_perout(ptpci, rq, on); case PTP_CLK_REQ_EXTTS: return lan8814_ptp_extts(ptpci, rq, on); default: return -EINVAL;
}
}
staticint lan8814_ptpci_verify(struct ptp_clock_info *ptp, unsignedint pin, enum ptp_pin_function func, unsignedint chan)
{ switch (func) { case PTP_PF_NONE: case PTP_PF_PEROUT: /* Only pins 0 and 1 can generate perout signals. And for pin 0 * there is only chan 0 (event A) and for pin 1 there is only * chan 1 (event B)
*/ if (pin >= LAN8814_PTP_PEROUT_NUM || pin != chan) return -1; break; case PTP_PF_EXTTS: if (pin != LAN8814_PTP_EXTTS_NUM) return -1; break; default: return -1;
}
/* If other timestamps are available in the FIFO, * process them.
*/
reg = lanphy_read_page_reg(phydev, LAN8814_PAGE_PORT_REGS,
PTP_CAP_INFO);
} while (PTP_CAP_INFO_TX_TS_CNT_GET_(reg) > 0);
}
/* If we failed to match the skb add it to the queue for when * the frame will come
*/ if (!lan8814_match_skb(ptp_priv, rx_ts)) {
spin_lock_irqsave(&ptp_priv->rx_ts_lock, flags);
list_add(&rx_ts->list, &ptp_priv->rx_ts_list);
spin_unlock_irqrestore(&ptp_priv->rx_ts_lock, flags);
} else {
kfree(rx_ts);
}
}
/* If other timestamps are available in the FIFO, * process them.
*/
reg = lanphy_read_page_reg(phydev, LAN8814_PAGE_PORT_REGS,
PTP_CAP_INFO);
} while (PTP_CAP_INFO_RX_TS_CNT_GET_(reg) > 0);
}
/* This is 0 because whatever was the input pin it was mapped it to * ltc gpio pin 0
*/
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, PTP_GPIO_SEL,
PTP_GPIO_SEL_GPIO_SEL(0),
PTP_GPIO_SEL_GPIO_SEL(0));
/* Make sure that the PHY will not stop generating the clock when the * link partner goes down
*/
lanphy_write_page_reg(phydev, LAN8814_PAGE_SYSTEM_CTRL,
LAN8814_CLOCK_MANAGEMENT, 0x27e);
lanphy_read_page_reg(phydev, LAN8814_PAGE_AFE_PMA, LAN8814_LINK_QUALITY);
return 0;
}
static irqreturn_t lan8804_handle_interrupt(struct phy_device *phydev)
{ int status;
status = phy_read(phydev, LAN8814_INTS); if (status < 0) {
phy_error(phydev); return IRQ_NONE;
}
staticint lan8804_config_intr(struct phy_device *phydev)
{ int err;
/* This is an internal PHY of lan966x and is not possible to change the * polarity on the GIC found in lan966x, therefore change the polarity * of the interrupt in the PHY from being active low instead of active * high.
*/
phy_write(phydev, LAN8804_CONTROL, LAN8804_CONTROL_INTR_POLARITY);
/* By default interrupt buffer is open-drain in which case the interrupt * can be active only low. Therefore change the interrupt buffer to be * push-pull to be able to change interrupt polarity
*/
phy_write(phydev, LAN8804_OUTPUT_CONTROL,
LAN8804_OUTPUT_CONTROL_INTR_BUFFER);
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
err = phy_read(phydev, LAN8814_INTS); if (err < 0) return err;
/* The EP.4 is shared between all the PHYs in the package and also it * can be accessed by any of the PHYs
*/
lanphy_write_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
LTC_HARD_RESET, LTC_HARD_RESET_);
lanphy_write_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, PTP_OPERATING_MODE,
PTP_OPERATING_MODE_STANDALONE_);
/* Enable ptp to run LTC clock for ptp and gpio 1PPS operation */
lanphy_write_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, PTP_CMD_CTL,
PTP_CMD_CTL_PTP_ENABLE_);
return 0;
}
staticvoid lan8814_setup_led(struct phy_device *phydev, int val)
{ int temp;
if (lan8814->led_mode >= 0)
lan8814_setup_led(phydev, lan8814->led_mode);
return 0;
}
/* It is expected that there will not be any 'lan8814_take_coma_mode' * function called in suspend. Because the GPIO line can be shared, so if one of * the phys goes back in coma mode, then all the other PHYs will go, which is * wrong.
*/ staticint lan8814_release_coma_mode(struct phy_device *phydev)
{ struct gpio_desc *gpiod;
gpiod_set_consumer_name(gpiod, "LAN8814 coma mode");
gpiod_set_value_cansleep(gpiod, 0);
return 0;
}
staticvoid 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 * link
*/
lanphy_modify_page_reg(phydev, LAN8814_PAGE_PCS_DIGITAL, LAN8814_EEE_STATE,
LAN8814_EEE_STATE_MASK2P5P,
0);
}
staticvoid lan8814_update_meas_time(struct phy_device *phydev)
{ /* By setting the measure time to a value of 0xb this will allow cables * longer than 100m to be used. This configuration can be used * regardless of the mode of operation of the PHY
*/
lanphy_modify_page_reg(phydev, LAN8814_PAGE_AFE_PMA, LAN8814_PD_CONTROLS,
LAN8814_PD_CONTROLS_PD_MEAS_TIME_MASK,
LAN8814_PD_CONTROLS_PD_MEAS_TIME_VAL);
}
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
err = phy_read(phydev, LAN8814_INTS); if (err < 0) return err;
/* Enable / disable interrupts. It is OK to enable PTP interrupt * even if it PTP is not enabled. Because the underneath blocks * will not enable the PTP so we will never get the PTP * interrupt.
*/
err = phy_write(phydev, LAN8814_INTC,
LAN8814_INT_LINK | LAN8841_INT_PTP);
} else {
err = phy_write(phydev, LAN8814_INTC, 0); if (err) return err;
err = phy_read(phydev, LAN8814_INTS); if (err < 0) return err;
/* Getting a positive value doesn't mean that is an error, it * just indicates what was the status. Therefore make sure to * clear the value and say that there is no error.
*/
err = 0;
}
if (enable) { /* Enable interrupts on the TX side */
phy_modify_mmd(phydev, 2, LAN8841_PTP_INT_EN,
LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN |
LAN8841_PTP_INT_EN_PTP_TX_TS_EN,
LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN |
LAN8841_PTP_INT_EN_PTP_TX_TS_EN);
/* Enable the modification of the frame on RX side, * this will add the ns and 2 bits of sec in the reserved field * of the PTP header
*/
phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
LAN8841_PTP_RX_MODE,
LAN8841_PTP_INSERT_TS_EN |
LAN8841_PTP_INSERT_TS_32BIT,
LAN8841_PTP_INSERT_TS_EN |
LAN8841_PTP_INSERT_TS_32BIT);
ptp_schedule_worker(ptp_priv->ptp_clock, 0);
} else { /* Disable interrupts on the TX side */
phy_modify_mmd(phydev, 2, LAN8841_PTP_INT_EN,
LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN |
LAN8841_PTP_INT_EN_PTP_TX_TS_EN, 0);
/* Disable modification of the RX frames */
phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
LAN8841_PTP_RX_MODE,
LAN8841_PTP_INSERT_TS_EN |
LAN8841_PTP_INSERT_TS_32BIT, 0);
/* Set the value to be stored */
mutex_lock(&ptp_priv->ptp_lock);
phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_SET_SEC_LO, lower_16_bits(ts->tv_sec));
phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_SET_SEC_MID, upper_16_bits(ts->tv_sec));
phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_SET_SEC_HI, upper_32_bits(ts->tv_sec) & 0xffff);
phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_SET_NS_LO, lower_16_bits(ts->tv_nsec));
phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_SET_NS_HI, upper_16_bits(ts->tv_nsec) & 0x3fff);
/* Set the command to load the LTC */
phy_write_mmd(phydev, 2, LAN8841_PTP_CMD_CTL,
LAN8841_PTP_CMD_CTL_PTP_LTC_LOAD);
ret = lan8841_ptp_update_target(ptp_priv, ts);
mutex_unlock(&ptp_priv->ptp_lock);
mutex_lock(&ptp_priv->ptp_lock); /* Issue the command to read the LTC */
phy_write_mmd(phydev, 2, LAN8841_PTP_CMD_CTL,
LAN8841_PTP_CMD_CTL_PTP_LTC_READ);
/* Read the LTC */
s = phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_HI);
s <<= 16;
s |= phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_MID);
s <<= 16;
s |= phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_LO);
mutex_lock(&ptp_priv->ptp_lock); /* Issue the command to read the LTC */
phy_write_mmd(phydev, 2, LAN8841_PTP_CMD_CTL,
LAN8841_PTP_CMD_CTL_PTP_LTC_READ);
/* Read the LTC */
s = phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_HI);
s <<= 16;
s |= phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_MID);
s <<= 16;
s |= phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_LO);
mutex_unlock(&ptp_priv->ptp_lock);
/* The HW allows up to 15 sec to adjust the time, but here we limit to * 10 sec the adjustment. The reason is, in case the adjustment is 14 * sec and 999999999 nsec, then we add 8ns to compansate the actual * increment so the value can be bigger than 15 sec. Therefore limit the * possible adjustments so we will not have these corner cases
*/ if (delta > 10000000000LL || delta < -10000000000LL) { /* The timeadjustment is too big, so fall back using set time */
u64 now;
ptp->gettime64(ptp, &ts);
now = ktime_to_ns(timespec64_to_ktime(ts));
ts = ns_to_timespec64(now + delta);
ptp->settime64(ptp, &ts); return 0;
}
sec = div_u64_rem(delta < 0 ? -delta : delta, NSEC_PER_SEC, &nsec); if (delta < 0 && nsec != 0) { /* It is not allowed to adjust low the nsec part, therefore * subtract more from second part and add to nanosecond such * that would roll over, so the second part will increase
*/
sec--;
nsec = NSEC_PER_SEC - nsec;
}
/* Calculate the adjustments and the direction */ if (delta < 0)
add = false;
if (nsec > 0) /* add 8 ns to cover the likely normal increment */
nsec += 8;
if (nsec >= NSEC_PER_SEC) { /* carry into seconds */
sec++;
nsec -= NSEC_PER_SEC;
}
staticint lan8841_ptp_remove_event(struct kszphy_ptp_priv *ptp_priv, int pin,
u8 event)
{ struct phy_device *phydev = ptp_priv->phydev;
u16 tmp; int ret;
/* Now remove pin from the event. GPIO_DATA_SEL1 contains the GPIO * pins 0-4 while GPIO_DATA_SEL2 contains GPIO pins 5-9, therefore * depending on the pin, it requires to read a different register
*/ if (pin < 5) {
tmp = LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_MASK << (3 * pin);
ret = phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_DATA_SEL1, tmp);
} else {
tmp = LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_MASK << (3 * (pin - 5));
ret = phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_DATA_SEL2, tmp);
} if (ret) return ret;
staticint lan8841_ptp_enable_event(struct kszphy_ptp_priv *ptp_priv, int pin,
u8 event, int pulse_width)
{ struct phy_device *phydev = ptp_priv->phydev;
u16 tmp; int ret;
/* Enable the event */ if (event == LAN8841_EVENT_A)
ret = phy_modify_mmd(phydev, 2, LAN8841_PTP_GENERAL_CONFIG,
LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_A |
LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_A_MASK,
LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_A |
pulse_width << LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_A); else
ret = phy_modify_mmd(phydev, 2, LAN8841_PTP_GENERAL_CONFIG,
LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_B |
LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_B_MASK,
LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_B |
pulse_width << LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_B); if (ret) return ret;
/* Now connect the pin to the event. GPIO_DATA_SEL1 contains the GPIO * pins 0-4 while GPIO_DATA_SEL2 contains GPIO pins 5-9, therefore * depending on the pin, it requires to read a different register
*/ if (event == LAN8841_EVENT_A)
tmp = LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_A; else
tmp = LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_B;
if (pin < 5)
ret = phy_set_bits_mmd(phydev, 2, LAN8841_GPIO_DATA_SEL1,
tmp << (3 * pin)); else
ret = phy_set_bits_mmd(phydev, 2, LAN8841_GPIO_DATA_SEL2,
tmp << (3 * (pin - 5)));
staticint lan8841_ptp_extts_on(struct kszphy_ptp_priv *ptp_priv, int pin,
u32 flags)
{ struct phy_device *phydev = ptp_priv->phydev;
u16 tmp = 0; int ret;
/* Set GPIO to be intput */
ret = phy_set_bits_mmd(phydev, 2, LAN8841_GPIO_EN, BIT(pin)); if (ret) return ret;
ret = phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_BUF, BIT(pin)); if (ret) return ret;
/* Enable capture on the edges of the pin */ if (flags & PTP_RISING_EDGE)
tmp |= LAN8841_PTP_GPIO_CAP_EN_GPIO_RE_CAPTURE_ENABLE(pin); if (flags & PTP_FALLING_EDGE)
tmp |= LAN8841_PTP_GPIO_CAP_EN_GPIO_FE_CAPTURE_ENABLE(pin);
ret = phy_write_mmd(phydev, 2, LAN8841_PTP_GPIO_CAP_EN, tmp); if (ret) return ret;
staticint lan8841_ptp_extts_off(struct kszphy_ptp_priv *ptp_priv, int pin)
{ struct phy_device *phydev = ptp_priv->phydev; int ret;
/* Set GPIO to be output */
ret = phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_EN, BIT(pin)); if (ret) return ret;
ret = phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_BUF, BIT(pin)); if (ret) return ret;
/* Disable capture on both of the edges */
ret = phy_modify_mmd(phydev, 2, LAN8841_PTP_GPIO_CAP_EN,
LAN8841_PTP_GPIO_CAP_EN_GPIO_RE_CAPTURE_ENABLE(pin) |
LAN8841_PTP_GPIO_CAP_EN_GPIO_FE_CAPTURE_ENABLE(pin),
0); if (ret) return ret;
mutex_lock(&ptp_priv->ptp_lock); if (on)
ret = lan8841_ptp_extts_on(ptp_priv, pin, rq->extts.flags); else
ret = lan8841_ptp_extts_off(ptp_priv, pin);
mutex_unlock(&ptp_priv->ptp_lock);
return ret;
}
staticint lan8841_ptp_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *rq, int on)
{ switch (rq->type) { case PTP_CLK_REQ_EXTTS: return lan8841_ptp_extts(ptp, rq, on); case PTP_CLK_REQ_PEROUT: return lan8841_ptp_perout(ptp, rq, on); default: return -EOPNOTSUPP;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.120Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.