1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Marvell PP2.2 TAI support
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Note:
6*4882a593Smuzhiyun * Do NOT use the event capture support.
7*4882a593Smuzhiyun * Do Not even set the MPP muxes to allow PTP_EVENT_REQ to be used.
8*4882a593Smuzhiyun * It will disrupt the operation of this driver, and there is nothing
9*4882a593Smuzhiyun * that this driver can do to prevent that. Even using PTP_EVENT_REQ
10*4882a593Smuzhiyun * as an output will be seen as a trigger input, which can't be masked.
11*4882a593Smuzhiyun * When ever a trigger input is seen, the action in the TCFCR0_TCF
12*4882a593Smuzhiyun * field will be performed - whether it is a set, increment, decrement
13*4882a593Smuzhiyun * read, or frequency update.
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * Other notes (useful, not specified in the documentation):
16*4882a593Smuzhiyun * - PTP_PULSE_OUT (PTP_EVENT_REQ MPP)
17*4882a593Smuzhiyun * It looks like the hardware can't generate a pulse at nsec=0. (The
18*4882a593Smuzhiyun * output doesn't trigger if the nsec field is zero.)
19*4882a593Smuzhiyun * Note: when configured as an output via the register at 0xfX441120,
20*4882a593Smuzhiyun * the input is still very much alive, and will trigger the current TCF
21*4882a593Smuzhiyun * function.
22*4882a593Smuzhiyun * - PTP_CLK_OUT (PTP_TRIG_GEN MPP)
23*4882a593Smuzhiyun * This generates a "PPS" signal determined by the CCC registers. It
24*4882a593Smuzhiyun * seems this is not aligned to the TOD counter in any way (it may be
25*4882a593Smuzhiyun * initially, but if you specify a non-round second interval, it won't,
26*4882a593Smuzhiyun * and you can't easily get it back.)
27*4882a593Smuzhiyun * - PTP_PCLK_OUT
28*4882a593Smuzhiyun * This generates a 50% duty cycle clock based on the TOD counter, and
29*4882a593Smuzhiyun * seems it can be set to any period of 1ns resolution. It is probably
30*4882a593Smuzhiyun * limited by the TOD step size. Its period is defined by the PCLK_CCC
31*4882a593Smuzhiyun * registers. Again, its alignment to the second is questionable.
32*4882a593Smuzhiyun *
33*4882a593Smuzhiyun * Consequently, we support none of these.
34*4882a593Smuzhiyun */
35*4882a593Smuzhiyun #include <linux/io.h>
36*4882a593Smuzhiyun #include <linux/ptp_clock_kernel.h>
37*4882a593Smuzhiyun #include <linux/slab.h>
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #include "mvpp2.h"
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define CR0_SW_NRESET BIT(0)
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #define TCFCR0_PHASE_UPDATE_ENABLE BIT(8)
44*4882a593Smuzhiyun #define TCFCR0_TCF_MASK (7 << 2)
45*4882a593Smuzhiyun #define TCFCR0_TCF_UPDATE (0 << 2)
46*4882a593Smuzhiyun #define TCFCR0_TCF_FREQUPDATE (1 << 2)
47*4882a593Smuzhiyun #define TCFCR0_TCF_INCREMENT (2 << 2)
48*4882a593Smuzhiyun #define TCFCR0_TCF_DECREMENT (3 << 2)
49*4882a593Smuzhiyun #define TCFCR0_TCF_CAPTURE (4 << 2)
50*4882a593Smuzhiyun #define TCFCR0_TCF_NOP (7 << 2)
51*4882a593Smuzhiyun #define TCFCR0_TCF_TRIGGER BIT(0)
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun #define TCSR_CAPTURE_1_VALID BIT(1)
54*4882a593Smuzhiyun #define TCSR_CAPTURE_0_VALID BIT(0)
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun struct mvpp2_tai {
57*4882a593Smuzhiyun struct ptp_clock_info caps;
58*4882a593Smuzhiyun struct ptp_clock *ptp_clock;
59*4882a593Smuzhiyun void __iomem *base;
60*4882a593Smuzhiyun spinlock_t lock;
61*4882a593Smuzhiyun u64 period; // nanosecond period in 32.32 fixed point
62*4882a593Smuzhiyun /* This timestamp is updated every two seconds */
63*4882a593Smuzhiyun struct timespec64 stamp;
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun
mvpp2_tai_modify(void __iomem * reg,u32 mask,u32 set)66*4882a593Smuzhiyun static void mvpp2_tai_modify(void __iomem *reg, u32 mask, u32 set)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun u32 val;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun val = readl_relaxed(reg) & ~mask;
71*4882a593Smuzhiyun val |= set & mask;
72*4882a593Smuzhiyun writel(val, reg);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
mvpp2_tai_write(u32 val,void __iomem * reg)75*4882a593Smuzhiyun static void mvpp2_tai_write(u32 val, void __iomem *reg)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun writel_relaxed(val & 0xffff, reg);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
mvpp2_tai_read(void __iomem * reg)80*4882a593Smuzhiyun static u32 mvpp2_tai_read(void __iomem *reg)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun return readl_relaxed(reg) & 0xffff;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
ptp_to_tai(struct ptp_clock_info * ptp)85*4882a593Smuzhiyun static struct mvpp2_tai *ptp_to_tai(struct ptp_clock_info *ptp)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun return container_of(ptp, struct mvpp2_tai, caps);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
mvpp22_tai_read_ts(struct timespec64 * ts,void __iomem * base)90*4882a593Smuzhiyun static void mvpp22_tai_read_ts(struct timespec64 *ts, void __iomem *base)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun ts->tv_sec = (u64)mvpp2_tai_read(base + 0) << 32 |
93*4882a593Smuzhiyun mvpp2_tai_read(base + 4) << 16 |
94*4882a593Smuzhiyun mvpp2_tai_read(base + 8);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun ts->tv_nsec = mvpp2_tai_read(base + 12) << 16 |
97*4882a593Smuzhiyun mvpp2_tai_read(base + 16);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* Read and discard fractional part */
100*4882a593Smuzhiyun readl_relaxed(base + 20);
101*4882a593Smuzhiyun readl_relaxed(base + 24);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
mvpp2_tai_write_tlv(const struct timespec64 * ts,u32 frac,void __iomem * base)104*4882a593Smuzhiyun static void mvpp2_tai_write_tlv(const struct timespec64 *ts, u32 frac,
105*4882a593Smuzhiyun void __iomem *base)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun mvpp2_tai_write(ts->tv_sec >> 32, base + MVPP22_TAI_TLV_SEC_HIGH);
108*4882a593Smuzhiyun mvpp2_tai_write(ts->tv_sec >> 16, base + MVPP22_TAI_TLV_SEC_MED);
109*4882a593Smuzhiyun mvpp2_tai_write(ts->tv_sec, base + MVPP22_TAI_TLV_SEC_LOW);
110*4882a593Smuzhiyun mvpp2_tai_write(ts->tv_nsec >> 16, base + MVPP22_TAI_TLV_NANO_HIGH);
111*4882a593Smuzhiyun mvpp2_tai_write(ts->tv_nsec, base + MVPP22_TAI_TLV_NANO_LOW);
112*4882a593Smuzhiyun mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TLV_FRAC_HIGH);
113*4882a593Smuzhiyun mvpp2_tai_write(frac, base + MVPP22_TAI_TLV_FRAC_LOW);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
mvpp2_tai_op(u32 op,void __iomem * base)116*4882a593Smuzhiyun static void mvpp2_tai_op(u32 op, void __iomem *base)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun /* Trigger the operation. Note that an external unmaskable
119*4882a593Smuzhiyun * event on PTP_EVENT_REQ will also trigger this action.
120*4882a593Smuzhiyun */
121*4882a593Smuzhiyun mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
122*4882a593Smuzhiyun TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
123*4882a593Smuzhiyun op | TCFCR0_TCF_TRIGGER);
124*4882a593Smuzhiyun mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
125*4882a593Smuzhiyun TCFCR0_TCF_NOP);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* The adjustment has a range of +0.5ns to -0.5ns in 2^32 steps, so has units
129*4882a593Smuzhiyun * of 2^-32 ns.
130*4882a593Smuzhiyun *
131*4882a593Smuzhiyun * units(s) = 1 / (2^32 * 10^9)
132*4882a593Smuzhiyun * fractional = abs_scaled_ppm / (2^16 * 10^6)
133*4882a593Smuzhiyun *
134*4882a593Smuzhiyun * What we want to achieve:
135*4882a593Smuzhiyun * freq_adjusted = freq_nominal * (1 + fractional)
136*4882a593Smuzhiyun * freq_delta = freq_adjusted - freq_nominal => positive = faster
137*4882a593Smuzhiyun * freq_delta = freq_nominal * (1 + fractional) - freq_nominal
138*4882a593Smuzhiyun * So: freq_delta = freq_nominal * fractional
139*4882a593Smuzhiyun *
140*4882a593Smuzhiyun * However, we are dealing with periods, so:
141*4882a593Smuzhiyun * period_adjusted = period_nominal / (1 + fractional)
142*4882a593Smuzhiyun * period_delta = period_nominal - period_adjusted => positive = faster
143*4882a593Smuzhiyun * period_delta = period_nominal * fractional / (1 + fractional)
144*4882a593Smuzhiyun *
145*4882a593Smuzhiyun * Hence:
146*4882a593Smuzhiyun * period_delta = period_nominal * abs_scaled_ppm /
147*4882a593Smuzhiyun * (2^16 * 10^6 + abs_scaled_ppm)
148*4882a593Smuzhiyun *
149*4882a593Smuzhiyun * To avoid overflow, we reduce both sides of the divide operation by a factor
150*4882a593Smuzhiyun * of 16.
151*4882a593Smuzhiyun */
mvpp22_calc_frac_ppm(struct mvpp2_tai * tai,long abs_scaled_ppm)152*4882a593Smuzhiyun static u64 mvpp22_calc_frac_ppm(struct mvpp2_tai *tai, long abs_scaled_ppm)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun u64 val = tai->period * abs_scaled_ppm >> 4;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun return div_u64(val, (1000000 << 12) + (abs_scaled_ppm >> 4));
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
mvpp22_calc_max_adj(struct mvpp2_tai * tai)159*4882a593Smuzhiyun static s32 mvpp22_calc_max_adj(struct mvpp2_tai *tai)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun return 1000000;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
mvpp22_tai_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)164*4882a593Smuzhiyun static int mvpp22_tai_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun struct mvpp2_tai *tai = ptp_to_tai(ptp);
167*4882a593Smuzhiyun unsigned long flags;
168*4882a593Smuzhiyun void __iomem *base;
169*4882a593Smuzhiyun bool neg_adj;
170*4882a593Smuzhiyun s32 frac;
171*4882a593Smuzhiyun u64 val;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun neg_adj = scaled_ppm < 0;
174*4882a593Smuzhiyun if (neg_adj)
175*4882a593Smuzhiyun scaled_ppm = -scaled_ppm;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun val = mvpp22_calc_frac_ppm(tai, scaled_ppm);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* Convert to a signed 32-bit adjustment */
180*4882a593Smuzhiyun if (neg_adj) {
181*4882a593Smuzhiyun /* -S32_MIN warns, -val < S32_MIN fails, so go for the easy
182*4882a593Smuzhiyun * solution.
183*4882a593Smuzhiyun */
184*4882a593Smuzhiyun if (val > 0x80000000)
185*4882a593Smuzhiyun return -ERANGE;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun frac = -val;
188*4882a593Smuzhiyun } else {
189*4882a593Smuzhiyun if (val > S32_MAX)
190*4882a593Smuzhiyun return -ERANGE;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun frac = val;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun base = tai->base;
196*4882a593Smuzhiyun spin_lock_irqsave(&tai->lock, flags);
197*4882a593Smuzhiyun mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TLV_FRAC_HIGH);
198*4882a593Smuzhiyun mvpp2_tai_write(frac, base + MVPP22_TAI_TLV_FRAC_LOW);
199*4882a593Smuzhiyun mvpp2_tai_op(TCFCR0_TCF_FREQUPDATE, base);
200*4882a593Smuzhiyun spin_unlock_irqrestore(&tai->lock, flags);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun return 0;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
mvpp22_tai_adjtime(struct ptp_clock_info * ptp,s64 delta)205*4882a593Smuzhiyun static int mvpp22_tai_adjtime(struct ptp_clock_info *ptp, s64 delta)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun struct mvpp2_tai *tai = ptp_to_tai(ptp);
208*4882a593Smuzhiyun struct timespec64 ts;
209*4882a593Smuzhiyun unsigned long flags;
210*4882a593Smuzhiyun void __iomem *base;
211*4882a593Smuzhiyun u32 tcf;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* We can't deal with S64_MIN */
214*4882a593Smuzhiyun if (delta == S64_MIN)
215*4882a593Smuzhiyun return -ERANGE;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun if (delta < 0) {
218*4882a593Smuzhiyun delta = -delta;
219*4882a593Smuzhiyun tcf = TCFCR0_TCF_DECREMENT;
220*4882a593Smuzhiyun } else {
221*4882a593Smuzhiyun tcf = TCFCR0_TCF_INCREMENT;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun ts = ns_to_timespec64(delta);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun base = tai->base;
227*4882a593Smuzhiyun spin_lock_irqsave(&tai->lock, flags);
228*4882a593Smuzhiyun mvpp2_tai_write_tlv(&ts, 0, base);
229*4882a593Smuzhiyun mvpp2_tai_op(tcf, base);
230*4882a593Smuzhiyun spin_unlock_irqrestore(&tai->lock, flags);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun return 0;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
mvpp22_tai_gettimex64(struct ptp_clock_info * ptp,struct timespec64 * ts,struct ptp_system_timestamp * sts)235*4882a593Smuzhiyun static int mvpp22_tai_gettimex64(struct ptp_clock_info *ptp,
236*4882a593Smuzhiyun struct timespec64 *ts,
237*4882a593Smuzhiyun struct ptp_system_timestamp *sts)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun struct mvpp2_tai *tai = ptp_to_tai(ptp);
240*4882a593Smuzhiyun unsigned long flags;
241*4882a593Smuzhiyun void __iomem *base;
242*4882a593Smuzhiyun u32 tcsr;
243*4882a593Smuzhiyun int ret;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun base = tai->base;
246*4882a593Smuzhiyun spin_lock_irqsave(&tai->lock, flags);
247*4882a593Smuzhiyun /* XXX: the only way to read the PTP time is for the CPU to trigger
248*4882a593Smuzhiyun * an event. However, there is no way to distinguish between the CPU
249*4882a593Smuzhiyun * triggered event, and an external event on PTP_EVENT_REQ. So this
250*4882a593Smuzhiyun * is incompatible with external use of PTP_EVENT_REQ.
251*4882a593Smuzhiyun */
252*4882a593Smuzhiyun ptp_read_system_prets(sts);
253*4882a593Smuzhiyun mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
254*4882a593Smuzhiyun TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
255*4882a593Smuzhiyun TCFCR0_TCF_CAPTURE | TCFCR0_TCF_TRIGGER);
256*4882a593Smuzhiyun ptp_read_system_postts(sts);
257*4882a593Smuzhiyun mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
258*4882a593Smuzhiyun TCFCR0_TCF_NOP);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun tcsr = readl(base + MVPP22_TAI_TCSR);
261*4882a593Smuzhiyun if (tcsr & TCSR_CAPTURE_1_VALID) {
262*4882a593Smuzhiyun mvpp22_tai_read_ts(ts, base + MVPP22_TAI_TCV1_SEC_HIGH);
263*4882a593Smuzhiyun ret = 0;
264*4882a593Smuzhiyun } else if (tcsr & TCSR_CAPTURE_0_VALID) {
265*4882a593Smuzhiyun mvpp22_tai_read_ts(ts, base + MVPP22_TAI_TCV0_SEC_HIGH);
266*4882a593Smuzhiyun ret = 0;
267*4882a593Smuzhiyun } else {
268*4882a593Smuzhiyun /* We don't seem to have a reading... */
269*4882a593Smuzhiyun ret = -EBUSY;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun spin_unlock_irqrestore(&tai->lock, flags);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun return ret;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
mvpp22_tai_settime64(struct ptp_clock_info * ptp,const struct timespec64 * ts)276*4882a593Smuzhiyun static int mvpp22_tai_settime64(struct ptp_clock_info *ptp,
277*4882a593Smuzhiyun const struct timespec64 *ts)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun struct mvpp2_tai *tai = ptp_to_tai(ptp);
280*4882a593Smuzhiyun unsigned long flags;
281*4882a593Smuzhiyun void __iomem *base;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun base = tai->base;
284*4882a593Smuzhiyun spin_lock_irqsave(&tai->lock, flags);
285*4882a593Smuzhiyun mvpp2_tai_write_tlv(ts, 0, base);
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun /* Trigger an update to load the value from the TLV registers
288*4882a593Smuzhiyun * into the TOD counter. Note that an external unmaskable event on
289*4882a593Smuzhiyun * PTP_EVENT_REQ will also trigger this action.
290*4882a593Smuzhiyun */
291*4882a593Smuzhiyun mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
292*4882a593Smuzhiyun TCFCR0_PHASE_UPDATE_ENABLE |
293*4882a593Smuzhiyun TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
294*4882a593Smuzhiyun TCFCR0_TCF_UPDATE | TCFCR0_TCF_TRIGGER);
295*4882a593Smuzhiyun mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
296*4882a593Smuzhiyun TCFCR0_TCF_NOP);
297*4882a593Smuzhiyun spin_unlock_irqrestore(&tai->lock, flags);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun return 0;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
mvpp22_tai_aux_work(struct ptp_clock_info * ptp)302*4882a593Smuzhiyun static long mvpp22_tai_aux_work(struct ptp_clock_info *ptp)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun struct mvpp2_tai *tai = ptp_to_tai(ptp);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun mvpp22_tai_gettimex64(ptp, &tai->stamp, NULL);
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun return msecs_to_jiffies(2000);
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
mvpp22_tai_set_step(struct mvpp2_tai * tai)311*4882a593Smuzhiyun static void mvpp22_tai_set_step(struct mvpp2_tai *tai)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun void __iomem *base = tai->base;
314*4882a593Smuzhiyun u32 nano, frac;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun nano = upper_32_bits(tai->period);
317*4882a593Smuzhiyun frac = lower_32_bits(tai->period);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /* As the fractional nanosecond is a signed offset, if the MSB (sign)
320*4882a593Smuzhiyun * bit is set, we have to increment the whole nanoseconds.
321*4882a593Smuzhiyun */
322*4882a593Smuzhiyun if (frac >= 0x80000000)
323*4882a593Smuzhiyun nano += 1;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun mvpp2_tai_write(nano, base + MVPP22_TAI_TOD_STEP_NANO_CR);
326*4882a593Smuzhiyun mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TOD_STEP_FRAC_HIGH);
327*4882a593Smuzhiyun mvpp2_tai_write(frac, base + MVPP22_TAI_TOD_STEP_FRAC_LOW);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
mvpp22_tai_init(struct mvpp2_tai * tai)330*4882a593Smuzhiyun static void mvpp22_tai_init(struct mvpp2_tai *tai)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun void __iomem *base = tai->base;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun mvpp22_tai_set_step(tai);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /* Release the TAI reset */
337*4882a593Smuzhiyun mvpp2_tai_modify(base + MVPP22_TAI_CR0, CR0_SW_NRESET, CR0_SW_NRESET);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
mvpp22_tai_ptp_clock_index(struct mvpp2_tai * tai)340*4882a593Smuzhiyun int mvpp22_tai_ptp_clock_index(struct mvpp2_tai *tai)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun return ptp_clock_index(tai->ptp_clock);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
mvpp22_tai_tstamp(struct mvpp2_tai * tai,u32 tstamp,struct skb_shared_hwtstamps * hwtstamp)345*4882a593Smuzhiyun void mvpp22_tai_tstamp(struct mvpp2_tai *tai, u32 tstamp,
346*4882a593Smuzhiyun struct skb_shared_hwtstamps *hwtstamp)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun struct timespec64 ts;
349*4882a593Smuzhiyun int delta;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun /* The tstamp consists of 2 bits of seconds and 30 bits of nanoseconds.
352*4882a593Smuzhiyun * We use our stored timestamp (tai->stamp) to form a full timestamp,
353*4882a593Smuzhiyun * and we must read the seconds exactly once.
354*4882a593Smuzhiyun */
355*4882a593Smuzhiyun ts.tv_sec = READ_ONCE(tai->stamp.tv_sec);
356*4882a593Smuzhiyun ts.tv_nsec = tstamp & 0x3fffffff;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun /* Calculate the delta in seconds between our stored timestamp and
359*4882a593Smuzhiyun * the value read from the queue. Allow timestamps one second in the
360*4882a593Smuzhiyun * past, otherwise consider them to be in the future.
361*4882a593Smuzhiyun */
362*4882a593Smuzhiyun delta = ((tstamp >> 30) - (ts.tv_sec & 3)) & 3;
363*4882a593Smuzhiyun if (delta == 3)
364*4882a593Smuzhiyun delta -= 4;
365*4882a593Smuzhiyun ts.tv_sec += delta;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun memset(hwtstamp, 0, sizeof(*hwtstamp));
368*4882a593Smuzhiyun hwtstamp->hwtstamp = timespec64_to_ktime(ts);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
mvpp22_tai_start(struct mvpp2_tai * tai)371*4882a593Smuzhiyun void mvpp22_tai_start(struct mvpp2_tai *tai)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun long delay;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun delay = mvpp22_tai_aux_work(&tai->caps);
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun ptp_schedule_worker(tai->ptp_clock, delay);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
mvpp22_tai_stop(struct mvpp2_tai * tai)380*4882a593Smuzhiyun void mvpp22_tai_stop(struct mvpp2_tai *tai)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun ptp_cancel_worker_sync(tai->ptp_clock);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
mvpp22_tai_remove(void * priv)385*4882a593Smuzhiyun static void mvpp22_tai_remove(void *priv)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun struct mvpp2_tai *tai = priv;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun if (!IS_ERR(tai->ptp_clock))
390*4882a593Smuzhiyun ptp_clock_unregister(tai->ptp_clock);
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
mvpp22_tai_probe(struct device * dev,struct mvpp2 * priv)393*4882a593Smuzhiyun int mvpp22_tai_probe(struct device *dev, struct mvpp2 *priv)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun struct mvpp2_tai *tai;
396*4882a593Smuzhiyun int ret;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun tai = devm_kzalloc(dev, sizeof(*tai), GFP_KERNEL);
399*4882a593Smuzhiyun if (!tai)
400*4882a593Smuzhiyun return -ENOMEM;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun spin_lock_init(&tai->lock);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun tai->base = priv->iface_base;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun /* The step size consists of three registers - a 16-bit nanosecond step
407*4882a593Smuzhiyun * size, and a 32-bit fractional nanosecond step size split over two
408*4882a593Smuzhiyun * registers. The fractional nanosecond step size has units of 2^-32ns.
409*4882a593Smuzhiyun *
410*4882a593Smuzhiyun * To calculate this, we calculate:
411*4882a593Smuzhiyun * (10^9 + freq / 2) / (freq * 2^-32)
412*4882a593Smuzhiyun * which gives us the nanosecond step to the nearest integer in 16.32
413*4882a593Smuzhiyun * fixed point format, and the fractional part of the step size with
414*4882a593Smuzhiyun * the MSB inverted. With rounding of the fractional nanosecond, and
415*4882a593Smuzhiyun * simplification, this becomes:
416*4882a593Smuzhiyun * (10^9 << 32 + freq << 31 + (freq + 1) >> 1) / freq
417*4882a593Smuzhiyun *
418*4882a593Smuzhiyun * So:
419*4882a593Smuzhiyun * div = (10^9 << 32 + freq << 31 + (freq + 1) >> 1) / freq
420*4882a593Smuzhiyun * nano = upper_32_bits(div);
421*4882a593Smuzhiyun * frac = lower_32_bits(div) ^ 0x80000000;
422*4882a593Smuzhiyun * Will give the values for the registers.
423*4882a593Smuzhiyun *
424*4882a593Smuzhiyun * This is all seems perfect, but alas it is not when considering the
425*4882a593Smuzhiyun * whole story. The system is clocked from 25MHz, which is multiplied
426*4882a593Smuzhiyun * by a PLL to 1GHz, and then divided by three, giving 333333333Hz
427*4882a593Smuzhiyun * (recurring). This gives exactly 3ns, but using 333333333Hz with
428*4882a593Smuzhiyun * the above gives an error of 13*2^-32ns.
429*4882a593Smuzhiyun *
430*4882a593Smuzhiyun * Consequently, we use the period rather than calculating from the
431*4882a593Smuzhiyun * frequency.
432*4882a593Smuzhiyun */
433*4882a593Smuzhiyun tai->period = 3ULL << 32;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun mvpp22_tai_init(tai);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun tai->caps.owner = THIS_MODULE;
438*4882a593Smuzhiyun strscpy(tai->caps.name, "Marvell PP2.2", sizeof(tai->caps.name));
439*4882a593Smuzhiyun tai->caps.max_adj = mvpp22_calc_max_adj(tai);
440*4882a593Smuzhiyun tai->caps.adjfine = mvpp22_tai_adjfine;
441*4882a593Smuzhiyun tai->caps.adjtime = mvpp22_tai_adjtime;
442*4882a593Smuzhiyun tai->caps.gettimex64 = mvpp22_tai_gettimex64;
443*4882a593Smuzhiyun tai->caps.settime64 = mvpp22_tai_settime64;
444*4882a593Smuzhiyun tai->caps.do_aux_work = mvpp22_tai_aux_work;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun ret = devm_add_action(dev, mvpp22_tai_remove, tai);
447*4882a593Smuzhiyun if (ret)
448*4882a593Smuzhiyun return ret;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun tai->ptp_clock = ptp_clock_register(&tai->caps, dev);
451*4882a593Smuzhiyun if (IS_ERR(tai->ptp_clock))
452*4882a593Smuzhiyun return PTR_ERR(tai->ptp_clock);
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun priv->tai = tai;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun return 0;
457*4882a593Smuzhiyun }
458