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