191dd7195SRussell King // SPDX-License-Identifier: GPL-2.0
291dd7195SRussell King /*
391dd7195SRussell King  * Marvell PP2.2 TAI support
491dd7195SRussell King  *
591dd7195SRussell King  * Note:
691dd7195SRussell King  *   Do NOT use the event capture support.
791dd7195SRussell King  *   Do Not even set the MPP muxes to allow PTP_EVENT_REQ to be used.
891dd7195SRussell King  *   It will disrupt the operation of this driver, and there is nothing
991dd7195SRussell King  *   that this driver can do to prevent that.  Even using PTP_EVENT_REQ
1091dd7195SRussell King  *   as an output will be seen as a trigger input, which can't be masked.
1191dd7195SRussell King  *   When ever a trigger input is seen, the action in the TCFCR0_TCF
1291dd7195SRussell King  *   field will be performed - whether it is a set, increment, decrement
1391dd7195SRussell King  *   read, or frequency update.
1491dd7195SRussell King  *
1591dd7195SRussell King  * Other notes (useful, not specified in the documentation):
1691dd7195SRussell King  * - PTP_PULSE_OUT (PTP_EVENT_REQ MPP)
1791dd7195SRussell King  *   It looks like the hardware can't generate a pulse at nsec=0. (The
1891dd7195SRussell King  *   output doesn't trigger if the nsec field is zero.)
1991dd7195SRussell King  *   Note: when configured as an output via the register at 0xfX441120,
2091dd7195SRussell King  *   the input is still very much alive, and will trigger the current TCF
2191dd7195SRussell King  *   function.
2291dd7195SRussell King  * - PTP_CLK_OUT (PTP_TRIG_GEN MPP)
2391dd7195SRussell King  *   This generates a "PPS" signal determined by the CCC registers. It
2491dd7195SRussell King  *   seems this is not aligned to the TOD counter in any way (it may be
2591dd7195SRussell King  *   initially, but if you specify a non-round second interval, it won't,
2691dd7195SRussell King  *   and you can't easily get it back.)
2791dd7195SRussell King  * - PTP_PCLK_OUT
2891dd7195SRussell King  *   This generates a 50% duty cycle clock based on the TOD counter, and
2991dd7195SRussell King  *   seems it can be set to any period of 1ns resolution. It is probably
3091dd7195SRussell King  *   limited by the TOD step size. Its period is defined by the PCLK_CCC
3191dd7195SRussell King  *   registers. Again, its alignment to the second is questionable.
3291dd7195SRussell King  *
3391dd7195SRussell King  * Consequently, we support none of these.
3491dd7195SRussell King  */
3591dd7195SRussell King #include <linux/io.h>
3691dd7195SRussell King #include <linux/ptp_clock_kernel.h>
3791dd7195SRussell King #include <linux/slab.h>
3891dd7195SRussell King 
3991dd7195SRussell King #include "mvpp2.h"
4091dd7195SRussell King 
4191dd7195SRussell King #define CR0_SW_NRESET			BIT(0)
4291dd7195SRussell King 
4391dd7195SRussell King #define TCFCR0_PHASE_UPDATE_ENABLE	BIT(8)
4491dd7195SRussell King #define TCFCR0_TCF_MASK			(7 << 2)
4591dd7195SRussell King #define TCFCR0_TCF_UPDATE		(0 << 2)
4691dd7195SRussell King #define TCFCR0_TCF_FREQUPDATE		(1 << 2)
4791dd7195SRussell King #define TCFCR0_TCF_INCREMENT		(2 << 2)
4891dd7195SRussell King #define TCFCR0_TCF_DECREMENT		(3 << 2)
4991dd7195SRussell King #define TCFCR0_TCF_CAPTURE		(4 << 2)
5091dd7195SRussell King #define TCFCR0_TCF_NOP			(7 << 2)
5191dd7195SRussell King #define TCFCR0_TCF_TRIGGER		BIT(0)
5291dd7195SRussell King 
5391dd7195SRussell King #define TCSR_CAPTURE_1_VALID		BIT(1)
5491dd7195SRussell King #define TCSR_CAPTURE_0_VALID		BIT(0)
5591dd7195SRussell King 
5691dd7195SRussell King struct mvpp2_tai {
5791dd7195SRussell King 	struct ptp_clock_info caps;
5891dd7195SRussell King 	struct ptp_clock *ptp_clock;
5991dd7195SRussell King 	void __iomem *base;
6091dd7195SRussell King 	spinlock_t lock;
6191dd7195SRussell King 	u64 period;		// nanosecond period in 32.32 fixed point
62ce3497e2SRussell King 	/* This timestamp is updated every two seconds */
63ce3497e2SRussell King 	struct timespec64 stamp;
6491dd7195SRussell King };
6591dd7195SRussell King 
mvpp2_tai_modify(void __iomem * reg,u32 mask,u32 set)6691dd7195SRussell King static void mvpp2_tai_modify(void __iomem *reg, u32 mask, u32 set)
6791dd7195SRussell King {
6891dd7195SRussell King 	u32 val;
6991dd7195SRussell King 
7091dd7195SRussell King 	val = readl_relaxed(reg) & ~mask;
7191dd7195SRussell King 	val |= set & mask;
7291dd7195SRussell King 	writel(val, reg);
7391dd7195SRussell King }
7491dd7195SRussell King 
mvpp2_tai_write(u32 val,void __iomem * reg)7591dd7195SRussell King static void mvpp2_tai_write(u32 val, void __iomem *reg)
7691dd7195SRussell King {
7791dd7195SRussell King 	writel_relaxed(val & 0xffff, reg);
7891dd7195SRussell King }
7991dd7195SRussell King 
mvpp2_tai_read(void __iomem * reg)8091dd7195SRussell King static u32 mvpp2_tai_read(void __iomem *reg)
8191dd7195SRussell King {
8291dd7195SRussell King 	return readl_relaxed(reg) & 0xffff;
8391dd7195SRussell King }
8491dd7195SRussell King 
ptp_to_tai(struct ptp_clock_info * ptp)8591dd7195SRussell King static struct mvpp2_tai *ptp_to_tai(struct ptp_clock_info *ptp)
8691dd7195SRussell King {
8791dd7195SRussell King 	return container_of(ptp, struct mvpp2_tai, caps);
8891dd7195SRussell King }
8991dd7195SRussell King 
mvpp22_tai_read_ts(struct timespec64 * ts,void __iomem * base)9091dd7195SRussell King static void mvpp22_tai_read_ts(struct timespec64 *ts, void __iomem *base)
9191dd7195SRussell King {
9291dd7195SRussell King 	ts->tv_sec = (u64)mvpp2_tai_read(base + 0) << 32 |
9391dd7195SRussell King 		     mvpp2_tai_read(base + 4) << 16 |
9491dd7195SRussell King 		     mvpp2_tai_read(base + 8);
9591dd7195SRussell King 
9691dd7195SRussell King 	ts->tv_nsec = mvpp2_tai_read(base + 12) << 16 |
9791dd7195SRussell King 		      mvpp2_tai_read(base + 16);
9891dd7195SRussell King 
9991dd7195SRussell King 	/* Read and discard fractional part */
10091dd7195SRussell King 	readl_relaxed(base + 20);
10191dd7195SRussell King 	readl_relaxed(base + 24);
10291dd7195SRussell King }
10391dd7195SRussell King 
mvpp2_tai_write_tlv(const struct timespec64 * ts,u32 frac,void __iomem * base)10491dd7195SRussell King static void mvpp2_tai_write_tlv(const struct timespec64 *ts, u32 frac,
10591dd7195SRussell King 			        void __iomem *base)
10691dd7195SRussell King {
10791dd7195SRussell King 	mvpp2_tai_write(ts->tv_sec >> 32, base + MVPP22_TAI_TLV_SEC_HIGH);
10891dd7195SRussell King 	mvpp2_tai_write(ts->tv_sec >> 16, base + MVPP22_TAI_TLV_SEC_MED);
10991dd7195SRussell King 	mvpp2_tai_write(ts->tv_sec, base + MVPP22_TAI_TLV_SEC_LOW);
11091dd7195SRussell King 	mvpp2_tai_write(ts->tv_nsec >> 16, base + MVPP22_TAI_TLV_NANO_HIGH);
11191dd7195SRussell King 	mvpp2_tai_write(ts->tv_nsec, base + MVPP22_TAI_TLV_NANO_LOW);
11291dd7195SRussell King 	mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TLV_FRAC_HIGH);
11391dd7195SRussell King 	mvpp2_tai_write(frac, base + MVPP22_TAI_TLV_FRAC_LOW);
11491dd7195SRussell King }
11591dd7195SRussell King 
mvpp2_tai_op(u32 op,void __iomem * base)11691dd7195SRussell King static void mvpp2_tai_op(u32 op, void __iomem *base)
11791dd7195SRussell King {
11891dd7195SRussell King 	/* Trigger the operation. Note that an external unmaskable
11991dd7195SRussell King 	 * event on PTP_EVENT_REQ will also trigger this action.
12091dd7195SRussell King 	 */
12191dd7195SRussell King 	mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
12291dd7195SRussell King 			 TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
12391dd7195SRussell King 			 op | TCFCR0_TCF_TRIGGER);
12491dd7195SRussell King 	mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
12591dd7195SRussell King 			 TCFCR0_TCF_NOP);
12691dd7195SRussell King }
12791dd7195SRussell King 
12891dd7195SRussell King /* The adjustment has a range of +0.5ns to -0.5ns in 2^32 steps, so has units
12991dd7195SRussell King  * of 2^-32 ns.
13091dd7195SRussell King  *
13191dd7195SRussell King  * units(s) = 1 / (2^32 * 10^9)
13291dd7195SRussell King  * fractional = abs_scaled_ppm / (2^16 * 10^6)
13391dd7195SRussell King  *
13491dd7195SRussell King  * What we want to achieve:
13591dd7195SRussell King  *  freq_adjusted = freq_nominal * (1 + fractional)
13691dd7195SRussell King  *  freq_delta = freq_adjusted - freq_nominal => positive = faster
13791dd7195SRussell King  *  freq_delta = freq_nominal * (1 + fractional) - freq_nominal
13891dd7195SRussell King  * So: freq_delta = freq_nominal * fractional
13991dd7195SRussell King  *
14091dd7195SRussell King  * However, we are dealing with periods, so:
14191dd7195SRussell King  *  period_adjusted = period_nominal / (1 + fractional)
14291dd7195SRussell King  *  period_delta = period_nominal - period_adjusted => positive = faster
14391dd7195SRussell King  *  period_delta = period_nominal * fractional / (1 + fractional)
14491dd7195SRussell King  *
14591dd7195SRussell King  * Hence:
14691dd7195SRussell King  *  period_delta = period_nominal * abs_scaled_ppm /
14791dd7195SRussell King  *		   (2^16 * 10^6 + abs_scaled_ppm)
14891dd7195SRussell King  *
14991dd7195SRussell King  * To avoid overflow, we reduce both sides of the divide operation by a factor
15091dd7195SRussell King  * of 16.
15191dd7195SRussell King  */
mvpp22_calc_frac_ppm(struct mvpp2_tai * tai,long abs_scaled_ppm)15291dd7195SRussell King static u64 mvpp22_calc_frac_ppm(struct mvpp2_tai *tai, long abs_scaled_ppm)
15391dd7195SRussell King {
15491dd7195SRussell King 	u64 val = tai->period * abs_scaled_ppm >> 4;
15591dd7195SRussell King 
15691dd7195SRussell King 	return div_u64(val, (1000000 << 12) + (abs_scaled_ppm >> 4));
15791dd7195SRussell King }
15891dd7195SRussell King 
mvpp22_calc_max_adj(struct mvpp2_tai * tai)15991dd7195SRussell King static s32 mvpp22_calc_max_adj(struct mvpp2_tai *tai)
16091dd7195SRussell King {
16191dd7195SRussell King 	return 1000000;
16291dd7195SRussell King }
16391dd7195SRussell King 
mvpp22_tai_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)16491dd7195SRussell King static int mvpp22_tai_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
16591dd7195SRussell King {
16691dd7195SRussell King 	struct mvpp2_tai *tai = ptp_to_tai(ptp);
16791dd7195SRussell King 	unsigned long flags;
16891dd7195SRussell King 	void __iomem *base;
16991dd7195SRussell King 	bool neg_adj;
17091dd7195SRussell King 	s32 frac;
17191dd7195SRussell King 	u64 val;
17291dd7195SRussell King 
17391dd7195SRussell King 	neg_adj = scaled_ppm < 0;
17491dd7195SRussell King 	if (neg_adj)
17591dd7195SRussell King 		scaled_ppm = -scaled_ppm;
17691dd7195SRussell King 
17791dd7195SRussell King 	val = mvpp22_calc_frac_ppm(tai, scaled_ppm);
17891dd7195SRussell King 
17991dd7195SRussell King 	/* Convert to a signed 32-bit adjustment */
18091dd7195SRussell King 	if (neg_adj) {
18191dd7195SRussell King 		/* -S32_MIN warns, -val < S32_MIN fails, so go for the easy
18291dd7195SRussell King 		 * solution.
18391dd7195SRussell King 		 */
18491dd7195SRussell King 		if (val > 0x80000000)
18591dd7195SRussell King 			return -ERANGE;
18691dd7195SRussell King 
18791dd7195SRussell King 		frac = -val;
18891dd7195SRussell King 	} else {
18991dd7195SRussell King 		if (val > S32_MAX)
19091dd7195SRussell King 			return -ERANGE;
19191dd7195SRussell King 
19291dd7195SRussell King 		frac = val;
19391dd7195SRussell King 	}
19491dd7195SRussell King 
19591dd7195SRussell King 	base = tai->base;
19691dd7195SRussell King 	spin_lock_irqsave(&tai->lock, flags);
19791dd7195SRussell King 	mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TLV_FRAC_HIGH);
19891dd7195SRussell King 	mvpp2_tai_write(frac, base + MVPP22_TAI_TLV_FRAC_LOW);
19991dd7195SRussell King 	mvpp2_tai_op(TCFCR0_TCF_FREQUPDATE, base);
20091dd7195SRussell King 	spin_unlock_irqrestore(&tai->lock, flags);
20191dd7195SRussell King 
20291dd7195SRussell King 	return 0;
20391dd7195SRussell King }
20491dd7195SRussell King 
mvpp22_tai_adjtime(struct ptp_clock_info * ptp,s64 delta)20591dd7195SRussell King static int mvpp22_tai_adjtime(struct ptp_clock_info *ptp, s64 delta)
20691dd7195SRussell King {
20791dd7195SRussell King 	struct mvpp2_tai *tai = ptp_to_tai(ptp);
20891dd7195SRussell King 	struct timespec64 ts;
20991dd7195SRussell King 	unsigned long flags;
21091dd7195SRussell King 	void __iomem *base;
21191dd7195SRussell King 	u32 tcf;
21291dd7195SRussell King 
21391dd7195SRussell King 	/* We can't deal with S64_MIN */
21491dd7195SRussell King 	if (delta == S64_MIN)
21591dd7195SRussell King 		return -ERANGE;
21691dd7195SRussell King 
21791dd7195SRussell King 	if (delta < 0) {
21891dd7195SRussell King 		delta = -delta;
21991dd7195SRussell King 		tcf = TCFCR0_TCF_DECREMENT;
22091dd7195SRussell King 	} else {
22191dd7195SRussell King 		tcf = TCFCR0_TCF_INCREMENT;
22291dd7195SRussell King 	}
22391dd7195SRussell King 
22491dd7195SRussell King 	ts = ns_to_timespec64(delta);
22591dd7195SRussell King 
22691dd7195SRussell King 	base = tai->base;
22791dd7195SRussell King 	spin_lock_irqsave(&tai->lock, flags);
22891dd7195SRussell King 	mvpp2_tai_write_tlv(&ts, 0, base);
22991dd7195SRussell King 	mvpp2_tai_op(tcf, base);
23091dd7195SRussell King 	spin_unlock_irqrestore(&tai->lock, flags);
23191dd7195SRussell King 
23291dd7195SRussell King 	return 0;
23391dd7195SRussell King }
23491dd7195SRussell King 
mvpp22_tai_gettimex64(struct ptp_clock_info * ptp,struct timespec64 * ts,struct ptp_system_timestamp * sts)23591dd7195SRussell King static int mvpp22_tai_gettimex64(struct ptp_clock_info *ptp,
23691dd7195SRussell King 				 struct timespec64 *ts,
23791dd7195SRussell King 				 struct ptp_system_timestamp *sts)
23891dd7195SRussell King {
23991dd7195SRussell King 	struct mvpp2_tai *tai = ptp_to_tai(ptp);
24091dd7195SRussell King 	unsigned long flags;
24191dd7195SRussell King 	void __iomem *base;
24291dd7195SRussell King 	u32 tcsr;
24391dd7195SRussell King 	int ret;
24491dd7195SRussell King 
24591dd7195SRussell King 	base = tai->base;
24691dd7195SRussell King 	spin_lock_irqsave(&tai->lock, flags);
24791dd7195SRussell King 	/* XXX: the only way to read the PTP time is for the CPU to trigger
24891dd7195SRussell King 	 * an event. However, there is no way to distinguish between the CPU
24991dd7195SRussell King 	 * triggered event, and an external event on PTP_EVENT_REQ. So this
25091dd7195SRussell King 	 * is incompatible with external use of PTP_EVENT_REQ.
25191dd7195SRussell King 	 */
25291dd7195SRussell King 	ptp_read_system_prets(sts);
25391dd7195SRussell King 	mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
25491dd7195SRussell King 			 TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
25591dd7195SRussell King 			 TCFCR0_TCF_CAPTURE | TCFCR0_TCF_TRIGGER);
25691dd7195SRussell King 	ptp_read_system_postts(sts);
25791dd7195SRussell King 	mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
25891dd7195SRussell King 			 TCFCR0_TCF_NOP);
25991dd7195SRussell King 
26091dd7195SRussell King 	tcsr = readl(base + MVPP22_TAI_TCSR);
26191dd7195SRussell King 	if (tcsr & TCSR_CAPTURE_1_VALID) {
26291dd7195SRussell King 		mvpp22_tai_read_ts(ts, base + MVPP22_TAI_TCV1_SEC_HIGH);
26391dd7195SRussell King 		ret = 0;
26491dd7195SRussell King 	} else if (tcsr & TCSR_CAPTURE_0_VALID) {
26591dd7195SRussell King 		mvpp22_tai_read_ts(ts, base + MVPP22_TAI_TCV0_SEC_HIGH);
26691dd7195SRussell King 		ret = 0;
26791dd7195SRussell King 	} else {
26891dd7195SRussell King 		/* We don't seem to have a reading... */
26991dd7195SRussell King 		ret = -EBUSY;
27091dd7195SRussell King 	}
27191dd7195SRussell King 	spin_unlock_irqrestore(&tai->lock, flags);
27291dd7195SRussell King 
27391dd7195SRussell King 	return ret;
27491dd7195SRussell King }
27591dd7195SRussell King 
mvpp22_tai_settime64(struct ptp_clock_info * ptp,const struct timespec64 * ts)27691dd7195SRussell King static int mvpp22_tai_settime64(struct ptp_clock_info *ptp,
27791dd7195SRussell King 				const struct timespec64 *ts)
27891dd7195SRussell King {
27991dd7195SRussell King 	struct mvpp2_tai *tai = ptp_to_tai(ptp);
28091dd7195SRussell King 	unsigned long flags;
28191dd7195SRussell King 	void __iomem *base;
28291dd7195SRussell King 
28391dd7195SRussell King 	base = tai->base;
28491dd7195SRussell King 	spin_lock_irqsave(&tai->lock, flags);
28591dd7195SRussell King 	mvpp2_tai_write_tlv(ts, 0, base);
28691dd7195SRussell King 
28791dd7195SRussell King 	/* Trigger an update to load the value from the TLV registers
28891dd7195SRussell King 	 * into the TOD counter. Note that an external unmaskable event on
28991dd7195SRussell King 	 * PTP_EVENT_REQ will also trigger this action.
29091dd7195SRussell King 	 */
29191dd7195SRussell King 	mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
29291dd7195SRussell King 			 TCFCR0_PHASE_UPDATE_ENABLE |
29391dd7195SRussell King 			 TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
29491dd7195SRussell King 			 TCFCR0_TCF_UPDATE | TCFCR0_TCF_TRIGGER);
29591dd7195SRussell King 	mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
29691dd7195SRussell King 			 TCFCR0_TCF_NOP);
29791dd7195SRussell King 	spin_unlock_irqrestore(&tai->lock, flags);
29891dd7195SRussell King 
29991dd7195SRussell King 	return 0;
30091dd7195SRussell King }
30191dd7195SRussell King 
mvpp22_tai_aux_work(struct ptp_clock_info * ptp)302ce3497e2SRussell King static long mvpp22_tai_aux_work(struct ptp_clock_info *ptp)
303ce3497e2SRussell King {
304ce3497e2SRussell King 	struct mvpp2_tai *tai = ptp_to_tai(ptp);
305ce3497e2SRussell King 
306ce3497e2SRussell King 	mvpp22_tai_gettimex64(ptp, &tai->stamp, NULL);
307ce3497e2SRussell King 
308ce3497e2SRussell King 	return msecs_to_jiffies(2000);
309ce3497e2SRussell King }
310ce3497e2SRussell King 
mvpp22_tai_set_step(struct mvpp2_tai * tai)31191dd7195SRussell King static void mvpp22_tai_set_step(struct mvpp2_tai *tai)
31291dd7195SRussell King {
31391dd7195SRussell King 	void __iomem *base = tai->base;
31491dd7195SRussell King 	u32 nano, frac;
31591dd7195SRussell King 
31691dd7195SRussell King 	nano = upper_32_bits(tai->period);
31791dd7195SRussell King 	frac = lower_32_bits(tai->period);
31891dd7195SRussell King 
31991dd7195SRussell King 	/* As the fractional nanosecond is a signed offset, if the MSB (sign)
32091dd7195SRussell King 	 * bit is set, we have to increment the whole nanoseconds.
32191dd7195SRussell King 	 */
32291dd7195SRussell King 	if (frac >= 0x80000000)
32391dd7195SRussell King 		nano += 1;
32491dd7195SRussell King 
32591dd7195SRussell King 	mvpp2_tai_write(nano, base + MVPP22_TAI_TOD_STEP_NANO_CR);
32691dd7195SRussell King 	mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TOD_STEP_FRAC_HIGH);
32791dd7195SRussell King 	mvpp2_tai_write(frac, base + MVPP22_TAI_TOD_STEP_FRAC_LOW);
32891dd7195SRussell King }
32991dd7195SRussell King 
mvpp22_tai_init(struct mvpp2_tai * tai)33091dd7195SRussell King static void mvpp22_tai_init(struct mvpp2_tai *tai)
33191dd7195SRussell King {
33291dd7195SRussell King 	void __iomem *base = tai->base;
33391dd7195SRussell King 
33491dd7195SRussell King 	mvpp22_tai_set_step(tai);
33591dd7195SRussell King 
33691dd7195SRussell King 	/* Release the TAI reset */
33791dd7195SRussell King 	mvpp2_tai_modify(base + MVPP22_TAI_CR0, CR0_SW_NRESET, CR0_SW_NRESET);
33891dd7195SRussell King }
33991dd7195SRussell King 
mvpp22_tai_ptp_clock_index(struct mvpp2_tai * tai)340ce3497e2SRussell King int mvpp22_tai_ptp_clock_index(struct mvpp2_tai *tai)
341ce3497e2SRussell King {
342ce3497e2SRussell King 	return ptp_clock_index(tai->ptp_clock);
343ce3497e2SRussell King }
344ce3497e2SRussell King 
mvpp22_tai_tstamp(struct mvpp2_tai * tai,u32 tstamp,struct skb_shared_hwtstamps * hwtstamp)345ce3497e2SRussell King void mvpp22_tai_tstamp(struct mvpp2_tai *tai, u32 tstamp,
346ce3497e2SRussell King 		       struct skb_shared_hwtstamps *hwtstamp)
347ce3497e2SRussell King {
348ce3497e2SRussell King 	struct timespec64 ts;
349ce3497e2SRussell King 	int delta;
350ce3497e2SRussell King 
351ce3497e2SRussell King 	/* The tstamp consists of 2 bits of seconds and 30 bits of nanoseconds.
352ce3497e2SRussell King 	 * We use our stored timestamp (tai->stamp) to form a full timestamp,
353ce3497e2SRussell King 	 * and we must read the seconds exactly once.
354ce3497e2SRussell King 	 */
355ce3497e2SRussell King 	ts.tv_sec = READ_ONCE(tai->stamp.tv_sec);
356ce3497e2SRussell King 	ts.tv_nsec = tstamp & 0x3fffffff;
357ce3497e2SRussell King 
358ce3497e2SRussell King 	/* Calculate the delta in seconds between our stored timestamp and
359ce3497e2SRussell King 	 * the value read from the queue. Allow timestamps one second in the
360ce3497e2SRussell King 	 * past, otherwise consider them to be in the future.
361ce3497e2SRussell King 	 */
362ce3497e2SRussell King 	delta = ((tstamp >> 30) - (ts.tv_sec & 3)) & 3;
363ce3497e2SRussell King 	if (delta == 3)
364ce3497e2SRussell King 		delta -= 4;
365ce3497e2SRussell King 	ts.tv_sec += delta;
366ce3497e2SRussell King 
367ce3497e2SRussell King 	memset(hwtstamp, 0, sizeof(*hwtstamp));
368ce3497e2SRussell King 	hwtstamp->hwtstamp = timespec64_to_ktime(ts);
369ce3497e2SRussell King }
370ce3497e2SRussell King 
mvpp22_tai_start(struct mvpp2_tai * tai)371ce3497e2SRussell King void mvpp22_tai_start(struct mvpp2_tai *tai)
372ce3497e2SRussell King {
373ce3497e2SRussell King 	long delay;
374ce3497e2SRussell King 
375ce3497e2SRussell King 	delay = mvpp22_tai_aux_work(&tai->caps);
376ce3497e2SRussell King 
377ce3497e2SRussell King 	ptp_schedule_worker(tai->ptp_clock, delay);
378ce3497e2SRussell King }
379ce3497e2SRussell King 
mvpp22_tai_stop(struct mvpp2_tai * tai)380ce3497e2SRussell King void mvpp22_tai_stop(struct mvpp2_tai *tai)
381ce3497e2SRussell King {
382ce3497e2SRussell King 	ptp_cancel_worker_sync(tai->ptp_clock);
383ce3497e2SRussell King }
384ce3497e2SRussell King 
mvpp22_tai_remove(void * priv)38591dd7195SRussell King static void mvpp22_tai_remove(void *priv)
38691dd7195SRussell King {
38791dd7195SRussell King 	struct mvpp2_tai *tai = priv;
38891dd7195SRussell King 
38991dd7195SRussell King 	if (!IS_ERR(tai->ptp_clock))
39091dd7195SRussell King 		ptp_clock_unregister(tai->ptp_clock);
39191dd7195SRussell King }
39291dd7195SRussell King 
mvpp22_tai_probe(struct device * dev,struct mvpp2 * priv)39391dd7195SRussell King int mvpp22_tai_probe(struct device *dev, struct mvpp2 *priv)
39491dd7195SRussell King {
39591dd7195SRussell King 	struct mvpp2_tai *tai;
39691dd7195SRussell King 	int ret;
39791dd7195SRussell King 
39891dd7195SRussell King 	tai = devm_kzalloc(dev, sizeof(*tai), GFP_KERNEL);
39991dd7195SRussell King 	if (!tai)
40091dd7195SRussell King 		return -ENOMEM;
40191dd7195SRussell King 
40291dd7195SRussell King 	spin_lock_init(&tai->lock);
40391dd7195SRussell King 
40491dd7195SRussell King 	tai->base = priv->iface_base;
40591dd7195SRussell King 
40691dd7195SRussell King 	/* The step size consists of three registers - a 16-bit nanosecond step
40791dd7195SRussell King 	 * size, and a 32-bit fractional nanosecond step size split over two
40891dd7195SRussell King 	 * registers. The fractional nanosecond step size has units of 2^-32ns.
40991dd7195SRussell King 	 *
41091dd7195SRussell King 	 * To calculate this, we calculate:
41191dd7195SRussell King 	 *   (10^9 + freq / 2) / (freq * 2^-32)
41291dd7195SRussell King 	 * which gives us the nanosecond step to the nearest integer in 16.32
41391dd7195SRussell King 	 * fixed point format, and the fractional part of the step size with
41491dd7195SRussell King 	 * the MSB inverted.  With rounding of the fractional nanosecond, and
41591dd7195SRussell King 	 * simplification, this becomes:
41691dd7195SRussell King 	 *   (10^9 << 32 + freq << 31 + (freq + 1) >> 1) / freq
41791dd7195SRussell King 	 *
41891dd7195SRussell King 	 * So:
41991dd7195SRussell King 	 *   div = (10^9 << 32 + freq << 31 + (freq + 1) >> 1) / freq
42091dd7195SRussell King 	 *   nano = upper_32_bits(div);
42191dd7195SRussell King 	 *   frac = lower_32_bits(div) ^ 0x80000000;
42291dd7195SRussell King 	 * Will give the values for the registers.
42391dd7195SRussell King 	 *
42491dd7195SRussell King 	 * This is all seems perfect, but alas it is not when considering the
42591dd7195SRussell King 	 * whole story.  The system is clocked from 25MHz, which is multiplied
42691dd7195SRussell King 	 * by a PLL to 1GHz, and then divided by three, giving 333333333Hz
42791dd7195SRussell King 	 * (recurring).  This gives exactly 3ns, but using 333333333Hz with
42891dd7195SRussell King 	 * the above gives an error of 13*2^-32ns.
42991dd7195SRussell King 	 *
43091dd7195SRussell King 	 * Consequently, we use the period rather than calculating from the
43191dd7195SRussell King 	 * frequency.
43291dd7195SRussell King 	 */
43391dd7195SRussell King 	tai->period = 3ULL << 32;
43491dd7195SRussell King 
43591dd7195SRussell King 	mvpp22_tai_init(tai);
43691dd7195SRussell King 
43791dd7195SRussell King 	tai->caps.owner = THIS_MODULE;
43891dd7195SRussell King 	strscpy(tai->caps.name, "Marvell PP2.2", sizeof(tai->caps.name));
43991dd7195SRussell King 	tai->caps.max_adj = mvpp22_calc_max_adj(tai);
44091dd7195SRussell King 	tai->caps.adjfine = mvpp22_tai_adjfine;
44191dd7195SRussell King 	tai->caps.adjtime = mvpp22_tai_adjtime;
44291dd7195SRussell King 	tai->caps.gettimex64 = mvpp22_tai_gettimex64;
44391dd7195SRussell King 	tai->caps.settime64 = mvpp22_tai_settime64;
444ce3497e2SRussell King 	tai->caps.do_aux_work = mvpp22_tai_aux_work;
44591dd7195SRussell King 
44691dd7195SRussell King 	ret = devm_add_action(dev, mvpp22_tai_remove, tai);
44791dd7195SRussell King 	if (ret)
44891dd7195SRussell King 		return ret;
44991dd7195SRussell King 
45091dd7195SRussell King 	tai->ptp_clock = ptp_clock_register(&tai->caps, dev);
45191dd7195SRussell King 	if (IS_ERR(tai->ptp_clock))
45291dd7195SRussell King 		return PTR_ERR(tai->ptp_clock);
45391dd7195SRussell King 
45491dd7195SRussell King 	priv->tai = tai;
45591dd7195SRussell King 
45691dd7195SRussell King 	return 0;
45791dd7195SRussell King }
458