1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/device.h>
19#include <linux/err.h>
20#include <linux/io.h>
21#include <linux/irq.h>
22#include <linux/interrupt.h>
23#include <linux/slab.h>
24#include <linux/kernel.h>
25#include <linux/ptp_clock_kernel.h>
26#include <linux/platform_device.h>
27#include <linux/of_irq.h>
28#include "xilinx_tsn_timer.h"
29
30struct xlnx_ptp_timer {
31 struct device *dev;
32 void __iomem *baseaddr;
33 struct ptp_clock *ptp_clock;
34 struct ptp_clock_info ptp_clock_info;
35 spinlock_t reg_lock;
36 int irq;
37 int pps_enable;
38 int countpulse;
39};
40
41static void xlnx_tod_read(struct xlnx_ptp_timer *timer, struct timespec64 *ts)
42{
43 u32 sec, nsec;
44
45 nsec = in_be32(timer->baseaddr + XTIMER1588_CURRENT_RTC_NS);
46 sec = in_be32(timer->baseaddr + XTIMER1588_CURRENT_RTC_SEC_L);
47
48 ts->tv_sec = sec;
49 ts->tv_nsec = nsec;
50}
51
52static void xlnx_rtc_offset_write(struct xlnx_ptp_timer *timer,
53 const struct timespec64 *ts)
54{
55 pr_debug("%s: sec: %ld nsec: %ld\n", __func__, ts->tv_sec, ts->tv_nsec);
56
57 out_be32((timer->baseaddr + XTIMER1588_RTC_OFFSET_SEC_H), 0);
58 out_be32((timer->baseaddr + XTIMER1588_RTC_OFFSET_SEC_L),
59 (ts->tv_sec));
60 out_be32((timer->baseaddr + XTIMER1588_RTC_OFFSET_NS), ts->tv_nsec);
61}
62
63static void xlnx_rtc_offset_read(struct xlnx_ptp_timer *timer,
64 struct timespec64 *ts)
65{
66 ts->tv_sec = in_be32(timer->baseaddr + XTIMER1588_RTC_OFFSET_SEC_L);
67 ts->tv_nsec = in_be32(timer->baseaddr + XTIMER1588_RTC_OFFSET_NS);
68}
69
70
71
72static int xlnx_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
73{
74 struct xlnx_ptp_timer *timer = container_of(ptp, struct xlnx_ptp_timer,
75 ptp_clock_info);
76
77 int neg_adj = 0;
78 u64 freq;
79 u32 diff, incval;
80
81
82
83
84 incval = 0x800000;
85
86
87 if (ppb < 0) {
88 neg_adj = 1;
89 ppb = -ppb;
90 }
91
92 freq = incval;
93 freq *= ppb;
94 diff = div_u64(freq, 1000000000ULL);
95
96 pr_debug("%s: adj: %d ppb: %d\n", __func__, diff, ppb);
97
98 incval = neg_adj ? (incval - diff) : (incval + diff);
99 out_be32((timer->baseaddr + XTIMER1588_RTC_INCREMENT), incval);
100 return 0;
101}
102
103static int xlnx_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
104{
105 unsigned long flags;
106 struct xlnx_ptp_timer *timer = container_of(ptp, struct xlnx_ptp_timer,
107 ptp_clock_info);
108 struct timespec64 now, then = ns_to_timespec64(delta);
109
110 spin_lock_irqsave(&timer->reg_lock, flags);
111
112 xlnx_rtc_offset_read(timer, &now);
113
114 now = timespec64_add(now, then);
115
116 xlnx_rtc_offset_write(timer, (const struct timespec64 *)&now);
117 spin_unlock_irqrestore(&timer->reg_lock, flags);
118
119 return 0;
120}
121
122static int xlnx_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
123{
124 unsigned long flags;
125 struct xlnx_ptp_timer *timer = container_of(ptp, struct xlnx_ptp_timer,
126 ptp_clock_info);
127 spin_lock_irqsave(&timer->reg_lock, flags);
128
129 xlnx_tod_read(timer, ts);
130
131 spin_unlock_irqrestore(&timer->reg_lock, flags);
132 return 0;
133}
134
135
136
137
138
139
140
141
142
143
144
145
146static int xlnx_ptp_settime(struct ptp_clock_info *ptp,
147 const struct timespec64 *ts)
148{
149 struct xlnx_ptp_timer *timer = container_of(ptp, struct xlnx_ptp_timer,
150 ptp_clock_info);
151 struct timespec64 delta, tod;
152 struct timespec64 offset;
153 unsigned long flags;
154
155 spin_lock_irqsave(&timer->reg_lock, flags);
156
157
158 offset.tv_sec = 0;
159 offset.tv_nsec = 0;
160 xlnx_rtc_offset_write(timer, &offset);
161
162
163 xlnx_tod_read(timer, &tod);
164
165
166 delta = timespec64_sub(*ts, tod);
167
168
169 if (delta.tv_sec <= 0) {
170 delta.tv_sec = 0;
171 if (delta.tv_nsec < 0)
172 delta.tv_nsec = 0;
173 }
174
175 xlnx_rtc_offset_write(timer, &delta);
176 spin_unlock_irqrestore(&timer->reg_lock, flags);
177 return 0;
178}
179
180static int xlnx_ptp_enable(struct ptp_clock_info *ptp,
181 struct ptp_clock_request *rq, int on)
182{
183 struct xlnx_ptp_timer *timer = container_of(ptp, struct xlnx_ptp_timer,
184 ptp_clock_info);
185
186 switch (rq->type) {
187 case PTP_CLK_REQ_PPS:
188 timer->pps_enable = 1;
189 return 0;
190 default:
191 break;
192 }
193
194 return -EOPNOTSUPP;
195}
196
197static struct ptp_clock_info xlnx_ptp_clock_info = {
198 .owner = THIS_MODULE,
199 .name = "Xilinx Timer",
200 .max_adj = 999999999,
201 .n_ext_ts = 0,
202 .pps = 1,
203 .adjfreq = xlnx_ptp_adjfreq,
204 .adjtime = xlnx_ptp_adjtime,
205 .gettime64 = xlnx_ptp_gettime,
206 .settime64 = xlnx_ptp_settime,
207 .enable = xlnx_ptp_enable,
208};
209
210
211
212
213
214
215
216
217
218
219
220
221
222static irqreturn_t xlnx_ptp_timer_isr(int irq, void *priv)
223{
224 struct xlnx_ptp_timer *timer = (struct xlnx_ptp_timer *)priv;
225 struct ptp_clock_event event;
226
227 event.type = PTP_CLOCK_PPS;
228 ++timer->countpulse;
229 if (timer->countpulse >= PULSESIN1PPS) {
230 timer->countpulse = 0;
231 if ((timer->ptp_clock) && (timer->pps_enable))
232 ptp_clock_event(timer->ptp_clock, &event);
233 }
234 out_be32((timer->baseaddr + XTIMER1588_INTERRUPT),
235 (1 << XTIMER1588_INT_SHIFT));
236
237 return IRQ_HANDLED;
238}
239
240int axienet_ptp_timer_remove(void *priv)
241{
242 struct xlnx_ptp_timer *timer = (struct xlnx_ptp_timer *)priv;
243
244 free_irq(timer->irq, (void *)timer);
245
246 axienet_phc_index = -1;
247 if (timer->ptp_clock) {
248 ptp_clock_unregister(timer->ptp_clock);
249 timer->ptp_clock = NULL;
250 }
251 kfree(timer);
252 return 0;
253}
254
255int axienet_get_phc_index(void *priv)
256{
257 struct xlnx_ptp_timer *timer = (struct xlnx_ptp_timer *)priv;
258
259 if (timer->ptp_clock)
260 return ptp_clock_index(timer->ptp_clock);
261 else
262 return -1;
263}
264
265void *axienet_ptp_timer_probe(void __iomem *base, struct platform_device *pdev)
266{
267 struct xlnx_ptp_timer *timer;
268 struct timespec64 ts;
269 int err = 0;
270
271 timer = kzalloc(sizeof(*timer), GFP_KERNEL);
272 if (!timer)
273 return NULL;
274
275 timer->baseaddr = base;
276
277 timer->irq = platform_get_irq_byname(pdev, "interrupt_ptp_timer");
278
279 if (timer->irq < 0) {
280 timer->irq = platform_get_irq_byname(pdev, "rtc_irq");
281 if (timer->irq > 0) {
282 pr_err("ptp timer interrupt name 'rtc_irq' is"
283 "deprecated\n");
284 } else {
285 pr_err("ptp timer interrupt not found\n");
286 kfree(timer);
287 return NULL;
288 }
289 }
290 spin_lock_init(&timer->reg_lock);
291
292 timer->ptp_clock_info = xlnx_ptp_clock_info;
293
294 timer->ptp_clock = ptp_clock_register(&timer->ptp_clock_info,
295 &pdev->dev);
296
297 if (IS_ERR(timer->ptp_clock)) {
298 err = PTR_ERR(timer->ptp_clock);
299 pr_debug("Failed to register ptp clock\n");
300 goto out;
301 }
302
303 axienet_phc_index = ptp_clock_index(timer->ptp_clock);
304
305 ts = ktime_to_timespec64(ktime_get_real());
306
307 xlnx_ptp_settime(&timer->ptp_clock_info, &ts);
308
309
310 err = request_irq(timer->irq,
311 xlnx_ptp_timer_isr,
312 0,
313 "ptp_rtc",
314 (void *)timer);
315 if (err)
316 goto err_irq;
317
318 return timer;
319
320err_irq:
321 ptp_clock_unregister(timer->ptp_clock);
322out:
323 timer->ptp_clock = NULL;
324 return NULL;
325}
326