Lines Matching +full:tx +full:- +full:internal +full:- +full:delay +full:- +full:ps

1 // SPDX-License-Identifier: GPL-2.0
4 * Author: Radu Pirea <radu-nicolae.pirea@oss.nxp.com>
7 #include <linux/delay.h>
174 #define NXP_C45_SKB_CB(skb) ((struct nxp_c45_skb_cb *)(skb)->cb)
214 return phydev->irq <= 0; in nxp_c45_poll_txts()
223 phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL, in _nxp_c45_ptp_gettimex64()
225 ts->tv_nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, in _nxp_c45_ptp_gettimex64()
227 ts->tv_nsec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, in _nxp_c45_ptp_gettimex64()
229 ts->tv_sec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, in _nxp_c45_ptp_gettimex64()
231 ts->tv_sec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, in _nxp_c45_ptp_gettimex64()
243 mutex_lock(&priv->ptp_lock); in nxp_c45_ptp_gettimex64()
245 mutex_unlock(&priv->ptp_lock); in nxp_c45_ptp_gettimex64()
255 phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_0, in _nxp_c45_ptp_settime64()
256 ts->tv_nsec); in _nxp_c45_ptp_settime64()
257 phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_1, in _nxp_c45_ptp_settime64()
258 ts->tv_nsec >> 16); in _nxp_c45_ptp_settime64()
259 phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_0, in _nxp_c45_ptp_settime64()
260 ts->tv_sec); in _nxp_c45_ptp_settime64()
261 phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_1, in _nxp_c45_ptp_settime64()
262 ts->tv_sec >> 16); in _nxp_c45_ptp_settime64()
263 phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL, in _nxp_c45_ptp_settime64()
274 mutex_lock(&priv->ptp_lock); in nxp_c45_ptp_settime64()
276 mutex_unlock(&priv->ptp_lock); in nxp_c45_ptp_settime64()
288 mutex_lock(&priv->ptp_lock); in nxp_c45_ptp_adjfine()
294 phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_0, in nxp_c45_ptp_adjfine()
301 phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_1, in nxp_c45_ptp_adjfine()
303 mutex_unlock(&priv->ptp_lock); in nxp_c45_ptp_adjfine()
313 mutex_lock(&priv->ptp_lock); in nxp_c45_ptp_adjtime()
318 mutex_unlock(&priv->ptp_lock); in nxp_c45_ptp_adjtime()
326 ts->tv_nsec = hwts->nsec; in nxp_c45_reconstruct_ts()
327 if ((ts->tv_sec & TS_SEC_MASK) < (hwts->sec & TS_SEC_MASK)) in nxp_c45_reconstruct_ts()
328 ts->tv_sec -= TS_SEC_MASK + 1; in nxp_c45_reconstruct_ts()
329 ts->tv_sec &= ~TS_SEC_MASK; in nxp_c45_reconstruct_ts()
330 ts->tv_sec |= hwts->sec & TS_SEC_MASK; in nxp_c45_reconstruct_ts()
337 return ntohs(header->sequence_id) == hwts->sequence_id && in nxp_c45_match_ts()
338 ptp_get_msgtype(header, type) == hwts->msg_type && in nxp_c45_match_ts()
339 header->domain_number == hwts->domain_number; in nxp_c45_match_ts()
348 mutex_lock(&priv->ptp_lock); in nxp_c45_get_hwtxts()
349 phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_CTRL, in nxp_c45_get_hwtxts()
351 reg = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_DATA_0); in nxp_c45_get_hwtxts()
356 hwts->domain_number = reg; in nxp_c45_get_hwtxts()
357 hwts->msg_type = (reg & RING_DATA_0_MSG_TYPE) >> 8; in nxp_c45_get_hwtxts()
358 hwts->sec = (reg & RING_DATA_0_SEC_4_2) >> 10; in nxp_c45_get_hwtxts()
359 hwts->sequence_id = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, in nxp_c45_get_hwtxts()
361 hwts->nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, in nxp_c45_get_hwtxts()
363 reg = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_DATA_3); in nxp_c45_get_hwtxts()
364 hwts->nsec |= (reg & RING_DATA_3_NSEC_29_16) << 16; in nxp_c45_get_hwtxts()
365 hwts->sec |= (reg & RING_DATA_3_SEC_1_0) >> 14; in nxp_c45_get_hwtxts()
368 mutex_unlock(&priv->ptp_lock); in nxp_c45_get_hwtxts()
382 spin_lock_irqsave(&priv->tx_queue.lock, flags); in nxp_c45_process_txts()
383 skb_queue_walk_safe(&priv->tx_queue, skb, tmp) { in nxp_c45_process_txts()
384 ts_match = nxp_c45_match_ts(NXP_C45_SKB_CB(skb)->header, txts, in nxp_c45_process_txts()
385 NXP_C45_SKB_CB(skb)->type); in nxp_c45_process_txts()
389 __skb_unlink(skb, &priv->tx_queue); in nxp_c45_process_txts()
392 spin_unlock_irqrestore(&priv->tx_queue.lock, flags); in nxp_c45_process_txts()
395 nxp_c45_ptp_gettimex64(&priv->caps, &ts, NULL); in nxp_c45_process_txts()
402 phydev_warn(priv->phydev, in nxp_c45_process_txts()
403 "the tx timestamp doesn't match with any skb\n"); in nxp_c45_process_txts()
410 bool poll_txts = nxp_c45_poll_txts(priv->phydev); in nxp_c45_do_aux_work()
419 while (!skb_queue_empty_lockless(&priv->tx_queue) && poll_txts) { in nxp_c45_do_aux_work()
430 while ((skb = skb_dequeue(&priv->rx_queue)) != NULL) { in nxp_c45_do_aux_work()
431 nxp_c45_ptp_gettimex64(&priv->caps, &ts, NULL); in nxp_c45_do_aux_work()
432 ts_raw = __be32_to_cpu(NXP_C45_SKB_CB(skb)->header->reserved2); in nxp_c45_do_aux_work()
437 shhwtstamps_rx->hwtstamp = ns_to_ktime(timespec64_to_ns(&ts)); in nxp_c45_do_aux_work()
438 NXP_C45_SKB_CB(skb)->header->reserved2 = 0; in nxp_c45_do_aux_work()
442 return reschedule ? 1 : -1; in nxp_c45_do_aux_work()
447 priv->caps = (struct ptp_clock_info) { in nxp_c45_init_ptp_clock()
458 priv->ptp_clock = ptp_clock_register(&priv->caps, in nxp_c45_init_ptp_clock()
459 &priv->phydev->mdio.dev); in nxp_c45_init_ptp_clock()
461 if (IS_ERR(priv->ptp_clock)) in nxp_c45_init_ptp_clock()
462 return PTR_ERR(priv->ptp_clock); in nxp_c45_init_ptp_clock()
464 if (!priv->ptp_clock) in nxp_c45_init_ptp_clock()
465 return -ENOMEM; in nxp_c45_init_ptp_clock()
476 switch (priv->hwts_tx) { in nxp_c45_txtstamp()
478 NXP_C45_SKB_CB(skb)->type = type; in nxp_c45_txtstamp()
479 NXP_C45_SKB_CB(skb)->header = ptp_parse_header(skb, type); in nxp_c45_txtstamp()
480 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; in nxp_c45_txtstamp()
481 skb_queue_tail(&priv->tx_queue, skb); in nxp_c45_txtstamp()
482 if (nxp_c45_poll_txts(priv->phydev)) in nxp_c45_txtstamp()
483 ptp_schedule_worker(priv->ptp_clock, 0); in nxp_c45_txtstamp()
502 if (!priv->hwts_rx) in nxp_c45_rxtstamp()
505 NXP_C45_SKB_CB(skb)->header = header; in nxp_c45_rxtstamp()
506 skb_queue_tail(&priv->rx_queue, skb); in nxp_c45_rxtstamp()
507 ptp_schedule_worker(priv->ptp_clock, 0); in nxp_c45_rxtstamp()
517 struct phy_device *phydev = priv->phydev; in nxp_c45_hwtstamp()
520 if (copy_from_user(&cfg, ifreq->ifr_data, sizeof(cfg))) in nxp_c45_hwtstamp()
521 return -EFAULT; in nxp_c45_hwtstamp()
524 return -ERANGE; in nxp_c45_hwtstamp()
526 priv->hwts_tx = cfg.tx_type; in nxp_c45_hwtstamp()
530 priv->hwts_rx = 0; in nxp_c45_hwtstamp()
535 priv->hwts_rx = 1; in nxp_c45_hwtstamp()
539 return -ERANGE; in nxp_c45_hwtstamp()
542 if (priv->hwts_rx || priv->hwts_tx) { in nxp_c45_hwtstamp()
555 if (nxp_c45_poll_txts(priv->phydev)) in nxp_c45_hwtstamp()
558 if (priv->hwts_tx) in nxp_c45_hwtstamp()
566 return copy_to_user(ifreq->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; in nxp_c45_hwtstamp()
575 ts_info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | in nxp_c45_ts_info()
578 ts_info->phc_index = ptp_clock_index(priv->ptp_clock); in nxp_c45_ts_info()
579 ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); in nxp_c45_ts_info()
580 ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | in nxp_c45_ts_info()
673 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) in nxp_c45_config_intr()
683 struct nxp_c45_phy *priv = phydev->priv; in nxp_c45_handle_interrupt()
773 switch (phydev->master_slave_set) { in nxp_c45_setup_master_slave()
789 return -EOPNOTSUPP; in nxp_c45_setup_master_slave()
799 phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; in nxp_c45_read_master_slave()
800 phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; in nxp_c45_read_master_slave()
807 phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; in nxp_c45_read_master_slave()
808 phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; in nxp_c45_read_master_slave()
810 phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; in nxp_c45_read_master_slave()
811 phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; in nxp_c45_read_master_slave()
843 return -EINVAL; in nxp_c45_get_sqi()
855 static int nxp_c45_check_delay(struct phy_device *phydev, u32 delay) in nxp_c45_check_delay() argument
857 if (delay < MIN_ID_PS) { in nxp_c45_check_delay()
858 phydev_err(phydev, "delay value smaller than %u\n", MIN_ID_PS); in nxp_c45_check_delay()
859 return -EINVAL; in nxp_c45_check_delay()
862 if (delay > MAX_ID_PS) { in nxp_c45_check_delay()
863 phydev_err(phydev, "delay value higher than %u\n", MAX_ID_PS); in nxp_c45_check_delay()
864 return -EINVAL; in nxp_c45_check_delay()
872 /* The delay in degree phase is 73.8 + phase_offset_raw * 0.9. in nxp_c45_get_phase_shift()
877 phase_offset_raw -= 738; in nxp_c45_get_phase_shift()
889 struct nxp_c45_phy *priv = phydev->priv; in nxp_c45_set_delays()
890 u64 tx_delay = priv->tx_delay; in nxp_c45_set_delays()
891 u64 rx_delay = priv->rx_delay; in nxp_c45_set_delays()
894 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || in nxp_c45_set_delays()
895 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { in nxp_c45_set_delays()
904 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || in nxp_c45_set_delays()
905 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { in nxp_c45_set_delays()
917 struct nxp_c45_phy *priv = phydev->priv; in nxp_c45_get_delays()
920 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || in nxp_c45_get_delays()
921 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { in nxp_c45_get_delays()
922 ret = device_property_read_u32(&phydev->mdio.dev, in nxp_c45_get_delays()
923 "tx-internal-delay-ps", in nxp_c45_get_delays()
924 &priv->tx_delay); in nxp_c45_get_delays()
926 priv->tx_delay = DEFAULT_ID_PS; in nxp_c45_get_delays()
928 ret = nxp_c45_check_delay(phydev, priv->tx_delay); in nxp_c45_get_delays()
931 "tx-internal-delay-ps invalid value\n"); in nxp_c45_get_delays()
936 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || in nxp_c45_get_delays()
937 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { in nxp_c45_get_delays()
938 ret = device_property_read_u32(&phydev->mdio.dev, in nxp_c45_get_delays()
939 "rx-internal-delay-ps", in nxp_c45_get_delays()
940 &priv->rx_delay); in nxp_c45_get_delays()
942 priv->rx_delay = DEFAULT_ID_PS; in nxp_c45_get_delays()
944 ret = nxp_c45_check_delay(phydev, priv->rx_delay); in nxp_c45_get_delays()
947 "rx-internal-delay-ps invalid value\n"); in nxp_c45_get_delays()
962 switch (phydev->interface) { in nxp_c45_set_phy_mode()
966 return -EINVAL; in nxp_c45_set_phy_mode()
976 phydev_err(phydev, "rgmii-id, rgmii-txid, rgmii-rxid modes are not supported\n"); in nxp_c45_set_phy_mode()
977 return -EINVAL; in nxp_c45_set_phy_mode()
990 return -EINVAL; in nxp_c45_set_phy_mode()
997 phydev_err(phydev, "rev-mii mode not supported\n"); in nxp_c45_set_phy_mode()
998 return -EINVAL; in nxp_c45_set_phy_mode()
1006 return -EINVAL; in nxp_c45_set_phy_mode()
1014 return -EINVAL; in nxp_c45_set_phy_mode()
1022 return -EINVAL; in nxp_c45_set_phy_mode()
1062 phydev->autoneg = AUTONEG_DISABLE; in nxp_c45_config_init()
1082 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); in nxp_c45_probe()
1084 return -ENOMEM; in nxp_c45_probe()
1086 skb_queue_head_init(&priv->tx_queue); in nxp_c45_probe()
1087 skb_queue_head_init(&priv->rx_queue); in nxp_c45_probe()
1089 priv->phydev = phydev; in nxp_c45_probe()
1091 phydev->priv = priv; in nxp_c45_probe()
1093 mutex_init(&priv->ptp_lock); in nxp_c45_probe()
1105 priv->mii_ts.rxtstamp = nxp_c45_rxtstamp; in nxp_c45_probe()
1106 priv->mii_ts.txtstamp = nxp_c45_txtstamp; in nxp_c45_probe()
1107 priv->mii_ts.hwtstamp = nxp_c45_hwtstamp; in nxp_c45_probe()
1108 priv->mii_ts.ts_info = nxp_c45_ts_info; in nxp_c45_probe()
1109 phydev->mii_ts = &priv->mii_ts; in nxp_c45_probe()
1154 MODULE_AUTHOR("Radu Pirea <radu-nicolae.pirea@oss.nxp.com>");