xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/marvell/mvpp2/mvpp2_tai.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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