16b1baefeSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c1167ceeSYang Shen /*
3ab91f0a9SRafal Ozieblo * 1588 PTP support for Cadence GEM device.
4ab91f0a9SRafal Ozieblo *
55d75c043SAlexander A. Klimov * Copyright (C) 2017 Cadence Design Systems - https://www.cadence.com
6ab91f0a9SRafal Ozieblo *
7ab91f0a9SRafal Ozieblo * Authors: Rafal Ozieblo <rafalo@cadence.com>
8ab91f0a9SRafal Ozieblo * Bartosz Folta <bfolta@cadence.com>
9ab91f0a9SRafal Ozieblo */
10ab91f0a9SRafal Ozieblo #include <linux/kernel.h>
11ab91f0a9SRafal Ozieblo #include <linux/types.h>
12ab91f0a9SRafal Ozieblo #include <linux/clk.h>
13ab91f0a9SRafal Ozieblo #include <linux/device.h>
14ab91f0a9SRafal Ozieblo #include <linux/etherdevice.h>
15ab91f0a9SRafal Ozieblo #include <linux/platform_device.h>
16ab91f0a9SRafal Ozieblo #include <linux/time64.h>
17ab91f0a9SRafal Ozieblo #include <linux/ptp_classify.h>
18ab91f0a9SRafal Ozieblo #include <linux/if_ether.h>
19ab91f0a9SRafal Ozieblo #include <linux/if_vlan.h>
20ab91f0a9SRafal Ozieblo #include <linux/net_tstamp.h>
21ab91f0a9SRafal Ozieblo #include <linux/circ_buf.h>
22ab91f0a9SRafal Ozieblo #include <linux/spinlock.h>
23ab91f0a9SRafal Ozieblo
24ab91f0a9SRafal Ozieblo #include "macb.h"
25ab91f0a9SRafal Ozieblo
26ab91f0a9SRafal Ozieblo #define GEM_PTP_TIMER_NAME "gem-ptp-timer"
27ab91f0a9SRafal Ozieblo
macb_ptp_desc(struct macb * bp,struct macb_dma_desc * desc)28ab91f0a9SRafal Ozieblo static struct macb_dma_desc_ptp *macb_ptp_desc(struct macb *bp,
29ab91f0a9SRafal Ozieblo struct macb_dma_desc *desc)
30ab91f0a9SRafal Ozieblo {
31ab91f0a9SRafal Ozieblo if (bp->hw_dma_cap == HW_DMA_CAP_PTP)
32ab91f0a9SRafal Ozieblo return (struct macb_dma_desc_ptp *)
33ab91f0a9SRafal Ozieblo ((u8 *)desc + sizeof(struct macb_dma_desc));
34ab91f0a9SRafal Ozieblo if (bp->hw_dma_cap == HW_DMA_CAP_64B_PTP)
35ab91f0a9SRafal Ozieblo return (struct macb_dma_desc_ptp *)
36ab91f0a9SRafal Ozieblo ((u8 *)desc + sizeof(struct macb_dma_desc)
37ab91f0a9SRafal Ozieblo + sizeof(struct macb_dma_desc_64));
38ab91f0a9SRafal Ozieblo return NULL;
39ab91f0a9SRafal Ozieblo }
40ab91f0a9SRafal Ozieblo
gem_tsu_get_time(struct ptp_clock_info * ptp,struct timespec64 * ts,struct ptp_system_timestamp * sts)41e51bb5c2SLars-Peter Clausen static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts,
42e51bb5c2SLars-Peter Clausen struct ptp_system_timestamp *sts)
43ab91f0a9SRafal Ozieblo {
44ab91f0a9SRafal Ozieblo struct macb *bp = container_of(ptp, struct macb, ptp_clock_info);
45ab91f0a9SRafal Ozieblo unsigned long flags;
46ab91f0a9SRafal Ozieblo long first, second;
47ab91f0a9SRafal Ozieblo u32 secl, sech;
48ab91f0a9SRafal Ozieblo
49ab91f0a9SRafal Ozieblo spin_lock_irqsave(&bp->tsu_clk_lock, flags);
50e51bb5c2SLars-Peter Clausen ptp_read_system_prets(sts);
51ab91f0a9SRafal Ozieblo first = gem_readl(bp, TN);
52e51bb5c2SLars-Peter Clausen ptp_read_system_postts(sts);
53ab91f0a9SRafal Ozieblo secl = gem_readl(bp, TSL);
54ab91f0a9SRafal Ozieblo sech = gem_readl(bp, TSH);
55ab91f0a9SRafal Ozieblo second = gem_readl(bp, TN);
56ab91f0a9SRafal Ozieblo
57ab91f0a9SRafal Ozieblo /* test for nsec rollover */
58ab91f0a9SRafal Ozieblo if (first > second) {
59ab91f0a9SRafal Ozieblo /* if so, use later read & re-read seconds
60ab91f0a9SRafal Ozieblo * (assume all done within 1s)
61ab91f0a9SRafal Ozieblo */
62e51bb5c2SLars-Peter Clausen ptp_read_system_prets(sts);
63ab91f0a9SRafal Ozieblo ts->tv_nsec = gem_readl(bp, TN);
64e51bb5c2SLars-Peter Clausen ptp_read_system_postts(sts);
65ab91f0a9SRafal Ozieblo secl = gem_readl(bp, TSL);
66ab91f0a9SRafal Ozieblo sech = gem_readl(bp, TSH);
67ab91f0a9SRafal Ozieblo } else {
68ab91f0a9SRafal Ozieblo ts->tv_nsec = first;
69ab91f0a9SRafal Ozieblo }
70ab91f0a9SRafal Ozieblo
71ab91f0a9SRafal Ozieblo spin_unlock_irqrestore(&bp->tsu_clk_lock, flags);
72ab91f0a9SRafal Ozieblo ts->tv_sec = (((u64)sech << GEM_TSL_SIZE) | secl)
73ab91f0a9SRafal Ozieblo & TSU_SEC_MAX_VAL;
74ab91f0a9SRafal Ozieblo return 0;
75ab91f0a9SRafal Ozieblo }
76ab91f0a9SRafal Ozieblo
gem_tsu_set_time(struct ptp_clock_info * ptp,const struct timespec64 * ts)77ab91f0a9SRafal Ozieblo static int gem_tsu_set_time(struct ptp_clock_info *ptp,
78ab91f0a9SRafal Ozieblo const struct timespec64 *ts)
79ab91f0a9SRafal Ozieblo {
80ab91f0a9SRafal Ozieblo struct macb *bp = container_of(ptp, struct macb, ptp_clock_info);
81ab91f0a9SRafal Ozieblo unsigned long flags;
82ab91f0a9SRafal Ozieblo u32 ns, sech, secl;
83ab91f0a9SRafal Ozieblo
84ab91f0a9SRafal Ozieblo secl = (u32)ts->tv_sec;
85ab91f0a9SRafal Ozieblo sech = (ts->tv_sec >> GEM_TSL_SIZE) & ((1 << GEM_TSH_SIZE) - 1);
86ab91f0a9SRafal Ozieblo ns = ts->tv_nsec;
87ab91f0a9SRafal Ozieblo
88ab91f0a9SRafal Ozieblo spin_lock_irqsave(&bp->tsu_clk_lock, flags);
89ab91f0a9SRafal Ozieblo
90ab91f0a9SRafal Ozieblo /* TSH doesn't latch the time and no atomicity! */
91ab91f0a9SRafal Ozieblo gem_writel(bp, TN, 0); /* clear to avoid overflow */
92ab91f0a9SRafal Ozieblo gem_writel(bp, TSH, sech);
93ab91f0a9SRafal Ozieblo /* write lower bits 2nd, for synchronized secs update */
94ab91f0a9SRafal Ozieblo gem_writel(bp, TSL, secl);
95ab91f0a9SRafal Ozieblo gem_writel(bp, TN, ns);
96ab91f0a9SRafal Ozieblo
97ab91f0a9SRafal Ozieblo spin_unlock_irqrestore(&bp->tsu_clk_lock, flags);
98ab91f0a9SRafal Ozieblo
99ab91f0a9SRafal Ozieblo return 0;
100ab91f0a9SRafal Ozieblo }
101ab91f0a9SRafal Ozieblo
gem_tsu_incr_set(struct macb * bp,struct tsu_incr * incr_spec)102ab91f0a9SRafal Ozieblo static int gem_tsu_incr_set(struct macb *bp, struct tsu_incr *incr_spec)
103ab91f0a9SRafal Ozieblo {
104ab91f0a9SRafal Ozieblo unsigned long flags;
105ab91f0a9SRafal Ozieblo
106ab91f0a9SRafal Ozieblo /* tsu_timer_incr register must be written after
107ab91f0a9SRafal Ozieblo * the tsu_timer_incr_sub_ns register and the write operation
108ab91f0a9SRafal Ozieblo * will cause the value written to the tsu_timer_incr_sub_ns register
109ab91f0a9SRafal Ozieblo * to take effect.
110ab91f0a9SRafal Ozieblo */
111ab91f0a9SRafal Ozieblo spin_lock_irqsave(&bp->tsu_clk_lock, flags);
1127ad342bcSHarini Katakam /* RegBit[15:0] = Subns[23:8]; RegBit[31:24] = Subns[7:0] */
1137ad342bcSHarini Katakam gem_writel(bp, TISUBN, GEM_BF(SUBNSINCRL, incr_spec->sub_ns) |
1147ad342bcSHarini Katakam GEM_BF(SUBNSINCRH, (incr_spec->sub_ns >>
1157ad342bcSHarini Katakam GEM_SUBNSINCRL_SIZE)));
116ab91f0a9SRafal Ozieblo gem_writel(bp, TI, GEM_BF(NSINCR, incr_spec->ns));
117ab91f0a9SRafal Ozieblo spin_unlock_irqrestore(&bp->tsu_clk_lock, flags);
118ab91f0a9SRafal Ozieblo
119ab91f0a9SRafal Ozieblo return 0;
120ab91f0a9SRafal Ozieblo }
121ab91f0a9SRafal Ozieblo
gem_ptp_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)122ab91f0a9SRafal Ozieblo static int gem_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
123ab91f0a9SRafal Ozieblo {
124ab91f0a9SRafal Ozieblo struct macb *bp = container_of(ptp, struct macb, ptp_clock_info);
125ab91f0a9SRafal Ozieblo struct tsu_incr incr_spec;
126ab91f0a9SRafal Ozieblo bool neg_adj = false;
127ab91f0a9SRafal Ozieblo u32 word;
128ab91f0a9SRafal Ozieblo u64 adj;
129ab91f0a9SRafal Ozieblo
130ab91f0a9SRafal Ozieblo if (scaled_ppm < 0) {
131ab91f0a9SRafal Ozieblo neg_adj = true;
132ab91f0a9SRafal Ozieblo scaled_ppm = -scaled_ppm;
133ab91f0a9SRafal Ozieblo }
134ab91f0a9SRafal Ozieblo
135ab91f0a9SRafal Ozieblo /* Adjustment is relative to base frequency */
136ab91f0a9SRafal Ozieblo incr_spec.sub_ns = bp->tsu_incr.sub_ns;
137ab91f0a9SRafal Ozieblo incr_spec.ns = bp->tsu_incr.ns;
138ab91f0a9SRafal Ozieblo
139ab91f0a9SRafal Ozieblo /* scaling: unused(8bit) | ns(8bit) | fractions(16bit) */
140ab91f0a9SRafal Ozieblo word = ((u64)incr_spec.ns << GEM_SUBNSINCR_SIZE) + incr_spec.sub_ns;
141ab91f0a9SRafal Ozieblo adj = (u64)scaled_ppm * word;
142ab91f0a9SRafal Ozieblo /* Divide with rounding, equivalent to floating dividing:
143ab91f0a9SRafal Ozieblo * (temp / USEC_PER_SEC) + 0.5
144ab91f0a9SRafal Ozieblo */
145ab91f0a9SRafal Ozieblo adj += (USEC_PER_SEC >> 1);
146a8ee4dc1SHarini Katakam adj >>= PPM_FRACTION; /* remove fractions */
147ab91f0a9SRafal Ozieblo adj = div_u64(adj, USEC_PER_SEC);
148ab91f0a9SRafal Ozieblo adj = neg_adj ? (word - adj) : (word + adj);
149ab91f0a9SRafal Ozieblo
150ab91f0a9SRafal Ozieblo incr_spec.ns = (adj >> GEM_SUBNSINCR_SIZE)
151ab91f0a9SRafal Ozieblo & ((1 << GEM_NSINCR_SIZE) - 1);
152ab91f0a9SRafal Ozieblo incr_spec.sub_ns = adj & ((1 << GEM_SUBNSINCR_SIZE) - 1);
153ab91f0a9SRafal Ozieblo gem_tsu_incr_set(bp, &incr_spec);
154ab91f0a9SRafal Ozieblo return 0;
155ab91f0a9SRafal Ozieblo }
156ab91f0a9SRafal Ozieblo
gem_ptp_adjtime(struct ptp_clock_info * ptp,s64 delta)157ab91f0a9SRafal Ozieblo static int gem_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
158ab91f0a9SRafal Ozieblo {
159ab91f0a9SRafal Ozieblo struct macb *bp = container_of(ptp, struct macb, ptp_clock_info);
160ab91f0a9SRafal Ozieblo struct timespec64 now, then = ns_to_timespec64(delta);
161ab91f0a9SRafal Ozieblo u32 adj, sign = 0;
162ab91f0a9SRafal Ozieblo
163ab91f0a9SRafal Ozieblo if (delta < 0) {
164ab91f0a9SRafal Ozieblo sign = 1;
165ab91f0a9SRafal Ozieblo delta = -delta;
166ab91f0a9SRafal Ozieblo }
167ab91f0a9SRafal Ozieblo
168ab91f0a9SRafal Ozieblo if (delta > TSU_NSEC_MAX_VAL) {
169e51bb5c2SLars-Peter Clausen gem_tsu_get_time(&bp->ptp_clock_info, &now, NULL);
170ab91f0a9SRafal Ozieblo now = timespec64_add(now, then);
171ab91f0a9SRafal Ozieblo
172ab91f0a9SRafal Ozieblo gem_tsu_set_time(&bp->ptp_clock_info,
173ab91f0a9SRafal Ozieblo (const struct timespec64 *)&now);
174ab91f0a9SRafal Ozieblo } else {
175ab91f0a9SRafal Ozieblo adj = (sign << GEM_ADDSUB_OFFSET) | delta;
176ab91f0a9SRafal Ozieblo
177ab91f0a9SRafal Ozieblo gem_writel(bp, TA, adj);
178ab91f0a9SRafal Ozieblo }
179ab91f0a9SRafal Ozieblo
180ab91f0a9SRafal Ozieblo return 0;
181ab91f0a9SRafal Ozieblo }
182ab91f0a9SRafal Ozieblo
gem_ptp_enable(struct ptp_clock_info * ptp,struct ptp_clock_request * rq,int on)183ab91f0a9SRafal Ozieblo static int gem_ptp_enable(struct ptp_clock_info *ptp,
184ab91f0a9SRafal Ozieblo struct ptp_clock_request *rq, int on)
185ab91f0a9SRafal Ozieblo {
186ab91f0a9SRafal Ozieblo return -EOPNOTSUPP;
187ab91f0a9SRafal Ozieblo }
188ab91f0a9SRafal Ozieblo
189b6d08bd8SBhumika Goyal static const struct ptp_clock_info gem_ptp_caps_template = {
190ab91f0a9SRafal Ozieblo .owner = THIS_MODULE,
191ab91f0a9SRafal Ozieblo .name = GEM_PTP_TIMER_NAME,
192ab91f0a9SRafal Ozieblo .max_adj = 0,
193ab91f0a9SRafal Ozieblo .n_alarm = 0,
194ab91f0a9SRafal Ozieblo .n_ext_ts = 0,
195ab91f0a9SRafal Ozieblo .n_per_out = 0,
196ab91f0a9SRafal Ozieblo .n_pins = 0,
197ab91f0a9SRafal Ozieblo .pps = 1,
198ab91f0a9SRafal Ozieblo .adjfine = gem_ptp_adjfine,
199ab91f0a9SRafal Ozieblo .adjtime = gem_ptp_adjtime,
200e51bb5c2SLars-Peter Clausen .gettimex64 = gem_tsu_get_time,
201ab91f0a9SRafal Ozieblo .settime64 = gem_tsu_set_time,
202ab91f0a9SRafal Ozieblo .enable = gem_ptp_enable,
203ab91f0a9SRafal Ozieblo };
204ab91f0a9SRafal Ozieblo
gem_ptp_init_timer(struct macb * bp)205ab91f0a9SRafal Ozieblo static void gem_ptp_init_timer(struct macb *bp)
206ab91f0a9SRafal Ozieblo {
207ab91f0a9SRafal Ozieblo u32 rem = 0;
208ab91f0a9SRafal Ozieblo u64 adj;
209ab91f0a9SRafal Ozieblo
210ab91f0a9SRafal Ozieblo bp->tsu_incr.ns = div_u64_rem(NSEC_PER_SEC, bp->tsu_rate, &rem);
211ab91f0a9SRafal Ozieblo if (rem) {
212ab91f0a9SRafal Ozieblo adj = rem;
213ab91f0a9SRafal Ozieblo adj <<= GEM_SUBNSINCR_SIZE;
214ab91f0a9SRafal Ozieblo bp->tsu_incr.sub_ns = div_u64(adj, bp->tsu_rate);
215ab91f0a9SRafal Ozieblo } else {
216ab91f0a9SRafal Ozieblo bp->tsu_incr.sub_ns = 0;
217ab91f0a9SRafal Ozieblo }
218ab91f0a9SRafal Ozieblo }
219ab91f0a9SRafal Ozieblo
gem_ptp_init_tsu(struct macb * bp)220ab91f0a9SRafal Ozieblo static void gem_ptp_init_tsu(struct macb *bp)
221ab91f0a9SRafal Ozieblo {
222ab91f0a9SRafal Ozieblo struct timespec64 ts;
223ab91f0a9SRafal Ozieblo
224ab91f0a9SRafal Ozieblo /* 1. get current system time */
225ab91f0a9SRafal Ozieblo ts = ns_to_timespec64(ktime_to_ns(ktime_get_real()));
226ab91f0a9SRafal Ozieblo
227ab91f0a9SRafal Ozieblo /* 2. set ptp timer */
228ab91f0a9SRafal Ozieblo gem_tsu_set_time(&bp->ptp_clock_info, &ts);
229ab91f0a9SRafal Ozieblo
230ab91f0a9SRafal Ozieblo /* 3. set PTP timer increment value to BASE_INCREMENT */
231ab91f0a9SRafal Ozieblo gem_tsu_incr_set(bp, &bp->tsu_incr);
232ab91f0a9SRafal Ozieblo
233ab91f0a9SRafal Ozieblo gem_writel(bp, TA, 0);
234ab91f0a9SRafal Ozieblo }
235ab91f0a9SRafal Ozieblo
gem_ptp_clear_timer(struct macb * bp)236ab91f0a9SRafal Ozieblo static void gem_ptp_clear_timer(struct macb *bp)
237ab91f0a9SRafal Ozieblo {
238ab91f0a9SRafal Ozieblo bp->tsu_incr.sub_ns = 0;
239ab91f0a9SRafal Ozieblo bp->tsu_incr.ns = 0;
240ab91f0a9SRafal Ozieblo
241ab91f0a9SRafal Ozieblo gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, 0));
242ab91f0a9SRafal Ozieblo gem_writel(bp, TI, GEM_BF(NSINCR, 0));
243ab91f0a9SRafal Ozieblo gem_writel(bp, TA, 0);
244ab91f0a9SRafal Ozieblo }
245ab91f0a9SRafal Ozieblo
gem_hw_timestamp(struct macb * bp,u32 dma_desc_ts_1,u32 dma_desc_ts_2,struct timespec64 * ts)246ab91f0a9SRafal Ozieblo static int gem_hw_timestamp(struct macb *bp, u32 dma_desc_ts_1,
247ab91f0a9SRafal Ozieblo u32 dma_desc_ts_2, struct timespec64 *ts)
248ab91f0a9SRafal Ozieblo {
249ab91f0a9SRafal Ozieblo struct timespec64 tsu;
250ab91f0a9SRafal Ozieblo
251ab91f0a9SRafal Ozieblo ts->tv_sec = (GEM_BFEXT(DMA_SECH, dma_desc_ts_2) << GEM_DMA_SECL_SIZE) |
252ab91f0a9SRafal Ozieblo GEM_BFEXT(DMA_SECL, dma_desc_ts_1);
253ab91f0a9SRafal Ozieblo ts->tv_nsec = GEM_BFEXT(DMA_NSEC, dma_desc_ts_1);
254ab91f0a9SRafal Ozieblo
255ab91f0a9SRafal Ozieblo /* TSU overlapping workaround
256ab91f0a9SRafal Ozieblo * The timestamp only contains lower few bits of seconds,
257ab91f0a9SRafal Ozieblo * so add value from 1588 timer
258ab91f0a9SRafal Ozieblo */
259e51bb5c2SLars-Peter Clausen gem_tsu_get_time(&bp->ptp_clock_info, &tsu, NULL);
260ab91f0a9SRafal Ozieblo
261*8c0d0fe0SHarini Katakam ts->tv_sec |= ((~GEM_DMA_SEC_MASK) & tsu.tv_sec);
262*8c0d0fe0SHarini Katakam
263ab91f0a9SRafal Ozieblo /* If the top bit is set in the timestamp,
264ab91f0a9SRafal Ozieblo * but not in 1588 timer, it has rolled over,
265ab91f0a9SRafal Ozieblo * so subtract max size
266ab91f0a9SRafal Ozieblo */
267ab91f0a9SRafal Ozieblo if ((ts->tv_sec & (GEM_DMA_SEC_TOP >> 1)) &&
268ab91f0a9SRafal Ozieblo !(tsu.tv_sec & (GEM_DMA_SEC_TOP >> 1)))
269ab91f0a9SRafal Ozieblo ts->tv_sec -= GEM_DMA_SEC_TOP;
270ab91f0a9SRafal Ozieblo
271ab91f0a9SRafal Ozieblo return 0;
272ab91f0a9SRafal Ozieblo }
273ab91f0a9SRafal Ozieblo
gem_ptp_rxstamp(struct macb * bp,struct sk_buff * skb,struct macb_dma_desc * desc)274ab91f0a9SRafal Ozieblo void gem_ptp_rxstamp(struct macb *bp, struct sk_buff *skb,
275ab91f0a9SRafal Ozieblo struct macb_dma_desc *desc)
276ab91f0a9SRafal Ozieblo {
277ab91f0a9SRafal Ozieblo struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
278ab91f0a9SRafal Ozieblo struct macb_dma_desc_ptp *desc_ptp;
279ab91f0a9SRafal Ozieblo struct timespec64 ts;
280ab91f0a9SRafal Ozieblo
281ab91f0a9SRafal Ozieblo if (GEM_BFEXT(DMA_RXVALID, desc->addr)) {
282ab91f0a9SRafal Ozieblo desc_ptp = macb_ptp_desc(bp, desc);
28385520079SHarini Katakam /* Unlikely but check */
28485520079SHarini Katakam if (!desc_ptp) {
28585520079SHarini Katakam dev_warn_ratelimited(&bp->pdev->dev,
28685520079SHarini Katakam "Timestamp not supported in BD\n");
28785520079SHarini Katakam return;
28885520079SHarini Katakam }
289ab91f0a9SRafal Ozieblo gem_hw_timestamp(bp, desc_ptp->ts_1, desc_ptp->ts_2, &ts);
290ab91f0a9SRafal Ozieblo memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
291ab91f0a9SRafal Ozieblo shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
292ab91f0a9SRafal Ozieblo }
293ab91f0a9SRafal Ozieblo }
294ab91f0a9SRafal Ozieblo
gem_ptp_txstamp(struct macb * bp,struct sk_buff * skb,struct macb_dma_desc * desc)2958e7610e6SRobert Hancock void gem_ptp_txstamp(struct macb *bp, struct sk_buff *skb,
2968e7610e6SRobert Hancock struct macb_dma_desc *desc)
297ab91f0a9SRafal Ozieblo {
298ab91f0a9SRafal Ozieblo struct skb_shared_hwtstamps shhwtstamps;
2998e7610e6SRobert Hancock struct macb_dma_desc_ptp *desc_ptp;
300ab91f0a9SRafal Ozieblo struct timespec64 ts;
301ab91f0a9SRafal Ozieblo
3028e7610e6SRobert Hancock if (!GEM_BFEXT(DMA_TXVALID, desc->ctrl)) {
3038e7610e6SRobert Hancock dev_warn_ratelimited(&bp->pdev->dev,
3048e7610e6SRobert Hancock "Timestamp not set in TX BD as expected\n");
3058e7610e6SRobert Hancock return;
3068e7610e6SRobert Hancock }
3078e7610e6SRobert Hancock
3088e7610e6SRobert Hancock desc_ptp = macb_ptp_desc(bp, desc);
3098e7610e6SRobert Hancock /* Unlikely but check */
3108e7610e6SRobert Hancock if (!desc_ptp) {
3118e7610e6SRobert Hancock dev_warn_ratelimited(&bp->pdev->dev,
3128e7610e6SRobert Hancock "Timestamp not supported in BD\n");
3138e7610e6SRobert Hancock return;
3148e7610e6SRobert Hancock }
3158e7610e6SRobert Hancock
3168e7610e6SRobert Hancock /* ensure ts_1/ts_2 is loaded after ctrl (TX_USED check) */
3178e7610e6SRobert Hancock dma_rmb();
318ab91f0a9SRafal Ozieblo gem_hw_timestamp(bp, desc_ptp->ts_1, desc_ptp->ts_2, &ts);
3198e7610e6SRobert Hancock
320ab91f0a9SRafal Ozieblo memset(&shhwtstamps, 0, sizeof(shhwtstamps));
321ab91f0a9SRafal Ozieblo shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
322ab91f0a9SRafal Ozieblo skb_tstamp_tx(skb, &shhwtstamps);
323ab91f0a9SRafal Ozieblo }
324ab91f0a9SRafal Ozieblo
gem_ptp_init(struct net_device * dev)325ab91f0a9SRafal Ozieblo void gem_ptp_init(struct net_device *dev)
326ab91f0a9SRafal Ozieblo {
327ab91f0a9SRafal Ozieblo struct macb *bp = netdev_priv(dev);
328ab91f0a9SRafal Ozieblo
329ab91f0a9SRafal Ozieblo bp->ptp_clock_info = gem_ptp_caps_template;
330ab91f0a9SRafal Ozieblo
331ab91f0a9SRafal Ozieblo /* nominal frequency and maximum adjustment in ppb */
332ab91f0a9SRafal Ozieblo bp->tsu_rate = bp->ptp_info->get_tsu_rate(bp);
333ab91f0a9SRafal Ozieblo bp->ptp_clock_info.max_adj = bp->ptp_info->get_ptp_max_adj();
334ab91f0a9SRafal Ozieblo gem_ptp_init_timer(bp);
335ab91f0a9SRafal Ozieblo bp->ptp_clock = ptp_clock_register(&bp->ptp_clock_info, &dev->dev);
336ab91f0a9SRafal Ozieblo if (IS_ERR(bp->ptp_clock)) {
337ab91f0a9SRafal Ozieblo pr_err("ptp clock register failed: %ld\n",
338ab91f0a9SRafal Ozieblo PTR_ERR(bp->ptp_clock));
339ab91f0a9SRafal Ozieblo bp->ptp_clock = NULL;
340ab91f0a9SRafal Ozieblo return;
341ab91f0a9SRafal Ozieblo } else if (bp->ptp_clock == NULL) {
342ab91f0a9SRafal Ozieblo pr_err("ptp clock register failed\n");
343ab91f0a9SRafal Ozieblo return;
344ab91f0a9SRafal Ozieblo }
345ab91f0a9SRafal Ozieblo
346ab91f0a9SRafal Ozieblo spin_lock_init(&bp->tsu_clk_lock);
347ab91f0a9SRafal Ozieblo
348ab91f0a9SRafal Ozieblo gem_ptp_init_tsu(bp);
349ab91f0a9SRafal Ozieblo
350ab91f0a9SRafal Ozieblo dev_info(&bp->pdev->dev, "%s ptp clock registered.\n",
351ab91f0a9SRafal Ozieblo GEM_PTP_TIMER_NAME);
352ab91f0a9SRafal Ozieblo }
353ab91f0a9SRafal Ozieblo
gem_ptp_remove(struct net_device * ndev)354ab91f0a9SRafal Ozieblo void gem_ptp_remove(struct net_device *ndev)
355ab91f0a9SRafal Ozieblo {
356ab91f0a9SRafal Ozieblo struct macb *bp = netdev_priv(ndev);
357ab91f0a9SRafal Ozieblo
358ab91f0a9SRafal Ozieblo if (bp->ptp_clock)
359ab91f0a9SRafal Ozieblo ptp_clock_unregister(bp->ptp_clock);
360ab91f0a9SRafal Ozieblo
361ab91f0a9SRafal Ozieblo gem_ptp_clear_timer(bp);
362ab91f0a9SRafal Ozieblo
363ab91f0a9SRafal Ozieblo dev_info(&bp->pdev->dev, "%s ptp clock unregistered.\n",
364ab91f0a9SRafal Ozieblo GEM_PTP_TIMER_NAME);
365ab91f0a9SRafal Ozieblo }
366ab91f0a9SRafal Ozieblo
gem_ptp_set_ts_mode(struct macb * bp,enum macb_bd_control tx_bd_control,enum macb_bd_control rx_bd_control)367ab91f0a9SRafal Ozieblo static int gem_ptp_set_ts_mode(struct macb *bp,
368ab91f0a9SRafal Ozieblo enum macb_bd_control tx_bd_control,
369ab91f0a9SRafal Ozieblo enum macb_bd_control rx_bd_control)
370ab91f0a9SRafal Ozieblo {
371ab91f0a9SRafal Ozieblo gem_writel(bp, TXBDCTRL, GEM_BF(TXTSMODE, tx_bd_control));
372ab91f0a9SRafal Ozieblo gem_writel(bp, RXBDCTRL, GEM_BF(RXTSMODE, rx_bd_control));
373ab91f0a9SRafal Ozieblo
374ab91f0a9SRafal Ozieblo return 0;
375ab91f0a9SRafal Ozieblo }
376ab91f0a9SRafal Ozieblo
gem_get_hwtst(struct net_device * dev,struct ifreq * rq)377ab91f0a9SRafal Ozieblo int gem_get_hwtst(struct net_device *dev, struct ifreq *rq)
378ab91f0a9SRafal Ozieblo {
379ab91f0a9SRafal Ozieblo struct hwtstamp_config *tstamp_config;
380ab91f0a9SRafal Ozieblo struct macb *bp = netdev_priv(dev);
381ab91f0a9SRafal Ozieblo
382ab91f0a9SRafal Ozieblo tstamp_config = &bp->tstamp_config;
383ab91f0a9SRafal Ozieblo if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0)
384ab91f0a9SRafal Ozieblo return -EOPNOTSUPP;
385ab91f0a9SRafal Ozieblo
386ab91f0a9SRafal Ozieblo if (copy_to_user(rq->ifr_data, tstamp_config, sizeof(*tstamp_config)))
387ab91f0a9SRafal Ozieblo return -EFAULT;
388ab91f0a9SRafal Ozieblo else
389ab91f0a9SRafal Ozieblo return 0;
390ab91f0a9SRafal Ozieblo }
391ab91f0a9SRafal Ozieblo
gem_ptp_set_one_step_sync(struct macb * bp,u8 enable)392263efe85SClaudiu Beznea static void gem_ptp_set_one_step_sync(struct macb *bp, u8 enable)
393ab91f0a9SRafal Ozieblo {
394ab91f0a9SRafal Ozieblo u32 reg_val;
395ab91f0a9SRafal Ozieblo
396ab91f0a9SRafal Ozieblo reg_val = macb_readl(bp, NCR);
397ab91f0a9SRafal Ozieblo
398ab91f0a9SRafal Ozieblo if (enable)
399ab91f0a9SRafal Ozieblo macb_writel(bp, NCR, reg_val | MACB_BIT(OSSMODE));
400ab91f0a9SRafal Ozieblo else
401ab91f0a9SRafal Ozieblo macb_writel(bp, NCR, reg_val & ~MACB_BIT(OSSMODE));
402ab91f0a9SRafal Ozieblo }
403ab91f0a9SRafal Ozieblo
gem_set_hwtst(struct net_device * dev,struct ifreq * ifr,int cmd)404ab91f0a9SRafal Ozieblo int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd)
405ab91f0a9SRafal Ozieblo {
406ab91f0a9SRafal Ozieblo enum macb_bd_control tx_bd_control = TSTAMP_DISABLED;
407ab91f0a9SRafal Ozieblo enum macb_bd_control rx_bd_control = TSTAMP_DISABLED;
408ab91f0a9SRafal Ozieblo struct hwtstamp_config *tstamp_config;
409ab91f0a9SRafal Ozieblo struct macb *bp = netdev_priv(dev);
410ab91f0a9SRafal Ozieblo u32 regval;
411ab91f0a9SRafal Ozieblo
412ab91f0a9SRafal Ozieblo tstamp_config = &bp->tstamp_config;
413ab91f0a9SRafal Ozieblo if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0)
414ab91f0a9SRafal Ozieblo return -EOPNOTSUPP;
415ab91f0a9SRafal Ozieblo
416ab91f0a9SRafal Ozieblo if (copy_from_user(tstamp_config, ifr->ifr_data,
417ab91f0a9SRafal Ozieblo sizeof(*tstamp_config)))
418ab91f0a9SRafal Ozieblo return -EFAULT;
419ab91f0a9SRafal Ozieblo
420ab91f0a9SRafal Ozieblo switch (tstamp_config->tx_type) {
421ab91f0a9SRafal Ozieblo case HWTSTAMP_TX_OFF:
422ab91f0a9SRafal Ozieblo break;
423ab91f0a9SRafal Ozieblo case HWTSTAMP_TX_ONESTEP_SYNC:
424263efe85SClaudiu Beznea gem_ptp_set_one_step_sync(bp, 1);
4255cebb40bSHarini Katakam tx_bd_control = TSTAMP_ALL_FRAMES;
4265cebb40bSHarini Katakam break;
427ab91f0a9SRafal Ozieblo case HWTSTAMP_TX_ON:
4285cebb40bSHarini Katakam gem_ptp_set_one_step_sync(bp, 0);
429ab91f0a9SRafal Ozieblo tx_bd_control = TSTAMP_ALL_FRAMES;
430ab91f0a9SRafal Ozieblo break;
431ab91f0a9SRafal Ozieblo default:
432ab91f0a9SRafal Ozieblo return -ERANGE;
433ab91f0a9SRafal Ozieblo }
434ab91f0a9SRafal Ozieblo
435ab91f0a9SRafal Ozieblo switch (tstamp_config->rx_filter) {
436ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_NONE:
437ab91f0a9SRafal Ozieblo break;
438ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
439ab91f0a9SRafal Ozieblo break;
440ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
441ab91f0a9SRafal Ozieblo break;
442ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V2_EVENT:
443ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
444ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
445ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V2_SYNC:
446ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
447ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
448ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
449ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
450ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
451ab91f0a9SRafal Ozieblo rx_bd_control = TSTAMP_ALL_PTP_FRAMES;
452ab91f0a9SRafal Ozieblo tstamp_config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
453ab91f0a9SRafal Ozieblo regval = macb_readl(bp, NCR);
454ab91f0a9SRafal Ozieblo macb_writel(bp, NCR, (regval | MACB_BIT(SRTSM)));
455ab91f0a9SRafal Ozieblo break;
456ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
457ab91f0a9SRafal Ozieblo case HWTSTAMP_FILTER_ALL:
458ab91f0a9SRafal Ozieblo rx_bd_control = TSTAMP_ALL_FRAMES;
459ab91f0a9SRafal Ozieblo tstamp_config->rx_filter = HWTSTAMP_FILTER_ALL;
460ab91f0a9SRafal Ozieblo break;
461ab91f0a9SRafal Ozieblo default:
462ab91f0a9SRafal Ozieblo tstamp_config->rx_filter = HWTSTAMP_FILTER_NONE;
463ab91f0a9SRafal Ozieblo return -ERANGE;
464ab91f0a9SRafal Ozieblo }
465ab91f0a9SRafal Ozieblo
466ab91f0a9SRafal Ozieblo if (gem_ptp_set_ts_mode(bp, tx_bd_control, rx_bd_control) != 0)
467ab91f0a9SRafal Ozieblo return -ERANGE;
468ab91f0a9SRafal Ozieblo
469ab91f0a9SRafal Ozieblo if (copy_to_user(ifr->ifr_data, tstamp_config, sizeof(*tstamp_config)))
470ab91f0a9SRafal Ozieblo return -EFAULT;
471ab91f0a9SRafal Ozieblo else
472ab91f0a9SRafal Ozieblo return 0;
473ab91f0a9SRafal Ozieblo }
474ab91f0a9SRafal Ozieblo
475