Lines Matching +full:pin +full:- +full:ctrl +full:- +full:enable
1 // SPDX-License-Identifier: GPL-2.0
16 #include "bcm-phy-lib.h"
134 struct ptp_pin_desc pin; member
158 #define BCM_SKB_CB(skb) ((struct bcm_ptp_skb_cb *)(skb)->cb)
161 #define BCM_MAX_PULSE_8NS ((1U << 9) - 1)
162 #define BCM_MAX_PERIOD_8NS ((1U << 30) - 1)
165 ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
192 ts->tv_sec = (hb[3] << 16) | hb[2]; in bcm_ptp_get_framesync_ts()
193 ts->tv_nsec = (hb[1] << 16) | hb[0]; in bcm_ptp_get_framesync_ts()
198 u16 ctrl = orig_ctrl & ~(NSE_FRAMESYNC_MASK | NSE_CAPTURE_EN); in bcm_ptp_framesync_disable() local
200 bcm_phy_write_exp(phydev, NSE_CTRL, ctrl); in bcm_ptp_framesync_disable()
202 return ctrl; in bcm_ptp_framesync_disable()
211 static void bcm_ptp_framesync(struct phy_device *phydev, u16 ctrl) in bcm_ptp_framesync() argument
213 /* trigger framesync - must have 0->1 transition. */ in bcm_ptp_framesync()
214 bcm_phy_write_exp(phydev, NSE_CTRL, ctrl | NSE_CPU_FRAMESYNC); in bcm_ptp_framesync()
222 u16 ctrl, reg; in bcm_ptp_framesync_ts() local
225 ctrl = bcm_ptp_framesync_disable(phydev, orig_ctrl); in bcm_ptp_framesync_ts()
230 bcm_ptp_framesync(phydev, ctrl | NSE_CAPTURE_EN); in bcm_ptp_framesync_ts()
245 return reg & INTC_FSYNC ? 0 : -ETIMEDOUT; in bcm_ptp_framesync_ts()
255 mutex_lock(&priv->mutex); in bcm_ptp_gettimex()
256 err = bcm_ptp_framesync_ts(priv->phydev, sts, ts, priv->nse_ctrl); in bcm_ptp_gettimex()
257 mutex_unlock(&priv->mutex); in bcm_ptp_gettimex()
265 struct phy_device *phydev = priv->phydev; in bcm_ptp_settime_locked()
266 u16 ctrl; in bcm_ptp_settime_locked() local
269 ctrl = bcm_ptp_framesync_disable(phydev, priv->nse_ctrl); in bcm_ptp_settime_locked()
272 bcm_phy_write_exp(phydev, TIME_CODE_0, ts->tv_nsec); in bcm_ptp_settime_locked()
273 bcm_phy_write_exp(phydev, TIME_CODE_1, ts->tv_nsec >> 16); in bcm_ptp_settime_locked()
274 bcm_phy_write_exp(phydev, TIME_CODE_2, ts->tv_sec); in bcm_ptp_settime_locked()
275 bcm_phy_write_exp(phydev, TIME_CODE_3, ts->tv_sec >> 16); in bcm_ptp_settime_locked()
276 bcm_phy_write_exp(phydev, TIME_CODE_4, ts->tv_sec >> 32); in bcm_ptp_settime_locked()
284 /* set up load on next frame sync (auto-clears due to NSE_INIT) */ in bcm_ptp_settime_locked()
288 bcm_ptp_framesync(phydev, ctrl | NSE_INIT); in bcm_ptp_settime_locked()
290 bcm_ptp_framesync_restore(phydev, priv->nse_ctrl); in bcm_ptp_settime_locked()
301 mutex_lock(&priv->mutex); in bcm_ptp_settime()
303 mutex_unlock(&priv->mutex); in bcm_ptp_settime()
315 err = bcm_ptp_framesync_ts(priv->phydev, NULL, &ts, priv->nse_ctrl); in bcm_ptp_adjtime_locked()
329 mutex_lock(&priv->mutex); in bcm_ptp_adjtime()
331 mutex_unlock(&priv->mutex); in bcm_ptp_adjtime()
349 u16 ctrl; in bcm_ptp_adjfine() local
354 scaled_ppm = -scaled_ppm; in bcm_ptp_adjfine()
359 freq = (8 << 28) + (neg_adj ? -diff : diff); in bcm_ptp_adjfine()
361 mutex_lock(&priv->mutex); in bcm_ptp_adjfine()
363 ctrl = bcm_ptp_framesync_disable(priv->phydev, priv->nse_ctrl); in bcm_ptp_adjfine()
365 bcm_phy_write_exp(priv->phydev, NCO_FREQ_LSB, freq); in bcm_ptp_adjfine()
366 bcm_phy_write_exp(priv->phydev, NCO_FREQ_MSB, freq >> 16); in bcm_ptp_adjfine()
368 bcm_phy_write_exp(priv->phydev, NCO_TIME_2_CTRL, FREQ_MDIO_SEL); in bcm_ptp_adjfine()
371 bcm_phy_write_exp(priv->phydev, SHADOW_LOAD, FREQ_LOAD); in bcm_ptp_adjfine()
373 bcm_ptp_framesync(priv->phydev, ctrl); in bcm_ptp_adjfine()
376 bcm_phy_write_exp(priv->phydev, SHADOW_LOAD, 0); in bcm_ptp_adjfine()
378 bcm_ptp_framesync_restore(priv->phydev, priv->nse_ctrl); in bcm_ptp_adjfine()
380 mutex_unlock(&priv->mutex); in bcm_ptp_adjfine()
395 if (!priv->hwts_rx) in bcm_ptp_rxtstamp()
407 hwts->hwtstamp = ktime_set(sec, nsec); in bcm_ptp_rxtstamp()
409 off = data - skb->data + 8; in bcm_ptp_rxtstamp()
410 if (off < skb->len) { in bcm_ptp_rxtstamp()
411 memmove(data, data + 8, skb->len - off); in bcm_ptp_rxtstamp()
412 __pskb_trim(skb, skb->len - 8); in bcm_ptp_rxtstamp()
421 struct phy_device *phydev = priv->phydev; in bcm_ptp_get_tstamp()
425 mutex_lock(&priv->mutex); in bcm_ptp_get_tstamp()
429 mutex_unlock(&priv->mutex); in bcm_ptp_get_tstamp()
441 capts->seq_id = bcm_phy_read_exp(priv->phydev, TS_INFO_0); in bcm_ptp_get_tstamp()
444 capts->msgtype = reg >> 12; in bcm_ptp_get_tstamp()
445 capts->tx_dir = !!(reg & BIT(11)); in bcm_ptp_get_tstamp()
450 mutex_unlock(&priv->mutex); in bcm_ptp_get_tstamp()
454 capts->hwtstamp = ktime_set(sec, nsec); in bcm_ptp_get_tstamp()
468 spin_lock_irqsave(&priv->tx_queue.lock, flags); in bcm_ptp_match_tstamp()
469 skb_queue_walk(&priv->tx_queue, skb) { in bcm_ptp_match_tstamp()
470 if (BCM_SKB_CB(skb)->seq_id == capts->seq_id && in bcm_ptp_match_tstamp()
471 BCM_SKB_CB(skb)->msgtype == capts->msgtype) { in bcm_ptp_match_tstamp()
472 first = skb_queue_is_first(&priv->tx_queue, skb); in bcm_ptp_match_tstamp()
473 __skb_unlink(skb, &priv->tx_queue); in bcm_ptp_match_tstamp()
478 spin_unlock_irqrestore(&priv->tx_queue.lock, flags); in bcm_ptp_match_tstamp()
480 /* TX captures one-step packets, discard them if needed. */ in bcm_ptp_match_tstamp()
482 if (BCM_SKB_CB(ts_skb)->discard) { in bcm_ptp_match_tstamp()
486 hwts.hwtstamp = capts->hwtstamp; in bcm_ptp_match_tstamp()
493 while ((skb = skb_dequeue(&priv->tx_queue))) { in bcm_ptp_match_tstamp()
494 if (!time_after(jiffies, BCM_SKB_CB(skb)->timeout)) { in bcm_ptp_match_tstamp()
495 skb_queue_head(&priv->tx_queue, skb); in bcm_ptp_match_tstamp()
509 while (!skb_queue_empty_lockless(&priv->tx_queue)) { in bcm_ptp_do_aux_work()
517 return reschedule ? 1 : -1; in bcm_ptp_do_aux_work()
522 if (!priv->pin_active) in bcm_ptp_cancel_func()
525 priv->pin_active = false; in bcm_ptp_cancel_func()
527 priv->nse_ctrl &= ~(NSE_SYNC_OUT_MASK | NSE_SYNC1_FRAMESYNC | in bcm_ptp_cancel_func()
529 bcm_phy_write_exp(priv->phydev, NSE_CTRL, priv->nse_ctrl); in bcm_ptp_cancel_func()
531 cancel_delayed_work_sync(&priv->pin_work); in bcm_ptp_cancel_func()
540 struct phy_device *phydev = priv->phydev; in bcm_ptp_perout_work()
543 u16 ctrl; in bcm_ptp_perout_work() local
545 mutex_lock(&priv->mutex); in bcm_ptp_perout_work()
548 if (!priv->pin_active) { in bcm_ptp_perout_work()
549 mutex_unlock(&priv->mutex); in bcm_ptp_perout_work()
553 bcm_ptp_framesync_ts(phydev, NULL, &ts, priv->nse_ctrl); in bcm_ptp_perout_work()
556 next = NSEC_PER_SEC - ts.tv_nsec; in bcm_ptp_perout_work()
562 /* force 0->1 transition for ONESHOT */ in bcm_ptp_perout_work()
563 ctrl = bcm_ptp_framesync_disable(phydev, in bcm_ptp_perout_work()
564 priv->nse_ctrl & ~NSE_ONESHOT_EN); in bcm_ptp_perout_work()
573 bcm_ptp_framesync(phydev, ctrl | NSE_ONESHOT_EN | NSE_INIT); in bcm_ptp_perout_work()
575 priv->nse_ctrl |= NSE_ONESHOT_EN; in bcm_ptp_perout_work()
576 bcm_ptp_framesync_restore(phydev, priv->nse_ctrl); in bcm_ptp_perout_work()
578 mutex_unlock(&priv->mutex); in bcm_ptp_perout_work()
581 schedule_delayed_work(&priv->pin_work, nsecs_to_jiffies(next)); in bcm_ptp_perout_work()
587 struct phy_device *phydev = priv->phydev; in bcm_ptp_perout_locked()
595 if (req->period.sec != 1 || req->period.nsec != 0) in bcm_ptp_perout_locked()
596 return -EINVAL; in bcm_ptp_perout_locked()
601 if (req->flags & ~PTP_PEROUT_DUTY_CYCLE) in bcm_ptp_perout_locked()
602 return -EOPNOTSUPP; in bcm_ptp_perout_locked()
604 if (req->flags & PTP_PEROUT_DUTY_CYCLE) in bcm_ptp_perout_locked()
605 pulse = ktime_to_ns(ktime_set(req->on.sec, req->on.nsec)); in bcm_ptp_perout_locked()
613 return -EINVAL; in bcm_ptp_perout_locked()
623 if (priv->pin_active) in bcm_ptp_perout_locked()
624 cancel_delayed_work_sync(&priv->pin_work); in bcm_ptp_perout_locked()
626 priv->pin_active = true; in bcm_ptp_perout_locked()
627 INIT_DELAYED_WORK(&priv->pin_work, bcm_ptp_perout_work); in bcm_ptp_perout_locked()
628 schedule_delayed_work(&priv->pin_work, 0); in bcm_ptp_perout_locked()
637 struct phy_device *phydev = priv->phydev; in bcm_ptp_extts_work()
642 mutex_lock(&priv->mutex); in bcm_ptp_extts_work()
645 if (!priv->pin_active) { in bcm_ptp_extts_work()
646 mutex_unlock(&priv->mutex); in bcm_ptp_extts_work()
659 ptp_clock_event(priv->ptp_clock, &event); in bcm_ptp_extts_work()
662 mutex_unlock(&priv->mutex); in bcm_ptp_extts_work()
663 schedule_delayed_work(&priv->pin_work, HZ / 4); in bcm_ptp_extts_work()
668 struct phy_device *phydev = priv->phydev; in bcm_ptp_extts_locked()
673 if (priv->pin_active) in bcm_ptp_extts_locked()
674 cancel_delayed_work_sync(&priv->pin_work); in bcm_ptp_extts_locked()
676 bcm_ptp_framesync_disable(phydev, priv->nse_ctrl); in bcm_ptp_extts_locked()
678 priv->nse_ctrl |= NSE_SYNC1_FRAMESYNC | NSE_CAPTURE_EN; in bcm_ptp_extts_locked()
680 bcm_ptp_framesync_restore(phydev, priv->nse_ctrl); in bcm_ptp_extts_locked()
682 priv->pin_active = true; in bcm_ptp_extts_locked()
683 INIT_DELAYED_WORK(&priv->pin_work, bcm_ptp_extts_work); in bcm_ptp_extts_locked()
684 schedule_delayed_work(&priv->pin_work, 0); in bcm_ptp_extts_locked()
693 int err = -EBUSY; in bcm_ptp_enable()
695 mutex_lock(&priv->mutex); in bcm_ptp_enable()
697 switch (rq->type) { in bcm_ptp_enable()
699 if (priv->pin.func == PTP_PF_PEROUT) in bcm_ptp_enable()
700 err = bcm_ptp_perout_locked(priv, &rq->perout, on); in bcm_ptp_enable()
703 if (priv->pin.func == PTP_PF_EXTTS) in bcm_ptp_enable()
707 err = -EOPNOTSUPP; in bcm_ptp_enable()
711 mutex_unlock(&priv->mutex); in bcm_ptp_enable()
716 static int bcm_ptp_verify(struct ptp_clock_info *info, unsigned int pin, in bcm_ptp_verify() argument
725 return -EOPNOTSUPP; in bcm_ptp_verify()
738 .enable = bcm_ptp_enable,
759 switch (priv->tx_type) { in bcm_ptp_txtstamp()
769 BCM_SKB_CB(skb)->timeout = jiffies + SKB_TS_TIMEOUT; in bcm_ptp_txtstamp()
770 BCM_SKB_CB(skb)->seq_id = be16_to_cpu(hdr->sequence_id); in bcm_ptp_txtstamp()
771 BCM_SKB_CB(skb)->msgtype = msgtype; in bcm_ptp_txtstamp()
772 BCM_SKB_CB(skb)->discard = discard; in bcm_ptp_txtstamp()
773 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; in bcm_ptp_txtstamp()
774 skb_queue_tail(&priv->tx_queue, skb); in bcm_ptp_txtstamp()
775 ptp_schedule_worker(priv->ptp_clock, 0); in bcm_ptp_txtstamp()
790 u16 mode, ctrl; in bcm_ptp_hwtstamp() local
792 switch (cfg->rx_filter) { in bcm_ptp_hwtstamp()
794 priv->hwts_rx = false; in bcm_ptp_hwtstamp()
805 cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; in bcm_ptp_hwtstamp()
806 priv->hwts_rx = true; in bcm_ptp_hwtstamp()
809 return -ERANGE; in bcm_ptp_hwtstamp()
812 priv->tx_type = cfg->tx_type; in bcm_ptp_hwtstamp()
814 ctrl = priv->hwts_rx ? SLICE_RX_EN : 0; in bcm_ptp_hwtstamp()
815 ctrl |= priv->tx_type != HWTSTAMP_TX_OFF ? SLICE_TX_EN : 0; in bcm_ptp_hwtstamp()
822 bcm_phy_write_exp(priv->phydev, TX_EVENT_MODE, mode); in bcm_ptp_hwtstamp()
829 bcm_phy_write_exp(priv->phydev, RX_EVENT_MODE, mode); in bcm_ptp_hwtstamp()
831 bcm_phy_write_exp(priv->phydev, SLICE_CTRL, ctrl); in bcm_ptp_hwtstamp()
833 if (ctrl & SLICE_TX_EN) in bcm_ptp_hwtstamp()
834 bcm_phy_write_exp(priv->phydev, TX_TS_CAPTURE, TX_TS_CAP_EN); in bcm_ptp_hwtstamp()
836 ptp_cancel_worker_sync(priv->ptp_clock); in bcm_ptp_hwtstamp()
839 skb_queue_purge(&priv->tx_queue); in bcm_ptp_hwtstamp()
849 ts_info->phc_index = ptp_clock_index(priv->ptp_clock); in bcm_ptp_ts_info()
850 ts_info->so_timestamping = in bcm_ptp_ts_info()
854 ts_info->tx_types = in bcm_ptp_ts_info()
859 ts_info->rx_filters = in bcm_ptp_ts_info()
868 ptp_cancel_worker_sync(priv->ptp_clock); in bcm_ptp_stop()
878 /* enable time sync (TX/RX SOP capture) */ in bcm_ptp_config_init()
896 priv->nse_ctrl = NSE_GMODE_EN; in bcm_ptp_init()
898 mutex_init(&priv->mutex); in bcm_ptp_init()
899 skb_queue_head_init(&priv->tx_queue); in bcm_ptp_init()
901 priv->mii_ts.rxtstamp = bcm_ptp_rxtstamp; in bcm_ptp_init()
902 priv->mii_ts.txtstamp = bcm_ptp_txtstamp; in bcm_ptp_init()
903 priv->mii_ts.hwtstamp = bcm_ptp_hwtstamp; in bcm_ptp_init()
904 priv->mii_ts.ts_info = bcm_ptp_ts_info; in bcm_ptp_init()
906 priv->phydev->mii_ts = &priv->mii_ts; in bcm_ptp_init()
921 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); in bcm_ptp_probe()
923 return ERR_PTR(-ENOMEM); in bcm_ptp_probe()
925 priv->ptp_info = bcm_ptp_clock_info; in bcm_ptp_probe()
927 snprintf(priv->pin.name, sizeof(priv->pin.name), "SYNC_OUT"); in bcm_ptp_probe()
928 priv->ptp_info.pin_config = &priv->pin; in bcm_ptp_probe()
930 clock = ptp_clock_register(&priv->ptp_info, &phydev->mdio.dev); in bcm_ptp_probe()
933 priv->ptp_clock = clock; in bcm_ptp_probe()
936 phydev->default_timestamp = true; in bcm_ptp_probe()
938 priv->phydev = phydev; in bcm_ptp_probe()