2 * TI Common Platform Time Sync
4 * Copyright (C) 2012 Richard Cochran <richardcochran@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <linux/err.h>
22 #include <linux/hrtimer.h>
23 #include <linux/module.h>
24 #include <linux/net_tstamp.h>
25 #include <linux/ptp_classify.h>
26 #include <linux/time.h>
27 #include <linux/uaccess.h>
28 #include <linux/workqueue.h>
29 #include <linux/if_ether.h>
30 #include <linux/if_vlan.h>
36 #define cpts_read32(c, r) __raw_readl(&c->reg->r)
37 #define cpts_write32(c, v, r) __raw_writel(v, &c->reg->r)
39 static int event_expired(struct cpts_event
*event
)
41 return time_after(jiffies
, event
->tmo
);
44 static int event_type(struct cpts_event
*event
)
46 return (event
->high
>> EVENT_TYPE_SHIFT
) & EVENT_TYPE_MASK
;
49 static int cpts_fifo_pop(struct cpts
*cpts
, u32
*high
, u32
*low
)
51 u32 r
= cpts_read32(cpts
, intstat_raw
);
53 if (r
& TS_PEND_RAW
) {
54 *high
= cpts_read32(cpts
, event_high
);
55 *low
= cpts_read32(cpts
, event_low
);
56 cpts_write32(cpts
, EVENT_POP
, event_pop
);
63 * Returns zero if matching event type was found.
65 static int cpts_fifo_read(struct cpts
*cpts
, int match
)
69 struct cpts_event
*event
;
71 for (i
= 0; i
< CPTS_FIFO_DEPTH
; i
++) {
72 if (cpts_fifo_pop(cpts
, &hi
, &lo
))
74 if (list_empty(&cpts
->pool
)) {
75 pr_err("cpts: event pool is empty\n");
78 event
= list_first_entry(&cpts
->pool
, struct cpts_event
, list
);
79 event
->tmo
= jiffies
+ 2;
82 type
= event_type(event
);
87 list_del_init(&event
->list
);
88 list_add_tail(&event
->list
, &cpts
->events
);
95 pr_err("cpts: unknown event type\n");
101 return type
== match
? 0 : -1;
104 static cycle_t
cpts_systim_read(const struct cyclecounter
*cc
)
107 struct cpts_event
*event
;
108 struct list_head
*this, *next
;
109 struct cpts
*cpts
= container_of(cc
, struct cpts
, cc
);
111 cpts_write32(cpts
, TS_PUSH
, ts_push
);
112 if (cpts_fifo_read(cpts
, CPTS_EV_PUSH
))
113 pr_err("cpts: unable to obtain a time stamp\n");
115 list_for_each_safe(this, next
, &cpts
->events
) {
116 event
= list_entry(this, struct cpts_event
, list
);
117 if (event_type(event
) == CPTS_EV_PUSH
) {
118 list_del_init(&event
->list
);
119 list_add(&event
->list
, &cpts
->pool
);
128 /* PTP clock operations */
130 static int cpts_ptp_adjfreq(struct ptp_clock_info
*ptp
, s32 ppb
)
136 struct cpts
*cpts
= container_of(ptp
, struct cpts
, info
);
142 mult
= cpts
->cc_mult
;
145 diff
= div_u64(adj
, 1000000000ULL);
147 spin_lock_irqsave(&cpts
->lock
, flags
);
149 timecounter_read(&cpts
->tc
);
151 cpts
->cc
.mult
= neg_adj
? mult
- diff
: mult
+ diff
;
153 spin_unlock_irqrestore(&cpts
->lock
, flags
);
158 static int cpts_ptp_adjtime(struct ptp_clock_info
*ptp
, s64 delta
)
161 struct cpts
*cpts
= container_of(ptp
, struct cpts
, info
);
163 spin_lock_irqsave(&cpts
->lock
, flags
);
164 timecounter_adjtime(&cpts
->tc
, delta
);
165 spin_unlock_irqrestore(&cpts
->lock
, flags
);
170 static int cpts_ptp_gettime(struct ptp_clock_info
*ptp
, struct timespec64
*ts
)
174 struct cpts
*cpts
= container_of(ptp
, struct cpts
, info
);
176 spin_lock_irqsave(&cpts
->lock
, flags
);
177 ns
= timecounter_read(&cpts
->tc
);
178 spin_unlock_irqrestore(&cpts
->lock
, flags
);
180 *ts
= ns_to_timespec64(ns
);
185 static int cpts_ptp_settime(struct ptp_clock_info
*ptp
,
186 const struct timespec64
*ts
)
190 struct cpts
*cpts
= container_of(ptp
, struct cpts
, info
);
192 ns
= timespec64_to_ns(ts
);
194 spin_lock_irqsave(&cpts
->lock
, flags
);
195 timecounter_init(&cpts
->tc
, &cpts
->cc
, ns
);
196 spin_unlock_irqrestore(&cpts
->lock
, flags
);
201 static int cpts_ptp_enable(struct ptp_clock_info
*ptp
,
202 struct ptp_clock_request
*rq
, int on
)
207 static struct ptp_clock_info cpts_info
= {
208 .owner
= THIS_MODULE
,
209 .name
= "CTPS timer",
214 .adjfreq
= cpts_ptp_adjfreq
,
215 .adjtime
= cpts_ptp_adjtime
,
216 .gettime64
= cpts_ptp_gettime
,
217 .settime64
= cpts_ptp_settime
,
218 .enable
= cpts_ptp_enable
,
221 static void cpts_overflow_check(struct work_struct
*work
)
223 struct timespec64 ts
;
224 struct cpts
*cpts
= container_of(work
, struct cpts
, overflow_work
.work
);
226 cpts_write32(cpts
, CPTS_EN
, control
);
227 cpts_write32(cpts
, TS_PEND_EN
, int_enable
);
228 cpts_ptp_gettime(&cpts
->info
, &ts
);
229 pr_debug("cpts overflow check at %lld.%09lu\n", ts
.tv_sec
, ts
.tv_nsec
);
230 schedule_delayed_work(&cpts
->overflow_work
, CPTS_OVERFLOW_PERIOD
);
233 static void cpts_clk_init(struct device
*dev
, struct cpts
*cpts
)
235 cpts
->refclk
= devm_clk_get(dev
, "cpts");
236 if (IS_ERR(cpts
->refclk
)) {
237 dev_err(dev
, "Failed to get cpts refclk\n");
241 clk_prepare_enable(cpts
->refclk
);
244 static void cpts_clk_release(struct cpts
*cpts
)
246 clk_disable(cpts
->refclk
);
249 static int cpts_match(struct sk_buff
*skb
, unsigned int ptp_class
,
250 u16 ts_seqid
, u8 ts_msgtype
)
253 unsigned int offset
= 0;
254 u8
*msgtype
, *data
= skb
->data
;
256 if (ptp_class
& PTP_CLASS_VLAN
)
259 switch (ptp_class
& PTP_CLASS_PMASK
) {
261 offset
+= ETH_HLEN
+ IPV4_HLEN(data
+ offset
) + UDP_HLEN
;
264 offset
+= ETH_HLEN
+ IP6_HLEN
+ UDP_HLEN
;
273 if (skb
->len
+ ETH_HLEN
< offset
+ OFF_PTP_SEQUENCE_ID
+ sizeof(*seqid
))
276 if (unlikely(ptp_class
& PTP_CLASS_V1
))
277 msgtype
= data
+ offset
+ OFF_PTP_CONTROL
;
279 msgtype
= data
+ offset
;
281 seqid
= (u16
*)(data
+ offset
+ OFF_PTP_SEQUENCE_ID
);
283 return (ts_msgtype
== (*msgtype
& 0xf) && ts_seqid
== ntohs(*seqid
));
286 static u64
cpts_find_ts(struct cpts
*cpts
, struct sk_buff
*skb
, int ev_type
)
289 struct cpts_event
*event
;
290 struct list_head
*this, *next
;
291 unsigned int class = ptp_classify_raw(skb
);
296 if (class == PTP_CLASS_NONE
)
299 spin_lock_irqsave(&cpts
->lock
, flags
);
300 cpts_fifo_read(cpts
, CPTS_EV_PUSH
);
301 list_for_each_safe(this, next
, &cpts
->events
) {
302 event
= list_entry(this, struct cpts_event
, list
);
303 if (event_expired(event
)) {
304 list_del_init(&event
->list
);
305 list_add(&event
->list
, &cpts
->pool
);
308 mtype
= (event
->high
>> MESSAGE_TYPE_SHIFT
) & MESSAGE_TYPE_MASK
;
309 seqid
= (event
->high
>> SEQUENCE_ID_SHIFT
) & SEQUENCE_ID_MASK
;
310 if (ev_type
== event_type(event
) &&
311 cpts_match(skb
, class, seqid
, mtype
)) {
312 ns
= timecounter_cyc2time(&cpts
->tc
, event
->low
);
313 list_del_init(&event
->list
);
314 list_add(&event
->list
, &cpts
->pool
);
318 spin_unlock_irqrestore(&cpts
->lock
, flags
);
323 void cpts_rx_timestamp(struct cpts
*cpts
, struct sk_buff
*skb
)
326 struct skb_shared_hwtstamps
*ssh
;
328 if (!cpts
->rx_enable
)
330 ns
= cpts_find_ts(cpts
, skb
, CPTS_EV_RX
);
333 ssh
= skb_hwtstamps(skb
);
334 memset(ssh
, 0, sizeof(*ssh
));
335 ssh
->hwtstamp
= ns_to_ktime(ns
);
338 void cpts_tx_timestamp(struct cpts
*cpts
, struct sk_buff
*skb
)
341 struct skb_shared_hwtstamps ssh
;
343 if (!(skb_shinfo(skb
)->tx_flags
& SKBTX_IN_PROGRESS
))
345 ns
= cpts_find_ts(cpts
, skb
, CPTS_EV_TX
);
348 memset(&ssh
, 0, sizeof(ssh
));
349 ssh
.hwtstamp
= ns_to_ktime(ns
);
350 skb_tstamp_tx(skb
, &ssh
);
353 #endif /*CONFIG_TI_CPTS*/
355 int cpts_register(struct device
*dev
, struct cpts
*cpts
,
358 #ifdef CONFIG_TI_CPTS
362 cpts
->info
= cpts_info
;
363 cpts
->clock
= ptp_clock_register(&cpts
->info
, dev
);
364 if (IS_ERR(cpts
->clock
)) {
365 err
= PTR_ERR(cpts
->clock
);
369 spin_lock_init(&cpts
->lock
);
371 cpts
->cc
.read
= cpts_systim_read
;
372 cpts
->cc
.mask
= CLOCKSOURCE_MASK(32);
373 cpts
->cc_mult
= mult
;
374 cpts
->cc
.mult
= mult
;
375 cpts
->cc
.shift
= shift
;
377 INIT_LIST_HEAD(&cpts
->events
);
378 INIT_LIST_HEAD(&cpts
->pool
);
379 for (i
= 0; i
< CPTS_MAX_EVENTS
; i
++)
380 list_add(&cpts
->pool_data
[i
].list
, &cpts
->pool
);
382 cpts_clk_init(dev
, cpts
);
383 cpts_write32(cpts
, CPTS_EN
, control
);
384 cpts_write32(cpts
, TS_PEND_EN
, int_enable
);
386 spin_lock_irqsave(&cpts
->lock
, flags
);
387 timecounter_init(&cpts
->tc
, &cpts
->cc
, ktime_to_ns(ktime_get_real()));
388 spin_unlock_irqrestore(&cpts
->lock
, flags
);
390 INIT_DELAYED_WORK(&cpts
->overflow_work
, cpts_overflow_check
);
391 schedule_delayed_work(&cpts
->overflow_work
, CPTS_OVERFLOW_PERIOD
);
393 cpts
->phc_index
= ptp_clock_index(cpts
->clock
);
398 void cpts_unregister(struct cpts
*cpts
)
400 #ifdef CONFIG_TI_CPTS
402 ptp_clock_unregister(cpts
->clock
);
403 cancel_delayed_work_sync(&cpts
->overflow_work
);
406 cpts_clk_release(cpts
);