@@ -121,6 +121,26 @@
#define PTP_TIMESTAMP_EN_PDREQ_ BIT(2)
#define PTP_TIMESTAMP_EN_PDRES_ BIT(3)
+#define PTP_RX_LATENCY_1000 0x0224
+#define PTP_TX_LATENCY_1000 0x0225
+
+#define PTP_RX_LATENCY_100 0x0222
+#define PTP_TX_LATENCY_100 0x0223
+
+#define PTP_RX_LATENCY_10 0x0220
+#define PTP_TX_LATENCY_10 0x0221
+
+#define PTP_LATENCY_1000_CRCTN_1S 0x000C
+#define PTP_LATENCY_100_CRCTN_1S 0x028D
+#define PTP_LATENCY_10_CRCTN_1S 0x01E
+
+#define PTP_RX_LATENCY_1000_CRCTN_2S 0x0048
+#define PTP_TX_LATENCY_1000_CRCTN_2S 0x0049
+#define PTP_RX_LATENCY_100_CRCTN_2S 0x0707
+#define PTP_TX_LATENCY_100_CRCTN_2S 0x0275
+#define PTP_RX_LATENCY_10_CRCTN_2S 0x17CE
+#define PTP_TX_LATENCY_10_CRCTN_2S 0x17CE
+
#define PTP_TX_PARSE_L2_ADDR_EN 0x0284
#define PTP_RX_PARSE_L2_ADDR_EN 0x0244
@@ -284,6 +304,15 @@ struct lan8814_ptp_rx_ts {
u16 seq_id;
};
+struct kszphy_latencies {
+ u16 rx_10;
+ u16 tx_10;
+ u16 rx_100;
+ u16 tx_100;
+ u16 rx_1000;
+ u16 tx_1000;
+};
+
struct kszphy_ptp_priv {
struct mii_timestamper mii_ts;
struct phy_device *phydev;
@@ -303,6 +332,7 @@ struct kszphy_ptp_priv {
struct kszphy_priv {
struct kszphy_ptp_priv ptp_priv;
+ struct kszphy_latencies latencies;
const struct kszphy_type *type;
int led_mode;
u16 vct_ctrl1000;
@@ -2087,16 +2117,82 @@ static void lan8814_flush_fifo(struct phy_device *phydev, bool egress)
lanphy_read_page_reg(phydev, 5, PTP_TSU_INT_STS);
}
+static void lan8814_get_latency(struct phy_device *phydev)
+{
+ struct kszphy_priv *priv = phydev->priv;
+ struct kszphy_latencies *latencies = &priv->latencies;
+
+ latencies->rx_1000 = lanphy_read_page_reg(phydev, 5, PTP_RX_LATENCY_1000);
+ latencies->rx_100 = lanphy_read_page_reg(phydev, 5, PTP_RX_LATENCY_100);
+ latencies->rx_10 = lanphy_read_page_reg(phydev, 5, PTP_RX_LATENCY_10);
+ latencies->tx_1000 = lanphy_read_page_reg(phydev, 5, PTP_TX_LATENCY_1000);
+ latencies->tx_100 = lanphy_read_page_reg(phydev, 5, PTP_TX_LATENCY_100);
+ latencies->tx_10 = lanphy_read_page_reg(phydev, 5, PTP_TX_LATENCY_10);
+}
+
+static void lan8814_latency_config(struct phy_device *phydev,
+ struct kszphy_latencies *latencies)
+{
+ switch (phydev->speed) {
+ case SPEED_1000:
+ lanphy_write_page_reg(phydev, 5, PTP_RX_LATENCY_1000,
+ latencies->rx_1000);
+ lanphy_write_page_reg(phydev, 5, PTP_TX_LATENCY_1000,
+ latencies->tx_1000);
+ break;
+ case SPEED_100:
+ lanphy_write_page_reg(phydev, 5, PTP_RX_LATENCY_100,
+ latencies->rx_100);
+ lanphy_write_page_reg(phydev, 5, PTP_TX_LATENCY_100,
+ latencies->tx_100);
+ break;
+ case SPEED_10:
+ lanphy_write_page_reg(phydev, 5, PTP_RX_LATENCY_10,
+ latencies->rx_10);
+ lanphy_write_page_reg(phydev, 5, PTP_TX_LATENCY_10,
+ latencies->tx_10);
+ break;
+ default:
+ break;
+ }
+}
+
+static void lan8814_latency_workaround(struct phy_device *phydev,
+ struct kszphy_latencies *latencies, bool onestep)
+{
+ struct kszphy_priv *priv = phydev->priv;
+ struct kszphy_latencies *priv_latencies = &priv->latencies;
+
+ if (onestep) {
+ latencies->rx_10 = priv_latencies->rx_10 - PTP_LATENCY_10_CRCTN_1S;
+ latencies->rx_100 = priv_latencies->rx_100 - PTP_LATENCY_100_CRCTN_1S;
+ latencies->rx_1000 = priv_latencies->rx_1000 - PTP_LATENCY_1000_CRCTN_1S;
+ latencies->tx_10 = priv_latencies->tx_10 - PTP_LATENCY_10_CRCTN_1S;
+ latencies->tx_100 = priv_latencies->tx_100 - PTP_LATENCY_100_CRCTN_1S;
+ latencies->tx_1000 = priv_latencies->tx_1000 - PTP_LATENCY_1000_CRCTN_1S;
+ } else {
+ latencies->rx_10 = priv_latencies->rx_10 - PTP_RX_LATENCY_10_CRCTN_2S;
+ latencies->rx_100 = priv_latencies->rx_100 - PTP_RX_LATENCY_100_CRCTN_2S;
+ latencies->rx_1000 = priv_latencies->rx_1000 - PTP_RX_LATENCY_1000_CRCTN_2S;
+ latencies->tx_10 = priv_latencies->tx_10 - PTP_TX_LATENCY_10_CRCTN_2S;
+ latencies->tx_100 = priv_latencies->tx_100 - PTP_TX_LATENCY_100_CRCTN_2S;
+ latencies->tx_1000 = priv_latencies->tx_1000 - PTP_TX_LATENCY_1000_CRCTN_2S;
+ }
+}
+
static int lan8814_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
{
struct kszphy_ptp_priv *ptp_priv =
container_of(mii_ts, struct kszphy_ptp_priv, mii_ts);
struct phy_device *phydev = ptp_priv->phydev;
struct lan8814_shared_priv *shared = phydev->shared->priv;
+ struct kszphy_priv *priv = phydev->priv;
struct lan8814_ptp_rx_ts *rx_ts, *tmp;
+ struct kszphy_latencies latencies;
struct hwtstamp_config config;
int txcfg = 0, rxcfg = 0;
int pkt_ts_enable;
+ u16 temp;
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT;
@@ -2146,9 +2242,21 @@ static int lan8814_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
lanphy_write_page_reg(ptp_priv->phydev, 5, PTP_RX_TIMESTAMP_EN, pkt_ts_enable);
lanphy_write_page_reg(ptp_priv->phydev, 5, PTP_TX_TIMESTAMP_EN, pkt_ts_enable);
- if (ptp_priv->hwts_tx_type == HWTSTAMP_TX_ONESTEP_SYNC)
- lanphy_write_page_reg(ptp_priv->phydev, 5, PTP_TX_MOD,
- PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_);
+ temp = lanphy_read_page_reg(phydev, 5, PTP_TX_MOD);
+ if (ptp_priv->hwts_tx_type == HWTSTAMP_TX_ONESTEP_SYNC) {
+ temp |= PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_;
+
+ lan8814_latency_workaround(phydev, &latencies, true);
+ lan8814_latency_config(phydev, &latencies);
+ } else if (ptp_priv->hwts_tx_type == HWTSTAMP_TX_ON) {
+ lan8814_latency_workaround(phydev, &latencies, false);
+ lan8814_latency_config(phydev, &latencies);
+ } else {
+ temp &= ~PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_;
+
+ lan8814_latency_config(phydev, &priv->latencies);
+ }
+ lanphy_write_page_reg(ptp_priv->phydev, 5, PTP_TX_MOD, temp);
if (config.rx_filter != HWTSTAMP_FILTER_NONE)
lan8814_config_ts_intr(ptp_priv->phydev, true);
@@ -2676,6 +2784,13 @@ static int lan8804_config_init(struct phy_device *phydev)
return 0;
}
+void lan8814_link_change_notify(struct phy_device *phydev)
+{
+ struct kszphy_priv *priv = phydev->priv;
+
+ lan8814_latency_config(phydev, &priv->latencies);
+}
+
static irqreturn_t lan8814_handle_interrupt(struct phy_device *phydev)
{
int irq_status, tsu_irq_status;
@@ -2923,6 +3038,7 @@ static int lan8814_probe(struct phy_device *phydev)
}
lan8814_ptp_init(phydev);
+ lan8814_get_latency(phydev);
return 0;
}
@@ -3117,6 +3233,7 @@ static struct phy_driver ksphy_driver[] = {
.resume = kszphy_resume,
.config_intr = lan8814_config_intr,
.handle_interrupt = lan8814_handle_interrupt,
+ .link_change_notify = lan8814_link_change_notify,
}, {
.phy_id = PHY_ID_LAN8804,
.phy_id_mask = MICREL_PHY_ID_MASK,
Latency adjustments done for 1-step and 2-step from default latency register values to fix negative and high mean path delays. Signed-off-by: Divya Koppera <Divya.Koppera@microchip.com> --- drivers/net/phy/micrel.c | 123 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-)