Lines Matching +full:sparx5 +full:- +full:switch
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver
6 * The Sparx5 Chip Register Model can be browsed at this location:
7 * https://github.com/microchip-ung/sparx-5_reginfo
27 static u64 sparx5_ptp_get_1ppm(struct sparx5 *sparx5) in sparx5_ptp_get_1ppm() argument
32 * (1/1000000)/((2^-59)/X) in sparx5_ptp_get_1ppm()
37 switch (sparx5->coreclock) { in sparx5_ptp_get_1ppm()
55 static u64 sparx5_ptp_get_nominal_value(struct sparx5 *sparx5) in sparx5_ptp_get_nominal_value() argument
59 switch (sparx5->coreclock) { in sparx5_ptp_get_nominal_value()
81 struct sparx5 *sparx5 = port->sparx5; in sparx5_ptp_hwtstamp_set() local
89 if (test_bit(port->portno, sparx5->bridge_mask)) in sparx5_ptp_hwtstamp_set()
90 return -EINVAL; in sparx5_ptp_hwtstamp_set()
92 switch (cfg->tx_type) { in sparx5_ptp_hwtstamp_set()
94 port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; in sparx5_ptp_hwtstamp_set()
97 port->ptp_cmd = IFH_REW_OP_ONE_STEP_PTP; in sparx5_ptp_hwtstamp_set()
100 port->ptp_cmd = IFH_REW_OP_NOOP; in sparx5_ptp_hwtstamp_set()
103 return -ERANGE; in sparx5_ptp_hwtstamp_set()
106 switch (cfg->rx_filter) { in sparx5_ptp_hwtstamp_set()
123 cfg->rx_filter = HWTSTAMP_FILTER_ALL; in sparx5_ptp_hwtstamp_set()
126 return -ERANGE; in sparx5_ptp_hwtstamp_set()
130 mutex_lock(&sparx5->ptp_lock); in sparx5_ptp_hwtstamp_set()
131 phc = &sparx5->phc[SPARX5_PHC_PORT]; in sparx5_ptp_hwtstamp_set()
132 phc->hwtstamp_config = *cfg; in sparx5_ptp_hwtstamp_set()
133 mutex_unlock(&sparx5->ptp_lock); in sparx5_ptp_hwtstamp_set()
141 struct sparx5 *sparx5 = port->sparx5; in sparx5_ptp_hwtstamp_get() local
144 phc = &sparx5->phc[SPARX5_PHC_PORT]; in sparx5_ptp_hwtstamp_get()
145 *cfg = phc->hwtstamp_config; in sparx5_ptp_hwtstamp_get()
155 if (port->ptp_cmd == IFH_REW_OP_NOOP) { in sparx5_ptp_classify()
186 if (port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { in sparx5_ptp_classify()
208 spin_lock_irqsave(&port->tx_skbs.lock, flags); in sparx5_ptp_txtstamp_old_release()
209 skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) { in sparx5_ptp_txtstamp_old_release()
210 if time_after(SPARX5_SKB_CB(skb)->jiffies + SPARX5_PTP_TIMEOUT, in sparx5_ptp_txtstamp_old_release()
214 __skb_unlink(skb, &port->tx_skbs); in sparx5_ptp_txtstamp_old_release()
217 spin_unlock_irqrestore(&port->tx_skbs.lock, flags); in sparx5_ptp_txtstamp_old_release()
223 struct sparx5 *sparx5 = port->sparx5; in sparx5_ptp_txtstamp_request() local
228 SPARX5_SKB_CB(skb)->rew_op = rew_op; in sparx5_ptp_txtstamp_request()
229 SPARX5_SKB_CB(skb)->pdu_type = pdu_type; in sparx5_ptp_txtstamp_request()
230 SPARX5_SKB_CB(skb)->pdu_w16_offset = pdu_w16_offset; in sparx5_ptp_txtstamp_request()
237 spin_lock_irqsave(&sparx5->ptp_ts_id_lock, flags); in sparx5_ptp_txtstamp_request()
238 if (sparx5->ptp_skbs == SPARX5_MAX_PTP_ID) { in sparx5_ptp_txtstamp_request()
239 spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags); in sparx5_ptp_txtstamp_request()
240 return -EBUSY; in sparx5_ptp_txtstamp_request()
243 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; in sparx5_ptp_txtstamp_request()
245 skb_queue_tail(&port->tx_skbs, skb); in sparx5_ptp_txtstamp_request()
246 SPARX5_SKB_CB(skb)->ts_id = port->ts_id; in sparx5_ptp_txtstamp_request()
247 SPARX5_SKB_CB(skb)->jiffies = jiffies; in sparx5_ptp_txtstamp_request()
249 sparx5->ptp_skbs++; in sparx5_ptp_txtstamp_request()
250 port->ts_id++; in sparx5_ptp_txtstamp_request()
251 if (port->ts_id == SPARX5_MAX_PTP_ID) in sparx5_ptp_txtstamp_request()
252 port->ts_id = 0; in sparx5_ptp_txtstamp_request()
254 spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags); in sparx5_ptp_txtstamp_request()
262 struct sparx5 *sparx5 = port->sparx5; in sparx5_ptp_txtstamp_release() local
265 spin_lock_irqsave(&sparx5->ptp_ts_id_lock, flags); in sparx5_ptp_txtstamp_release()
266 port->ts_id--; in sparx5_ptp_txtstamp_release()
267 sparx5->ptp_skbs--; in sparx5_ptp_txtstamp_release()
268 skb_unlink(skb, &port->tx_skbs); in sparx5_ptp_txtstamp_release()
269 spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags); in sparx5_ptp_txtstamp_release()
272 static void sparx5_get_hwtimestamp(struct sparx5 *sparx5, in sparx5_get_hwtimestamp() argument
280 spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); in sparx5_get_hwtimestamp()
288 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); in sparx5_get_hwtimestamp()
290 ts->tv_sec = spx5_rd(sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN)); in sparx5_get_hwtimestamp()
291 curr_nsec = spx5_rd(sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); in sparx5_get_hwtimestamp()
293 ts->tv_nsec = nsec; in sparx5_get_hwtimestamp()
297 ts->tv_sec--; in sparx5_get_hwtimestamp()
299 spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); in sparx5_get_hwtimestamp()
305 struct sparx5 *sparx5 = args; in sparx5_ptp_irq_handler() local
307 while (budget--) { in sparx5_ptp_irq_handler()
316 val = spx5_rd(sparx5, REW_PTP_TWOSTEP_CTRL); in sparx5_ptp_irq_handler()
331 port = sparx5->ports[txport]; in sparx5_ptp_irq_handler()
334 delay = spx5_rd(sparx5, REW_PTP_TWOSTEP_STAMP); in sparx5_ptp_irq_handler()
342 sparx5, REW_PTP_TWOSTEP_CTRL); in sparx5_ptp_irq_handler()
344 val = spx5_rd(sparx5, REW_PTP_TWOSTEP_CTRL); in sparx5_ptp_irq_handler()
351 id = spx5_rd(sparx5, REW_PTP_TWOSTEP_STAMP); in sparx5_ptp_irq_handler()
353 id |= spx5_rd(sparx5, REW_PTP_TWOSTEP_STAMP_SUBNS); in sparx5_ptp_irq_handler()
355 spin_lock_irqsave(&port->tx_skbs.lock, flags); in sparx5_ptp_irq_handler()
356 skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) { in sparx5_ptp_irq_handler()
357 if (SPARX5_SKB_CB(skb)->ts_id != id) in sparx5_ptp_irq_handler()
360 __skb_unlink(skb, &port->tx_skbs); in sparx5_ptp_irq_handler()
364 spin_unlock_irqrestore(&port->tx_skbs.lock, flags); in sparx5_ptp_irq_handler()
369 sparx5, REW_PTP_TWOSTEP_CTRL); in sparx5_ptp_irq_handler()
374 spin_lock(&sparx5->ptp_ts_id_lock); in sparx5_ptp_irq_handler()
375 sparx5->ptp_skbs--; in sparx5_ptp_irq_handler()
376 spin_unlock(&sparx5->ptp_ts_id_lock); in sparx5_ptp_irq_handler()
379 sparx5_get_hwtimestamp(sparx5, &ts, delay); in sparx5_ptp_irq_handler()
394 struct sparx5 *sparx5 = phc->sparx5; in sparx5_ptp_adjfine() local
405 scaled_ppm = -scaled_ppm; in sparx5_ptp_adjfine()
408 tod_inc = sparx5_ptp_get_nominal_value(sparx5); in sparx5_ptp_adjfine()
414 ref = sparx5_ptp_get_1ppm(sparx5) * (scaled_ppm >> 16); in sparx5_ptp_adjfine()
415 ref += (sparx5_ptp_get_1ppm(sparx5) * (0xffff & scaled_ppm)) >> 16; in sparx5_ptp_adjfine()
416 tod_inc = neg_adj ? tod_inc - ref : tod_inc + ref; in sparx5_ptp_adjfine()
418 spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); in sparx5_ptp_adjfine()
420 spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(1 << BIT(phc->index)), in sparx5_ptp_adjfine()
422 sparx5, PTP_PTP_DOM_CFG); in sparx5_ptp_adjfine()
424 spx5_wr((u32)tod_inc & 0xFFFFFFFF, sparx5, in sparx5_ptp_adjfine()
425 PTP_CLK_PER_CFG(phc->index, 0)); in sparx5_ptp_adjfine()
426 spx5_wr((u32)(tod_inc >> 32), sparx5, in sparx5_ptp_adjfine()
427 PTP_CLK_PER_CFG(phc->index, 1)); in sparx5_ptp_adjfine()
430 PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS, sparx5, in sparx5_ptp_adjfine()
433 spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); in sparx5_ptp_adjfine()
442 struct sparx5 *sparx5 = phc->sparx5; in sparx5_ptp_settime64() local
445 spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); in sparx5_ptp_settime64()
449 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) | in sparx5_ptp_settime64()
454 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); in sparx5_ptp_settime64()
457 spx5_wr(PTP_PTP_TOD_SEC_MSB_PTP_TOD_SEC_MSB_SET(upper_32_bits(ts->tv_sec)), in sparx5_ptp_settime64()
458 sparx5, PTP_PTP_TOD_SEC_MSB(TOD_ACC_PIN)); in sparx5_ptp_settime64()
459 spx5_wr(lower_32_bits(ts->tv_sec), in sparx5_ptp_settime64()
460 sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN)); in sparx5_ptp_settime64()
461 spx5_wr(ts->tv_nsec, sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); in sparx5_ptp_settime64()
465 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) | in sparx5_ptp_settime64()
470 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); in sparx5_ptp_settime64()
472 spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); in sparx5_ptp_settime64()
480 struct sparx5 *sparx5 = phc->sparx5; in sparx5_ptp_gettime64() local
485 spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); in sparx5_ptp_gettime64()
488 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) | in sparx5_ptp_gettime64()
493 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); in sparx5_ptp_gettime64()
495 s = spx5_rd(sparx5, PTP_PTP_TOD_SEC_MSB(TOD_ACC_PIN)); in sparx5_ptp_gettime64()
497 s |= spx5_rd(sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN)); in sparx5_ptp_gettime64()
498 ns = spx5_rd(sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); in sparx5_ptp_gettime64()
501 spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); in sparx5_ptp_gettime64()
505 s--; in sparx5_ptp_gettime64()
517 struct sparx5 *sparx5 = phc->sparx5; in sparx5_ptp_adjtime() local
519 if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) { in sparx5_ptp_adjtime()
522 spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); in sparx5_ptp_adjtime()
526 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) | in sparx5_ptp_adjtime()
531 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); in sparx5_ptp_adjtime()
534 sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); in sparx5_ptp_adjtime()
538 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) | in sparx5_ptp_adjtime()
543 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); in sparx5_ptp_adjtime()
545 spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); in sparx5_ptp_adjtime()
564 .name = "sparx5 ptp",
572 static int sparx5_ptp_phc_init(struct sparx5 *sparx5, in sparx5_ptp_phc_init() argument
576 struct sparx5_phc *phc = &sparx5->phc[index]; in sparx5_ptp_phc_init()
578 phc->info = *clock_info; in sparx5_ptp_phc_init()
579 phc->clock = ptp_clock_register(&phc->info, sparx5->dev); in sparx5_ptp_phc_init()
580 if (IS_ERR(phc->clock)) in sparx5_ptp_phc_init()
581 return PTR_ERR(phc->clock); in sparx5_ptp_phc_init()
583 phc->index = index; in sparx5_ptp_phc_init()
584 phc->sparx5 = sparx5; in sparx5_ptp_phc_init()
587 phc->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; in sparx5_ptp_phc_init()
592 int sparx5_ptp_init(struct sparx5 *sparx5) in sparx5_ptp_init() argument
594 u64 tod_adj = sparx5_ptp_get_nominal_value(sparx5); in sparx5_ptp_init()
598 if (!sparx5->ptp) in sparx5_ptp_init()
602 err = sparx5_ptp_phc_init(sparx5, i, &sparx5_ptp_clock_info); in sparx5_ptp_init()
607 spin_lock_init(&sparx5->ptp_clock_lock); in sparx5_ptp_init()
608 spin_lock_init(&sparx5->ptp_ts_id_lock); in sparx5_ptp_init()
609 mutex_init(&sparx5->ptp_lock); in sparx5_ptp_init()
612 spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0), sparx5, PTP_PTP_DOM_CFG); in sparx5_ptp_init()
617 sparx5, PTP_PTP_DOM_CFG); in sparx5_ptp_init()
620 spx5_wr((u32)tod_adj & 0xFFFFFFFF, sparx5, in sparx5_ptp_init()
622 spx5_wr((u32)(tod_adj >> 32), sparx5, in sparx5_ptp_init()
628 sparx5, PTP_PTP_DOM_CFG); in sparx5_ptp_init()
631 spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0x7), sparx5, PTP_PTP_DOM_CFG); in sparx5_ptp_init()
634 port = sparx5->ports[i]; in sparx5_ptp_init()
638 skb_queue_head_init(&port->tx_skbs); in sparx5_ptp_init()
644 void sparx5_ptp_deinit(struct sparx5 *sparx5) in sparx5_ptp_deinit() argument
650 port = sparx5->ports[i]; in sparx5_ptp_deinit()
654 skb_queue_purge(&port->tx_skbs); in sparx5_ptp_deinit()
658 ptp_clock_unregister(sparx5->phc[i].clock); in sparx5_ptp_deinit()
661 void sparx5_ptp_rxtstamp(struct sparx5 *sparx5, struct sk_buff *skb, in sparx5_ptp_rxtstamp() argument
669 if (!sparx5->ptp) in sparx5_ptp_rxtstamp()
672 phc = &sparx5->phc[SPARX5_PHC_PORT]; in sparx5_ptp_rxtstamp()
673 sparx5_ptp_gettime64(&phc->info, &ts); in sparx5_ptp_rxtstamp()
676 ts.tv_sec--; in sparx5_ptp_rxtstamp()
681 shhwtstamps->hwtstamp = full_ts_in_ns; in sparx5_ptp_rxtstamp()