1c9c12d33SAleksey Makarov // SPDX-License-Identifier: GPL-2.0
2*cb0e3ec4SSunil Goutham /* Marvell RVU Ethernet driver
3c9c12d33SAleksey Makarov  *
4*cb0e3ec4SSunil Goutham  * Copyright (C) 2020 Marvell.
5*cb0e3ec4SSunil 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 
30c9c12d33SAleksey Makarov static u64 ptp_cc_read(const struct cyclecounter *cc)
31c9c12d33SAleksey Makarov {
32c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = container_of(cc, struct otx2_ptp, cycle_counter);
33c9c12d33SAleksey Makarov 	struct ptp_req *req;
34c9c12d33SAleksey Makarov 	struct ptp_rsp *rsp;
35c9c12d33SAleksey Makarov 	int err;
36c9c12d33SAleksey Makarov 
37c9c12d33SAleksey Makarov 	if (!ptp->nic)
38c9c12d33SAleksey Makarov 		return 0;
39c9c12d33SAleksey Makarov 
40c9c12d33SAleksey Makarov 	req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
41c9c12d33SAleksey Makarov 	if (!req)
42c9c12d33SAleksey Makarov 		return 0;
43c9c12d33SAleksey Makarov 
44c9c12d33SAleksey Makarov 	req->op = PTP_OP_GET_CLOCK;
45c9c12d33SAleksey Makarov 
46c9c12d33SAleksey Makarov 	err = otx2_sync_mbox_msg(&ptp->nic->mbox);
47c9c12d33SAleksey Makarov 	if (err)
48c9c12d33SAleksey Makarov 		return 0;
49c9c12d33SAleksey Makarov 
50c9c12d33SAleksey Makarov 	rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0,
51c9c12d33SAleksey Makarov 						  &req->hdr);
52c9c12d33SAleksey Makarov 	if (IS_ERR(rsp))
53c9c12d33SAleksey Makarov 		return 0;
54c9c12d33SAleksey Makarov 
55c9c12d33SAleksey Makarov 	return rsp->clk;
56c9c12d33SAleksey Makarov }
57c9c12d33SAleksey Makarov 
58c9c12d33SAleksey Makarov static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
59c9c12d33SAleksey Makarov {
60c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
61c9c12d33SAleksey Makarov 					    ptp_info);
62c9c12d33SAleksey Makarov 	struct otx2_nic *pfvf = ptp->nic;
63c9c12d33SAleksey Makarov 
64c9c12d33SAleksey Makarov 	mutex_lock(&pfvf->mbox.lock);
65c9c12d33SAleksey Makarov 	timecounter_adjtime(&ptp->time_counter, delta);
66c9c12d33SAleksey Makarov 	mutex_unlock(&pfvf->mbox.lock);
67c9c12d33SAleksey Makarov 
68c9c12d33SAleksey Makarov 	return 0;
69c9c12d33SAleksey Makarov }
70c9c12d33SAleksey Makarov 
71c9c12d33SAleksey Makarov static int otx2_ptp_gettime(struct ptp_clock_info *ptp_info,
72c9c12d33SAleksey Makarov 			    struct timespec64 *ts)
73c9c12d33SAleksey Makarov {
74c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
75c9c12d33SAleksey Makarov 					    ptp_info);
76c9c12d33SAleksey Makarov 	struct otx2_nic *pfvf = ptp->nic;
77c9c12d33SAleksey Makarov 	u64 nsec;
78c9c12d33SAleksey Makarov 
79c9c12d33SAleksey Makarov 	mutex_lock(&pfvf->mbox.lock);
80c9c12d33SAleksey Makarov 	nsec = timecounter_read(&ptp->time_counter);
81c9c12d33SAleksey Makarov 	mutex_unlock(&pfvf->mbox.lock);
82c9c12d33SAleksey Makarov 
83c9c12d33SAleksey Makarov 	*ts = ns_to_timespec64(nsec);
84c9c12d33SAleksey Makarov 
85c9c12d33SAleksey Makarov 	return 0;
86c9c12d33SAleksey Makarov }
87c9c12d33SAleksey Makarov 
88c9c12d33SAleksey Makarov static int otx2_ptp_settime(struct ptp_clock_info *ptp_info,
89c9c12d33SAleksey Makarov 			    const struct timespec64 *ts)
90c9c12d33SAleksey Makarov {
91c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
92c9c12d33SAleksey Makarov 					    ptp_info);
93c9c12d33SAleksey Makarov 	struct otx2_nic *pfvf = ptp->nic;
94c9c12d33SAleksey Makarov 	u64 nsec;
95c9c12d33SAleksey Makarov 
96c9c12d33SAleksey Makarov 	nsec = timespec64_to_ns(ts);
97c9c12d33SAleksey Makarov 
98c9c12d33SAleksey Makarov 	mutex_lock(&pfvf->mbox.lock);
99c9c12d33SAleksey Makarov 	timecounter_init(&ptp->time_counter, &ptp->cycle_counter, nsec);
100c9c12d33SAleksey Makarov 	mutex_unlock(&pfvf->mbox.lock);
101c9c12d33SAleksey Makarov 
102c9c12d33SAleksey Makarov 	return 0;
103c9c12d33SAleksey Makarov }
104c9c12d33SAleksey Makarov 
105c9c12d33SAleksey Makarov static int otx2_ptp_enable(struct ptp_clock_info *ptp_info,
106c9c12d33SAleksey Makarov 			   struct ptp_clock_request *rq, int on)
107c9c12d33SAleksey Makarov {
108c9c12d33SAleksey Makarov 	return -EOPNOTSUPP;
109c9c12d33SAleksey Makarov }
110c9c12d33SAleksey Makarov 
111c9c12d33SAleksey Makarov int otx2_ptp_init(struct otx2_nic *pfvf)
112c9c12d33SAleksey Makarov {
113c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp_ptr;
114c9c12d33SAleksey Makarov 	struct cyclecounter *cc;
115c9c12d33SAleksey Makarov 	struct ptp_req *req;
116c9c12d33SAleksey Makarov 	int err;
117c9c12d33SAleksey Makarov 
118c9c12d33SAleksey Makarov 	mutex_lock(&pfvf->mbox.lock);
119c9c12d33SAleksey Makarov 	/* check if PTP block is available */
120c9c12d33SAleksey Makarov 	req = otx2_mbox_alloc_msg_ptp_op(&pfvf->mbox);
121c9c12d33SAleksey Makarov 	if (!req) {
122c9c12d33SAleksey Makarov 		mutex_unlock(&pfvf->mbox.lock);
123c9c12d33SAleksey Makarov 		return -ENOMEM;
124c9c12d33SAleksey Makarov 	}
125c9c12d33SAleksey Makarov 
126c9c12d33SAleksey Makarov 	req->op = PTP_OP_GET_CLOCK;
127c9c12d33SAleksey Makarov 
128c9c12d33SAleksey Makarov 	err = otx2_sync_mbox_msg(&pfvf->mbox);
129c9c12d33SAleksey Makarov 	if (err) {
130c9c12d33SAleksey Makarov 		mutex_unlock(&pfvf->mbox.lock);
131c9c12d33SAleksey Makarov 		return err;
132c9c12d33SAleksey Makarov 	}
133c9c12d33SAleksey Makarov 	mutex_unlock(&pfvf->mbox.lock);
134c9c12d33SAleksey Makarov 
135c9c12d33SAleksey Makarov 	ptp_ptr = kzalloc(sizeof(*ptp_ptr), GFP_KERNEL);
136c9c12d33SAleksey Makarov 	if (!ptp_ptr) {
137c9c12d33SAleksey Makarov 		err = -ENOMEM;
138c9c12d33SAleksey Makarov 		goto error;
139c9c12d33SAleksey Makarov 	}
140c9c12d33SAleksey Makarov 
141c9c12d33SAleksey Makarov 	ptp_ptr->nic = pfvf;
142c9c12d33SAleksey Makarov 
143c9c12d33SAleksey Makarov 	cc = &ptp_ptr->cycle_counter;
144c9c12d33SAleksey Makarov 	cc->read = ptp_cc_read;
145c9c12d33SAleksey Makarov 	cc->mask = CYCLECOUNTER_MASK(64);
146c9c12d33SAleksey Makarov 	cc->mult = 1;
147c9c12d33SAleksey Makarov 	cc->shift = 0;
148c9c12d33SAleksey Makarov 
149c9c12d33SAleksey Makarov 	timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter,
150c9c12d33SAleksey Makarov 			 ktime_to_ns(ktime_get_real()));
151c9c12d33SAleksey Makarov 
152c9c12d33SAleksey Makarov 	ptp_ptr->ptp_info = (struct ptp_clock_info) {
153c9c12d33SAleksey Makarov 		.owner          = THIS_MODULE,
154c9c12d33SAleksey Makarov 		.name           = "OcteonTX2 PTP",
155c9c12d33SAleksey Makarov 		.max_adj        = 1000000000ull,
156c9c12d33SAleksey Makarov 		.n_ext_ts       = 0,
157c9c12d33SAleksey Makarov 		.n_pins         = 0,
158c9c12d33SAleksey Makarov 		.pps            = 0,
159c9c12d33SAleksey Makarov 		.adjfine        = otx2_ptp_adjfine,
160c9c12d33SAleksey Makarov 		.adjtime        = otx2_ptp_adjtime,
161c9c12d33SAleksey Makarov 		.gettime64      = otx2_ptp_gettime,
162c9c12d33SAleksey Makarov 		.settime64      = otx2_ptp_settime,
163c9c12d33SAleksey Makarov 		.enable         = otx2_ptp_enable,
164c9c12d33SAleksey Makarov 	};
165c9c12d33SAleksey Makarov 
166c9c12d33SAleksey Makarov 	ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev);
167c9c12d33SAleksey Makarov 	if (IS_ERR_OR_NULL(ptp_ptr->ptp_clock)) {
168c9c12d33SAleksey Makarov 		err = ptp_ptr->ptp_clock ?
169c9c12d33SAleksey Makarov 		      PTR_ERR(ptp_ptr->ptp_clock) : -ENODEV;
170c9c12d33SAleksey Makarov 		kfree(ptp_ptr);
171c9c12d33SAleksey Makarov 		goto error;
172c9c12d33SAleksey Makarov 	}
173c9c12d33SAleksey Makarov 
174c9c12d33SAleksey Makarov 	pfvf->ptp = ptp_ptr;
175c9c12d33SAleksey Makarov 
176c9c12d33SAleksey Makarov error:
177c9c12d33SAleksey Makarov 	return err;
178c9c12d33SAleksey Makarov }
179c9c12d33SAleksey Makarov 
180c9c12d33SAleksey Makarov void otx2_ptp_destroy(struct otx2_nic *pfvf)
181c9c12d33SAleksey Makarov {
182c9c12d33SAleksey Makarov 	struct otx2_ptp *ptp = pfvf->ptp;
183c9c12d33SAleksey Makarov 
184c9c12d33SAleksey Makarov 	if (!ptp)
185c9c12d33SAleksey Makarov 		return;
186c9c12d33SAleksey Makarov 
187c9c12d33SAleksey Makarov 	ptp_clock_unregister(ptp->ptp_clock);
188c9c12d33SAleksey Makarov 	kfree(ptp);
189c9c12d33SAleksey Makarov 	pfvf->ptp = NULL;
190c9c12d33SAleksey Makarov }
191c9c12d33SAleksey Makarov 
192c9c12d33SAleksey Makarov int otx2_ptp_clock_index(struct otx2_nic *pfvf)
193c9c12d33SAleksey Makarov {
194c9c12d33SAleksey Makarov 	if (!pfvf->ptp)
195c9c12d33SAleksey Makarov 		return -ENODEV;
196c9c12d33SAleksey Makarov 
197c9c12d33SAleksey Makarov 	return ptp_clock_index(pfvf->ptp->ptp_clock);
198c9c12d33SAleksey Makarov }
199c9c12d33SAleksey Makarov 
200c9c12d33SAleksey Makarov int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns)
201c9c12d33SAleksey Makarov {
202c9c12d33SAleksey Makarov 	if (!pfvf->ptp)
203c9c12d33SAleksey Makarov 		return -ENODEV;
204c9c12d33SAleksey Makarov 
205c9c12d33SAleksey Makarov 	*tsns = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp);
206c9c12d33SAleksey Makarov 
207c9c12d33SAleksey Makarov 	return 0;
208c9c12d33SAleksey Makarov }
209