10933bd04SHoratiu Vultur // SPDX-License-Identifier: GPL-2.0+
20933bd04SHoratiu Vultur /* Microchip Sparx5 Switch driver
30933bd04SHoratiu Vultur  *
40933bd04SHoratiu Vultur  * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
50933bd04SHoratiu Vultur  *
60933bd04SHoratiu Vultur  * The Sparx5 Chip Register Model can be browsed at this location:
70933bd04SHoratiu Vultur  * https://github.com/microchip-ung/sparx-5_reginfo
80933bd04SHoratiu Vultur  */
90933bd04SHoratiu Vultur #include <linux/ptp_classify.h>
100933bd04SHoratiu Vultur 
110933bd04SHoratiu Vultur #include "sparx5_main_regs.h"
120933bd04SHoratiu Vultur #include "sparx5_main.h"
130933bd04SHoratiu Vultur 
140933bd04SHoratiu Vultur #define SPARX5_MAX_PTP_ID	512
150933bd04SHoratiu Vultur 
160933bd04SHoratiu Vultur #define TOD_ACC_PIN		0x4
170933bd04SHoratiu Vultur 
180933bd04SHoratiu Vultur enum {
190933bd04SHoratiu Vultur 	PTP_PIN_ACTION_IDLE = 0,
200933bd04SHoratiu Vultur 	PTP_PIN_ACTION_LOAD,
210933bd04SHoratiu Vultur 	PTP_PIN_ACTION_SAVE,
220933bd04SHoratiu Vultur 	PTP_PIN_ACTION_CLOCK,
230933bd04SHoratiu Vultur 	PTP_PIN_ACTION_DELTA,
240933bd04SHoratiu Vultur 	PTP_PIN_ACTION_TOD
250933bd04SHoratiu Vultur };
260933bd04SHoratiu Vultur 
sparx5_ptp_get_1ppm(struct sparx5 * sparx5)270933bd04SHoratiu Vultur static u64 sparx5_ptp_get_1ppm(struct sparx5 *sparx5)
280933bd04SHoratiu Vultur {
290933bd04SHoratiu Vultur 	/* Represents 1ppm adjustment in 2^59 format with 1.59687500000(625)
300933bd04SHoratiu Vultur 	 * 1.99609375000(500), 3.99218750000(250) as reference
310933bd04SHoratiu Vultur 	 * The value is calculated as following:
320933bd04SHoratiu Vultur 	 * (1/1000000)/((2^-59)/X)
330933bd04SHoratiu Vultur 	 */
340933bd04SHoratiu Vultur 
35349fa279SHoratiu Vultur 	u64 res = 0;
360933bd04SHoratiu Vultur 
370933bd04SHoratiu Vultur 	switch (sparx5->coreclock) {
380933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_250MHZ:
390933bd04SHoratiu Vultur 		res = 2301339409586;
400933bd04SHoratiu Vultur 		break;
410933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_500MHZ:
420933bd04SHoratiu Vultur 		res = 1150669704793;
430933bd04SHoratiu Vultur 		break;
440933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_625MHZ:
450933bd04SHoratiu Vultur 		res =  920535763834;
460933bd04SHoratiu Vultur 		break;
470933bd04SHoratiu Vultur 	default:
48c24f6577SDan Carpenter 		WARN(1, "Invalid core clock");
490933bd04SHoratiu Vultur 		break;
500933bd04SHoratiu Vultur 	}
510933bd04SHoratiu Vultur 
520933bd04SHoratiu Vultur 	return res;
530933bd04SHoratiu Vultur }
540933bd04SHoratiu Vultur 
sparx5_ptp_get_nominal_value(struct sparx5 * sparx5)550933bd04SHoratiu Vultur static u64 sparx5_ptp_get_nominal_value(struct sparx5 *sparx5)
560933bd04SHoratiu Vultur {
57349fa279SHoratiu Vultur 	u64 res = 0;
580933bd04SHoratiu Vultur 
590933bd04SHoratiu Vultur 	switch (sparx5->coreclock) {
600933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_250MHZ:
610933bd04SHoratiu Vultur 		res = 0x1FF0000000000000;
620933bd04SHoratiu Vultur 		break;
630933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_500MHZ:
640933bd04SHoratiu Vultur 		res = 0x0FF8000000000000;
650933bd04SHoratiu Vultur 		break;
660933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_625MHZ:
670933bd04SHoratiu Vultur 		res = 0x0CC6666666666666;
680933bd04SHoratiu Vultur 		break;
690933bd04SHoratiu Vultur 	default:
70c24f6577SDan Carpenter 		WARN(1, "Invalid core clock");
710933bd04SHoratiu Vultur 		break;
720933bd04SHoratiu Vultur 	}
730933bd04SHoratiu Vultur 
740933bd04SHoratiu Vultur 	return res;
750933bd04SHoratiu Vultur }
760933bd04SHoratiu Vultur 
sparx5_ptp_hwtstamp_set(struct sparx5_port * port,struct kernel_hwtstamp_config * cfg,struct netlink_ext_ack * extack)77*7bdde444SVladimir Oltean int sparx5_ptp_hwtstamp_set(struct sparx5_port *port,
78*7bdde444SVladimir Oltean 			    struct kernel_hwtstamp_config *cfg,
79*7bdde444SVladimir Oltean 			    struct netlink_ext_ack *extack)
80589a07b8SHoratiu Vultur {
81589a07b8SHoratiu Vultur 	struct sparx5 *sparx5 = port->sparx5;
82589a07b8SHoratiu Vultur 	struct sparx5_phc *phc;
83589a07b8SHoratiu Vultur 
84589a07b8SHoratiu Vultur 	/* For now don't allow to run ptp on ports that are part of a bridge,
85589a07b8SHoratiu Vultur 	 * because in case of transparent clock the HW will still forward the
86589a07b8SHoratiu Vultur 	 * frames, so there would be duplicate frames
87589a07b8SHoratiu Vultur 	 */
88589a07b8SHoratiu Vultur 
89589a07b8SHoratiu Vultur 	if (test_bit(port->portno, sparx5->bridge_mask))
90589a07b8SHoratiu Vultur 		return -EINVAL;
91589a07b8SHoratiu Vultur 
92*7bdde444SVladimir Oltean 	switch (cfg->tx_type) {
93589a07b8SHoratiu Vultur 	case HWTSTAMP_TX_ON:
94589a07b8SHoratiu Vultur 		port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
95589a07b8SHoratiu Vultur 		break;
96589a07b8SHoratiu Vultur 	case HWTSTAMP_TX_ONESTEP_SYNC:
97589a07b8SHoratiu Vultur 		port->ptp_cmd = IFH_REW_OP_ONE_STEP_PTP;
98589a07b8SHoratiu Vultur 		break;
99589a07b8SHoratiu Vultur 	case HWTSTAMP_TX_OFF:
100589a07b8SHoratiu Vultur 		port->ptp_cmd = IFH_REW_OP_NOOP;
101589a07b8SHoratiu Vultur 		break;
102589a07b8SHoratiu Vultur 	default:
103589a07b8SHoratiu Vultur 		return -ERANGE;
104589a07b8SHoratiu Vultur 	}
105589a07b8SHoratiu Vultur 
106*7bdde444SVladimir Oltean 	switch (cfg->rx_filter) {
107589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_NONE:
108589a07b8SHoratiu Vultur 		break;
109589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_ALL:
110589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
111589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
112589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
113589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
114589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
115589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
116589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
117589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
118589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
119589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
120589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
121589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
122589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_NTP_ALL:
123*7bdde444SVladimir Oltean 		cfg->rx_filter = HWTSTAMP_FILTER_ALL;
124589a07b8SHoratiu Vultur 		break;
125589a07b8SHoratiu Vultur 	default:
126589a07b8SHoratiu Vultur 		return -ERANGE;
127589a07b8SHoratiu Vultur 	}
128589a07b8SHoratiu Vultur 
129589a07b8SHoratiu Vultur 	/* Commit back the result & save it */
130589a07b8SHoratiu Vultur 	mutex_lock(&sparx5->ptp_lock);
131589a07b8SHoratiu Vultur 	phc = &sparx5->phc[SPARX5_PHC_PORT];
132*7bdde444SVladimir Oltean 	phc->hwtstamp_config = *cfg;
133589a07b8SHoratiu Vultur 	mutex_unlock(&sparx5->ptp_lock);
134589a07b8SHoratiu Vultur 
135*7bdde444SVladimir Oltean 	return 0;
136589a07b8SHoratiu Vultur }
137589a07b8SHoratiu Vultur 
sparx5_ptp_hwtstamp_get(struct sparx5_port * port,struct kernel_hwtstamp_config * cfg)138*7bdde444SVladimir Oltean void sparx5_ptp_hwtstamp_get(struct sparx5_port *port,
139*7bdde444SVladimir Oltean 			     struct kernel_hwtstamp_config *cfg)
140589a07b8SHoratiu Vultur {
141589a07b8SHoratiu Vultur 	struct sparx5 *sparx5 = port->sparx5;
142589a07b8SHoratiu Vultur 	struct sparx5_phc *phc;
143589a07b8SHoratiu Vultur 
144589a07b8SHoratiu Vultur 	phc = &sparx5->phc[SPARX5_PHC_PORT];
145*7bdde444SVladimir Oltean 	*cfg = phc->hwtstamp_config;
146589a07b8SHoratiu Vultur }
147589a07b8SHoratiu Vultur 
sparx5_ptp_classify(struct sparx5_port * port,struct sk_buff * skb,u8 * rew_op,u8 * pdu_type,u8 * pdu_w16_offset)14870dfe25cSHoratiu Vultur static void sparx5_ptp_classify(struct sparx5_port *port, struct sk_buff *skb,
14970dfe25cSHoratiu Vultur 				u8 *rew_op, u8 *pdu_type, u8 *pdu_w16_offset)
15070dfe25cSHoratiu Vultur {
15170dfe25cSHoratiu Vultur 	struct ptp_header *header;
15270dfe25cSHoratiu Vultur 	u8 msgtype;
15370dfe25cSHoratiu Vultur 	int type;
15470dfe25cSHoratiu Vultur 
15570dfe25cSHoratiu Vultur 	if (port->ptp_cmd == IFH_REW_OP_NOOP) {
15670dfe25cSHoratiu Vultur 		*rew_op = IFH_REW_OP_NOOP;
15770dfe25cSHoratiu Vultur 		*pdu_type = IFH_PDU_TYPE_NONE;
15870dfe25cSHoratiu Vultur 		*pdu_w16_offset = 0;
15970dfe25cSHoratiu Vultur 		return;
16070dfe25cSHoratiu Vultur 	}
16170dfe25cSHoratiu Vultur 
16270dfe25cSHoratiu Vultur 	type = ptp_classify_raw(skb);
16370dfe25cSHoratiu Vultur 	if (type == PTP_CLASS_NONE) {
16470dfe25cSHoratiu Vultur 		*rew_op = IFH_REW_OP_NOOP;
16570dfe25cSHoratiu Vultur 		*pdu_type = IFH_PDU_TYPE_NONE;
16670dfe25cSHoratiu Vultur 		*pdu_w16_offset = 0;
16770dfe25cSHoratiu Vultur 		return;
16870dfe25cSHoratiu Vultur 	}
16970dfe25cSHoratiu Vultur 
17070dfe25cSHoratiu Vultur 	header = ptp_parse_header(skb, type);
17170dfe25cSHoratiu Vultur 	if (!header) {
17270dfe25cSHoratiu Vultur 		*rew_op = IFH_REW_OP_NOOP;
17370dfe25cSHoratiu Vultur 		*pdu_type = IFH_PDU_TYPE_NONE;
17470dfe25cSHoratiu Vultur 		*pdu_w16_offset = 0;
17570dfe25cSHoratiu Vultur 		return;
17670dfe25cSHoratiu Vultur 	}
17770dfe25cSHoratiu Vultur 
17870dfe25cSHoratiu Vultur 	*pdu_w16_offset = 7;
17970dfe25cSHoratiu Vultur 	if (type & PTP_CLASS_L2)
18070dfe25cSHoratiu Vultur 		*pdu_type = IFH_PDU_TYPE_PTP;
18170dfe25cSHoratiu Vultur 	if (type & PTP_CLASS_IPV4)
18270dfe25cSHoratiu Vultur 		*pdu_type = IFH_PDU_TYPE_IPV4_UDP_PTP;
18370dfe25cSHoratiu Vultur 	if (type & PTP_CLASS_IPV6)
18470dfe25cSHoratiu Vultur 		*pdu_type = IFH_PDU_TYPE_IPV6_UDP_PTP;
18570dfe25cSHoratiu Vultur 
18670dfe25cSHoratiu Vultur 	if (port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
18770dfe25cSHoratiu Vultur 		*rew_op = IFH_REW_OP_TWO_STEP_PTP;
18870dfe25cSHoratiu Vultur 		return;
18970dfe25cSHoratiu Vultur 	}
19070dfe25cSHoratiu Vultur 
19170dfe25cSHoratiu Vultur 	/* If it is sync and run 1 step then set the correct operation,
19270dfe25cSHoratiu Vultur 	 * otherwise run as 2 step
19370dfe25cSHoratiu Vultur 	 */
19470dfe25cSHoratiu Vultur 	msgtype = ptp_get_msgtype(header, type);
19570dfe25cSHoratiu Vultur 	if ((msgtype & 0xf) == 0) {
19670dfe25cSHoratiu Vultur 		*rew_op = IFH_REW_OP_ONE_STEP_PTP;
19770dfe25cSHoratiu Vultur 		return;
19870dfe25cSHoratiu Vultur 	}
19970dfe25cSHoratiu Vultur 
20070dfe25cSHoratiu Vultur 	*rew_op = IFH_REW_OP_TWO_STEP_PTP;
20170dfe25cSHoratiu Vultur }
20270dfe25cSHoratiu Vultur 
sparx5_ptp_txtstamp_old_release(struct sparx5_port * port)20370dfe25cSHoratiu Vultur static void sparx5_ptp_txtstamp_old_release(struct sparx5_port *port)
20470dfe25cSHoratiu Vultur {
20570dfe25cSHoratiu Vultur 	struct sk_buff *skb, *skb_tmp;
20670dfe25cSHoratiu Vultur 	unsigned long flags;
20770dfe25cSHoratiu Vultur 
20870dfe25cSHoratiu Vultur 	spin_lock_irqsave(&port->tx_skbs.lock, flags);
20970dfe25cSHoratiu Vultur 	skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
21070dfe25cSHoratiu Vultur 		if time_after(SPARX5_SKB_CB(skb)->jiffies + SPARX5_PTP_TIMEOUT,
21170dfe25cSHoratiu Vultur 			      jiffies)
21270dfe25cSHoratiu Vultur 			break;
21370dfe25cSHoratiu Vultur 
21470dfe25cSHoratiu Vultur 		__skb_unlink(skb, &port->tx_skbs);
21570dfe25cSHoratiu Vultur 		dev_kfree_skb_any(skb);
21670dfe25cSHoratiu Vultur 	}
21770dfe25cSHoratiu Vultur 	spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
21870dfe25cSHoratiu Vultur }
21970dfe25cSHoratiu Vultur 
sparx5_ptp_txtstamp_request(struct sparx5_port * port,struct sk_buff * skb)22070dfe25cSHoratiu Vultur int sparx5_ptp_txtstamp_request(struct sparx5_port *port,
22170dfe25cSHoratiu Vultur 				struct sk_buff *skb)
22270dfe25cSHoratiu Vultur {
22370dfe25cSHoratiu Vultur 	struct sparx5 *sparx5 = port->sparx5;
22470dfe25cSHoratiu Vultur 	u8 rew_op, pdu_type, pdu_w16_offset;
22570dfe25cSHoratiu Vultur 	unsigned long flags;
22670dfe25cSHoratiu Vultur 
22770dfe25cSHoratiu Vultur 	sparx5_ptp_classify(port, skb, &rew_op, &pdu_type, &pdu_w16_offset);
22870dfe25cSHoratiu Vultur 	SPARX5_SKB_CB(skb)->rew_op = rew_op;
22970dfe25cSHoratiu Vultur 	SPARX5_SKB_CB(skb)->pdu_type = pdu_type;
23070dfe25cSHoratiu Vultur 	SPARX5_SKB_CB(skb)->pdu_w16_offset = pdu_w16_offset;
23170dfe25cSHoratiu Vultur 
23270dfe25cSHoratiu Vultur 	if (rew_op != IFH_REW_OP_TWO_STEP_PTP)
23370dfe25cSHoratiu Vultur 		return 0;
23470dfe25cSHoratiu Vultur 
23570dfe25cSHoratiu Vultur 	sparx5_ptp_txtstamp_old_release(port);
23670dfe25cSHoratiu Vultur 
23770dfe25cSHoratiu Vultur 	spin_lock_irqsave(&sparx5->ptp_ts_id_lock, flags);
23870dfe25cSHoratiu Vultur 	if (sparx5->ptp_skbs == SPARX5_MAX_PTP_ID) {
23970dfe25cSHoratiu Vultur 		spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags);
24070dfe25cSHoratiu Vultur 		return -EBUSY;
24170dfe25cSHoratiu Vultur 	}
24270dfe25cSHoratiu Vultur 
24370dfe25cSHoratiu Vultur 	skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
24470dfe25cSHoratiu Vultur 
24570dfe25cSHoratiu Vultur 	skb_queue_tail(&port->tx_skbs, skb);
24670dfe25cSHoratiu Vultur 	SPARX5_SKB_CB(skb)->ts_id = port->ts_id;
24770dfe25cSHoratiu Vultur 	SPARX5_SKB_CB(skb)->jiffies = jiffies;
24870dfe25cSHoratiu Vultur 
24970dfe25cSHoratiu Vultur 	sparx5->ptp_skbs++;
25070dfe25cSHoratiu Vultur 	port->ts_id++;
25170dfe25cSHoratiu Vultur 	if (port->ts_id == SPARX5_MAX_PTP_ID)
25270dfe25cSHoratiu Vultur 		port->ts_id = 0;
25370dfe25cSHoratiu Vultur 
25470dfe25cSHoratiu Vultur 	spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags);
25570dfe25cSHoratiu Vultur 
25670dfe25cSHoratiu Vultur 	return 0;
25770dfe25cSHoratiu Vultur }
25870dfe25cSHoratiu Vultur 
sparx5_ptp_txtstamp_release(struct sparx5_port * port,struct sk_buff * skb)25970dfe25cSHoratiu Vultur void sparx5_ptp_txtstamp_release(struct sparx5_port *port,
26070dfe25cSHoratiu Vultur 				 struct sk_buff *skb)
26170dfe25cSHoratiu Vultur {
26270dfe25cSHoratiu Vultur 	struct sparx5 *sparx5 = port->sparx5;
26370dfe25cSHoratiu Vultur 	unsigned long flags;
26470dfe25cSHoratiu Vultur 
26570dfe25cSHoratiu Vultur 	spin_lock_irqsave(&sparx5->ptp_ts_id_lock, flags);
26670dfe25cSHoratiu Vultur 	port->ts_id--;
26770dfe25cSHoratiu Vultur 	sparx5->ptp_skbs--;
26870dfe25cSHoratiu Vultur 	skb_unlink(skb, &port->tx_skbs);
26970dfe25cSHoratiu Vultur 	spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags);
27070dfe25cSHoratiu Vultur }
27170dfe25cSHoratiu Vultur 
sparx5_get_hwtimestamp(struct sparx5 * sparx5,struct timespec64 * ts,u32 nsec)272d31d3791SHoratiu Vultur static void sparx5_get_hwtimestamp(struct sparx5 *sparx5,
273d31d3791SHoratiu Vultur 				   struct timespec64 *ts,
274d31d3791SHoratiu Vultur 				   u32 nsec)
275d31d3791SHoratiu Vultur {
276d31d3791SHoratiu Vultur 	/* Read current PTP time to get seconds */
277d31d3791SHoratiu Vultur 	unsigned long flags;
278d31d3791SHoratiu Vultur 	u32 curr_nsec;
279d31d3791SHoratiu Vultur 
280d31d3791SHoratiu Vultur 	spin_lock_irqsave(&sparx5->ptp_clock_lock, flags);
281d31d3791SHoratiu Vultur 
282d31d3791SHoratiu Vultur 	spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_SAVE) |
283d31d3791SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(SPARX5_PHC_PORT) |
284d31d3791SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
285d31d3791SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
286d31d3791SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
287d31d3791SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
288d31d3791SHoratiu Vultur 		 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
289d31d3791SHoratiu Vultur 
290d31d3791SHoratiu Vultur 	ts->tv_sec = spx5_rd(sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN));
291d31d3791SHoratiu Vultur 	curr_nsec = spx5_rd(sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN));
292d31d3791SHoratiu Vultur 
293d31d3791SHoratiu Vultur 	ts->tv_nsec = nsec;
294d31d3791SHoratiu Vultur 
295d31d3791SHoratiu Vultur 	/* Sec has incremented since the ts was registered */
296d31d3791SHoratiu Vultur 	if (curr_nsec < nsec)
297d31d3791SHoratiu Vultur 		ts->tv_sec--;
298d31d3791SHoratiu Vultur 
299d31d3791SHoratiu Vultur 	spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
300d31d3791SHoratiu Vultur }
301d31d3791SHoratiu Vultur 
sparx5_ptp_irq_handler(int irq,void * args)302d31d3791SHoratiu Vultur irqreturn_t sparx5_ptp_irq_handler(int irq, void *args)
303d31d3791SHoratiu Vultur {
304d31d3791SHoratiu Vultur 	int budget = SPARX5_MAX_PTP_ID;
305d31d3791SHoratiu Vultur 	struct sparx5 *sparx5 = args;
306d31d3791SHoratiu Vultur 
307d31d3791SHoratiu Vultur 	while (budget--) {
308d31d3791SHoratiu Vultur 		struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
309d31d3791SHoratiu Vultur 		struct skb_shared_hwtstamps shhwtstamps;
310d31d3791SHoratiu Vultur 		struct sparx5_port *port;
311d31d3791SHoratiu Vultur 		struct timespec64 ts;
312d31d3791SHoratiu Vultur 		unsigned long flags;
313d31d3791SHoratiu Vultur 		u32 val, id, txport;
314d31d3791SHoratiu Vultur 		u32 delay;
315d31d3791SHoratiu Vultur 
316d31d3791SHoratiu Vultur 		val = spx5_rd(sparx5, REW_PTP_TWOSTEP_CTRL);
317d31d3791SHoratiu Vultur 
318d31d3791SHoratiu Vultur 		/* Check if a timestamp can be retrieved */
319d31d3791SHoratiu Vultur 		if (!(val & REW_PTP_TWOSTEP_CTRL_PTP_VLD))
320d31d3791SHoratiu Vultur 			break;
321d31d3791SHoratiu Vultur 
322d31d3791SHoratiu Vultur 		WARN_ON(val & REW_PTP_TWOSTEP_CTRL_PTP_OVFL);
323d31d3791SHoratiu Vultur 
324d31d3791SHoratiu Vultur 		if (!(val & REW_PTP_TWOSTEP_CTRL_STAMP_TX))
325d31d3791SHoratiu Vultur 			continue;
326d31d3791SHoratiu Vultur 
327d31d3791SHoratiu Vultur 		/* Retrieve the ts Tx port */
328d31d3791SHoratiu Vultur 		txport = REW_PTP_TWOSTEP_CTRL_STAMP_PORT_GET(val);
329d31d3791SHoratiu Vultur 
330d31d3791SHoratiu Vultur 		/* Retrieve its associated skb */
331d31d3791SHoratiu Vultur 		port = sparx5->ports[txport];
332d31d3791SHoratiu Vultur 
333d31d3791SHoratiu Vultur 		/* Retrieve the delay */
334d31d3791SHoratiu Vultur 		delay = spx5_rd(sparx5, REW_PTP_TWOSTEP_STAMP);
335d31d3791SHoratiu Vultur 		delay = REW_PTP_TWOSTEP_STAMP_STAMP_NSEC_GET(delay);
336d31d3791SHoratiu Vultur 
337d31d3791SHoratiu Vultur 		/* Get next timestamp from fifo, which needs to be the
338d31d3791SHoratiu Vultur 		 * rx timestamp which represents the id of the frame
339d31d3791SHoratiu Vultur 		 */
340d31d3791SHoratiu Vultur 		spx5_rmw(REW_PTP_TWOSTEP_CTRL_PTP_NXT_SET(1),
341d31d3791SHoratiu Vultur 			 REW_PTP_TWOSTEP_CTRL_PTP_NXT,
342d31d3791SHoratiu Vultur 			 sparx5, REW_PTP_TWOSTEP_CTRL);
343d31d3791SHoratiu Vultur 
344d31d3791SHoratiu Vultur 		val = spx5_rd(sparx5, REW_PTP_TWOSTEP_CTRL);
345d31d3791SHoratiu Vultur 
346d31d3791SHoratiu Vultur 		/* Check if a timestamp can be retried */
347d31d3791SHoratiu Vultur 		if (!(val & REW_PTP_TWOSTEP_CTRL_PTP_VLD))
348d31d3791SHoratiu Vultur 			break;
349d31d3791SHoratiu Vultur 
350d31d3791SHoratiu Vultur 		/* Read RX timestamping to get the ID */
351d31d3791SHoratiu Vultur 		id = spx5_rd(sparx5, REW_PTP_TWOSTEP_STAMP);
352d31d3791SHoratiu Vultur 		id <<= 8;
353d31d3791SHoratiu Vultur 		id |= spx5_rd(sparx5, REW_PTP_TWOSTEP_STAMP_SUBNS);
354d31d3791SHoratiu Vultur 
355d31d3791SHoratiu Vultur 		spin_lock_irqsave(&port->tx_skbs.lock, flags);
356d31d3791SHoratiu Vultur 		skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
357d31d3791SHoratiu Vultur 			if (SPARX5_SKB_CB(skb)->ts_id != id)
358d31d3791SHoratiu Vultur 				continue;
359d31d3791SHoratiu Vultur 
360d31d3791SHoratiu Vultur 			__skb_unlink(skb, &port->tx_skbs);
361d31d3791SHoratiu Vultur 			skb_match = skb;
362d31d3791SHoratiu Vultur 			break;
363d31d3791SHoratiu Vultur 		}
364d31d3791SHoratiu Vultur 		spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
365d31d3791SHoratiu Vultur 
366d31d3791SHoratiu Vultur 		/* Next ts */
367d31d3791SHoratiu Vultur 		spx5_rmw(REW_PTP_TWOSTEP_CTRL_PTP_NXT_SET(1),
368d31d3791SHoratiu Vultur 			 REW_PTP_TWOSTEP_CTRL_PTP_NXT,
369d31d3791SHoratiu Vultur 			 sparx5, REW_PTP_TWOSTEP_CTRL);
370d31d3791SHoratiu Vultur 
371d31d3791SHoratiu Vultur 		if (WARN_ON(!skb_match))
372d31d3791SHoratiu Vultur 			continue;
373d31d3791SHoratiu Vultur 
374d31d3791SHoratiu Vultur 		spin_lock(&sparx5->ptp_ts_id_lock);
375d31d3791SHoratiu Vultur 		sparx5->ptp_skbs--;
376d31d3791SHoratiu Vultur 		spin_unlock(&sparx5->ptp_ts_id_lock);
377d31d3791SHoratiu Vultur 
378d31d3791SHoratiu Vultur 		/* Get the h/w timestamp */
379d31d3791SHoratiu Vultur 		sparx5_get_hwtimestamp(sparx5, &ts, delay);
380d31d3791SHoratiu Vultur 
381d31d3791SHoratiu Vultur 		/* Set the timestamp into the skb */
382d31d3791SHoratiu Vultur 		shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
383d31d3791SHoratiu Vultur 		skb_tstamp_tx(skb_match, &shhwtstamps);
384d31d3791SHoratiu Vultur 
385d31d3791SHoratiu Vultur 		dev_kfree_skb_any(skb_match);
386d31d3791SHoratiu Vultur 	}
387d31d3791SHoratiu Vultur 
388d31d3791SHoratiu Vultur 	return IRQ_HANDLED;
389d31d3791SHoratiu Vultur }
390d31d3791SHoratiu Vultur 
sparx5_ptp_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)3910933bd04SHoratiu Vultur static int sparx5_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
3920933bd04SHoratiu Vultur {
3930933bd04SHoratiu Vultur 	struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info);
3940933bd04SHoratiu Vultur 	struct sparx5 *sparx5 = phc->sparx5;
3950933bd04SHoratiu Vultur 	unsigned long flags;
3960933bd04SHoratiu Vultur 	bool neg_adj = 0;
3970933bd04SHoratiu Vultur 	u64 tod_inc;
3980933bd04SHoratiu Vultur 	u64 ref;
3990933bd04SHoratiu Vultur 
4000933bd04SHoratiu Vultur 	if (!scaled_ppm)
4010933bd04SHoratiu Vultur 		return 0;
4020933bd04SHoratiu Vultur 
4030933bd04SHoratiu Vultur 	if (scaled_ppm < 0) {
4040933bd04SHoratiu Vultur 		neg_adj = 1;
4050933bd04SHoratiu Vultur 		scaled_ppm = -scaled_ppm;
4060933bd04SHoratiu Vultur 	}
4070933bd04SHoratiu Vultur 
4080933bd04SHoratiu Vultur 	tod_inc = sparx5_ptp_get_nominal_value(sparx5);
4090933bd04SHoratiu Vultur 
4100933bd04SHoratiu Vultur 	/* The multiplication is split in 2 separate additions because of
4110933bd04SHoratiu Vultur 	 * overflow issues. If scaled_ppm with 16bit fractional part was bigger
4120933bd04SHoratiu Vultur 	 * than 20ppm then we got overflow.
4130933bd04SHoratiu Vultur 	 */
4140933bd04SHoratiu Vultur 	ref = sparx5_ptp_get_1ppm(sparx5) * (scaled_ppm >> 16);
4150933bd04SHoratiu Vultur 	ref += (sparx5_ptp_get_1ppm(sparx5) * (0xffff & scaled_ppm)) >> 16;
4160933bd04SHoratiu Vultur 	tod_inc = neg_adj ? tod_inc - ref : tod_inc + ref;
4170933bd04SHoratiu Vultur 
4180933bd04SHoratiu Vultur 	spin_lock_irqsave(&sparx5->ptp_clock_lock, flags);
4190933bd04SHoratiu Vultur 
4200933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(1 << BIT(phc->index)),
4210933bd04SHoratiu Vultur 		 PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS,
4220933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_DOM_CFG);
4230933bd04SHoratiu Vultur 
4240933bd04SHoratiu Vultur 	spx5_wr((u32)tod_inc & 0xFFFFFFFF, sparx5,
4250933bd04SHoratiu Vultur 		PTP_CLK_PER_CFG(phc->index, 0));
4260933bd04SHoratiu Vultur 	spx5_wr((u32)(tod_inc >> 32), sparx5,
4270933bd04SHoratiu Vultur 		PTP_CLK_PER_CFG(phc->index, 1));
4280933bd04SHoratiu Vultur 
4290933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(0),
4300933bd04SHoratiu Vultur 		 PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS, sparx5,
4310933bd04SHoratiu Vultur 		 PTP_PTP_DOM_CFG);
4320933bd04SHoratiu Vultur 
4330933bd04SHoratiu Vultur 	spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
4340933bd04SHoratiu Vultur 
4350933bd04SHoratiu Vultur 	return 0;
4360933bd04SHoratiu Vultur }
4370933bd04SHoratiu Vultur 
sparx5_ptp_settime64(struct ptp_clock_info * ptp,const struct timespec64 * ts)4380933bd04SHoratiu Vultur static int sparx5_ptp_settime64(struct ptp_clock_info *ptp,
4390933bd04SHoratiu Vultur 				const struct timespec64 *ts)
4400933bd04SHoratiu Vultur {
4410933bd04SHoratiu Vultur 	struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info);
4420933bd04SHoratiu Vultur 	struct sparx5 *sparx5 = phc->sparx5;
4430933bd04SHoratiu Vultur 	unsigned long flags;
4440933bd04SHoratiu Vultur 
4450933bd04SHoratiu Vultur 	spin_lock_irqsave(&sparx5->ptp_clock_lock, flags);
4460933bd04SHoratiu Vultur 
4470933bd04SHoratiu Vultur 	/* Must be in IDLE mode before the time can be loaded */
4480933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_IDLE) |
4490933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
4500933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
4510933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
4520933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
4530933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
4540933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
4550933bd04SHoratiu Vultur 
4560933bd04SHoratiu Vultur 	/* Set new value */
4570933bd04SHoratiu Vultur 	spx5_wr(PTP_PTP_TOD_SEC_MSB_PTP_TOD_SEC_MSB_SET(upper_32_bits(ts->tv_sec)),
4580933bd04SHoratiu Vultur 		sparx5, PTP_PTP_TOD_SEC_MSB(TOD_ACC_PIN));
4590933bd04SHoratiu Vultur 	spx5_wr(lower_32_bits(ts->tv_sec),
4600933bd04SHoratiu Vultur 		sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN));
4610933bd04SHoratiu Vultur 	spx5_wr(ts->tv_nsec, sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN));
4620933bd04SHoratiu Vultur 
4630933bd04SHoratiu Vultur 	/* Apply new values */
4640933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_LOAD) |
4650933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
4660933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
4670933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
4680933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
4690933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
4700933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
4710933bd04SHoratiu Vultur 
4720933bd04SHoratiu Vultur 	spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
4730933bd04SHoratiu Vultur 
4740933bd04SHoratiu Vultur 	return 0;
4750933bd04SHoratiu Vultur }
4760933bd04SHoratiu Vultur 
sparx5_ptp_gettime64(struct ptp_clock_info * ptp,struct timespec64 * ts)4779e02131eSDaniel Machon int sparx5_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts)
4780933bd04SHoratiu Vultur {
4790933bd04SHoratiu Vultur 	struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info);
4800933bd04SHoratiu Vultur 	struct sparx5 *sparx5 = phc->sparx5;
4810933bd04SHoratiu Vultur 	unsigned long flags;
4820933bd04SHoratiu Vultur 	time64_t s;
4830933bd04SHoratiu Vultur 	s64 ns;
4840933bd04SHoratiu Vultur 
4850933bd04SHoratiu Vultur 	spin_lock_irqsave(&sparx5->ptp_clock_lock, flags);
4860933bd04SHoratiu Vultur 
4870933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_SAVE) |
4880933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
4890933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
4900933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
4910933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
4920933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
4930933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
4940933bd04SHoratiu Vultur 
4950933bd04SHoratiu Vultur 	s = spx5_rd(sparx5, PTP_PTP_TOD_SEC_MSB(TOD_ACC_PIN));
4960933bd04SHoratiu Vultur 	s <<= 32;
4970933bd04SHoratiu Vultur 	s |= spx5_rd(sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN));
4980933bd04SHoratiu Vultur 	ns = spx5_rd(sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN));
4990933bd04SHoratiu Vultur 	ns &= PTP_PTP_TOD_NSEC_PTP_TOD_NSEC;
5000933bd04SHoratiu Vultur 
5010933bd04SHoratiu Vultur 	spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
5020933bd04SHoratiu Vultur 
5030933bd04SHoratiu Vultur 	/* Deal with negative values */
5040933bd04SHoratiu Vultur 	if ((ns & 0xFFFFFFF0) == 0x3FFFFFF0) {
5050933bd04SHoratiu Vultur 		s--;
5060933bd04SHoratiu Vultur 		ns &= 0xf;
5070933bd04SHoratiu Vultur 		ns += 999999984;
5080933bd04SHoratiu Vultur 	}
5090933bd04SHoratiu Vultur 
5100933bd04SHoratiu Vultur 	set_normalized_timespec64(ts, s, ns);
5110933bd04SHoratiu Vultur 	return 0;
5120933bd04SHoratiu Vultur }
5130933bd04SHoratiu Vultur 
sparx5_ptp_adjtime(struct ptp_clock_info * ptp,s64 delta)5140933bd04SHoratiu Vultur static int sparx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
5150933bd04SHoratiu Vultur {
5160933bd04SHoratiu Vultur 	struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info);
5170933bd04SHoratiu Vultur 	struct sparx5 *sparx5 = phc->sparx5;
5180933bd04SHoratiu Vultur 
5190933bd04SHoratiu Vultur 	if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) {
5200933bd04SHoratiu Vultur 		unsigned long flags;
5210933bd04SHoratiu Vultur 
5220933bd04SHoratiu Vultur 		spin_lock_irqsave(&sparx5->ptp_clock_lock, flags);
5230933bd04SHoratiu Vultur 
5240933bd04SHoratiu Vultur 		/* Must be in IDLE mode before the time can be loaded */
5250933bd04SHoratiu Vultur 		spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_IDLE) |
5260933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
5270933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
5280933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
5290933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
5300933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
5310933bd04SHoratiu Vultur 			 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
5320933bd04SHoratiu Vultur 
5330933bd04SHoratiu Vultur 		spx5_wr(PTP_PTP_TOD_NSEC_PTP_TOD_NSEC_SET(delta),
5340933bd04SHoratiu Vultur 			sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN));
5350933bd04SHoratiu Vultur 
5360933bd04SHoratiu Vultur 		/* Adjust time with the value of PTP_TOD_NSEC */
5370933bd04SHoratiu Vultur 		spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_DELTA) |
5380933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
5390933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
5400933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
5410933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
5420933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
5430933bd04SHoratiu Vultur 			 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
5440933bd04SHoratiu Vultur 
5450933bd04SHoratiu Vultur 		spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
5460933bd04SHoratiu Vultur 	} else {
5470933bd04SHoratiu Vultur 		/* Fall back using sparx5_ptp_settime64 which is not exact */
5480933bd04SHoratiu Vultur 		struct timespec64 ts;
5490933bd04SHoratiu Vultur 		u64 now;
5500933bd04SHoratiu Vultur 
5510933bd04SHoratiu Vultur 		sparx5_ptp_gettime64(ptp, &ts);
5520933bd04SHoratiu Vultur 
5530933bd04SHoratiu Vultur 		now = ktime_to_ns(timespec64_to_ktime(ts));
5540933bd04SHoratiu Vultur 		ts = ns_to_timespec64(now + delta);
5550933bd04SHoratiu Vultur 
5560933bd04SHoratiu Vultur 		sparx5_ptp_settime64(ptp, &ts);
5570933bd04SHoratiu Vultur 	}
5580933bd04SHoratiu Vultur 
5590933bd04SHoratiu Vultur 	return 0;
5600933bd04SHoratiu Vultur }
5610933bd04SHoratiu Vultur 
5620933bd04SHoratiu Vultur static struct ptp_clock_info sparx5_ptp_clock_info = {
5630933bd04SHoratiu Vultur 	.owner		= THIS_MODULE,
5640933bd04SHoratiu Vultur 	.name		= "sparx5 ptp",
5650933bd04SHoratiu Vultur 	.max_adj	= 200000,
5660933bd04SHoratiu Vultur 	.gettime64	= sparx5_ptp_gettime64,
5670933bd04SHoratiu Vultur 	.settime64	= sparx5_ptp_settime64,
5680933bd04SHoratiu Vultur 	.adjtime	= sparx5_ptp_adjtime,
5690933bd04SHoratiu Vultur 	.adjfine	= sparx5_ptp_adjfine,
5700933bd04SHoratiu Vultur };
5710933bd04SHoratiu Vultur 
sparx5_ptp_phc_init(struct sparx5 * sparx5,int index,struct ptp_clock_info * clock_info)5720933bd04SHoratiu Vultur static int sparx5_ptp_phc_init(struct sparx5 *sparx5,
5730933bd04SHoratiu Vultur 			       int index,
5740933bd04SHoratiu Vultur 			       struct ptp_clock_info *clock_info)
5750933bd04SHoratiu Vultur {
5760933bd04SHoratiu Vultur 	struct sparx5_phc *phc = &sparx5->phc[index];
5770933bd04SHoratiu Vultur 
5780933bd04SHoratiu Vultur 	phc->info = *clock_info;
5790933bd04SHoratiu Vultur 	phc->clock = ptp_clock_register(&phc->info, sparx5->dev);
5800933bd04SHoratiu Vultur 	if (IS_ERR(phc->clock))
5810933bd04SHoratiu Vultur 		return PTR_ERR(phc->clock);
5820933bd04SHoratiu Vultur 
5830933bd04SHoratiu Vultur 	phc->index = index;
5840933bd04SHoratiu Vultur 	phc->sparx5 = sparx5;
5850933bd04SHoratiu Vultur 
5860933bd04SHoratiu Vultur 	/* PTP Rx stamping is always enabled.  */
5870933bd04SHoratiu Vultur 	phc->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
5880933bd04SHoratiu Vultur 
5890933bd04SHoratiu Vultur 	return 0;
5900933bd04SHoratiu Vultur }
5910933bd04SHoratiu Vultur 
sparx5_ptp_init(struct sparx5 * sparx5)5920933bd04SHoratiu Vultur int sparx5_ptp_init(struct sparx5 *sparx5)
5930933bd04SHoratiu Vultur {
5940933bd04SHoratiu Vultur 	u64 tod_adj = sparx5_ptp_get_nominal_value(sparx5);
59570dfe25cSHoratiu Vultur 	struct sparx5_port *port;
5960933bd04SHoratiu Vultur 	int err, i;
5970933bd04SHoratiu Vultur 
5980933bd04SHoratiu Vultur 	if (!sparx5->ptp)
5990933bd04SHoratiu Vultur 		return 0;
6000933bd04SHoratiu Vultur 
6010933bd04SHoratiu Vultur 	for (i = 0; i < SPARX5_PHC_COUNT; ++i) {
6020933bd04SHoratiu Vultur 		err = sparx5_ptp_phc_init(sparx5, i, &sparx5_ptp_clock_info);
6030933bd04SHoratiu Vultur 		if (err)
6040933bd04SHoratiu Vultur 			return err;
6050933bd04SHoratiu Vultur 	}
6060933bd04SHoratiu Vultur 
6070933bd04SHoratiu Vultur 	spin_lock_init(&sparx5->ptp_clock_lock);
60870dfe25cSHoratiu Vultur 	spin_lock_init(&sparx5->ptp_ts_id_lock);
609589a07b8SHoratiu Vultur 	mutex_init(&sparx5->ptp_lock);
6100933bd04SHoratiu Vultur 
6110933bd04SHoratiu Vultur 	/* Disable master counters */
6120933bd04SHoratiu Vultur 	spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0), sparx5, PTP_PTP_DOM_CFG);
6130933bd04SHoratiu Vultur 
6140933bd04SHoratiu Vultur 	/* Configure the nominal TOD increment per clock cycle */
6150933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(0x7),
6160933bd04SHoratiu Vultur 		 PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS,
6170933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_DOM_CFG);
6180933bd04SHoratiu Vultur 
6190933bd04SHoratiu Vultur 	for (i = 0; i < SPARX5_PHC_COUNT; ++i) {
6200933bd04SHoratiu Vultur 		spx5_wr((u32)tod_adj & 0xFFFFFFFF, sparx5,
6210933bd04SHoratiu Vultur 			PTP_CLK_PER_CFG(i, 0));
6220933bd04SHoratiu Vultur 		spx5_wr((u32)(tod_adj >> 32), sparx5,
6230933bd04SHoratiu Vultur 			PTP_CLK_PER_CFG(i, 1));
6240933bd04SHoratiu Vultur 	}
6250933bd04SHoratiu Vultur 
6260933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(0),
6270933bd04SHoratiu Vultur 		 PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS,
6280933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_DOM_CFG);
6290933bd04SHoratiu Vultur 
6300933bd04SHoratiu Vultur 	/* Enable master counters */
6310933bd04SHoratiu Vultur 	spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0x7), sparx5, PTP_PTP_DOM_CFG);
6320933bd04SHoratiu Vultur 
633d7d94b26SCasper Andersson 	for (i = 0; i < SPX5_PORTS; i++) {
63470dfe25cSHoratiu Vultur 		port = sparx5->ports[i];
63570dfe25cSHoratiu Vultur 		if (!port)
63670dfe25cSHoratiu Vultur 			continue;
63770dfe25cSHoratiu Vultur 
63870dfe25cSHoratiu Vultur 		skb_queue_head_init(&port->tx_skbs);
63970dfe25cSHoratiu Vultur 	}
64070dfe25cSHoratiu Vultur 
6410933bd04SHoratiu Vultur 	return 0;
6420933bd04SHoratiu Vultur }
6430933bd04SHoratiu Vultur 
sparx5_ptp_deinit(struct sparx5 * sparx5)6440933bd04SHoratiu Vultur void sparx5_ptp_deinit(struct sparx5 *sparx5)
6450933bd04SHoratiu Vultur {
64670dfe25cSHoratiu Vultur 	struct sparx5_port *port;
6470933bd04SHoratiu Vultur 	int i;
6480933bd04SHoratiu Vultur 
649d7d94b26SCasper Andersson 	for (i = 0; i < SPX5_PORTS; i++) {
65070dfe25cSHoratiu Vultur 		port = sparx5->ports[i];
65170dfe25cSHoratiu Vultur 		if (!port)
65270dfe25cSHoratiu Vultur 			continue;
65370dfe25cSHoratiu Vultur 
65470dfe25cSHoratiu Vultur 		skb_queue_purge(&port->tx_skbs);
65570dfe25cSHoratiu Vultur 	}
65670dfe25cSHoratiu Vultur 
6570933bd04SHoratiu Vultur 	for (i = 0; i < SPARX5_PHC_COUNT; ++i)
6580933bd04SHoratiu Vultur 		ptp_clock_unregister(sparx5->phc[i].clock);
6590933bd04SHoratiu Vultur }
66070dfe25cSHoratiu Vultur 
sparx5_ptp_rxtstamp(struct sparx5 * sparx5,struct sk_buff * skb,u64 timestamp)66170dfe25cSHoratiu Vultur void sparx5_ptp_rxtstamp(struct sparx5 *sparx5, struct sk_buff *skb,
66270dfe25cSHoratiu Vultur 			 u64 timestamp)
66370dfe25cSHoratiu Vultur {
66470dfe25cSHoratiu Vultur 	struct skb_shared_hwtstamps *shhwtstamps;
66570dfe25cSHoratiu Vultur 	struct sparx5_phc *phc;
66670dfe25cSHoratiu Vultur 	struct timespec64 ts;
66770dfe25cSHoratiu Vultur 	u64 full_ts_in_ns;
66870dfe25cSHoratiu Vultur 
66970dfe25cSHoratiu Vultur 	if (!sparx5->ptp)
67070dfe25cSHoratiu Vultur 		return;
67170dfe25cSHoratiu Vultur 
67270dfe25cSHoratiu Vultur 	phc = &sparx5->phc[SPARX5_PHC_PORT];
67370dfe25cSHoratiu Vultur 	sparx5_ptp_gettime64(&phc->info, &ts);
67470dfe25cSHoratiu Vultur 
67570dfe25cSHoratiu Vultur 	if (ts.tv_nsec < timestamp)
67670dfe25cSHoratiu Vultur 		ts.tv_sec--;
67770dfe25cSHoratiu Vultur 	ts.tv_nsec = timestamp;
67870dfe25cSHoratiu Vultur 	full_ts_in_ns = ktime_set(ts.tv_sec, ts.tv_nsec);
67970dfe25cSHoratiu Vultur 
68070dfe25cSHoratiu Vultur 	shhwtstamps = skb_hwtstamps(skb);
68170dfe25cSHoratiu Vultur 	shhwtstamps->hwtstamp = full_ts_in_ns;
68270dfe25cSHoratiu Vultur }
683