1c9c12d33SAleksey Makarov // SPDX-License-Identifier: GPL-2.0
2cb0e3ec4SSunil Goutham /* Marvell RVU Ethernet driver
3c9c12d33SAleksey Makarov  *
4cb0e3ec4SSunil Goutham  * Copyright (C) 2020 Marvell.
5cb0e3ec4SSunil Goutham  *
6c9c12d33SAleksey Makarov  */
7c9c12d33SAleksey Makarov 
8c9c12d33SAleksey Makarov #include "otx2_common.h"
9c9c12d33SAleksey Makarov #include "otx2_ptp.h"
10c9c12d33SAleksey Makarov 
11c9c12d33SAleksey Makarov static int otx2_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
12c9c12d33SAleksey Makarov {
13c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
14c9c12d33SAleksey Makarov 					    ptp_info);
15c9c12d33SAleksey Makarov 	struct ptp_req *req;
16c9c12d33SAleksey Makarov 
17c9c12d33SAleksey Makarov 	if (!ptp->nic)
18c9c12d33SAleksey Makarov 		return -ENODEV;
19c9c12d33SAleksey Makarov 
20c9c12d33SAleksey Makarov 	req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
21c9c12d33SAleksey Makarov 	if (!req)
22c9c12d33SAleksey Makarov 		return -ENOMEM;
23c9c12d33SAleksey Makarov 
24c9c12d33SAleksey Makarov 	req->op = PTP_OP_ADJFINE;
25c9c12d33SAleksey Makarov 	req->scaled_ppm = scaled_ppm;
26c9c12d33SAleksey Makarov 
27b8d90937SZheng Yongjun 	return otx2_sync_mbox_msg(&ptp->nic->mbox);
28c9c12d33SAleksey Makarov }
29c9c12d33SAleksey Makarov 
30*99bbc4aeSYi Guo static int ptp_set_thresh(struct otx2_ptp *ptp, u64 thresh)
31*99bbc4aeSYi Guo {
32*99bbc4aeSYi Guo 	struct ptp_req *req;
33*99bbc4aeSYi Guo 
34*99bbc4aeSYi Guo 	if (!ptp->nic)
35*99bbc4aeSYi Guo 		return -ENODEV;
36*99bbc4aeSYi Guo 
37*99bbc4aeSYi Guo 	req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
38*99bbc4aeSYi Guo 	if (!req)
39*99bbc4aeSYi Guo 		return -ENOMEM;
40*99bbc4aeSYi Guo 
41*99bbc4aeSYi Guo 	req->op = PTP_OP_SET_THRESH;
42*99bbc4aeSYi Guo 	req->thresh = thresh;
43*99bbc4aeSYi Guo 
44*99bbc4aeSYi Guo 	return otx2_sync_mbox_msg(&ptp->nic->mbox);
45*99bbc4aeSYi Guo }
46*99bbc4aeSYi Guo 
47c9c12d33SAleksey Makarov static u64 ptp_cc_read(const struct cyclecounter *cc)
48c9c12d33SAleksey Makarov {
49c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = container_of(cc, struct otx2_ptp, cycle_counter);
50c9c12d33SAleksey Makarov 	struct ptp_req *req;
51c9c12d33SAleksey Makarov 	struct ptp_rsp *rsp;
52c9c12d33SAleksey Makarov 	int err;
53c9c12d33SAleksey Makarov 
54c9c12d33SAleksey Makarov 	if (!ptp->nic)
55c9c12d33SAleksey Makarov 		return 0;
56c9c12d33SAleksey Makarov 
57c9c12d33SAleksey Makarov 	req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
58c9c12d33SAleksey Makarov 	if (!req)
59c9c12d33SAleksey Makarov 		return 0;
60c9c12d33SAleksey Makarov 
61c9c12d33SAleksey Makarov 	req->op = PTP_OP_GET_CLOCK;
62c9c12d33SAleksey Makarov 
63c9c12d33SAleksey Makarov 	err = otx2_sync_mbox_msg(&ptp->nic->mbox);
64c9c12d33SAleksey Makarov 	if (err)
65c9c12d33SAleksey Makarov 		return 0;
66c9c12d33SAleksey Makarov 
67c9c12d33SAleksey Makarov 	rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0,
68c9c12d33SAleksey Makarov 						  &req->hdr);
69c9c12d33SAleksey Makarov 	if (IS_ERR(rsp))
70c9c12d33SAleksey Makarov 		return 0;
71c9c12d33SAleksey Makarov 
72c9c12d33SAleksey Makarov 	return rsp->clk;
73c9c12d33SAleksey Makarov }
74c9c12d33SAleksey Makarov 
75*99bbc4aeSYi Guo static u64 ptp_tstmp_read(struct otx2_ptp *ptp)
76*99bbc4aeSYi Guo {
77*99bbc4aeSYi Guo 	struct ptp_req *req;
78*99bbc4aeSYi Guo 	struct ptp_rsp *rsp;
79*99bbc4aeSYi Guo 	int err;
80*99bbc4aeSYi Guo 
81*99bbc4aeSYi Guo 	if (!ptp->nic)
82*99bbc4aeSYi Guo 		return 0;
83*99bbc4aeSYi Guo 
84*99bbc4aeSYi Guo 	req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
85*99bbc4aeSYi Guo 	if (!req)
86*99bbc4aeSYi Guo 		return 0;
87*99bbc4aeSYi Guo 
88*99bbc4aeSYi Guo 	req->op = PTP_OP_GET_TSTMP;
89*99bbc4aeSYi Guo 
90*99bbc4aeSYi Guo 	err = otx2_sync_mbox_msg(&ptp->nic->mbox);
91*99bbc4aeSYi Guo 	if (err)
92*99bbc4aeSYi Guo 		return 0;
93*99bbc4aeSYi Guo 
94*99bbc4aeSYi Guo 	rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0,
95*99bbc4aeSYi Guo 						  &req->hdr);
96*99bbc4aeSYi Guo 	if (IS_ERR(rsp))
97*99bbc4aeSYi Guo 		return 0;
98*99bbc4aeSYi Guo 
99*99bbc4aeSYi Guo 	return rsp->clk;
100*99bbc4aeSYi Guo }
101*99bbc4aeSYi Guo 
102c9c12d33SAleksey Makarov static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
103c9c12d33SAleksey Makarov {
104c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
105c9c12d33SAleksey Makarov 					    ptp_info);
106c9c12d33SAleksey Makarov 	struct otx2_nic *pfvf = ptp->nic;
107c9c12d33SAleksey Makarov 
108c9c12d33SAleksey Makarov 	mutex_lock(&pfvf->mbox.lock);
109c9c12d33SAleksey Makarov 	timecounter_adjtime(&ptp->time_counter, delta);
110c9c12d33SAleksey Makarov 	mutex_unlock(&pfvf->mbox.lock);
111c9c12d33SAleksey Makarov 
112c9c12d33SAleksey Makarov 	return 0;
113c9c12d33SAleksey Makarov }
114c9c12d33SAleksey Makarov 
115c9c12d33SAleksey Makarov static int otx2_ptp_gettime(struct ptp_clock_info *ptp_info,
116c9c12d33SAleksey Makarov 			    struct timespec64 *ts)
117c9c12d33SAleksey Makarov {
118c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
119c9c12d33SAleksey Makarov 					    ptp_info);
120c9c12d33SAleksey Makarov 	struct otx2_nic *pfvf = ptp->nic;
121c9c12d33SAleksey Makarov 	u64 nsec;
122c9c12d33SAleksey Makarov 
123c9c12d33SAleksey Makarov 	mutex_lock(&pfvf->mbox.lock);
124c9c12d33SAleksey Makarov 	nsec = timecounter_read(&ptp->time_counter);
125c9c12d33SAleksey Makarov 	mutex_unlock(&pfvf->mbox.lock);
126c9c12d33SAleksey Makarov 
127c9c12d33SAleksey Makarov 	*ts = ns_to_timespec64(nsec);
128c9c12d33SAleksey Makarov 
129c9c12d33SAleksey Makarov 	return 0;
130c9c12d33SAleksey Makarov }
131c9c12d33SAleksey Makarov 
132c9c12d33SAleksey Makarov static int otx2_ptp_settime(struct ptp_clock_info *ptp_info,
133c9c12d33SAleksey Makarov 			    const struct timespec64 *ts)
134c9c12d33SAleksey Makarov {
135c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
136c9c12d33SAleksey Makarov 					    ptp_info);
137c9c12d33SAleksey Makarov 	struct otx2_nic *pfvf = ptp->nic;
138c9c12d33SAleksey Makarov 	u64 nsec;
139c9c12d33SAleksey Makarov 
140c9c12d33SAleksey Makarov 	nsec = timespec64_to_ns(ts);
141c9c12d33SAleksey Makarov 
142c9c12d33SAleksey Makarov 	mutex_lock(&pfvf->mbox.lock);
143c9c12d33SAleksey Makarov 	timecounter_init(&ptp->time_counter, &ptp->cycle_counter, nsec);
144c9c12d33SAleksey Makarov 	mutex_unlock(&pfvf->mbox.lock);
145c9c12d33SAleksey Makarov 
146c9c12d33SAleksey Makarov 	return 0;
147c9c12d33SAleksey Makarov }
148c9c12d33SAleksey Makarov 
149*99bbc4aeSYi Guo static int otx2_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
150*99bbc4aeSYi Guo 			       enum ptp_pin_function func, unsigned int chan)
151*99bbc4aeSYi Guo {
152*99bbc4aeSYi Guo 	switch (func) {
153*99bbc4aeSYi Guo 	case PTP_PF_NONE:
154*99bbc4aeSYi Guo 	case PTP_PF_EXTTS:
155*99bbc4aeSYi Guo 		break;
156*99bbc4aeSYi Guo 	case PTP_PF_PEROUT:
157*99bbc4aeSYi Guo 	case PTP_PF_PHYSYNC:
158*99bbc4aeSYi Guo 		return -1;
159*99bbc4aeSYi Guo 	}
160*99bbc4aeSYi Guo 	return 0;
161*99bbc4aeSYi Guo }
162*99bbc4aeSYi Guo 
163*99bbc4aeSYi Guo static void otx2_ptp_extts_check(struct work_struct *work)
164*99bbc4aeSYi Guo {
165*99bbc4aeSYi Guo 	struct otx2_ptp *ptp = container_of(work, struct otx2_ptp,
166*99bbc4aeSYi Guo 					    extts_work.work);
167*99bbc4aeSYi Guo 	struct ptp_clock_event event;
168*99bbc4aeSYi Guo 	u64 tstmp, new_thresh;
169*99bbc4aeSYi Guo 
170*99bbc4aeSYi Guo 	mutex_lock(&ptp->nic->mbox.lock);
171*99bbc4aeSYi Guo 	tstmp = ptp_tstmp_read(ptp);
172*99bbc4aeSYi Guo 	mutex_unlock(&ptp->nic->mbox.lock);
173*99bbc4aeSYi Guo 
174*99bbc4aeSYi Guo 	if (tstmp != ptp->last_extts) {
175*99bbc4aeSYi Guo 		event.type = PTP_CLOCK_EXTTS;
176*99bbc4aeSYi Guo 		event.index = 0;
177*99bbc4aeSYi Guo 		event.timestamp = timecounter_cyc2time(&ptp->time_counter, tstmp);
178*99bbc4aeSYi Guo 		ptp_clock_event(ptp->ptp_clock, &event);
179*99bbc4aeSYi Guo 		ptp->last_extts = tstmp;
180*99bbc4aeSYi Guo 
181*99bbc4aeSYi Guo 		new_thresh = tstmp % 500000000;
182*99bbc4aeSYi Guo 		if (ptp->thresh != new_thresh) {
183*99bbc4aeSYi Guo 			mutex_lock(&ptp->nic->mbox.lock);
184*99bbc4aeSYi Guo 			ptp_set_thresh(ptp, new_thresh);
185*99bbc4aeSYi Guo 			mutex_unlock(&ptp->nic->mbox.lock);
186*99bbc4aeSYi Guo 			ptp->thresh = new_thresh;
187*99bbc4aeSYi Guo 		}
188*99bbc4aeSYi Guo 	}
189*99bbc4aeSYi Guo 	schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200));
190*99bbc4aeSYi Guo }
191*99bbc4aeSYi Guo 
192c9c12d33SAleksey Makarov static int otx2_ptp_enable(struct ptp_clock_info *ptp_info,
193c9c12d33SAleksey Makarov 			   struct ptp_clock_request *rq, int on)
194c9c12d33SAleksey Makarov {
195*99bbc4aeSYi Guo 	struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
196*99bbc4aeSYi Guo 					    ptp_info);
197*99bbc4aeSYi Guo 	int pin = -1;
198*99bbc4aeSYi Guo 
199*99bbc4aeSYi Guo 	if (!ptp->nic)
200*99bbc4aeSYi Guo 		return -ENODEV;
201*99bbc4aeSYi Guo 
202*99bbc4aeSYi Guo 	switch (rq->type) {
203*99bbc4aeSYi Guo 	case PTP_CLK_REQ_EXTTS:
204*99bbc4aeSYi Guo 		pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS,
205*99bbc4aeSYi Guo 				   rq->extts.index);
206*99bbc4aeSYi Guo 		if (pin < 0)
207*99bbc4aeSYi Guo 			return -EBUSY;
208*99bbc4aeSYi Guo 		if (on)
209*99bbc4aeSYi Guo 			schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200));
210*99bbc4aeSYi Guo 		else
211*99bbc4aeSYi Guo 			cancel_delayed_work_sync(&ptp->extts_work);
212*99bbc4aeSYi Guo 		return 0;
213*99bbc4aeSYi Guo 	default:
214*99bbc4aeSYi Guo 		break;
215*99bbc4aeSYi Guo 	}
216c9c12d33SAleksey Makarov 	return -EOPNOTSUPP;
217c9c12d33SAleksey Makarov }
218c9c12d33SAleksey Makarov 
219c9c12d33SAleksey Makarov int otx2_ptp_init(struct otx2_nic *pfvf)
220c9c12d33SAleksey Makarov {
221c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp_ptr;
222c9c12d33SAleksey Makarov 	struct cyclecounter *cc;
223c9c12d33SAleksey Makarov 	struct ptp_req *req;
224c9c12d33SAleksey Makarov 	int err;
225c9c12d33SAleksey Makarov 
226c9c12d33SAleksey Makarov 	mutex_lock(&pfvf->mbox.lock);
227c9c12d33SAleksey Makarov 	/* check if PTP block is available */
228c9c12d33SAleksey Makarov 	req = otx2_mbox_alloc_msg_ptp_op(&pfvf->mbox);
229c9c12d33SAleksey Makarov 	if (!req) {
230c9c12d33SAleksey Makarov 		mutex_unlock(&pfvf->mbox.lock);
231c9c12d33SAleksey Makarov 		return -ENOMEM;
232c9c12d33SAleksey Makarov 	}
233c9c12d33SAleksey Makarov 
234c9c12d33SAleksey Makarov 	req->op = PTP_OP_GET_CLOCK;
235c9c12d33SAleksey Makarov 
236c9c12d33SAleksey Makarov 	err = otx2_sync_mbox_msg(&pfvf->mbox);
237c9c12d33SAleksey Makarov 	if (err) {
238c9c12d33SAleksey Makarov 		mutex_unlock(&pfvf->mbox.lock);
239c9c12d33SAleksey Makarov 		return err;
240c9c12d33SAleksey Makarov 	}
241c9c12d33SAleksey Makarov 	mutex_unlock(&pfvf->mbox.lock);
242c9c12d33SAleksey Makarov 
243c9c12d33SAleksey Makarov 	ptp_ptr = kzalloc(sizeof(*ptp_ptr), GFP_KERNEL);
244c9c12d33SAleksey Makarov 	if (!ptp_ptr) {
245c9c12d33SAleksey Makarov 		err = -ENOMEM;
246c9c12d33SAleksey Makarov 		goto error;
247c9c12d33SAleksey Makarov 	}
248c9c12d33SAleksey Makarov 
249c9c12d33SAleksey Makarov 	ptp_ptr->nic = pfvf;
250c9c12d33SAleksey Makarov 
251c9c12d33SAleksey Makarov 	cc = &ptp_ptr->cycle_counter;
252c9c12d33SAleksey Makarov 	cc->read = ptp_cc_read;
253c9c12d33SAleksey Makarov 	cc->mask = CYCLECOUNTER_MASK(64);
254c9c12d33SAleksey Makarov 	cc->mult = 1;
255c9c12d33SAleksey Makarov 	cc->shift = 0;
256c9c12d33SAleksey Makarov 
257c9c12d33SAleksey Makarov 	timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter,
258c9c12d33SAleksey Makarov 			 ktime_to_ns(ktime_get_real()));
259c9c12d33SAleksey Makarov 
260*99bbc4aeSYi Guo 	snprintf(ptp_ptr->extts_config.name, sizeof(ptp_ptr->extts_config.name), "TSTAMP");
261*99bbc4aeSYi Guo 	ptp_ptr->extts_config.index = 0;
262*99bbc4aeSYi Guo 	ptp_ptr->extts_config.func = PTP_PF_NONE;
263*99bbc4aeSYi Guo 
264c9c12d33SAleksey Makarov 	ptp_ptr->ptp_info = (struct ptp_clock_info) {
265c9c12d33SAleksey Makarov 		.owner          = THIS_MODULE,
266c9c12d33SAleksey Makarov 		.name           = "OcteonTX2 PTP",
267c9c12d33SAleksey Makarov 		.max_adj        = 1000000000ull,
268*99bbc4aeSYi Guo 		.n_ext_ts       = 1,
269*99bbc4aeSYi Guo 		.n_pins         = 1,
270c9c12d33SAleksey Makarov 		.pps            = 0,
271*99bbc4aeSYi Guo 		.pin_config     = &ptp_ptr->extts_config,
272c9c12d33SAleksey Makarov 		.adjfine        = otx2_ptp_adjfine,
273c9c12d33SAleksey Makarov 		.adjtime        = otx2_ptp_adjtime,
274c9c12d33SAleksey Makarov 		.gettime64      = otx2_ptp_gettime,
275c9c12d33SAleksey Makarov 		.settime64      = otx2_ptp_settime,
276c9c12d33SAleksey Makarov 		.enable         = otx2_ptp_enable,
277*99bbc4aeSYi Guo 		.verify         = otx2_ptp_verify_pin,
278c9c12d33SAleksey Makarov 	};
279c9c12d33SAleksey Makarov 
280*99bbc4aeSYi Guo 	INIT_DELAYED_WORK(&ptp_ptr->extts_work, otx2_ptp_extts_check);
281*99bbc4aeSYi Guo 
282c9c12d33SAleksey Makarov 	ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev);
283c9c12d33SAleksey Makarov 	if (IS_ERR_OR_NULL(ptp_ptr->ptp_clock)) {
284c9c12d33SAleksey Makarov 		err = ptp_ptr->ptp_clock ?
285c9c12d33SAleksey Makarov 		      PTR_ERR(ptp_ptr->ptp_clock) : -ENODEV;
286c9c12d33SAleksey Makarov 		kfree(ptp_ptr);
287c9c12d33SAleksey Makarov 		goto error;
288c9c12d33SAleksey Makarov 	}
289c9c12d33SAleksey Makarov 
290c9c12d33SAleksey Makarov 	pfvf->ptp = ptp_ptr;
291c9c12d33SAleksey Makarov 
292c9c12d33SAleksey Makarov error:
293c9c12d33SAleksey Makarov 	return err;
294c9c12d33SAleksey Makarov }
295c9c12d33SAleksey Makarov 
296c9c12d33SAleksey Makarov void otx2_ptp_destroy(struct otx2_nic *pfvf)
297c9c12d33SAleksey Makarov {
298c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = pfvf->ptp;
299c9c12d33SAleksey Makarov 
300c9c12d33SAleksey Makarov 	if (!ptp)
301c9c12d33SAleksey Makarov 		return;
302c9c12d33SAleksey Makarov 
303c9c12d33SAleksey Makarov 	ptp_clock_unregister(ptp->ptp_clock);
304c9c12d33SAleksey Makarov 	kfree(ptp);
305c9c12d33SAleksey Makarov 	pfvf->ptp = NULL;
306c9c12d33SAleksey Makarov }
307c9c12d33SAleksey Makarov 
308c9c12d33SAleksey Makarov int otx2_ptp_clock_index(struct otx2_nic *pfvf)
309c9c12d33SAleksey Makarov {
310c9c12d33SAleksey Makarov 	if (!pfvf->ptp)
311c9c12d33SAleksey Makarov 		return -ENODEV;
312c9c12d33SAleksey Makarov 
313c9c12d33SAleksey Makarov 	return ptp_clock_index(pfvf->ptp->ptp_clock);
314c9c12d33SAleksey Makarov }
315c9c12d33SAleksey Makarov 
316c9c12d33SAleksey Makarov int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns)
317c9c12d33SAleksey Makarov {
318c9c12d33SAleksey Makarov 	if (!pfvf->ptp)
319c9c12d33SAleksey Makarov 		return -ENODEV;
320c9c12d33SAleksey Makarov 
321c9c12d33SAleksey Makarov 	*tsns = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp);
322c9c12d33SAleksey Makarov 
323c9c12d33SAleksey Makarov 	return 0;
324c9c12d33SAleksey Makarov }
325