xref: /openbmc/linux/drivers/net/ethernet/microchip/lan743x_ptp.c (revision 07624df1c9efd4b7f2f6762581587c590b03c7a2)
1*07624df1SBryan Whitehead /* SPDX-License-Identifier: GPL-2.0+ */
2*07624df1SBryan Whitehead /* Copyright (C) 2018 Microchip Technology Inc. */
3*07624df1SBryan Whitehead 
4*07624df1SBryan Whitehead #include <linux/netdevice.h>
5*07624df1SBryan Whitehead #include "lan743x_main.h"
6*07624df1SBryan Whitehead 
7*07624df1SBryan Whitehead #include <linux/module.h>
8*07624df1SBryan Whitehead #include <linux/pci.h>
9*07624df1SBryan Whitehead #include <linux/netdevice.h>
10*07624df1SBryan Whitehead #include <linux/net_tstamp.h>
11*07624df1SBryan Whitehead 
12*07624df1SBryan Whitehead #include "lan743x_ptp.h"
13*07624df1SBryan Whitehead 
14*07624df1SBryan Whitehead #define LAN743X_NUMBER_OF_GPIO			(12)
15*07624df1SBryan Whitehead #define LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB		(31249999)
16*07624df1SBryan Whitehead #define LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM	(2047999934)
17*07624df1SBryan Whitehead 
18*07624df1SBryan Whitehead static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter);
19*07624df1SBryan Whitehead static void lan743x_ptp_enable(struct lan743x_adapter *adapter);
20*07624df1SBryan Whitehead static void lan743x_ptp_disable(struct lan743x_adapter *adapter);
21*07624df1SBryan Whitehead static void lan743x_ptp_reset(struct lan743x_adapter *adapter);
22*07624df1SBryan Whitehead static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter,
23*07624df1SBryan Whitehead 				  u32 seconds, u32 nano_seconds,
24*07624df1SBryan Whitehead 				  u32 sub_nano_seconds);
25*07624df1SBryan Whitehead 
26*07624df1SBryan Whitehead int lan743x_gpio_init(struct lan743x_adapter *adapter)
27*07624df1SBryan Whitehead {
28*07624df1SBryan Whitehead 	struct lan743x_gpio *gpio = &adapter->gpio;
29*07624df1SBryan Whitehead 
30*07624df1SBryan Whitehead 	spin_lock_init(&gpio->gpio_lock);
31*07624df1SBryan Whitehead 
32*07624df1SBryan Whitehead 	gpio->gpio_cfg0 = 0; /* set all direction to input, data = 0 */
33*07624df1SBryan Whitehead 	gpio->gpio_cfg1 = 0x0FFF0000;/* disable all gpio, set to open drain */
34*07624df1SBryan Whitehead 	gpio->gpio_cfg2 = 0;/* set all to 1588 low polarity level */
35*07624df1SBryan Whitehead 	gpio->gpio_cfg3 = 0;/* disable all 1588 output */
36*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
37*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
38*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2);
39*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3);
40*07624df1SBryan Whitehead 
41*07624df1SBryan Whitehead 	return 0;
42*07624df1SBryan Whitehead }
43*07624df1SBryan Whitehead 
44*07624df1SBryan Whitehead static void lan743x_ptp_wait_till_cmd_done(struct lan743x_adapter *adapter,
45*07624df1SBryan Whitehead 					   u32 bit_mask)
46*07624df1SBryan Whitehead {
47*07624df1SBryan Whitehead 	int timeout = 1000;
48*07624df1SBryan Whitehead 	u32 data = 0;
49*07624df1SBryan Whitehead 
50*07624df1SBryan Whitehead 	while (timeout &&
51*07624df1SBryan Whitehead 	       (data = (lan743x_csr_read(adapter, PTP_CMD_CTL) &
52*07624df1SBryan Whitehead 	       bit_mask))) {
53*07624df1SBryan Whitehead 		usleep_range(1000, 20000);
54*07624df1SBryan Whitehead 		timeout--;
55*07624df1SBryan Whitehead 	}
56*07624df1SBryan Whitehead 	if (data) {
57*07624df1SBryan Whitehead 		netif_err(adapter, drv, adapter->netdev,
58*07624df1SBryan Whitehead 			  "timeout waiting for cmd to be done, cmd = 0x%08X\n",
59*07624df1SBryan Whitehead 			  bit_mask);
60*07624df1SBryan Whitehead 	}
61*07624df1SBryan Whitehead }
62*07624df1SBryan Whitehead 
63*07624df1SBryan Whitehead static void lan743x_ptp_tx_ts_enqueue_ts(struct lan743x_adapter *adapter,
64*07624df1SBryan Whitehead 					 u32 seconds, u32 nano_seconds,
65*07624df1SBryan Whitehead 					 u32 header)
66*07624df1SBryan Whitehead {
67*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
68*07624df1SBryan Whitehead 
69*07624df1SBryan Whitehead 	spin_lock_bh(&ptp->tx_ts_lock);
70*07624df1SBryan Whitehead 	if (ptp->tx_ts_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
71*07624df1SBryan Whitehead 		ptp->tx_ts_seconds_queue[ptp->tx_ts_queue_size] = seconds;
72*07624df1SBryan Whitehead 		ptp->tx_ts_nseconds_queue[ptp->tx_ts_queue_size] = nano_seconds;
73*07624df1SBryan Whitehead 		ptp->tx_ts_header_queue[ptp->tx_ts_queue_size] = header;
74*07624df1SBryan Whitehead 		ptp->tx_ts_queue_size++;
75*07624df1SBryan Whitehead 	} else {
76*07624df1SBryan Whitehead 		netif_err(adapter, drv, adapter->netdev,
77*07624df1SBryan Whitehead 			  "tx ts queue overflow\n");
78*07624df1SBryan Whitehead 	}
79*07624df1SBryan Whitehead 	spin_unlock_bh(&ptp->tx_ts_lock);
80*07624df1SBryan Whitehead }
81*07624df1SBryan Whitehead 
82*07624df1SBryan Whitehead static void lan743x_ptp_tx_ts_complete(struct lan743x_adapter *adapter)
83*07624df1SBryan Whitehead {
84*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
85*07624df1SBryan Whitehead 	struct skb_shared_hwtstamps tstamps;
86*07624df1SBryan Whitehead 	u32 header, nseconds, seconds;
87*07624df1SBryan Whitehead 	bool ignore_sync = false;
88*07624df1SBryan Whitehead 	struct sk_buff *skb;
89*07624df1SBryan Whitehead 	int c, i;
90*07624df1SBryan Whitehead 
91*07624df1SBryan Whitehead 	spin_lock_bh(&ptp->tx_ts_lock);
92*07624df1SBryan Whitehead 	c = ptp->tx_ts_skb_queue_size;
93*07624df1SBryan Whitehead 
94*07624df1SBryan Whitehead 	if (c > ptp->tx_ts_queue_size)
95*07624df1SBryan Whitehead 		c = ptp->tx_ts_queue_size;
96*07624df1SBryan Whitehead 	if (c <= 0)
97*07624df1SBryan Whitehead 		goto done;
98*07624df1SBryan Whitehead 
99*07624df1SBryan Whitehead 	for (i = 0; i < c; i++) {
100*07624df1SBryan Whitehead 		ignore_sync = ((ptp->tx_ts_ignore_sync_queue &
101*07624df1SBryan Whitehead 				BIT(i)) != 0);
102*07624df1SBryan Whitehead 		skb = ptp->tx_ts_skb_queue[i];
103*07624df1SBryan Whitehead 		nseconds = ptp->tx_ts_nseconds_queue[i];
104*07624df1SBryan Whitehead 		seconds = ptp->tx_ts_seconds_queue[i];
105*07624df1SBryan Whitehead 		header = ptp->tx_ts_header_queue[i];
106*07624df1SBryan Whitehead 
107*07624df1SBryan Whitehead 		memset(&tstamps, 0, sizeof(tstamps));
108*07624df1SBryan Whitehead 		tstamps.hwtstamp = ktime_set(seconds, nseconds);
109*07624df1SBryan Whitehead 		if (!ignore_sync ||
110*07624df1SBryan Whitehead 		    ((header & PTP_TX_MSG_HEADER_MSG_TYPE_) !=
111*07624df1SBryan Whitehead 		    PTP_TX_MSG_HEADER_MSG_TYPE_SYNC_))
112*07624df1SBryan Whitehead 			skb_tstamp_tx(skb, &tstamps);
113*07624df1SBryan Whitehead 
114*07624df1SBryan Whitehead 		dev_kfree_skb(skb);
115*07624df1SBryan Whitehead 
116*07624df1SBryan Whitehead 		ptp->tx_ts_skb_queue[i] = NULL;
117*07624df1SBryan Whitehead 		ptp->tx_ts_seconds_queue[i] = 0;
118*07624df1SBryan Whitehead 		ptp->tx_ts_nseconds_queue[i] = 0;
119*07624df1SBryan Whitehead 		ptp->tx_ts_header_queue[i] = 0;
120*07624df1SBryan Whitehead 	}
121*07624df1SBryan Whitehead 
122*07624df1SBryan Whitehead 	/* shift queue */
123*07624df1SBryan Whitehead 	ptp->tx_ts_ignore_sync_queue >>= c;
124*07624df1SBryan Whitehead 	for (i = c; i < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS; i++) {
125*07624df1SBryan Whitehead 		ptp->tx_ts_skb_queue[i - c] = ptp->tx_ts_skb_queue[i];
126*07624df1SBryan Whitehead 		ptp->tx_ts_seconds_queue[i - c] = ptp->tx_ts_seconds_queue[i];
127*07624df1SBryan Whitehead 		ptp->tx_ts_nseconds_queue[i - c] = ptp->tx_ts_nseconds_queue[i];
128*07624df1SBryan Whitehead 		ptp->tx_ts_header_queue[i - c] = ptp->tx_ts_header_queue[i];
129*07624df1SBryan Whitehead 
130*07624df1SBryan Whitehead 		ptp->tx_ts_skb_queue[i] = NULL;
131*07624df1SBryan Whitehead 		ptp->tx_ts_seconds_queue[i] = 0;
132*07624df1SBryan Whitehead 		ptp->tx_ts_nseconds_queue[i] = 0;
133*07624df1SBryan Whitehead 		ptp->tx_ts_header_queue[i] = 0;
134*07624df1SBryan Whitehead 	}
135*07624df1SBryan Whitehead 	ptp->tx_ts_skb_queue_size -= c;
136*07624df1SBryan Whitehead 	ptp->tx_ts_queue_size -= c;
137*07624df1SBryan Whitehead done:
138*07624df1SBryan Whitehead 	ptp->pending_tx_timestamps -= c;
139*07624df1SBryan Whitehead 	spin_unlock_bh(&ptp->tx_ts_lock);
140*07624df1SBryan Whitehead }
141*07624df1SBryan Whitehead 
142*07624df1SBryan Whitehead #ifdef CONFIG_PTP_1588_CLOCK
143*07624df1SBryan Whitehead static int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter)
144*07624df1SBryan Whitehead {
145*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
146*07624df1SBryan Whitehead 	int result = -ENODEV;
147*07624df1SBryan Whitehead 	int index = 0;
148*07624df1SBryan Whitehead 
149*07624df1SBryan Whitehead 	mutex_lock(&ptp->command_lock);
150*07624df1SBryan Whitehead 	for (index = 0; index < LAN743X_PTP_NUMBER_OF_EVENT_CHANNELS; index++) {
151*07624df1SBryan Whitehead 		if (!(test_bit(index, &ptp->used_event_ch))) {
152*07624df1SBryan Whitehead 			ptp->used_event_ch |= BIT(index);
153*07624df1SBryan Whitehead 			result = index;
154*07624df1SBryan Whitehead 			break;
155*07624df1SBryan Whitehead 		}
156*07624df1SBryan Whitehead 	}
157*07624df1SBryan Whitehead 	mutex_unlock(&ptp->command_lock);
158*07624df1SBryan Whitehead 	return result;
159*07624df1SBryan Whitehead }
160*07624df1SBryan Whitehead 
161*07624df1SBryan Whitehead static void lan743x_ptp_release_event_ch(struct lan743x_adapter *adapter,
162*07624df1SBryan Whitehead 					 int event_channel)
163*07624df1SBryan Whitehead {
164*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
165*07624df1SBryan Whitehead 
166*07624df1SBryan Whitehead 	mutex_lock(&ptp->command_lock);
167*07624df1SBryan Whitehead 	if (test_bit(event_channel, &ptp->used_event_ch)) {
168*07624df1SBryan Whitehead 		ptp->used_event_ch &= ~BIT(event_channel);
169*07624df1SBryan Whitehead 	} else {
170*07624df1SBryan Whitehead 		netif_warn(adapter, drv, adapter->netdev,
171*07624df1SBryan Whitehead 			   "attempted release on a not used event_channel = %d\n",
172*07624df1SBryan Whitehead 			   event_channel);
173*07624df1SBryan Whitehead 	}
174*07624df1SBryan Whitehead 	mutex_unlock(&ptp->command_lock);
175*07624df1SBryan Whitehead }
176*07624df1SBryan Whitehead 
177*07624df1SBryan Whitehead static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter,
178*07624df1SBryan Whitehead 				  u32 *seconds, u32 *nano_seconds,
179*07624df1SBryan Whitehead 				  u32 *sub_nano_seconds);
180*07624df1SBryan Whitehead static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter,
181*07624df1SBryan Whitehead 				   s64 time_step_ns);
182*07624df1SBryan Whitehead 
183*07624df1SBryan Whitehead static int lan743x_gpio_rsrv_ptp_out(struct lan743x_adapter *adapter,
184*07624df1SBryan Whitehead 				     int bit, int ptp_channel)
185*07624df1SBryan Whitehead {
186*07624df1SBryan Whitehead 	struct lan743x_gpio *gpio = &adapter->gpio;
187*07624df1SBryan Whitehead 	unsigned long irq_flags = 0;
188*07624df1SBryan Whitehead 	int bit_mask = BIT(bit);
189*07624df1SBryan Whitehead 	int ret = -EBUSY;
190*07624df1SBryan Whitehead 
191*07624df1SBryan Whitehead 	spin_lock_irqsave(&gpio->gpio_lock, irq_flags);
192*07624df1SBryan Whitehead 
193*07624df1SBryan Whitehead 	if (!(gpio->used_bits & bit_mask)) {
194*07624df1SBryan Whitehead 		gpio->used_bits |= bit_mask;
195*07624df1SBryan Whitehead 		gpio->output_bits |= bit_mask;
196*07624df1SBryan Whitehead 		gpio->ptp_bits |= bit_mask;
197*07624df1SBryan Whitehead 
198*07624df1SBryan Whitehead 		/* set as output, and zero initial value */
199*07624df1SBryan Whitehead 		gpio->gpio_cfg0 |= GPIO_CFG0_GPIO_DIR_BIT_(bit);
200*07624df1SBryan Whitehead 		gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(bit);
201*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
202*07624df1SBryan Whitehead 
203*07624df1SBryan Whitehead 		/* enable gpio, and set buffer type to push pull */
204*07624df1SBryan Whitehead 		gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOEN_BIT_(bit);
205*07624df1SBryan Whitehead 		gpio->gpio_cfg1 |= GPIO_CFG1_GPIOBUF_BIT_(bit);
206*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
207*07624df1SBryan Whitehead 
208*07624df1SBryan Whitehead 		/* set 1588 polarity to high */
209*07624df1SBryan Whitehead 		gpio->gpio_cfg2 |= GPIO_CFG2_1588_POL_BIT_(bit);
210*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2);
211*07624df1SBryan Whitehead 
212*07624df1SBryan Whitehead 		if (!ptp_channel) {
213*07624df1SBryan Whitehead 			/* use channel A */
214*07624df1SBryan Whitehead 			gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_CH_SEL_BIT_(bit);
215*07624df1SBryan Whitehead 		} else {
216*07624df1SBryan Whitehead 			/* use channel B */
217*07624df1SBryan Whitehead 			gpio->gpio_cfg3 |= GPIO_CFG3_1588_CH_SEL_BIT_(bit);
218*07624df1SBryan Whitehead 		}
219*07624df1SBryan Whitehead 		gpio->gpio_cfg3 |= GPIO_CFG3_1588_OE_BIT_(bit);
220*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3);
221*07624df1SBryan Whitehead 
222*07624df1SBryan Whitehead 		ret = bit;
223*07624df1SBryan Whitehead 	}
224*07624df1SBryan Whitehead 	spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags);
225*07624df1SBryan Whitehead 	return ret;
226*07624df1SBryan Whitehead }
227*07624df1SBryan Whitehead 
228*07624df1SBryan Whitehead static void lan743x_gpio_release(struct lan743x_adapter *adapter, int bit)
229*07624df1SBryan Whitehead {
230*07624df1SBryan Whitehead 	struct lan743x_gpio *gpio = &adapter->gpio;
231*07624df1SBryan Whitehead 	unsigned long irq_flags = 0;
232*07624df1SBryan Whitehead 	int bit_mask = BIT(bit);
233*07624df1SBryan Whitehead 
234*07624df1SBryan Whitehead 	spin_lock_irqsave(&gpio->gpio_lock, irq_flags);
235*07624df1SBryan Whitehead 	if (gpio->used_bits & bit_mask) {
236*07624df1SBryan Whitehead 		gpio->used_bits &= ~bit_mask;
237*07624df1SBryan Whitehead 		if (gpio->output_bits & bit_mask) {
238*07624df1SBryan Whitehead 			gpio->output_bits &= ~bit_mask;
239*07624df1SBryan Whitehead 
240*07624df1SBryan Whitehead 			if (gpio->ptp_bits & bit_mask) {
241*07624df1SBryan Whitehead 				gpio->ptp_bits &= ~bit_mask;
242*07624df1SBryan Whitehead 				/* disable ptp output */
243*07624df1SBryan Whitehead 				gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_OE_BIT_(bit);
244*07624df1SBryan Whitehead 				lan743x_csr_write(adapter, GPIO_CFG3,
245*07624df1SBryan Whitehead 						  gpio->gpio_cfg3);
246*07624df1SBryan Whitehead 			}
247*07624df1SBryan Whitehead 			/* release gpio output */
248*07624df1SBryan Whitehead 
249*07624df1SBryan Whitehead 			/* disable gpio */
250*07624df1SBryan Whitehead 			gpio->gpio_cfg1 |= GPIO_CFG1_GPIOEN_BIT_(bit);
251*07624df1SBryan Whitehead 			gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOBUF_BIT_(bit);
252*07624df1SBryan Whitehead 			lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
253*07624df1SBryan Whitehead 
254*07624df1SBryan Whitehead 			/* reset back to input */
255*07624df1SBryan Whitehead 			gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DIR_BIT_(bit);
256*07624df1SBryan Whitehead 			gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(bit);
257*07624df1SBryan Whitehead 			lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
258*07624df1SBryan Whitehead 		}
259*07624df1SBryan Whitehead 	}
260*07624df1SBryan Whitehead 	spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags);
261*07624df1SBryan Whitehead }
262*07624df1SBryan Whitehead 
263*07624df1SBryan Whitehead static int lan743x_ptpci_adjfine(struct ptp_clock_info *ptpci, long scaled_ppm)
264*07624df1SBryan Whitehead {
265*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp =
266*07624df1SBryan Whitehead 		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
267*07624df1SBryan Whitehead 	struct lan743x_adapter *adapter =
268*07624df1SBryan Whitehead 		container_of(ptp, struct lan743x_adapter, ptp);
269*07624df1SBryan Whitehead 	u32 lan743x_rate_adj = 0;
270*07624df1SBryan Whitehead 	bool positive = true;
271*07624df1SBryan Whitehead 	u64 u64_delta = 0;
272*07624df1SBryan Whitehead 
273*07624df1SBryan Whitehead 	if ((scaled_ppm < (-LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM)) ||
274*07624df1SBryan Whitehead 	    scaled_ppm > LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM) {
275*07624df1SBryan Whitehead 		return -EINVAL;
276*07624df1SBryan Whitehead 	}
277*07624df1SBryan Whitehead 	if (scaled_ppm > 0) {
278*07624df1SBryan Whitehead 		u64_delta = (u64)scaled_ppm;
279*07624df1SBryan Whitehead 		positive = true;
280*07624df1SBryan Whitehead 	} else {
281*07624df1SBryan Whitehead 		u64_delta = (u64)(-scaled_ppm);
282*07624df1SBryan Whitehead 		positive = false;
283*07624df1SBryan Whitehead 	}
284*07624df1SBryan Whitehead 	u64_delta = (u64_delta << 19);
285*07624df1SBryan Whitehead 	lan743x_rate_adj = div_u64(u64_delta, 1000000);
286*07624df1SBryan Whitehead 
287*07624df1SBryan Whitehead 	if (positive)
288*07624df1SBryan Whitehead 		lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
289*07624df1SBryan Whitehead 
290*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ,
291*07624df1SBryan Whitehead 			  lan743x_rate_adj);
292*07624df1SBryan Whitehead 
293*07624df1SBryan Whitehead 	return 0;
294*07624df1SBryan Whitehead }
295*07624df1SBryan Whitehead 
296*07624df1SBryan Whitehead static int lan743x_ptpci_adjfreq(struct ptp_clock_info *ptpci, s32 delta_ppb)
297*07624df1SBryan Whitehead {
298*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp =
299*07624df1SBryan Whitehead 		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
300*07624df1SBryan Whitehead 	struct lan743x_adapter *adapter =
301*07624df1SBryan Whitehead 		container_of(ptp, struct lan743x_adapter, ptp);
302*07624df1SBryan Whitehead 	u32 lan743x_rate_adj = 0;
303*07624df1SBryan Whitehead 	bool positive = true;
304*07624df1SBryan Whitehead 	u32 u32_delta = 0;
305*07624df1SBryan Whitehead 	u64 u64_delta = 0;
306*07624df1SBryan Whitehead 
307*07624df1SBryan Whitehead 	if ((delta_ppb < (-LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB)) ||
308*07624df1SBryan Whitehead 	    delta_ppb > LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB) {
309*07624df1SBryan Whitehead 		return -EINVAL;
310*07624df1SBryan Whitehead 	}
311*07624df1SBryan Whitehead 	if (delta_ppb > 0) {
312*07624df1SBryan Whitehead 		u32_delta = (u32)delta_ppb;
313*07624df1SBryan Whitehead 		positive = true;
314*07624df1SBryan Whitehead 	} else {
315*07624df1SBryan Whitehead 		u32_delta = (u32)(-delta_ppb);
316*07624df1SBryan Whitehead 		positive = false;
317*07624df1SBryan Whitehead 	}
318*07624df1SBryan Whitehead 	u64_delta = (((u64)u32_delta) << 35);
319*07624df1SBryan Whitehead 	lan743x_rate_adj = div_u64(u64_delta, 1000000000);
320*07624df1SBryan Whitehead 
321*07624df1SBryan Whitehead 	if (positive)
322*07624df1SBryan Whitehead 		lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
323*07624df1SBryan Whitehead 
324*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ,
325*07624df1SBryan Whitehead 			  lan743x_rate_adj);
326*07624df1SBryan Whitehead 
327*07624df1SBryan Whitehead 	return 0;
328*07624df1SBryan Whitehead }
329*07624df1SBryan Whitehead 
330*07624df1SBryan Whitehead static int lan743x_ptpci_adjtime(struct ptp_clock_info *ptpci, s64 delta)
331*07624df1SBryan Whitehead {
332*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp =
333*07624df1SBryan Whitehead 		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
334*07624df1SBryan Whitehead 	struct lan743x_adapter *adapter =
335*07624df1SBryan Whitehead 		container_of(ptp, struct lan743x_adapter, ptp);
336*07624df1SBryan Whitehead 
337*07624df1SBryan Whitehead 	lan743x_ptp_clock_step(adapter, delta);
338*07624df1SBryan Whitehead 
339*07624df1SBryan Whitehead 	return 0;
340*07624df1SBryan Whitehead }
341*07624df1SBryan Whitehead 
342*07624df1SBryan Whitehead static int lan743x_ptpci_gettime64(struct ptp_clock_info *ptpci,
343*07624df1SBryan Whitehead 				   struct timespec64 *ts)
344*07624df1SBryan Whitehead {
345*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp =
346*07624df1SBryan Whitehead 		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
347*07624df1SBryan Whitehead 	struct lan743x_adapter *adapter =
348*07624df1SBryan Whitehead 		container_of(ptp, struct lan743x_adapter, ptp);
349*07624df1SBryan Whitehead 	u32 nano_seconds = 0;
350*07624df1SBryan Whitehead 	u32 seconds = 0;
351*07624df1SBryan Whitehead 
352*07624df1SBryan Whitehead 	lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL);
353*07624df1SBryan Whitehead 	ts->tv_sec = seconds;
354*07624df1SBryan Whitehead 	ts->tv_nsec = nano_seconds;
355*07624df1SBryan Whitehead 
356*07624df1SBryan Whitehead 	return 0;
357*07624df1SBryan Whitehead }
358*07624df1SBryan Whitehead 
359*07624df1SBryan Whitehead static int lan743x_ptpci_settime64(struct ptp_clock_info *ptpci,
360*07624df1SBryan Whitehead 				   const struct timespec64 *ts)
361*07624df1SBryan Whitehead {
362*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp =
363*07624df1SBryan Whitehead 		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
364*07624df1SBryan Whitehead 	struct lan743x_adapter *adapter =
365*07624df1SBryan Whitehead 		container_of(ptp, struct lan743x_adapter, ptp);
366*07624df1SBryan Whitehead 	u32 nano_seconds = 0;
367*07624df1SBryan Whitehead 	u32 seconds = 0;
368*07624df1SBryan Whitehead 
369*07624df1SBryan Whitehead 	if (ts) {
370*07624df1SBryan Whitehead 		if (ts->tv_sec > 0xFFFFFFFFLL ||
371*07624df1SBryan Whitehead 		    ts->tv_sec < 0) {
372*07624df1SBryan Whitehead 			netif_warn(adapter, drv, adapter->netdev,
373*07624df1SBryan Whitehead 				   "ts->tv_sec out of range, %lld\n",
374*07624df1SBryan Whitehead 				   ts->tv_sec);
375*07624df1SBryan Whitehead 			return -ERANGE;
376*07624df1SBryan Whitehead 		}
377*07624df1SBryan Whitehead 		if (ts->tv_nsec >= 1000000000L ||
378*07624df1SBryan Whitehead 		    ts->tv_nsec < 0) {
379*07624df1SBryan Whitehead 			netif_warn(adapter, drv, adapter->netdev,
380*07624df1SBryan Whitehead 				   "ts->tv_nsec out of range, %ld\n",
381*07624df1SBryan Whitehead 				   ts->tv_nsec);
382*07624df1SBryan Whitehead 			return -ERANGE;
383*07624df1SBryan Whitehead 		}
384*07624df1SBryan Whitehead 		seconds = ts->tv_sec;
385*07624df1SBryan Whitehead 		nano_seconds = ts->tv_nsec;
386*07624df1SBryan Whitehead 		lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0);
387*07624df1SBryan Whitehead 	} else {
388*07624df1SBryan Whitehead 		netif_warn(adapter, drv, adapter->netdev, "ts == NULL\n");
389*07624df1SBryan Whitehead 		return -EINVAL;
390*07624df1SBryan Whitehead 	}
391*07624df1SBryan Whitehead 
392*07624df1SBryan Whitehead 	return 0;
393*07624df1SBryan Whitehead }
394*07624df1SBryan Whitehead 
395*07624df1SBryan Whitehead static void lan743x_ptp_perout_off(struct lan743x_adapter *adapter)
396*07624df1SBryan Whitehead {
397*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
398*07624df1SBryan Whitehead 	u32 general_config = 0;
399*07624df1SBryan Whitehead 
400*07624df1SBryan Whitehead 	if (ptp->perout_gpio_bit >= 0) {
401*07624df1SBryan Whitehead 		lan743x_gpio_release(adapter, ptp->perout_gpio_bit);
402*07624df1SBryan Whitehead 		ptp->perout_gpio_bit = -1;
403*07624df1SBryan Whitehead 	}
404*07624df1SBryan Whitehead 
405*07624df1SBryan Whitehead 	if (ptp->perout_event_ch >= 0) {
406*07624df1SBryan Whitehead 		/* set target to far in the future, effectively disabling it */
407*07624df1SBryan Whitehead 		lan743x_csr_write(adapter,
408*07624df1SBryan Whitehead 				  PTP_CLOCK_TARGET_SEC_X(ptp->perout_event_ch),
409*07624df1SBryan Whitehead 				  0xFFFF0000);
410*07624df1SBryan Whitehead 		lan743x_csr_write(adapter,
411*07624df1SBryan Whitehead 				  PTP_CLOCK_TARGET_NS_X(ptp->perout_event_ch),
412*07624df1SBryan Whitehead 				  0);
413*07624df1SBryan Whitehead 
414*07624df1SBryan Whitehead 		general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG);
415*07624df1SBryan Whitehead 		general_config |= PTP_GENERAL_CONFIG_RELOAD_ADD_X_
416*07624df1SBryan Whitehead 				  (ptp->perout_event_ch);
417*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config);
418*07624df1SBryan Whitehead 		lan743x_ptp_release_event_ch(adapter, ptp->perout_event_ch);
419*07624df1SBryan Whitehead 		ptp->perout_event_ch = -1;
420*07624df1SBryan Whitehead 	}
421*07624df1SBryan Whitehead }
422*07624df1SBryan Whitehead 
423*07624df1SBryan Whitehead static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on,
424*07624df1SBryan Whitehead 			      struct ptp_perout_request *perout)
425*07624df1SBryan Whitehead {
426*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
427*07624df1SBryan Whitehead 	u32 period_sec = 0, period_nsec = 0;
428*07624df1SBryan Whitehead 	u32 start_sec = 0, start_nsec = 0;
429*07624df1SBryan Whitehead 	u32 general_config = 0;
430*07624df1SBryan Whitehead 	int pulse_width = 0;
431*07624df1SBryan Whitehead 	int perout_bit = 0;
432*07624df1SBryan Whitehead 
433*07624df1SBryan Whitehead 	if (!on) {
434*07624df1SBryan Whitehead 		lan743x_ptp_perout_off(adapter);
435*07624df1SBryan Whitehead 		return 0;
436*07624df1SBryan Whitehead 	}
437*07624df1SBryan Whitehead 
438*07624df1SBryan Whitehead 	if (ptp->perout_event_ch >= 0 ||
439*07624df1SBryan Whitehead 	    ptp->perout_gpio_bit >= 0) {
440*07624df1SBryan Whitehead 		/* already on, turn off first */
441*07624df1SBryan Whitehead 		lan743x_ptp_perout_off(adapter);
442*07624df1SBryan Whitehead 	}
443*07624df1SBryan Whitehead 
444*07624df1SBryan Whitehead 	ptp->perout_event_ch = lan743x_ptp_reserve_event_ch(adapter);
445*07624df1SBryan Whitehead 	if (ptp->perout_event_ch < 0) {
446*07624df1SBryan Whitehead 		netif_warn(adapter, drv, adapter->netdev,
447*07624df1SBryan Whitehead 			   "Failed to reserve event channel for PEROUT\n");
448*07624df1SBryan Whitehead 		goto failed;
449*07624df1SBryan Whitehead 	}
450*07624df1SBryan Whitehead 
451*07624df1SBryan Whitehead 	switch (adapter->csr.id_rev & ID_REV_ID_MASK_) {
452*07624df1SBryan Whitehead 	case ID_REV_ID_LAN7430_:
453*07624df1SBryan Whitehead 		perout_bit = 2;/* GPIO 2 is preferred on EVB LAN7430 */
454*07624df1SBryan Whitehead 		break;
455*07624df1SBryan Whitehead 	case ID_REV_ID_LAN7431_:
456*07624df1SBryan Whitehead 		perout_bit = 4;/* GPIO 4 is preferred on EVB LAN7431 */
457*07624df1SBryan Whitehead 		break;
458*07624df1SBryan Whitehead 	}
459*07624df1SBryan Whitehead 
460*07624df1SBryan Whitehead 	ptp->perout_gpio_bit = lan743x_gpio_rsrv_ptp_out(adapter,
461*07624df1SBryan Whitehead 							 perout_bit,
462*07624df1SBryan Whitehead 							 ptp->perout_event_ch);
463*07624df1SBryan Whitehead 
464*07624df1SBryan Whitehead 	if (ptp->perout_gpio_bit < 0) {
465*07624df1SBryan Whitehead 		netif_warn(adapter, drv, adapter->netdev,
466*07624df1SBryan Whitehead 			   "Failed to reserve gpio %d for PEROUT\n",
467*07624df1SBryan Whitehead 			   perout_bit);
468*07624df1SBryan Whitehead 		goto failed;
469*07624df1SBryan Whitehead 	}
470*07624df1SBryan Whitehead 
471*07624df1SBryan Whitehead 	start_sec = perout->start.sec;
472*07624df1SBryan Whitehead 	start_sec += perout->start.nsec / 1000000000;
473*07624df1SBryan Whitehead 	start_nsec = perout->start.nsec % 1000000000;
474*07624df1SBryan Whitehead 
475*07624df1SBryan Whitehead 	period_sec = perout->period.sec;
476*07624df1SBryan Whitehead 	period_sec += perout->period.nsec / 1000000000;
477*07624df1SBryan Whitehead 	period_nsec = perout->period.nsec % 1000000000;
478*07624df1SBryan Whitehead 
479*07624df1SBryan Whitehead 	if (period_sec == 0) {
480*07624df1SBryan Whitehead 		if (period_nsec >= 400000000) {
481*07624df1SBryan Whitehead 			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_;
482*07624df1SBryan Whitehead 		} else if (period_nsec >= 20000000) {
483*07624df1SBryan Whitehead 			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_;
484*07624df1SBryan Whitehead 		} else if (period_nsec >= 2000000) {
485*07624df1SBryan Whitehead 			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_;
486*07624df1SBryan Whitehead 		} else if (period_nsec >= 200000) {
487*07624df1SBryan Whitehead 			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_;
488*07624df1SBryan Whitehead 		} else if (period_nsec >= 20000) {
489*07624df1SBryan Whitehead 			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_;
490*07624df1SBryan Whitehead 		} else if (period_nsec >= 200) {
491*07624df1SBryan Whitehead 			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_;
492*07624df1SBryan Whitehead 		} else {
493*07624df1SBryan Whitehead 			netif_warn(adapter, drv, adapter->netdev,
494*07624df1SBryan Whitehead 				   "perout period too small, minimum is 200nS\n");
495*07624df1SBryan Whitehead 			goto failed;
496*07624df1SBryan Whitehead 		}
497*07624df1SBryan Whitehead 	} else {
498*07624df1SBryan Whitehead 		pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_;
499*07624df1SBryan Whitehead 	}
500*07624df1SBryan Whitehead 
501*07624df1SBryan Whitehead 	/* turn off by setting target far in future */
502*07624df1SBryan Whitehead 	lan743x_csr_write(adapter,
503*07624df1SBryan Whitehead 			  PTP_CLOCK_TARGET_SEC_X(ptp->perout_event_ch),
504*07624df1SBryan Whitehead 			  0xFFFF0000);
505*07624df1SBryan Whitehead 	lan743x_csr_write(adapter,
506*07624df1SBryan Whitehead 			  PTP_CLOCK_TARGET_NS_X(ptp->perout_event_ch), 0);
507*07624df1SBryan Whitehead 
508*07624df1SBryan Whitehead 	/* Configure to pulse every period */
509*07624df1SBryan Whitehead 	general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG);
510*07624df1SBryan Whitehead 	general_config &= ~(PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_
511*07624df1SBryan Whitehead 			  (ptp->perout_event_ch));
512*07624df1SBryan Whitehead 	general_config |= PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_
513*07624df1SBryan Whitehead 			  (ptp->perout_event_ch, pulse_width);
514*07624df1SBryan Whitehead 	general_config &= ~PTP_GENERAL_CONFIG_RELOAD_ADD_X_
515*07624df1SBryan Whitehead 			  (ptp->perout_event_ch);
516*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config);
517*07624df1SBryan Whitehead 
518*07624df1SBryan Whitehead 	/* set the reload to one toggle cycle */
519*07624df1SBryan Whitehead 	lan743x_csr_write(adapter,
520*07624df1SBryan Whitehead 			  PTP_CLOCK_TARGET_RELOAD_SEC_X(ptp->perout_event_ch),
521*07624df1SBryan Whitehead 			  period_sec);
522*07624df1SBryan Whitehead 	lan743x_csr_write(adapter,
523*07624df1SBryan Whitehead 			  PTP_CLOCK_TARGET_RELOAD_NS_X(ptp->perout_event_ch),
524*07624df1SBryan Whitehead 			  period_nsec);
525*07624df1SBryan Whitehead 
526*07624df1SBryan Whitehead 	/* set the start time */
527*07624df1SBryan Whitehead 	lan743x_csr_write(adapter,
528*07624df1SBryan Whitehead 			  PTP_CLOCK_TARGET_SEC_X(ptp->perout_event_ch),
529*07624df1SBryan Whitehead 			  start_sec);
530*07624df1SBryan Whitehead 	lan743x_csr_write(adapter,
531*07624df1SBryan Whitehead 			  PTP_CLOCK_TARGET_NS_X(ptp->perout_event_ch),
532*07624df1SBryan Whitehead 			  start_nsec);
533*07624df1SBryan Whitehead 
534*07624df1SBryan Whitehead 	return 0;
535*07624df1SBryan Whitehead 
536*07624df1SBryan Whitehead failed:
537*07624df1SBryan Whitehead 	lan743x_ptp_perout_off(adapter);
538*07624df1SBryan Whitehead 	return -ENODEV;
539*07624df1SBryan Whitehead }
540*07624df1SBryan Whitehead 
541*07624df1SBryan Whitehead static int lan743x_ptpci_enable(struct ptp_clock_info *ptpci,
542*07624df1SBryan Whitehead 				struct ptp_clock_request *request, int on)
543*07624df1SBryan Whitehead {
544*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp =
545*07624df1SBryan Whitehead 		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
546*07624df1SBryan Whitehead 	struct lan743x_adapter *adapter =
547*07624df1SBryan Whitehead 		container_of(ptp, struct lan743x_adapter, ptp);
548*07624df1SBryan Whitehead 
549*07624df1SBryan Whitehead 	if (request) {
550*07624df1SBryan Whitehead 		switch (request->type) {
551*07624df1SBryan Whitehead 		case PTP_CLK_REQ_EXTTS:
552*07624df1SBryan Whitehead 			return -EINVAL;
553*07624df1SBryan Whitehead 		case PTP_CLK_REQ_PEROUT:
554*07624df1SBryan Whitehead 			if (request->perout.index == 0)
555*07624df1SBryan Whitehead 				return lan743x_ptp_perout(adapter, on,
556*07624df1SBryan Whitehead 							  &request->perout);
557*07624df1SBryan Whitehead 			return -EINVAL;
558*07624df1SBryan Whitehead 		case PTP_CLK_REQ_PPS:
559*07624df1SBryan Whitehead 			return -EINVAL;
560*07624df1SBryan Whitehead 		default:
561*07624df1SBryan Whitehead 			netif_err(adapter, drv, adapter->netdev,
562*07624df1SBryan Whitehead 				  "request->type == %d, Unknown\n",
563*07624df1SBryan Whitehead 				  request->type);
564*07624df1SBryan Whitehead 			break;
565*07624df1SBryan Whitehead 		}
566*07624df1SBryan Whitehead 	} else {
567*07624df1SBryan Whitehead 		netif_err(adapter, drv, adapter->netdev, "request == NULL\n");
568*07624df1SBryan Whitehead 	}
569*07624df1SBryan Whitehead 	return 0;
570*07624df1SBryan Whitehead }
571*07624df1SBryan Whitehead 
572*07624df1SBryan Whitehead static long lan743x_ptpci_do_aux_work(struct ptp_clock_info *ptpci)
573*07624df1SBryan Whitehead {
574*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp =
575*07624df1SBryan Whitehead 		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
576*07624df1SBryan Whitehead 	struct lan743x_adapter *adapter =
577*07624df1SBryan Whitehead 		container_of(ptp, struct lan743x_adapter, ptp);
578*07624df1SBryan Whitehead 	u32 cap_info, cause, header, nsec, seconds;
579*07624df1SBryan Whitehead 	bool new_timestamp_available = false;
580*07624df1SBryan Whitehead 	int count = 0;
581*07624df1SBryan Whitehead 
582*07624df1SBryan Whitehead 	while ((count < 100) &&
583*07624df1SBryan Whitehead 	       (lan743x_csr_read(adapter, PTP_INT_STS) & PTP_INT_BIT_TX_TS_)) {
584*07624df1SBryan Whitehead 		count++;
585*07624df1SBryan Whitehead 		cap_info = lan743x_csr_read(adapter, PTP_CAP_INFO);
586*07624df1SBryan Whitehead 
587*07624df1SBryan Whitehead 		if (PTP_CAP_INFO_TX_TS_CNT_GET_(cap_info) > 0) {
588*07624df1SBryan Whitehead 			seconds = lan743x_csr_read(adapter,
589*07624df1SBryan Whitehead 						   PTP_TX_EGRESS_SEC);
590*07624df1SBryan Whitehead 			nsec = lan743x_csr_read(adapter, PTP_TX_EGRESS_NS);
591*07624df1SBryan Whitehead 			cause = (nsec &
592*07624df1SBryan Whitehead 				 PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_);
593*07624df1SBryan Whitehead 			header = lan743x_csr_read(adapter,
594*07624df1SBryan Whitehead 						  PTP_TX_MSG_HEADER);
595*07624df1SBryan Whitehead 
596*07624df1SBryan Whitehead 			if (cause == PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_) {
597*07624df1SBryan Whitehead 				nsec &= PTP_TX_EGRESS_NS_TS_NS_MASK_;
598*07624df1SBryan Whitehead 				lan743x_ptp_tx_ts_enqueue_ts(adapter,
599*07624df1SBryan Whitehead 							     seconds, nsec,
600*07624df1SBryan Whitehead 							     header);
601*07624df1SBryan Whitehead 				new_timestamp_available = true;
602*07624df1SBryan Whitehead 			} else if (cause ==
603*07624df1SBryan Whitehead 				PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_) {
604*07624df1SBryan Whitehead 				netif_err(adapter, drv, adapter->netdev,
605*07624df1SBryan Whitehead 					  "Auto capture cause not supported\n");
606*07624df1SBryan Whitehead 			} else {
607*07624df1SBryan Whitehead 				netif_warn(adapter, drv, adapter->netdev,
608*07624df1SBryan Whitehead 					   "unknown tx timestamp capture cause\n");
609*07624df1SBryan Whitehead 			}
610*07624df1SBryan Whitehead 		} else {
611*07624df1SBryan Whitehead 			netif_warn(adapter, drv, adapter->netdev,
612*07624df1SBryan Whitehead 				   "TX TS INT but no TX TS CNT\n");
613*07624df1SBryan Whitehead 		}
614*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_INT_STS, PTP_INT_BIT_TX_TS_);
615*07624df1SBryan Whitehead 	}
616*07624df1SBryan Whitehead 
617*07624df1SBryan Whitehead 	if (new_timestamp_available)
618*07624df1SBryan Whitehead 		lan743x_ptp_tx_ts_complete(adapter);
619*07624df1SBryan Whitehead 
620*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
621*07624df1SBryan Whitehead 
622*07624df1SBryan Whitehead 	return -1;
623*07624df1SBryan Whitehead }
624*07624df1SBryan Whitehead 
625*07624df1SBryan Whitehead static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter,
626*07624df1SBryan Whitehead 				  u32 *seconds, u32 *nano_seconds,
627*07624df1SBryan Whitehead 				  u32 *sub_nano_seconds)
628*07624df1SBryan Whitehead {
629*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
630*07624df1SBryan Whitehead 
631*07624df1SBryan Whitehead 	mutex_lock(&ptp->command_lock);
632*07624df1SBryan Whitehead 
633*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_);
634*07624df1SBryan Whitehead 	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_);
635*07624df1SBryan Whitehead 
636*07624df1SBryan Whitehead 	if (seconds)
637*07624df1SBryan Whitehead 		(*seconds) = lan743x_csr_read(adapter, PTP_CLOCK_SEC);
638*07624df1SBryan Whitehead 
639*07624df1SBryan Whitehead 	if (nano_seconds)
640*07624df1SBryan Whitehead 		(*nano_seconds) = lan743x_csr_read(adapter, PTP_CLOCK_NS);
641*07624df1SBryan Whitehead 
642*07624df1SBryan Whitehead 	if (sub_nano_seconds)
643*07624df1SBryan Whitehead 		(*sub_nano_seconds) =
644*07624df1SBryan Whitehead 		lan743x_csr_read(adapter, PTP_CLOCK_SUBNS);
645*07624df1SBryan Whitehead 
646*07624df1SBryan Whitehead 	mutex_unlock(&ptp->command_lock);
647*07624df1SBryan Whitehead }
648*07624df1SBryan Whitehead 
649*07624df1SBryan Whitehead static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter,
650*07624df1SBryan Whitehead 				   s64 time_step_ns)
651*07624df1SBryan Whitehead {
652*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
653*07624df1SBryan Whitehead 	u32 nano_seconds_step = 0;
654*07624df1SBryan Whitehead 	u64 abs_time_step_ns = 0;
655*07624df1SBryan Whitehead 	u32 unsigned_seconds = 0;
656*07624df1SBryan Whitehead 	u32 nano_seconds = 0;
657*07624df1SBryan Whitehead 	u32 remainder = 0;
658*07624df1SBryan Whitehead 	s32 seconds = 0;
659*07624df1SBryan Whitehead 
660*07624df1SBryan Whitehead 	if (time_step_ns >  15000000000LL) {
661*07624df1SBryan Whitehead 		/* convert to clock set */
662*07624df1SBryan Whitehead 		lan743x_ptp_clock_get(adapter, &unsigned_seconds,
663*07624df1SBryan Whitehead 				      &nano_seconds, NULL);
664*07624df1SBryan Whitehead 		unsigned_seconds += div_u64_rem(time_step_ns, 1000000000LL,
665*07624df1SBryan Whitehead 						&remainder);
666*07624df1SBryan Whitehead 		nano_seconds += remainder;
667*07624df1SBryan Whitehead 		if (nano_seconds >= 1000000000) {
668*07624df1SBryan Whitehead 			unsigned_seconds++;
669*07624df1SBryan Whitehead 			nano_seconds -= 1000000000;
670*07624df1SBryan Whitehead 		}
671*07624df1SBryan Whitehead 		lan743x_ptp_clock_set(adapter, unsigned_seconds,
672*07624df1SBryan Whitehead 				      nano_seconds, 0);
673*07624df1SBryan Whitehead 		return;
674*07624df1SBryan Whitehead 	} else if (time_step_ns < -15000000000LL) {
675*07624df1SBryan Whitehead 		/* convert to clock set */
676*07624df1SBryan Whitehead 		time_step_ns = -time_step_ns;
677*07624df1SBryan Whitehead 
678*07624df1SBryan Whitehead 		lan743x_ptp_clock_get(adapter, &unsigned_seconds,
679*07624df1SBryan Whitehead 				      &nano_seconds, NULL);
680*07624df1SBryan Whitehead 		unsigned_seconds -= div_u64_rem(time_step_ns, 1000000000LL,
681*07624df1SBryan Whitehead 						&remainder);
682*07624df1SBryan Whitehead 		nano_seconds_step = remainder;
683*07624df1SBryan Whitehead 		if (nano_seconds < nano_seconds_step) {
684*07624df1SBryan Whitehead 			unsigned_seconds--;
685*07624df1SBryan Whitehead 			nano_seconds += 1000000000;
686*07624df1SBryan Whitehead 		}
687*07624df1SBryan Whitehead 		nano_seconds -= nano_seconds_step;
688*07624df1SBryan Whitehead 		lan743x_ptp_clock_set(adapter, unsigned_seconds,
689*07624df1SBryan Whitehead 				      nano_seconds, 0);
690*07624df1SBryan Whitehead 		return;
691*07624df1SBryan Whitehead 	}
692*07624df1SBryan Whitehead 
693*07624df1SBryan Whitehead 	/* do clock step */
694*07624df1SBryan Whitehead 	if (time_step_ns >= 0) {
695*07624df1SBryan Whitehead 		abs_time_step_ns = (u64)(time_step_ns);
696*07624df1SBryan Whitehead 		seconds = (s32)div_u64_rem(abs_time_step_ns, 1000000000,
697*07624df1SBryan Whitehead 					   &remainder);
698*07624df1SBryan Whitehead 		nano_seconds = (u32)remainder;
699*07624df1SBryan Whitehead 	} else {
700*07624df1SBryan Whitehead 		abs_time_step_ns = (u64)(-time_step_ns);
701*07624df1SBryan Whitehead 		seconds = -((s32)div_u64_rem(abs_time_step_ns, 1000000000,
702*07624df1SBryan Whitehead 					     &remainder));
703*07624df1SBryan Whitehead 		nano_seconds = (u32)remainder;
704*07624df1SBryan Whitehead 		if (nano_seconds > 0) {
705*07624df1SBryan Whitehead 			/* subtracting nano seconds is not allowed
706*07624df1SBryan Whitehead 			 * convert to subtracting from seconds,
707*07624df1SBryan Whitehead 			 * and adding to nanoseconds
708*07624df1SBryan Whitehead 			 */
709*07624df1SBryan Whitehead 			seconds--;
710*07624df1SBryan Whitehead 			nano_seconds = (1000000000 - nano_seconds);
711*07624df1SBryan Whitehead 		}
712*07624df1SBryan Whitehead 	}
713*07624df1SBryan Whitehead 
714*07624df1SBryan Whitehead 	if (nano_seconds > 0) {
715*07624df1SBryan Whitehead 		/* add 8 ns to cover the likely normal increment */
716*07624df1SBryan Whitehead 		nano_seconds += 8;
717*07624df1SBryan Whitehead 	}
718*07624df1SBryan Whitehead 
719*07624df1SBryan Whitehead 	if (nano_seconds >= 1000000000) {
720*07624df1SBryan Whitehead 		/* carry into seconds */
721*07624df1SBryan Whitehead 		seconds++;
722*07624df1SBryan Whitehead 		nano_seconds -= 1000000000;
723*07624df1SBryan Whitehead 	}
724*07624df1SBryan Whitehead 
725*07624df1SBryan Whitehead 	while (seconds) {
726*07624df1SBryan Whitehead 		mutex_lock(&ptp->command_lock);
727*07624df1SBryan Whitehead 		if (seconds > 0) {
728*07624df1SBryan Whitehead 			u32 adjustment_value = (u32)seconds;
729*07624df1SBryan Whitehead 
730*07624df1SBryan Whitehead 			if (adjustment_value > 0xF)
731*07624df1SBryan Whitehead 				adjustment_value = 0xF;
732*07624df1SBryan Whitehead 			lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
733*07624df1SBryan Whitehead 					  PTP_CLOCK_STEP_ADJ_DIR_ |
734*07624df1SBryan Whitehead 					  adjustment_value);
735*07624df1SBryan Whitehead 			seconds -= ((s32)adjustment_value);
736*07624df1SBryan Whitehead 		} else {
737*07624df1SBryan Whitehead 			u32 adjustment_value = (u32)(-seconds);
738*07624df1SBryan Whitehead 
739*07624df1SBryan Whitehead 			if (adjustment_value > 0xF)
740*07624df1SBryan Whitehead 				adjustment_value = 0xF;
741*07624df1SBryan Whitehead 			lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
742*07624df1SBryan Whitehead 					  adjustment_value);
743*07624df1SBryan Whitehead 			seconds += ((s32)adjustment_value);
744*07624df1SBryan Whitehead 		}
745*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_CMD_CTL,
746*07624df1SBryan Whitehead 				  PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_);
747*07624df1SBryan Whitehead 		lan743x_ptp_wait_till_cmd_done(adapter,
748*07624df1SBryan Whitehead 					       PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_);
749*07624df1SBryan Whitehead 		mutex_unlock(&ptp->command_lock);
750*07624df1SBryan Whitehead 	}
751*07624df1SBryan Whitehead 	if (nano_seconds) {
752*07624df1SBryan Whitehead 		mutex_lock(&ptp->command_lock);
753*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
754*07624df1SBryan Whitehead 				  PTP_CLOCK_STEP_ADJ_DIR_ |
755*07624df1SBryan Whitehead 				  (nano_seconds &
756*07624df1SBryan Whitehead 				  PTP_CLOCK_STEP_ADJ_VALUE_MASK_));
757*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_CMD_CTL,
758*07624df1SBryan Whitehead 				  PTP_CMD_CTL_PTP_CLK_STP_NSEC_);
759*07624df1SBryan Whitehead 		lan743x_ptp_wait_till_cmd_done(adapter,
760*07624df1SBryan Whitehead 					       PTP_CMD_CTL_PTP_CLK_STP_NSEC_);
761*07624df1SBryan Whitehead 		mutex_unlock(&ptp->command_lock);
762*07624df1SBryan Whitehead 	}
763*07624df1SBryan Whitehead }
764*07624df1SBryan Whitehead #endif /* CONFIG_PTP_1588_CLOCK */
765*07624df1SBryan Whitehead 
766*07624df1SBryan Whitehead void lan743x_ptp_isr(void *context)
767*07624df1SBryan Whitehead {
768*07624df1SBryan Whitehead 	struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
769*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = NULL;
770*07624df1SBryan Whitehead 	int enable_flag = 1;
771*07624df1SBryan Whitehead 	u32 ptp_int_sts = 0;
772*07624df1SBryan Whitehead 
773*07624df1SBryan Whitehead 	ptp = &adapter->ptp;
774*07624df1SBryan Whitehead 
775*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_);
776*07624df1SBryan Whitehead 
777*07624df1SBryan Whitehead 	ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS);
778*07624df1SBryan Whitehead 	ptp_int_sts &= lan743x_csr_read(adapter, PTP_INT_EN_SET);
779*07624df1SBryan Whitehead 
780*07624df1SBryan Whitehead 	if (ptp_int_sts & PTP_INT_BIT_TX_TS_) {
781*07624df1SBryan Whitehead 		ptp_schedule_worker(ptp->ptp_clock, 0);
782*07624df1SBryan Whitehead 		enable_flag = 0;/* tasklet will re-enable later */
783*07624df1SBryan Whitehead 	}
784*07624df1SBryan Whitehead 	if (ptp_int_sts & PTP_INT_BIT_TX_SWTS_ERR_) {
785*07624df1SBryan Whitehead 		netif_err(adapter, drv, adapter->netdev,
786*07624df1SBryan Whitehead 			  "PTP TX Software Timestamp Error\n");
787*07624df1SBryan Whitehead 		/* clear int status bit */
788*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_INT_STS,
789*07624df1SBryan Whitehead 				  PTP_INT_BIT_TX_SWTS_ERR_);
790*07624df1SBryan Whitehead 	}
791*07624df1SBryan Whitehead 	if (ptp_int_sts & PTP_INT_BIT_TIMER_B_) {
792*07624df1SBryan Whitehead 		/* clear int status bit */
793*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_INT_STS,
794*07624df1SBryan Whitehead 				  PTP_INT_BIT_TIMER_B_);
795*07624df1SBryan Whitehead 	}
796*07624df1SBryan Whitehead 	if (ptp_int_sts & PTP_INT_BIT_TIMER_A_) {
797*07624df1SBryan Whitehead 		/* clear int status bit */
798*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_INT_STS,
799*07624df1SBryan Whitehead 				  PTP_INT_BIT_TIMER_A_);
800*07624df1SBryan Whitehead 	}
801*07624df1SBryan Whitehead 
802*07624df1SBryan Whitehead 	if (enable_flag) {
803*07624df1SBryan Whitehead 		/* re-enable isr */
804*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
805*07624df1SBryan Whitehead 	}
806*07624df1SBryan Whitehead }
807*07624df1SBryan Whitehead 
808*07624df1SBryan Whitehead static void lan743x_ptp_tx_ts_enqueue_skb(struct lan743x_adapter *adapter,
809*07624df1SBryan Whitehead 					  struct sk_buff *skb, bool ignore_sync)
810*07624df1SBryan Whitehead {
811*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
812*07624df1SBryan Whitehead 
813*07624df1SBryan Whitehead 	spin_lock_bh(&ptp->tx_ts_lock);
814*07624df1SBryan Whitehead 	if (ptp->tx_ts_skb_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
815*07624df1SBryan Whitehead 		ptp->tx_ts_skb_queue[ptp->tx_ts_skb_queue_size] = skb;
816*07624df1SBryan Whitehead 		if (ignore_sync)
817*07624df1SBryan Whitehead 			ptp->tx_ts_ignore_sync_queue |=
818*07624df1SBryan Whitehead 				BIT(ptp->tx_ts_skb_queue_size);
819*07624df1SBryan Whitehead 		ptp->tx_ts_skb_queue_size++;
820*07624df1SBryan Whitehead 	} else {
821*07624df1SBryan Whitehead 		/* this should never happen, so long as the tx channel
822*07624df1SBryan Whitehead 		 * calls and honors the result from
823*07624df1SBryan Whitehead 		 * lan743x_ptp_request_tx_timestamp
824*07624df1SBryan Whitehead 		 */
825*07624df1SBryan Whitehead 		netif_err(adapter, drv, adapter->netdev,
826*07624df1SBryan Whitehead 			  "tx ts skb queue overflow\n");
827*07624df1SBryan Whitehead 		dev_kfree_skb(skb);
828*07624df1SBryan Whitehead 	}
829*07624df1SBryan Whitehead 	spin_unlock_bh(&ptp->tx_ts_lock);
830*07624df1SBryan Whitehead }
831*07624df1SBryan Whitehead 
832*07624df1SBryan Whitehead static void lan743x_ptp_sync_to_system_clock(struct lan743x_adapter *adapter)
833*07624df1SBryan Whitehead {
834*07624df1SBryan Whitehead 	struct timespec64 ts;
835*07624df1SBryan Whitehead 
836*07624df1SBryan Whitehead 	memset(&ts, 0, sizeof(ts));
837*07624df1SBryan Whitehead 	timekeeping_clocktai64(&ts);
838*07624df1SBryan Whitehead 
839*07624df1SBryan Whitehead 	lan743x_ptp_clock_set(adapter, ts.tv_sec, ts.tv_nsec, 0);
840*07624df1SBryan Whitehead }
841*07624df1SBryan Whitehead 
842*07624df1SBryan Whitehead void lan743x_ptp_update_latency(struct lan743x_adapter *adapter,
843*07624df1SBryan Whitehead 				u32 link_speed)
844*07624df1SBryan Whitehead {
845*07624df1SBryan Whitehead 	switch (link_speed) {
846*07624df1SBryan Whitehead 	case 10:
847*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_LATENCY,
848*07624df1SBryan Whitehead 				  PTP_LATENCY_TX_SET_(0) |
849*07624df1SBryan Whitehead 				  PTP_LATENCY_RX_SET_(0));
850*07624df1SBryan Whitehead 		break;
851*07624df1SBryan Whitehead 	case 100:
852*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_LATENCY,
853*07624df1SBryan Whitehead 				  PTP_LATENCY_TX_SET_(181) |
854*07624df1SBryan Whitehead 				  PTP_LATENCY_RX_SET_(594));
855*07624df1SBryan Whitehead 		break;
856*07624df1SBryan Whitehead 	case 1000:
857*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_LATENCY,
858*07624df1SBryan Whitehead 				  PTP_LATENCY_TX_SET_(30) |
859*07624df1SBryan Whitehead 				  PTP_LATENCY_RX_SET_(525));
860*07624df1SBryan Whitehead 		break;
861*07624df1SBryan Whitehead 	}
862*07624df1SBryan Whitehead }
863*07624df1SBryan Whitehead 
864*07624df1SBryan Whitehead int lan743x_ptp_init(struct lan743x_adapter *adapter)
865*07624df1SBryan Whitehead {
866*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
867*07624df1SBryan Whitehead 
868*07624df1SBryan Whitehead 	mutex_init(&ptp->command_lock);
869*07624df1SBryan Whitehead 	spin_lock_init(&ptp->tx_ts_lock);
870*07624df1SBryan Whitehead 	ptp->used_event_ch = 0;
871*07624df1SBryan Whitehead 	ptp->perout_event_ch = -1;
872*07624df1SBryan Whitehead 	ptp->perout_gpio_bit = -1;
873*07624df1SBryan Whitehead 	return 0;
874*07624df1SBryan Whitehead }
875*07624df1SBryan Whitehead 
876*07624df1SBryan Whitehead int lan743x_ptp_open(struct lan743x_adapter *adapter)
877*07624df1SBryan Whitehead {
878*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
879*07624df1SBryan Whitehead 	int ret = -ENODEV;
880*07624df1SBryan Whitehead 	u32 temp;
881*07624df1SBryan Whitehead 
882*07624df1SBryan Whitehead 	lan743x_ptp_reset(adapter);
883*07624df1SBryan Whitehead 	lan743x_ptp_sync_to_system_clock(adapter);
884*07624df1SBryan Whitehead 	temp = lan743x_csr_read(adapter, PTP_TX_MOD2);
885*07624df1SBryan Whitehead 	temp |= PTP_TX_MOD2_TX_PTP_CLR_UDPV4_CHKSUM_;
886*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_TX_MOD2, temp);
887*07624df1SBryan Whitehead 	lan743x_ptp_enable(adapter);
888*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
889*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_INT_EN_SET,
890*07624df1SBryan Whitehead 			  PTP_INT_BIT_TX_SWTS_ERR_ | PTP_INT_BIT_TX_TS_);
891*07624df1SBryan Whitehead 	ptp->flags |= PTP_FLAG_ISR_ENABLED;
892*07624df1SBryan Whitehead 
893*07624df1SBryan Whitehead #ifdef CONFIG_PTP_1588_CLOCK
894*07624df1SBryan Whitehead 	snprintf(ptp->pin_config[0].name, 32, "lan743x_ptp_pin_0");
895*07624df1SBryan Whitehead 	ptp->pin_config[0].index = 0;
896*07624df1SBryan Whitehead 	ptp->pin_config[0].func = PTP_PF_PEROUT;
897*07624df1SBryan Whitehead 	ptp->pin_config[0].chan = 0;
898*07624df1SBryan Whitehead 
899*07624df1SBryan Whitehead 	ptp->ptp_clock_info.owner = THIS_MODULE;
900*07624df1SBryan Whitehead 	snprintf(ptp->ptp_clock_info.name, 16, "%pm",
901*07624df1SBryan Whitehead 		 adapter->netdev->dev_addr);
902*07624df1SBryan Whitehead 	ptp->ptp_clock_info.max_adj = LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB;
903*07624df1SBryan Whitehead 	ptp->ptp_clock_info.n_alarm = 0;
904*07624df1SBryan Whitehead 	ptp->ptp_clock_info.n_ext_ts = 0;
905*07624df1SBryan Whitehead 	ptp->ptp_clock_info.n_per_out = 1;
906*07624df1SBryan Whitehead 	ptp->ptp_clock_info.n_pins = 0;
907*07624df1SBryan Whitehead 	ptp->ptp_clock_info.pps = 0;
908*07624df1SBryan Whitehead 	ptp->ptp_clock_info.pin_config = NULL;
909*07624df1SBryan Whitehead 	ptp->ptp_clock_info.adjfine = lan743x_ptpci_adjfine;
910*07624df1SBryan Whitehead 	ptp->ptp_clock_info.adjfreq = lan743x_ptpci_adjfreq;
911*07624df1SBryan Whitehead 	ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime;
912*07624df1SBryan Whitehead 	ptp->ptp_clock_info.gettime64 = lan743x_ptpci_gettime64;
913*07624df1SBryan Whitehead 	ptp->ptp_clock_info.getcrosststamp = NULL;
914*07624df1SBryan Whitehead 	ptp->ptp_clock_info.settime64 = lan743x_ptpci_settime64;
915*07624df1SBryan Whitehead 	ptp->ptp_clock_info.enable = lan743x_ptpci_enable;
916*07624df1SBryan Whitehead 	ptp->ptp_clock_info.do_aux_work = lan743x_ptpci_do_aux_work;
917*07624df1SBryan Whitehead 	ptp->ptp_clock_info.verify = NULL;
918*07624df1SBryan Whitehead 
919*07624df1SBryan Whitehead 	ptp->ptp_clock = ptp_clock_register(&ptp->ptp_clock_info,
920*07624df1SBryan Whitehead 					    &adapter->pdev->dev);
921*07624df1SBryan Whitehead 
922*07624df1SBryan Whitehead 	if (IS_ERR(ptp->ptp_clock)) {
923*07624df1SBryan Whitehead 		netif_err(adapter, ifup, adapter->netdev,
924*07624df1SBryan Whitehead 			  "ptp_clock_register failed\n");
925*07624df1SBryan Whitehead 		goto done;
926*07624df1SBryan Whitehead 	}
927*07624df1SBryan Whitehead 	ptp->flags |= PTP_FLAG_PTP_CLOCK_REGISTERED;
928*07624df1SBryan Whitehead 	netif_info(adapter, ifup, adapter->netdev,
929*07624df1SBryan Whitehead 		   "successfully registered ptp clock\n");
930*07624df1SBryan Whitehead 
931*07624df1SBryan Whitehead 	return 0;
932*07624df1SBryan Whitehead done:
933*07624df1SBryan Whitehead 	lan743x_ptp_close(adapter);
934*07624df1SBryan Whitehead 	return ret;
935*07624df1SBryan Whitehead #else
936*07624df1SBryan Whitehead 	return 0;
937*07624df1SBryan Whitehead #endif
938*07624df1SBryan Whitehead }
939*07624df1SBryan Whitehead 
940*07624df1SBryan Whitehead void lan743x_ptp_close(struct lan743x_adapter *adapter)
941*07624df1SBryan Whitehead {
942*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
943*07624df1SBryan Whitehead 	int index;
944*07624df1SBryan Whitehead 
945*07624df1SBryan Whitehead #ifdef CONFIG_PTP_1588_CLOCK
946*07624df1SBryan Whitehead 	if (ptp->flags & PTP_FLAG_PTP_CLOCK_REGISTERED) {
947*07624df1SBryan Whitehead 		ptp_clock_unregister(ptp->ptp_clock);
948*07624df1SBryan Whitehead 		ptp->ptp_clock = NULL;
949*07624df1SBryan Whitehead 		ptp->flags &= ~PTP_FLAG_PTP_CLOCK_REGISTERED;
950*07624df1SBryan Whitehead 		netif_info(adapter, drv, adapter->netdev,
951*07624df1SBryan Whitehead 			   "ptp clock unregister\n");
952*07624df1SBryan Whitehead 	}
953*07624df1SBryan Whitehead #endif
954*07624df1SBryan Whitehead 
955*07624df1SBryan Whitehead 	if (ptp->flags & PTP_FLAG_ISR_ENABLED) {
956*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, PTP_INT_EN_CLR,
957*07624df1SBryan Whitehead 				  PTP_INT_BIT_TX_SWTS_ERR_ |
958*07624df1SBryan Whitehead 				  PTP_INT_BIT_TX_TS_);
959*07624df1SBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_);
960*07624df1SBryan Whitehead 		ptp->flags &= ~PTP_FLAG_ISR_ENABLED;
961*07624df1SBryan Whitehead 	}
962*07624df1SBryan Whitehead 
963*07624df1SBryan Whitehead 	/* clean up pending timestamp requests */
964*07624df1SBryan Whitehead 	lan743x_ptp_tx_ts_complete(adapter);
965*07624df1SBryan Whitehead 	spin_lock_bh(&ptp->tx_ts_lock);
966*07624df1SBryan Whitehead 	for (index = 0;
967*07624df1SBryan Whitehead 		index < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS;
968*07624df1SBryan Whitehead 		index++) {
969*07624df1SBryan Whitehead 		struct sk_buff *skb = ptp->tx_ts_skb_queue[index];
970*07624df1SBryan Whitehead 
971*07624df1SBryan Whitehead 		if (skb)
972*07624df1SBryan Whitehead 			dev_kfree_skb(skb);
973*07624df1SBryan Whitehead 		ptp->tx_ts_skb_queue[index] = NULL;
974*07624df1SBryan Whitehead 		ptp->tx_ts_seconds_queue[index] = 0;
975*07624df1SBryan Whitehead 		ptp->tx_ts_nseconds_queue[index] = 0;
976*07624df1SBryan Whitehead 	}
977*07624df1SBryan Whitehead 	ptp->tx_ts_skb_queue_size = 0;
978*07624df1SBryan Whitehead 	ptp->tx_ts_queue_size = 0;
979*07624df1SBryan Whitehead 	ptp->pending_tx_timestamps = 0;
980*07624df1SBryan Whitehead 	spin_unlock_bh(&ptp->tx_ts_lock);
981*07624df1SBryan Whitehead 
982*07624df1SBryan Whitehead 	lan743x_ptp_disable(adapter);
983*07624df1SBryan Whitehead }
984*07624df1SBryan Whitehead 
985*07624df1SBryan Whitehead void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter,
986*07624df1SBryan Whitehead 				    bool ts_insert_enable)
987*07624df1SBryan Whitehead {
988*07624df1SBryan Whitehead 	u32 ptp_tx_mod = lan743x_csr_read(adapter, PTP_TX_MOD);
989*07624df1SBryan Whitehead 
990*07624df1SBryan Whitehead 	if (ts_insert_enable)
991*07624df1SBryan Whitehead 		ptp_tx_mod |= PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_;
992*07624df1SBryan Whitehead 	else
993*07624df1SBryan Whitehead 		ptp_tx_mod &= ~PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_;
994*07624df1SBryan Whitehead 
995*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_TX_MOD, ptp_tx_mod);
996*07624df1SBryan Whitehead }
997*07624df1SBryan Whitehead 
998*07624df1SBryan Whitehead static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter)
999*07624df1SBryan Whitehead {
1000*07624df1SBryan Whitehead 	if (lan743x_csr_read(adapter, PTP_CMD_CTL) & PTP_CMD_CTL_PTP_ENABLE_)
1001*07624df1SBryan Whitehead 		return true;
1002*07624df1SBryan Whitehead 	return false;
1003*07624df1SBryan Whitehead }
1004*07624df1SBryan Whitehead 
1005*07624df1SBryan Whitehead static void lan743x_ptp_enable(struct lan743x_adapter *adapter)
1006*07624df1SBryan Whitehead {
1007*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
1008*07624df1SBryan Whitehead 
1009*07624df1SBryan Whitehead 	mutex_lock(&ptp->command_lock);
1010*07624df1SBryan Whitehead 
1011*07624df1SBryan Whitehead 	if (lan743x_ptp_is_enabled(adapter)) {
1012*07624df1SBryan Whitehead 		netif_warn(adapter, drv, adapter->netdev,
1013*07624df1SBryan Whitehead 			   "PTP already enabled\n");
1014*07624df1SBryan Whitehead 		goto done;
1015*07624df1SBryan Whitehead 	}
1016*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_ENABLE_);
1017*07624df1SBryan Whitehead done:
1018*07624df1SBryan Whitehead 	mutex_unlock(&ptp->command_lock);
1019*07624df1SBryan Whitehead }
1020*07624df1SBryan Whitehead 
1021*07624df1SBryan Whitehead static void lan743x_ptp_disable(struct lan743x_adapter *adapter)
1022*07624df1SBryan Whitehead {
1023*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
1024*07624df1SBryan Whitehead 
1025*07624df1SBryan Whitehead 	mutex_lock(&ptp->command_lock);
1026*07624df1SBryan Whitehead 	if (!lan743x_ptp_is_enabled(adapter)) {
1027*07624df1SBryan Whitehead 		netif_warn(adapter, drv, adapter->netdev,
1028*07624df1SBryan Whitehead 			   "PTP already disabled\n");
1029*07624df1SBryan Whitehead 		goto done;
1030*07624df1SBryan Whitehead 	}
1031*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_DISABLE_);
1032*07624df1SBryan Whitehead 	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_ENABLE_);
1033*07624df1SBryan Whitehead done:
1034*07624df1SBryan Whitehead 	mutex_unlock(&ptp->command_lock);
1035*07624df1SBryan Whitehead }
1036*07624df1SBryan Whitehead 
1037*07624df1SBryan Whitehead static void lan743x_ptp_reset(struct lan743x_adapter *adapter)
1038*07624df1SBryan Whitehead {
1039*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
1040*07624df1SBryan Whitehead 
1041*07624df1SBryan Whitehead 	mutex_lock(&ptp->command_lock);
1042*07624df1SBryan Whitehead 
1043*07624df1SBryan Whitehead 	if (lan743x_ptp_is_enabled(adapter)) {
1044*07624df1SBryan Whitehead 		netif_err(adapter, drv, adapter->netdev,
1045*07624df1SBryan Whitehead 			  "Attempting reset while enabled\n");
1046*07624df1SBryan Whitehead 		goto done;
1047*07624df1SBryan Whitehead 	}
1048*07624df1SBryan Whitehead 
1049*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_RESET_);
1050*07624df1SBryan Whitehead 	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_RESET_);
1051*07624df1SBryan Whitehead done:
1052*07624df1SBryan Whitehead 	mutex_unlock(&ptp->command_lock);
1053*07624df1SBryan Whitehead }
1054*07624df1SBryan Whitehead 
1055*07624df1SBryan Whitehead static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter,
1056*07624df1SBryan Whitehead 				  u32 seconds, u32 nano_seconds,
1057*07624df1SBryan Whitehead 				  u32 sub_nano_seconds)
1058*07624df1SBryan Whitehead {
1059*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
1060*07624df1SBryan Whitehead 
1061*07624df1SBryan Whitehead 	mutex_lock(&ptp->command_lock);
1062*07624df1SBryan Whitehead 
1063*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_CLOCK_SEC, seconds);
1064*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_CLOCK_NS, nano_seconds);
1065*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_CLOCK_SUBNS, sub_nano_seconds);
1066*07624df1SBryan Whitehead 
1067*07624df1SBryan Whitehead 	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_LOAD_);
1068*07624df1SBryan Whitehead 	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_LOAD_);
1069*07624df1SBryan Whitehead 	mutex_unlock(&ptp->command_lock);
1070*07624df1SBryan Whitehead }
1071*07624df1SBryan Whitehead 
1072*07624df1SBryan Whitehead bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter)
1073*07624df1SBryan Whitehead {
1074*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
1075*07624df1SBryan Whitehead 	bool result = false;
1076*07624df1SBryan Whitehead 
1077*07624df1SBryan Whitehead 	spin_lock_bh(&ptp->tx_ts_lock);
1078*07624df1SBryan Whitehead 	if (ptp->pending_tx_timestamps < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
1079*07624df1SBryan Whitehead 		/* request granted */
1080*07624df1SBryan Whitehead 		ptp->pending_tx_timestamps++;
1081*07624df1SBryan Whitehead 		result = true;
1082*07624df1SBryan Whitehead 	}
1083*07624df1SBryan Whitehead 	spin_unlock_bh(&ptp->tx_ts_lock);
1084*07624df1SBryan Whitehead 	return result;
1085*07624df1SBryan Whitehead }
1086*07624df1SBryan Whitehead 
1087*07624df1SBryan Whitehead void lan743x_ptp_unrequest_tx_timestamp(struct lan743x_adapter *adapter)
1088*07624df1SBryan Whitehead {
1089*07624df1SBryan Whitehead 	struct lan743x_ptp *ptp = &adapter->ptp;
1090*07624df1SBryan Whitehead 
1091*07624df1SBryan Whitehead 	spin_lock_bh(&ptp->tx_ts_lock);
1092*07624df1SBryan Whitehead 	if (ptp->pending_tx_timestamps > 0)
1093*07624df1SBryan Whitehead 		ptp->pending_tx_timestamps--;
1094*07624df1SBryan Whitehead 	else
1095*07624df1SBryan Whitehead 		netif_err(adapter, drv, adapter->netdev,
1096*07624df1SBryan Whitehead 			  "unrequest failed, pending_tx_timestamps==0\n");
1097*07624df1SBryan Whitehead 	spin_unlock_bh(&ptp->tx_ts_lock);
1098*07624df1SBryan Whitehead }
1099*07624df1SBryan Whitehead 
1100*07624df1SBryan Whitehead void lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter,
1101*07624df1SBryan Whitehead 				  struct sk_buff *skb, bool ignore_sync)
1102*07624df1SBryan Whitehead {
1103*07624df1SBryan Whitehead 	lan743x_ptp_tx_ts_enqueue_skb(adapter, skb, ignore_sync);
1104*07624df1SBryan Whitehead 
1105*07624df1SBryan Whitehead 	lan743x_ptp_tx_ts_complete(adapter);
1106*07624df1SBryan Whitehead }
1107*07624df1SBryan Whitehead 
1108*07624df1SBryan Whitehead int lan743x_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
1109*07624df1SBryan Whitehead {
1110*07624df1SBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
1111*07624df1SBryan Whitehead 	struct hwtstamp_config config;
1112*07624df1SBryan Whitehead 	int ret = 0;
1113*07624df1SBryan Whitehead 	int index;
1114*07624df1SBryan Whitehead 
1115*07624df1SBryan Whitehead 	if (!ifr) {
1116*07624df1SBryan Whitehead 		netif_err(adapter, drv, adapter->netdev,
1117*07624df1SBryan Whitehead 			  "SIOCSHWTSTAMP, ifr == NULL\n");
1118*07624df1SBryan Whitehead 		return -EINVAL;
1119*07624df1SBryan Whitehead 	}
1120*07624df1SBryan Whitehead 
1121*07624df1SBryan Whitehead 	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
1122*07624df1SBryan Whitehead 		return -EFAULT;
1123*07624df1SBryan Whitehead 
1124*07624df1SBryan Whitehead 	if (config.flags) {
1125*07624df1SBryan Whitehead 		netif_warn(adapter, drv, adapter->netdev,
1126*07624df1SBryan Whitehead 			   "ignoring hwtstamp_config.flags == 0x%08X, expected 0\n",
1127*07624df1SBryan Whitehead 			   config.flags);
1128*07624df1SBryan Whitehead 	}
1129*07624df1SBryan Whitehead 
1130*07624df1SBryan Whitehead 	switch (config.tx_type) {
1131*07624df1SBryan Whitehead 	case HWTSTAMP_TX_OFF:
1132*07624df1SBryan Whitehead 		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
1133*07624df1SBryan Whitehead 			index++)
1134*07624df1SBryan Whitehead 			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
1135*07624df1SBryan Whitehead 							 false, false);
1136*07624df1SBryan Whitehead 		lan743x_ptp_set_sync_ts_insert(adapter, false);
1137*07624df1SBryan Whitehead 		break;
1138*07624df1SBryan Whitehead 	case HWTSTAMP_TX_ON:
1139*07624df1SBryan Whitehead 		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
1140*07624df1SBryan Whitehead 			index++)
1141*07624df1SBryan Whitehead 			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
1142*07624df1SBryan Whitehead 							 true, false);
1143*07624df1SBryan Whitehead 		lan743x_ptp_set_sync_ts_insert(adapter, false);
1144*07624df1SBryan Whitehead 		break;
1145*07624df1SBryan Whitehead 	case HWTSTAMP_TX_ONESTEP_SYNC:
1146*07624df1SBryan Whitehead 		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
1147*07624df1SBryan Whitehead 			index++)
1148*07624df1SBryan Whitehead 			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
1149*07624df1SBryan Whitehead 							 true, true);
1150*07624df1SBryan Whitehead 
1151*07624df1SBryan Whitehead 		lan743x_ptp_set_sync_ts_insert(adapter, true);
1152*07624df1SBryan Whitehead 		break;
1153*07624df1SBryan Whitehead 	default:
1154*07624df1SBryan Whitehead 		netif_warn(adapter, drv, adapter->netdev,
1155*07624df1SBryan Whitehead 			   "  tx_type = %d, UNKNOWN\n", config.tx_type);
1156*07624df1SBryan Whitehead 		ret = -EINVAL;
1157*07624df1SBryan Whitehead 		break;
1158*07624df1SBryan Whitehead 	}
1159*07624df1SBryan Whitehead 
1160*07624df1SBryan Whitehead 	if (!ret)
1161*07624df1SBryan Whitehead 		return copy_to_user(ifr->ifr_data, &config,
1162*07624df1SBryan Whitehead 			sizeof(config)) ? -EFAULT : 0;
1163*07624df1SBryan Whitehead 	return ret;
1164*07624df1SBryan Whitehead }
1165