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 
3099bbc4aeSYi Guo static int ptp_set_thresh(struct otx2_ptp *ptp, u64 thresh)
3199bbc4aeSYi Guo {
3299bbc4aeSYi Guo 	struct ptp_req *req;
3399bbc4aeSYi Guo 
3499bbc4aeSYi Guo 	if (!ptp->nic)
3599bbc4aeSYi Guo 		return -ENODEV;
3699bbc4aeSYi Guo 
3799bbc4aeSYi Guo 	req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
3899bbc4aeSYi Guo 	if (!req)
3999bbc4aeSYi Guo 		return -ENOMEM;
4099bbc4aeSYi Guo 
4199bbc4aeSYi Guo 	req->op = PTP_OP_SET_THRESH;
4299bbc4aeSYi Guo 	req->thresh = thresh;
4399bbc4aeSYi Guo 
4499bbc4aeSYi Guo 	return otx2_sync_mbox_msg(&ptp->nic->mbox);
4599bbc4aeSYi Guo }
4699bbc4aeSYi 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 
7599bbc4aeSYi Guo static u64 ptp_tstmp_read(struct otx2_ptp *ptp)
7699bbc4aeSYi Guo {
7799bbc4aeSYi Guo 	struct ptp_req *req;
7899bbc4aeSYi Guo 	struct ptp_rsp *rsp;
7999bbc4aeSYi Guo 	int err;
8099bbc4aeSYi Guo 
8199bbc4aeSYi Guo 	if (!ptp->nic)
8299bbc4aeSYi Guo 		return 0;
8399bbc4aeSYi Guo 
8499bbc4aeSYi Guo 	req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
8599bbc4aeSYi Guo 	if (!req)
8699bbc4aeSYi Guo 		return 0;
8799bbc4aeSYi Guo 
8899bbc4aeSYi Guo 	req->op = PTP_OP_GET_TSTMP;
8999bbc4aeSYi Guo 
9099bbc4aeSYi Guo 	err = otx2_sync_mbox_msg(&ptp->nic->mbox);
9199bbc4aeSYi Guo 	if (err)
9299bbc4aeSYi Guo 		return 0;
9399bbc4aeSYi Guo 
9499bbc4aeSYi Guo 	rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0,
9599bbc4aeSYi Guo 						  &req->hdr);
9699bbc4aeSYi Guo 	if (IS_ERR(rsp))
9799bbc4aeSYi Guo 		return 0;
9899bbc4aeSYi Guo 
9999bbc4aeSYi Guo 	return rsp->clk;
10099bbc4aeSYi Guo }
10199bbc4aeSYi 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 
14999bbc4aeSYi Guo static int otx2_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
15099bbc4aeSYi Guo 			       enum ptp_pin_function func, unsigned int chan)
15199bbc4aeSYi Guo {
15299bbc4aeSYi Guo 	switch (func) {
15399bbc4aeSYi Guo 	case PTP_PF_NONE:
15499bbc4aeSYi Guo 	case PTP_PF_EXTTS:
15599bbc4aeSYi Guo 		break;
15699bbc4aeSYi Guo 	case PTP_PF_PEROUT:
15799bbc4aeSYi Guo 	case PTP_PF_PHYSYNC:
15899bbc4aeSYi Guo 		return -1;
15999bbc4aeSYi Guo 	}
16099bbc4aeSYi Guo 	return 0;
16199bbc4aeSYi Guo }
16299bbc4aeSYi Guo 
16399bbc4aeSYi Guo static void otx2_ptp_extts_check(struct work_struct *work)
16499bbc4aeSYi Guo {
16599bbc4aeSYi Guo 	struct otx2_ptp *ptp = container_of(work, struct otx2_ptp,
16699bbc4aeSYi Guo 					    extts_work.work);
16799bbc4aeSYi Guo 	struct ptp_clock_event event;
16899bbc4aeSYi Guo 	u64 tstmp, new_thresh;
16999bbc4aeSYi Guo 
17099bbc4aeSYi Guo 	mutex_lock(&ptp->nic->mbox.lock);
17199bbc4aeSYi Guo 	tstmp = ptp_tstmp_read(ptp);
17299bbc4aeSYi Guo 	mutex_unlock(&ptp->nic->mbox.lock);
17399bbc4aeSYi Guo 
17499bbc4aeSYi Guo 	if (tstmp != ptp->last_extts) {
17599bbc4aeSYi Guo 		event.type = PTP_CLOCK_EXTTS;
17699bbc4aeSYi Guo 		event.index = 0;
17799bbc4aeSYi Guo 		event.timestamp = timecounter_cyc2time(&ptp->time_counter, tstmp);
17899bbc4aeSYi Guo 		ptp_clock_event(ptp->ptp_clock, &event);
17999bbc4aeSYi Guo 		ptp->last_extts = tstmp;
18099bbc4aeSYi Guo 
18199bbc4aeSYi Guo 		new_thresh = tstmp % 500000000;
18299bbc4aeSYi Guo 		if (ptp->thresh != new_thresh) {
18399bbc4aeSYi Guo 			mutex_lock(&ptp->nic->mbox.lock);
18499bbc4aeSYi Guo 			ptp_set_thresh(ptp, new_thresh);
18599bbc4aeSYi Guo 			mutex_unlock(&ptp->nic->mbox.lock);
18699bbc4aeSYi Guo 			ptp->thresh = new_thresh;
18799bbc4aeSYi Guo 		}
18899bbc4aeSYi Guo 	}
18999bbc4aeSYi Guo 	schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200));
19099bbc4aeSYi Guo }
19199bbc4aeSYi 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 {
19599bbc4aeSYi Guo 	struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
19699bbc4aeSYi Guo 					    ptp_info);
197*75f81afbSColin Ian King 	int pin;
19899bbc4aeSYi Guo 
19999bbc4aeSYi Guo 	if (!ptp->nic)
20099bbc4aeSYi Guo 		return -ENODEV;
20199bbc4aeSYi Guo 
20299bbc4aeSYi Guo 	switch (rq->type) {
20399bbc4aeSYi Guo 	case PTP_CLK_REQ_EXTTS:
20499bbc4aeSYi Guo 		pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS,
20599bbc4aeSYi Guo 				   rq->extts.index);
20699bbc4aeSYi Guo 		if (pin < 0)
20799bbc4aeSYi Guo 			return -EBUSY;
20899bbc4aeSYi Guo 		if (on)
20999bbc4aeSYi Guo 			schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200));
21099bbc4aeSYi Guo 		else
21199bbc4aeSYi Guo 			cancel_delayed_work_sync(&ptp->extts_work);
21299bbc4aeSYi Guo 		return 0;
21399bbc4aeSYi Guo 	default:
21499bbc4aeSYi Guo 		break;
21599bbc4aeSYi 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 
22643510ef4SNaveen Mamindlapalli 	if (is_otx2_lbkvf(pfvf->pdev)) {
22743510ef4SNaveen Mamindlapalli 		pfvf->ptp = NULL;
22843510ef4SNaveen Mamindlapalli 		return 0;
22943510ef4SNaveen Mamindlapalli 	}
23043510ef4SNaveen Mamindlapalli 
231c9c12d33SAleksey Makarov 	mutex_lock(&pfvf->mbox.lock);
232c9c12d33SAleksey Makarov 	/* check if PTP block is available */
233c9c12d33SAleksey Makarov 	req = otx2_mbox_alloc_msg_ptp_op(&pfvf->mbox);
234c9c12d33SAleksey Makarov 	if (!req) {
235c9c12d33SAleksey Makarov 		mutex_unlock(&pfvf->mbox.lock);
236c9c12d33SAleksey Makarov 		return -ENOMEM;
237c9c12d33SAleksey Makarov 	}
238c9c12d33SAleksey Makarov 
239c9c12d33SAleksey Makarov 	req->op = PTP_OP_GET_CLOCK;
240c9c12d33SAleksey Makarov 
241c9c12d33SAleksey Makarov 	err = otx2_sync_mbox_msg(&pfvf->mbox);
242c9c12d33SAleksey Makarov 	if (err) {
243c9c12d33SAleksey Makarov 		mutex_unlock(&pfvf->mbox.lock);
244c9c12d33SAleksey Makarov 		return err;
245c9c12d33SAleksey Makarov 	}
246c9c12d33SAleksey Makarov 	mutex_unlock(&pfvf->mbox.lock);
247c9c12d33SAleksey Makarov 
248c9c12d33SAleksey Makarov 	ptp_ptr = kzalloc(sizeof(*ptp_ptr), GFP_KERNEL);
249c9c12d33SAleksey Makarov 	if (!ptp_ptr) {
250c9c12d33SAleksey Makarov 		err = -ENOMEM;
251c9c12d33SAleksey Makarov 		goto error;
252c9c12d33SAleksey Makarov 	}
253c9c12d33SAleksey Makarov 
254c9c12d33SAleksey Makarov 	ptp_ptr->nic = pfvf;
255c9c12d33SAleksey Makarov 
256c9c12d33SAleksey Makarov 	cc = &ptp_ptr->cycle_counter;
257c9c12d33SAleksey Makarov 	cc->read = ptp_cc_read;
258c9c12d33SAleksey Makarov 	cc->mask = CYCLECOUNTER_MASK(64);
259c9c12d33SAleksey Makarov 	cc->mult = 1;
260c9c12d33SAleksey Makarov 	cc->shift = 0;
261c9c12d33SAleksey Makarov 
262c9c12d33SAleksey Makarov 	timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter,
263c9c12d33SAleksey Makarov 			 ktime_to_ns(ktime_get_real()));
264c9c12d33SAleksey Makarov 
26599bbc4aeSYi Guo 	snprintf(ptp_ptr->extts_config.name, sizeof(ptp_ptr->extts_config.name), "TSTAMP");
26699bbc4aeSYi Guo 	ptp_ptr->extts_config.index = 0;
26799bbc4aeSYi Guo 	ptp_ptr->extts_config.func = PTP_PF_NONE;
26899bbc4aeSYi Guo 
269c9c12d33SAleksey Makarov 	ptp_ptr->ptp_info = (struct ptp_clock_info) {
270c9c12d33SAleksey Makarov 		.owner          = THIS_MODULE,
271c9c12d33SAleksey Makarov 		.name           = "OcteonTX2 PTP",
272c9c12d33SAleksey Makarov 		.max_adj        = 1000000000ull,
27399bbc4aeSYi Guo 		.n_ext_ts       = 1,
27499bbc4aeSYi Guo 		.n_pins         = 1,
275c9c12d33SAleksey Makarov 		.pps            = 0,
27699bbc4aeSYi Guo 		.pin_config     = &ptp_ptr->extts_config,
277c9c12d33SAleksey Makarov 		.adjfine        = otx2_ptp_adjfine,
278c9c12d33SAleksey Makarov 		.adjtime        = otx2_ptp_adjtime,
279c9c12d33SAleksey Makarov 		.gettime64      = otx2_ptp_gettime,
280c9c12d33SAleksey Makarov 		.settime64      = otx2_ptp_settime,
281c9c12d33SAleksey Makarov 		.enable         = otx2_ptp_enable,
28299bbc4aeSYi Guo 		.verify         = otx2_ptp_verify_pin,
283c9c12d33SAleksey Makarov 	};
284c9c12d33SAleksey Makarov 
28599bbc4aeSYi Guo 	INIT_DELAYED_WORK(&ptp_ptr->extts_work, otx2_ptp_extts_check);
28699bbc4aeSYi Guo 
287c9c12d33SAleksey Makarov 	ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev);
288c9c12d33SAleksey Makarov 	if (IS_ERR_OR_NULL(ptp_ptr->ptp_clock)) {
289c9c12d33SAleksey Makarov 		err = ptp_ptr->ptp_clock ?
290c9c12d33SAleksey Makarov 		      PTR_ERR(ptp_ptr->ptp_clock) : -ENODEV;
291c9c12d33SAleksey Makarov 		kfree(ptp_ptr);
292c9c12d33SAleksey Makarov 		goto error;
293c9c12d33SAleksey Makarov 	}
294c9c12d33SAleksey Makarov 
295c9c12d33SAleksey Makarov 	pfvf->ptp = ptp_ptr;
296c9c12d33SAleksey Makarov 
297c9c12d33SAleksey Makarov error:
298c9c12d33SAleksey Makarov 	return err;
299c9c12d33SAleksey Makarov }
300c9c12d33SAleksey Makarov 
301c9c12d33SAleksey Makarov void otx2_ptp_destroy(struct otx2_nic *pfvf)
302c9c12d33SAleksey Makarov {
303c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = pfvf->ptp;
304c9c12d33SAleksey Makarov 
305c9c12d33SAleksey Makarov 	if (!ptp)
306c9c12d33SAleksey Makarov 		return;
307c9c12d33SAleksey Makarov 
308c9c12d33SAleksey Makarov 	ptp_clock_unregister(ptp->ptp_clock);
309c9c12d33SAleksey Makarov 	kfree(ptp);
310c9c12d33SAleksey Makarov 	pfvf->ptp = NULL;
311c9c12d33SAleksey Makarov }
312c9c12d33SAleksey Makarov 
313c9c12d33SAleksey Makarov int otx2_ptp_clock_index(struct otx2_nic *pfvf)
314c9c12d33SAleksey Makarov {
315c9c12d33SAleksey Makarov 	if (!pfvf->ptp)
316c9c12d33SAleksey Makarov 		return -ENODEV;
317c9c12d33SAleksey Makarov 
318c9c12d33SAleksey Makarov 	return ptp_clock_index(pfvf->ptp->ptp_clock);
319c9c12d33SAleksey Makarov }
320c9c12d33SAleksey Makarov 
321c9c12d33SAleksey Makarov int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns)
322c9c12d33SAleksey Makarov {
323c9c12d33SAleksey Makarov 	if (!pfvf->ptp)
324c9c12d33SAleksey Makarov 		return -ENODEV;
325c9c12d33SAleksey Makarov 
326c9c12d33SAleksey Makarov 	*tsns = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp);
327c9c12d33SAleksey Makarov 
328c9c12d33SAleksey Makarov 	return 0;
329c9c12d33SAleksey Makarov }
330