10933bd04SHoratiu Vultur // SPDX-License-Identifier: GPL-2.0+
20933bd04SHoratiu Vultur /* Microchip Sparx5 Switch driver
30933bd04SHoratiu Vultur  *
40933bd04SHoratiu Vultur  * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
50933bd04SHoratiu Vultur  *
60933bd04SHoratiu Vultur  * The Sparx5 Chip Register Model can be browsed at this location:
70933bd04SHoratiu Vultur  * https://github.com/microchip-ung/sparx-5_reginfo
80933bd04SHoratiu Vultur  */
90933bd04SHoratiu Vultur #include <linux/ptp_classify.h>
100933bd04SHoratiu Vultur 
110933bd04SHoratiu Vultur #include "sparx5_main_regs.h"
120933bd04SHoratiu Vultur #include "sparx5_main.h"
130933bd04SHoratiu Vultur 
140933bd04SHoratiu Vultur #define SPARX5_MAX_PTP_ID	512
150933bd04SHoratiu Vultur 
160933bd04SHoratiu Vultur #define TOD_ACC_PIN		0x4
170933bd04SHoratiu Vultur 
180933bd04SHoratiu Vultur enum {
190933bd04SHoratiu Vultur 	PTP_PIN_ACTION_IDLE = 0,
200933bd04SHoratiu Vultur 	PTP_PIN_ACTION_LOAD,
210933bd04SHoratiu Vultur 	PTP_PIN_ACTION_SAVE,
220933bd04SHoratiu Vultur 	PTP_PIN_ACTION_CLOCK,
230933bd04SHoratiu Vultur 	PTP_PIN_ACTION_DELTA,
240933bd04SHoratiu Vultur 	PTP_PIN_ACTION_TOD
250933bd04SHoratiu Vultur };
260933bd04SHoratiu Vultur 
270933bd04SHoratiu Vultur static u64 sparx5_ptp_get_1ppm(struct sparx5 *sparx5)
280933bd04SHoratiu Vultur {
290933bd04SHoratiu Vultur 	/* Represents 1ppm adjustment in 2^59 format with 1.59687500000(625)
300933bd04SHoratiu Vultur 	 * 1.99609375000(500), 3.99218750000(250) as reference
310933bd04SHoratiu Vultur 	 * The value is calculated as following:
320933bd04SHoratiu Vultur 	 * (1/1000000)/((2^-59)/X)
330933bd04SHoratiu Vultur 	 */
340933bd04SHoratiu Vultur 
350933bd04SHoratiu Vultur 	u64 res;
360933bd04SHoratiu Vultur 
370933bd04SHoratiu Vultur 	switch (sparx5->coreclock) {
380933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_250MHZ:
390933bd04SHoratiu Vultur 		res = 2301339409586;
400933bd04SHoratiu Vultur 		break;
410933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_500MHZ:
420933bd04SHoratiu Vultur 		res = 1150669704793;
430933bd04SHoratiu Vultur 		break;
440933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_625MHZ:
450933bd04SHoratiu Vultur 		res =  920535763834;
460933bd04SHoratiu Vultur 		break;
470933bd04SHoratiu Vultur 	default:
480933bd04SHoratiu Vultur 		WARN_ON("Invalid core clock");
490933bd04SHoratiu Vultur 		break;
500933bd04SHoratiu Vultur 	}
510933bd04SHoratiu Vultur 
520933bd04SHoratiu Vultur 	return res;
530933bd04SHoratiu Vultur }
540933bd04SHoratiu Vultur 
550933bd04SHoratiu Vultur static u64 sparx5_ptp_get_nominal_value(struct sparx5 *sparx5)
560933bd04SHoratiu Vultur {
570933bd04SHoratiu Vultur 	u64 res;
580933bd04SHoratiu Vultur 
590933bd04SHoratiu Vultur 	switch (sparx5->coreclock) {
600933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_250MHZ:
610933bd04SHoratiu Vultur 		res = 0x1FF0000000000000;
620933bd04SHoratiu Vultur 		break;
630933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_500MHZ:
640933bd04SHoratiu Vultur 		res = 0x0FF8000000000000;
650933bd04SHoratiu Vultur 		break;
660933bd04SHoratiu Vultur 	case SPX5_CORE_CLOCK_625MHZ:
670933bd04SHoratiu Vultur 		res = 0x0CC6666666666666;
680933bd04SHoratiu Vultur 		break;
690933bd04SHoratiu Vultur 	default:
700933bd04SHoratiu Vultur 		WARN_ON("Invalid core clock");
710933bd04SHoratiu Vultur 		break;
720933bd04SHoratiu Vultur 	}
730933bd04SHoratiu Vultur 
740933bd04SHoratiu Vultur 	return res;
750933bd04SHoratiu Vultur }
760933bd04SHoratiu Vultur 
77*589a07b8SHoratiu Vultur int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
78*589a07b8SHoratiu Vultur {
79*589a07b8SHoratiu Vultur 	struct sparx5 *sparx5 = port->sparx5;
80*589a07b8SHoratiu Vultur 	struct hwtstamp_config cfg;
81*589a07b8SHoratiu Vultur 	struct sparx5_phc *phc;
82*589a07b8SHoratiu Vultur 
83*589a07b8SHoratiu Vultur 	/* For now don't allow to run ptp on ports that are part of a bridge,
84*589a07b8SHoratiu Vultur 	 * because in case of transparent clock the HW will still forward the
85*589a07b8SHoratiu Vultur 	 * frames, so there would be duplicate frames
86*589a07b8SHoratiu Vultur 	 */
87*589a07b8SHoratiu Vultur 
88*589a07b8SHoratiu Vultur 	if (test_bit(port->portno, sparx5->bridge_mask))
89*589a07b8SHoratiu Vultur 		return -EINVAL;
90*589a07b8SHoratiu Vultur 
91*589a07b8SHoratiu Vultur 	if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
92*589a07b8SHoratiu Vultur 		return -EFAULT;
93*589a07b8SHoratiu Vultur 
94*589a07b8SHoratiu Vultur 	switch (cfg.tx_type) {
95*589a07b8SHoratiu Vultur 	case HWTSTAMP_TX_ON:
96*589a07b8SHoratiu Vultur 		port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
97*589a07b8SHoratiu Vultur 		break;
98*589a07b8SHoratiu Vultur 	case HWTSTAMP_TX_ONESTEP_SYNC:
99*589a07b8SHoratiu Vultur 		port->ptp_cmd = IFH_REW_OP_ONE_STEP_PTP;
100*589a07b8SHoratiu Vultur 		break;
101*589a07b8SHoratiu Vultur 	case HWTSTAMP_TX_OFF:
102*589a07b8SHoratiu Vultur 		port->ptp_cmd = IFH_REW_OP_NOOP;
103*589a07b8SHoratiu Vultur 		break;
104*589a07b8SHoratiu Vultur 	default:
105*589a07b8SHoratiu Vultur 		return -ERANGE;
106*589a07b8SHoratiu Vultur 	}
107*589a07b8SHoratiu Vultur 
108*589a07b8SHoratiu Vultur 	switch (cfg.rx_filter) {
109*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_NONE:
110*589a07b8SHoratiu Vultur 		break;
111*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_ALL:
112*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
113*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
114*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
115*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
116*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
117*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
118*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
119*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
120*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
121*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
122*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
123*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
124*589a07b8SHoratiu Vultur 	case HWTSTAMP_FILTER_NTP_ALL:
125*589a07b8SHoratiu Vultur 		cfg.rx_filter = HWTSTAMP_FILTER_ALL;
126*589a07b8SHoratiu Vultur 		break;
127*589a07b8SHoratiu Vultur 	default:
128*589a07b8SHoratiu Vultur 		return -ERANGE;
129*589a07b8SHoratiu Vultur 	}
130*589a07b8SHoratiu Vultur 
131*589a07b8SHoratiu Vultur 	/* Commit back the result & save it */
132*589a07b8SHoratiu Vultur 	mutex_lock(&sparx5->ptp_lock);
133*589a07b8SHoratiu Vultur 	phc = &sparx5->phc[SPARX5_PHC_PORT];
134*589a07b8SHoratiu Vultur 	memcpy(&phc->hwtstamp_config, &cfg, sizeof(cfg));
135*589a07b8SHoratiu Vultur 	mutex_unlock(&sparx5->ptp_lock);
136*589a07b8SHoratiu Vultur 
137*589a07b8SHoratiu Vultur 	return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
138*589a07b8SHoratiu Vultur }
139*589a07b8SHoratiu Vultur 
140*589a07b8SHoratiu Vultur int sparx5_ptp_hwtstamp_get(struct sparx5_port *port, struct ifreq *ifr)
141*589a07b8SHoratiu Vultur {
142*589a07b8SHoratiu Vultur 	struct sparx5 *sparx5 = port->sparx5;
143*589a07b8SHoratiu Vultur 	struct sparx5_phc *phc;
144*589a07b8SHoratiu Vultur 
145*589a07b8SHoratiu Vultur 	phc = &sparx5->phc[SPARX5_PHC_PORT];
146*589a07b8SHoratiu Vultur 	return copy_to_user(ifr->ifr_data, &phc->hwtstamp_config,
147*589a07b8SHoratiu Vultur 			    sizeof(phc->hwtstamp_config)) ? -EFAULT : 0;
148*589a07b8SHoratiu Vultur }
149*589a07b8SHoratiu Vultur 
1500933bd04SHoratiu Vultur static int sparx5_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
1510933bd04SHoratiu Vultur {
1520933bd04SHoratiu Vultur 	struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info);
1530933bd04SHoratiu Vultur 	struct sparx5 *sparx5 = phc->sparx5;
1540933bd04SHoratiu Vultur 	unsigned long flags;
1550933bd04SHoratiu Vultur 	bool neg_adj = 0;
1560933bd04SHoratiu Vultur 	u64 tod_inc;
1570933bd04SHoratiu Vultur 	u64 ref;
1580933bd04SHoratiu Vultur 
1590933bd04SHoratiu Vultur 	if (!scaled_ppm)
1600933bd04SHoratiu Vultur 		return 0;
1610933bd04SHoratiu Vultur 
1620933bd04SHoratiu Vultur 	if (scaled_ppm < 0) {
1630933bd04SHoratiu Vultur 		neg_adj = 1;
1640933bd04SHoratiu Vultur 		scaled_ppm = -scaled_ppm;
1650933bd04SHoratiu Vultur 	}
1660933bd04SHoratiu Vultur 
1670933bd04SHoratiu Vultur 	tod_inc = sparx5_ptp_get_nominal_value(sparx5);
1680933bd04SHoratiu Vultur 
1690933bd04SHoratiu Vultur 	/* The multiplication is split in 2 separate additions because of
1700933bd04SHoratiu Vultur 	 * overflow issues. If scaled_ppm with 16bit fractional part was bigger
1710933bd04SHoratiu Vultur 	 * than 20ppm then we got overflow.
1720933bd04SHoratiu Vultur 	 */
1730933bd04SHoratiu Vultur 	ref = sparx5_ptp_get_1ppm(sparx5) * (scaled_ppm >> 16);
1740933bd04SHoratiu Vultur 	ref += (sparx5_ptp_get_1ppm(sparx5) * (0xffff & scaled_ppm)) >> 16;
1750933bd04SHoratiu Vultur 	tod_inc = neg_adj ? tod_inc - ref : tod_inc + ref;
1760933bd04SHoratiu Vultur 
1770933bd04SHoratiu Vultur 	spin_lock_irqsave(&sparx5->ptp_clock_lock, flags);
1780933bd04SHoratiu Vultur 
1790933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(1 << BIT(phc->index)),
1800933bd04SHoratiu Vultur 		 PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS,
1810933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_DOM_CFG);
1820933bd04SHoratiu Vultur 
1830933bd04SHoratiu Vultur 	spx5_wr((u32)tod_inc & 0xFFFFFFFF, sparx5,
1840933bd04SHoratiu Vultur 		PTP_CLK_PER_CFG(phc->index, 0));
1850933bd04SHoratiu Vultur 	spx5_wr((u32)(tod_inc >> 32), sparx5,
1860933bd04SHoratiu Vultur 		PTP_CLK_PER_CFG(phc->index, 1));
1870933bd04SHoratiu Vultur 
1880933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(0),
1890933bd04SHoratiu Vultur 		 PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS, sparx5,
1900933bd04SHoratiu Vultur 		 PTP_PTP_DOM_CFG);
1910933bd04SHoratiu Vultur 
1920933bd04SHoratiu Vultur 	spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
1930933bd04SHoratiu Vultur 
1940933bd04SHoratiu Vultur 	return 0;
1950933bd04SHoratiu Vultur }
1960933bd04SHoratiu Vultur 
1970933bd04SHoratiu Vultur static int sparx5_ptp_settime64(struct ptp_clock_info *ptp,
1980933bd04SHoratiu Vultur 				const struct timespec64 *ts)
1990933bd04SHoratiu Vultur {
2000933bd04SHoratiu Vultur 	struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info);
2010933bd04SHoratiu Vultur 	struct sparx5 *sparx5 = phc->sparx5;
2020933bd04SHoratiu Vultur 	unsigned long flags;
2030933bd04SHoratiu Vultur 
2040933bd04SHoratiu Vultur 	spin_lock_irqsave(&sparx5->ptp_clock_lock, flags);
2050933bd04SHoratiu Vultur 
2060933bd04SHoratiu Vultur 	/* Must be in IDLE mode before the time can be loaded */
2070933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_IDLE) |
2080933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
2090933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
2100933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
2110933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
2120933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
2130933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
2140933bd04SHoratiu Vultur 
2150933bd04SHoratiu Vultur 	/* Set new value */
2160933bd04SHoratiu Vultur 	spx5_wr(PTP_PTP_TOD_SEC_MSB_PTP_TOD_SEC_MSB_SET(upper_32_bits(ts->tv_sec)),
2170933bd04SHoratiu Vultur 		sparx5, PTP_PTP_TOD_SEC_MSB(TOD_ACC_PIN));
2180933bd04SHoratiu Vultur 	spx5_wr(lower_32_bits(ts->tv_sec),
2190933bd04SHoratiu Vultur 		sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN));
2200933bd04SHoratiu Vultur 	spx5_wr(ts->tv_nsec, sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN));
2210933bd04SHoratiu Vultur 
2220933bd04SHoratiu Vultur 	/* Apply new values */
2230933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_LOAD) |
2240933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
2250933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
2260933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
2270933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
2280933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
2290933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
2300933bd04SHoratiu Vultur 
2310933bd04SHoratiu Vultur 	spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
2320933bd04SHoratiu Vultur 
2330933bd04SHoratiu Vultur 	return 0;
2340933bd04SHoratiu Vultur }
2350933bd04SHoratiu Vultur 
2360933bd04SHoratiu Vultur static int sparx5_ptp_gettime64(struct ptp_clock_info *ptp,
2370933bd04SHoratiu Vultur 				struct timespec64 *ts)
2380933bd04SHoratiu Vultur {
2390933bd04SHoratiu Vultur 	struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info);
2400933bd04SHoratiu Vultur 	struct sparx5 *sparx5 = phc->sparx5;
2410933bd04SHoratiu Vultur 	unsigned long flags;
2420933bd04SHoratiu Vultur 	time64_t s;
2430933bd04SHoratiu Vultur 	s64 ns;
2440933bd04SHoratiu Vultur 
2450933bd04SHoratiu Vultur 	spin_lock_irqsave(&sparx5->ptp_clock_lock, flags);
2460933bd04SHoratiu Vultur 
2470933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_SAVE) |
2480933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
2490933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
2500933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
2510933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
2520933bd04SHoratiu Vultur 		 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
2530933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
2540933bd04SHoratiu Vultur 
2550933bd04SHoratiu Vultur 	s = spx5_rd(sparx5, PTP_PTP_TOD_SEC_MSB(TOD_ACC_PIN));
2560933bd04SHoratiu Vultur 	s <<= 32;
2570933bd04SHoratiu Vultur 	s |= spx5_rd(sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN));
2580933bd04SHoratiu Vultur 	ns = spx5_rd(sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN));
2590933bd04SHoratiu Vultur 	ns &= PTP_PTP_TOD_NSEC_PTP_TOD_NSEC;
2600933bd04SHoratiu Vultur 
2610933bd04SHoratiu Vultur 	spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
2620933bd04SHoratiu Vultur 
2630933bd04SHoratiu Vultur 	/* Deal with negative values */
2640933bd04SHoratiu Vultur 	if ((ns & 0xFFFFFFF0) == 0x3FFFFFF0) {
2650933bd04SHoratiu Vultur 		s--;
2660933bd04SHoratiu Vultur 		ns &= 0xf;
2670933bd04SHoratiu Vultur 		ns += 999999984;
2680933bd04SHoratiu Vultur 	}
2690933bd04SHoratiu Vultur 
2700933bd04SHoratiu Vultur 	set_normalized_timespec64(ts, s, ns);
2710933bd04SHoratiu Vultur 	return 0;
2720933bd04SHoratiu Vultur }
2730933bd04SHoratiu Vultur 
2740933bd04SHoratiu Vultur static int sparx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
2750933bd04SHoratiu Vultur {
2760933bd04SHoratiu Vultur 	struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info);
2770933bd04SHoratiu Vultur 	struct sparx5 *sparx5 = phc->sparx5;
2780933bd04SHoratiu Vultur 
2790933bd04SHoratiu Vultur 	if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) {
2800933bd04SHoratiu Vultur 		unsigned long flags;
2810933bd04SHoratiu Vultur 
2820933bd04SHoratiu Vultur 		spin_lock_irqsave(&sparx5->ptp_clock_lock, flags);
2830933bd04SHoratiu Vultur 
2840933bd04SHoratiu Vultur 		/* Must be in IDLE mode before the time can be loaded */
2850933bd04SHoratiu Vultur 		spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_IDLE) |
2860933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
2870933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
2880933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
2890933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
2900933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
2910933bd04SHoratiu Vultur 			 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
2920933bd04SHoratiu Vultur 
2930933bd04SHoratiu Vultur 		spx5_wr(PTP_PTP_TOD_NSEC_PTP_TOD_NSEC_SET(delta),
2940933bd04SHoratiu Vultur 			sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN));
2950933bd04SHoratiu Vultur 
2960933bd04SHoratiu Vultur 		/* Adjust time with the value of PTP_TOD_NSEC */
2970933bd04SHoratiu Vultur 		spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_DELTA) |
2980933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
2990933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
3000933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
3010933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_DOM |
3020933bd04SHoratiu Vultur 			 PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
3030933bd04SHoratiu Vultur 			 sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN));
3040933bd04SHoratiu Vultur 
3050933bd04SHoratiu Vultur 		spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
3060933bd04SHoratiu Vultur 	} else {
3070933bd04SHoratiu Vultur 		/* Fall back using sparx5_ptp_settime64 which is not exact */
3080933bd04SHoratiu Vultur 		struct timespec64 ts;
3090933bd04SHoratiu Vultur 		u64 now;
3100933bd04SHoratiu Vultur 
3110933bd04SHoratiu Vultur 		sparx5_ptp_gettime64(ptp, &ts);
3120933bd04SHoratiu Vultur 
3130933bd04SHoratiu Vultur 		now = ktime_to_ns(timespec64_to_ktime(ts));
3140933bd04SHoratiu Vultur 		ts = ns_to_timespec64(now + delta);
3150933bd04SHoratiu Vultur 
3160933bd04SHoratiu Vultur 		sparx5_ptp_settime64(ptp, &ts);
3170933bd04SHoratiu Vultur 	}
3180933bd04SHoratiu Vultur 
3190933bd04SHoratiu Vultur 	return 0;
3200933bd04SHoratiu Vultur }
3210933bd04SHoratiu Vultur 
3220933bd04SHoratiu Vultur static struct ptp_clock_info sparx5_ptp_clock_info = {
3230933bd04SHoratiu Vultur 	.owner		= THIS_MODULE,
3240933bd04SHoratiu Vultur 	.name		= "sparx5 ptp",
3250933bd04SHoratiu Vultur 	.max_adj	= 200000,
3260933bd04SHoratiu Vultur 	.gettime64	= sparx5_ptp_gettime64,
3270933bd04SHoratiu Vultur 	.settime64	= sparx5_ptp_settime64,
3280933bd04SHoratiu Vultur 	.adjtime	= sparx5_ptp_adjtime,
3290933bd04SHoratiu Vultur 	.adjfine	= sparx5_ptp_adjfine,
3300933bd04SHoratiu Vultur };
3310933bd04SHoratiu Vultur 
3320933bd04SHoratiu Vultur static int sparx5_ptp_phc_init(struct sparx5 *sparx5,
3330933bd04SHoratiu Vultur 			       int index,
3340933bd04SHoratiu Vultur 			       struct ptp_clock_info *clock_info)
3350933bd04SHoratiu Vultur {
3360933bd04SHoratiu Vultur 	struct sparx5_phc *phc = &sparx5->phc[index];
3370933bd04SHoratiu Vultur 
3380933bd04SHoratiu Vultur 	phc->info = *clock_info;
3390933bd04SHoratiu Vultur 	phc->clock = ptp_clock_register(&phc->info, sparx5->dev);
3400933bd04SHoratiu Vultur 	if (IS_ERR(phc->clock))
3410933bd04SHoratiu Vultur 		return PTR_ERR(phc->clock);
3420933bd04SHoratiu Vultur 
3430933bd04SHoratiu Vultur 	phc->index = index;
3440933bd04SHoratiu Vultur 	phc->sparx5 = sparx5;
3450933bd04SHoratiu Vultur 
3460933bd04SHoratiu Vultur 	/* PTP Rx stamping is always enabled.  */
3470933bd04SHoratiu Vultur 	phc->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
3480933bd04SHoratiu Vultur 
3490933bd04SHoratiu Vultur 	return 0;
3500933bd04SHoratiu Vultur }
3510933bd04SHoratiu Vultur 
3520933bd04SHoratiu Vultur int sparx5_ptp_init(struct sparx5 *sparx5)
3530933bd04SHoratiu Vultur {
3540933bd04SHoratiu Vultur 	u64 tod_adj = sparx5_ptp_get_nominal_value(sparx5);
3550933bd04SHoratiu Vultur 	int err, i;
3560933bd04SHoratiu Vultur 
3570933bd04SHoratiu Vultur 	if (!sparx5->ptp)
3580933bd04SHoratiu Vultur 		return 0;
3590933bd04SHoratiu Vultur 
3600933bd04SHoratiu Vultur 	for (i = 0; i < SPARX5_PHC_COUNT; ++i) {
3610933bd04SHoratiu Vultur 		err = sparx5_ptp_phc_init(sparx5, i, &sparx5_ptp_clock_info);
3620933bd04SHoratiu Vultur 		if (err)
3630933bd04SHoratiu Vultur 			return err;
3640933bd04SHoratiu Vultur 	}
3650933bd04SHoratiu Vultur 
3660933bd04SHoratiu Vultur 	spin_lock_init(&sparx5->ptp_clock_lock);
367*589a07b8SHoratiu Vultur 	mutex_init(&sparx5->ptp_lock);
3680933bd04SHoratiu Vultur 
3690933bd04SHoratiu Vultur 	/* Disable master counters */
3700933bd04SHoratiu Vultur 	spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0), sparx5, PTP_PTP_DOM_CFG);
3710933bd04SHoratiu Vultur 
3720933bd04SHoratiu Vultur 	/* Configure the nominal TOD increment per clock cycle */
3730933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(0x7),
3740933bd04SHoratiu Vultur 		 PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS,
3750933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_DOM_CFG);
3760933bd04SHoratiu Vultur 
3770933bd04SHoratiu Vultur 	for (i = 0; i < SPARX5_PHC_COUNT; ++i) {
3780933bd04SHoratiu Vultur 		spx5_wr((u32)tod_adj & 0xFFFFFFFF, sparx5,
3790933bd04SHoratiu Vultur 			PTP_CLK_PER_CFG(i, 0));
3800933bd04SHoratiu Vultur 		spx5_wr((u32)(tod_adj >> 32), sparx5,
3810933bd04SHoratiu Vultur 			PTP_CLK_PER_CFG(i, 1));
3820933bd04SHoratiu Vultur 	}
3830933bd04SHoratiu Vultur 
3840933bd04SHoratiu Vultur 	spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(0),
3850933bd04SHoratiu Vultur 		 PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS,
3860933bd04SHoratiu Vultur 		 sparx5, PTP_PTP_DOM_CFG);
3870933bd04SHoratiu Vultur 
3880933bd04SHoratiu Vultur 	/* Enable master counters */
3890933bd04SHoratiu Vultur 	spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0x7), sparx5, PTP_PTP_DOM_CFG);
3900933bd04SHoratiu Vultur 
3910933bd04SHoratiu Vultur 	return 0;
3920933bd04SHoratiu Vultur }
3930933bd04SHoratiu Vultur 
3940933bd04SHoratiu Vultur void sparx5_ptp_deinit(struct sparx5 *sparx5)
3950933bd04SHoratiu Vultur {
3960933bd04SHoratiu Vultur 	int i;
3970933bd04SHoratiu Vultur 
3980933bd04SHoratiu Vultur 	for (i = 0; i < SPARX5_PHC_COUNT; ++i)
3990933bd04SHoratiu Vultur 		ptp_clock_unregister(sparx5->phc[i].clock);
4000933bd04SHoratiu Vultur }
401