xref: /openbmc/linux/drivers/net/dsa/microchip/ksz_ptp.c (revision 26d0dfbb16fcb17d128a79dc70f3020ea6992af0)
1eac1ea20SChristian Eggers // SPDX-License-Identifier: GPL-2.0
2eac1ea20SChristian Eggers /* Microchip KSZ PTP Implementation
3eac1ea20SChristian Eggers  *
4eac1ea20SChristian Eggers  * Copyright (C) 2020 ARRI Lighting
5eac1ea20SChristian Eggers  * Copyright (C) 2022 Microchip Technology Inc.
6eac1ea20SChristian Eggers  */
7eac1ea20SChristian Eggers 
8c2977c61SArun Ramadoss #include <linux/dsa/ksz_common.h>
9cc13ab18SArun Ramadoss #include <linux/irq.h>
10cc13ab18SArun Ramadoss #include <linux/irqdomain.h>
11eac1ea20SChristian Eggers #include <linux/kernel.h>
12eac1ea20SChristian Eggers #include <linux/ptp_classify.h>
13eac1ea20SChristian Eggers #include <linux/ptp_clock_kernel.h>
14eac1ea20SChristian Eggers 
15eac1ea20SChristian Eggers #include "ksz_common.h"
16eac1ea20SChristian Eggers #include "ksz_ptp.h"
17eac1ea20SChristian Eggers #include "ksz_ptp_reg.h"
18eac1ea20SChristian Eggers 
19eac1ea20SChristian Eggers #define ptp_caps_to_data(d) container_of((d), struct ksz_ptp_data, caps)
20eac1ea20SChristian Eggers #define ptp_data_to_ksz_dev(d) container_of((d), struct ksz_device, ptp_data)
21ab32f56aSChristian Eggers #define work_to_xmit_work(w) \
22ab32f56aSChristian Eggers 		container_of((w), struct ksz_deferred_xmit_work, work)
23eac1ea20SChristian Eggers 
24eac1ea20SChristian Eggers /* Sub-nanoseconds-adj,max * sub-nanoseconds / 40ns * 1ns
25eac1ea20SChristian Eggers  * = (2^30-1) * (2 ^ 32) / 40 ns * 1 ns = 6249999
26eac1ea20SChristian Eggers  */
27eac1ea20SChristian Eggers #define KSZ_MAX_DRIFT_CORR 6249999
281f12ae5bSChristian Eggers #define KSZ_MAX_PULSE_WIDTH 125000000LL
29eac1ea20SChristian Eggers 
30eac1ea20SChristian Eggers #define KSZ_PTP_INC_NS 40ULL  /* HW clock is incremented every 40 ns (by 40) */
31eac1ea20SChristian Eggers #define KSZ_PTP_SUBNS_BITS 32
32eac1ea20SChristian Eggers 
33cc13ab18SArun Ramadoss #define KSZ_PTP_INT_START 13
34cc13ab18SArun Ramadoss 
ksz_ptp_tou_gpio(struct ksz_device * dev)35168a5940SArun Ramadoss static int ksz_ptp_tou_gpio(struct ksz_device *dev)
36168a5940SArun Ramadoss {
37168a5940SArun Ramadoss 	int ret;
38168a5940SArun Ramadoss 
39168a5940SArun Ramadoss 	if (!is_lan937x(dev))
40168a5940SArun Ramadoss 		return 0;
41168a5940SArun Ramadoss 
42168a5940SArun Ramadoss 	ret = ksz_rmw32(dev, REG_PTP_CTRL_STAT__4, GPIO_OUT,
43168a5940SArun Ramadoss 			GPIO_OUT);
44168a5940SArun Ramadoss 	if (ret)
45168a5940SArun Ramadoss 		return ret;
46168a5940SArun Ramadoss 
47168a5940SArun Ramadoss 	ret = ksz_rmw32(dev, REG_SW_GLOBAL_LED_OVR__4, LED_OVR_1 | LED_OVR_2,
48168a5940SArun Ramadoss 			LED_OVR_1 | LED_OVR_2);
49168a5940SArun Ramadoss 	if (ret)
50168a5940SArun Ramadoss 		return ret;
51168a5940SArun Ramadoss 
52168a5940SArun Ramadoss 	return ksz_rmw32(dev, REG_SW_GLOBAL_LED_SRC__4,
53168a5940SArun Ramadoss 			 LED_SRC_PTP_GPIO_1 | LED_SRC_PTP_GPIO_2,
54168a5940SArun Ramadoss 			 LED_SRC_PTP_GPIO_1 | LED_SRC_PTP_GPIO_2);
55168a5940SArun Ramadoss }
56168a5940SArun Ramadoss 
ksz_ptp_tou_reset(struct ksz_device * dev,u8 unit)571f12ae5bSChristian Eggers static int ksz_ptp_tou_reset(struct ksz_device *dev, u8 unit)
581f12ae5bSChristian Eggers {
591f12ae5bSChristian Eggers 	u32 data;
601f12ae5bSChristian Eggers 	int ret;
611f12ae5bSChristian Eggers 
621f12ae5bSChristian Eggers 	/* Reset trigger unit (clears TRIGGER_EN, but not GPIOSTATx) */
631f12ae5bSChristian Eggers 	ret = ksz_rmw32(dev, REG_PTP_CTRL_STAT__4, TRIG_RESET, TRIG_RESET);
641f12ae5bSChristian Eggers 
651f12ae5bSChristian Eggers 	data = FIELD_PREP(TRIG_DONE_M, BIT(unit));
661f12ae5bSChristian Eggers 	ret = ksz_write32(dev, REG_PTP_TRIG_STATUS__4, data);
671f12ae5bSChristian Eggers 	if (ret)
681f12ae5bSChristian Eggers 		return ret;
691f12ae5bSChristian Eggers 
701f12ae5bSChristian Eggers 	data = FIELD_PREP(TRIG_INT_M, BIT(unit));
711f12ae5bSChristian Eggers 	ret = ksz_write32(dev, REG_PTP_INT_STATUS__4, data);
721f12ae5bSChristian Eggers 	if (ret)
731f12ae5bSChristian Eggers 		return ret;
741f12ae5bSChristian Eggers 
751f12ae5bSChristian Eggers 	/* Clear reset and set GPIO direction */
761f12ae5bSChristian Eggers 	return ksz_rmw32(dev, REG_PTP_CTRL_STAT__4, (TRIG_RESET | TRIG_ENABLE),
771f12ae5bSChristian Eggers 			 0);
781f12ae5bSChristian Eggers }
791f12ae5bSChristian Eggers 
ksz_ptp_tou_pulse_verify(u64 pulse_ns)801f12ae5bSChristian Eggers static int ksz_ptp_tou_pulse_verify(u64 pulse_ns)
811f12ae5bSChristian Eggers {
821f12ae5bSChristian Eggers 	u32 data;
831f12ae5bSChristian Eggers 
841f12ae5bSChristian Eggers 	if (pulse_ns & 0x3)
851f12ae5bSChristian Eggers 		return -EINVAL;
861f12ae5bSChristian Eggers 
871f12ae5bSChristian Eggers 	data = (pulse_ns / 8);
881f12ae5bSChristian Eggers 	if (!FIELD_FIT(TRIG_PULSE_WIDTH_M, data))
891f12ae5bSChristian Eggers 		return -ERANGE;
901f12ae5bSChristian Eggers 
911f12ae5bSChristian Eggers 	return 0;
921f12ae5bSChristian Eggers }
931f12ae5bSChristian Eggers 
ksz_ptp_tou_target_time_set(struct ksz_device * dev,struct timespec64 const * ts)941f12ae5bSChristian Eggers static int ksz_ptp_tou_target_time_set(struct ksz_device *dev,
951f12ae5bSChristian Eggers 				       struct timespec64 const *ts)
961f12ae5bSChristian Eggers {
971f12ae5bSChristian Eggers 	int ret;
981f12ae5bSChristian Eggers 
991f12ae5bSChristian Eggers 	/* Hardware has only 32 bit */
1001f12ae5bSChristian Eggers 	if ((ts->tv_sec & 0xffffffff) != ts->tv_sec)
1011f12ae5bSChristian Eggers 		return -EINVAL;
1021f12ae5bSChristian Eggers 
1031f12ae5bSChristian Eggers 	ret = ksz_write32(dev, REG_TRIG_TARGET_NANOSEC, ts->tv_nsec);
1041f12ae5bSChristian Eggers 	if (ret)
1051f12ae5bSChristian Eggers 		return ret;
1061f12ae5bSChristian Eggers 
1071f12ae5bSChristian Eggers 	ret = ksz_write32(dev, REG_TRIG_TARGET_SEC, ts->tv_sec);
1081f12ae5bSChristian Eggers 	if (ret)
1091f12ae5bSChristian Eggers 		return ret;
1101f12ae5bSChristian Eggers 
1111f12ae5bSChristian Eggers 	return 0;
1121f12ae5bSChristian Eggers }
1131f12ae5bSChristian Eggers 
ksz_ptp_tou_start(struct ksz_device * dev,u8 unit)1141f12ae5bSChristian Eggers static int ksz_ptp_tou_start(struct ksz_device *dev, u8 unit)
1151f12ae5bSChristian Eggers {
1161f12ae5bSChristian Eggers 	u32 data;
1171f12ae5bSChristian Eggers 	int ret;
1181f12ae5bSChristian Eggers 
1191f12ae5bSChristian Eggers 	ret = ksz_rmw32(dev, REG_PTP_CTRL_STAT__4, TRIG_ENABLE, TRIG_ENABLE);
1201f12ae5bSChristian Eggers 	if (ret)
1211f12ae5bSChristian Eggers 		return ret;
1221f12ae5bSChristian Eggers 
1231f12ae5bSChristian Eggers 	/* Check error flag:
1241f12ae5bSChristian Eggers 	 * - the ACTIVE flag is NOT cleared an error!
1251f12ae5bSChristian Eggers 	 */
1261f12ae5bSChristian Eggers 	ret = ksz_read32(dev, REG_PTP_TRIG_STATUS__4, &data);
1271f12ae5bSChristian Eggers 	if (ret)
1281f12ae5bSChristian Eggers 		return ret;
1291f12ae5bSChristian Eggers 
1301f12ae5bSChristian Eggers 	if (FIELD_GET(TRIG_ERROR_M, data) & (1 << unit)) {
1311f12ae5bSChristian Eggers 		dev_err(dev->dev, "%s: Trigger unit%d error!\n", __func__,
1321f12ae5bSChristian Eggers 			unit);
1331f12ae5bSChristian Eggers 		ret = -EIO;
1341f12ae5bSChristian Eggers 		/* Unit will be reset on next access */
1351f12ae5bSChristian Eggers 		return ret;
1361f12ae5bSChristian Eggers 	}
1371f12ae5bSChristian Eggers 
1381f12ae5bSChristian Eggers 	return 0;
1391f12ae5bSChristian Eggers }
1401f12ae5bSChristian Eggers 
ksz_ptp_configure_perout(struct ksz_device * dev,u32 cycle_width_ns,u32 pulse_width_ns,struct timespec64 const * target_time,u8 index)1411f12ae5bSChristian Eggers static int ksz_ptp_configure_perout(struct ksz_device *dev,
1421f12ae5bSChristian Eggers 				    u32 cycle_width_ns, u32 pulse_width_ns,
1431f12ae5bSChristian Eggers 				    struct timespec64 const *target_time,
1441f12ae5bSChristian Eggers 				    u8 index)
1451f12ae5bSChristian Eggers {
1461f12ae5bSChristian Eggers 	u32 data;
1471f12ae5bSChristian Eggers 	int ret;
1481f12ae5bSChristian Eggers 
1491f12ae5bSChristian Eggers 	data = FIELD_PREP(TRIG_NOTIFY, 1) |
1501f12ae5bSChristian Eggers 		FIELD_PREP(TRIG_GPO_M, index) |
1511f12ae5bSChristian Eggers 		FIELD_PREP(TRIG_PATTERN_M, TRIG_POS_PERIOD);
1521f12ae5bSChristian Eggers 	ret = ksz_write32(dev, REG_TRIG_CTRL__4, data);
1531f12ae5bSChristian Eggers 	if (ret)
1541f12ae5bSChristian Eggers 		return ret;
1551f12ae5bSChristian Eggers 
1561f12ae5bSChristian Eggers 	ret = ksz_write32(dev, REG_TRIG_CYCLE_WIDTH, cycle_width_ns);
1571f12ae5bSChristian Eggers 	if (ret)
1581f12ae5bSChristian Eggers 		return ret;
1591f12ae5bSChristian Eggers 
1601f12ae5bSChristian Eggers 	/* Set cycle count 0 - Infinite */
1611f12ae5bSChristian Eggers 	ret = ksz_rmw32(dev, REG_TRIG_CYCLE_CNT, TRIG_CYCLE_CNT_M, 0);
1621f12ae5bSChristian Eggers 	if (ret)
1631f12ae5bSChristian Eggers 		return ret;
1641f12ae5bSChristian Eggers 
1651f12ae5bSChristian Eggers 	data = (pulse_width_ns / 8);
1661f12ae5bSChristian Eggers 	ret = ksz_write32(dev, REG_TRIG_PULSE_WIDTH__4, data);
1671f12ae5bSChristian Eggers 	if (ret)
1681f12ae5bSChristian Eggers 		return ret;
1691f12ae5bSChristian Eggers 
1701f12ae5bSChristian Eggers 	ret = ksz_ptp_tou_target_time_set(dev, target_time);
1711f12ae5bSChristian Eggers 	if (ret)
1721f12ae5bSChristian Eggers 		return ret;
1731f12ae5bSChristian Eggers 
1741f12ae5bSChristian Eggers 	return 0;
1751f12ae5bSChristian Eggers }
1761f12ae5bSChristian Eggers 
ksz_ptp_enable_perout(struct ksz_device * dev,struct ptp_perout_request const * request,int on)1771f12ae5bSChristian Eggers static int ksz_ptp_enable_perout(struct ksz_device *dev,
1781f12ae5bSChristian Eggers 				 struct ptp_perout_request const *request,
1791f12ae5bSChristian Eggers 				 int on)
1801f12ae5bSChristian Eggers {
1811f12ae5bSChristian Eggers 	struct ksz_ptp_data *ptp_data = &dev->ptp_data;
1821f12ae5bSChristian Eggers 	u64 req_pulse_width_ns;
1831f12ae5bSChristian Eggers 	u64 cycle_width_ns;
1841f12ae5bSChristian Eggers 	u64 pulse_width_ns;
1851f12ae5bSChristian Eggers 	int pin = 0;
1861f12ae5bSChristian Eggers 	u32 data32;
1871f12ae5bSChristian Eggers 	int ret;
1881f12ae5bSChristian Eggers 
1891f12ae5bSChristian Eggers 	if (request->flags & ~PTP_PEROUT_DUTY_CYCLE)
1901f12ae5bSChristian Eggers 		return -EOPNOTSUPP;
1911f12ae5bSChristian Eggers 
1921f12ae5bSChristian Eggers 	if (ptp_data->tou_mode != KSZ_PTP_TOU_PEROUT &&
1931f12ae5bSChristian Eggers 	    ptp_data->tou_mode != KSZ_PTP_TOU_IDLE)
1941f12ae5bSChristian Eggers 		return -EBUSY;
1951f12ae5bSChristian Eggers 
196343d3bd8SArun Ramadoss 	pin = ptp_find_pin(ptp_data->clock, PTP_PF_PEROUT, request->index);
197343d3bd8SArun Ramadoss 	if (pin < 0)
198343d3bd8SArun Ramadoss 		return -EINVAL;
199343d3bd8SArun Ramadoss 
2001f12ae5bSChristian Eggers 	data32 = FIELD_PREP(PTP_GPIO_INDEX, pin) |
2011f12ae5bSChristian Eggers 		 FIELD_PREP(PTP_TOU_INDEX, request->index);
2021f12ae5bSChristian Eggers 	ret = ksz_rmw32(dev, REG_PTP_UNIT_INDEX__4,
2031f12ae5bSChristian Eggers 			PTP_GPIO_INDEX | PTP_TOU_INDEX, data32);
2041f12ae5bSChristian Eggers 	if (ret)
2051f12ae5bSChristian Eggers 		return ret;
2061f12ae5bSChristian Eggers 
2071f12ae5bSChristian Eggers 	ret = ksz_ptp_tou_reset(dev, request->index);
2081f12ae5bSChristian Eggers 	if (ret)
2091f12ae5bSChristian Eggers 		return ret;
2101f12ae5bSChristian Eggers 
2111f12ae5bSChristian Eggers 	if (!on) {
2121f12ae5bSChristian Eggers 		ptp_data->tou_mode = KSZ_PTP_TOU_IDLE;
2131f12ae5bSChristian Eggers 		return 0;
2141f12ae5bSChristian Eggers 	}
2151f12ae5bSChristian Eggers 
2161f12ae5bSChristian Eggers 	ptp_data->perout_target_time_first.tv_sec  = request->start.sec;
2171f12ae5bSChristian Eggers 	ptp_data->perout_target_time_first.tv_nsec = request->start.nsec;
2181f12ae5bSChristian Eggers 
2191f12ae5bSChristian Eggers 	ptp_data->perout_period.tv_sec = request->period.sec;
2201f12ae5bSChristian Eggers 	ptp_data->perout_period.tv_nsec = request->period.nsec;
2211f12ae5bSChristian Eggers 
2221f12ae5bSChristian Eggers 	cycle_width_ns = timespec64_to_ns(&ptp_data->perout_period);
2231f12ae5bSChristian Eggers 	if ((cycle_width_ns & TRIG_CYCLE_WIDTH_M) != cycle_width_ns)
2241f12ae5bSChristian Eggers 		return -EINVAL;
2251f12ae5bSChristian Eggers 
2261f12ae5bSChristian Eggers 	if (request->flags & PTP_PEROUT_DUTY_CYCLE) {
2271f12ae5bSChristian Eggers 		pulse_width_ns = request->on.sec * NSEC_PER_SEC +
2281f12ae5bSChristian Eggers 			request->on.nsec;
2291f12ae5bSChristian Eggers 	} else {
2301f12ae5bSChristian Eggers 		/* Use a duty cycle of 50%. Maximum pulse width supported by the
2311f12ae5bSChristian Eggers 		 * hardware is a little bit more than 125 ms.
2321f12ae5bSChristian Eggers 		 */
2331f12ae5bSChristian Eggers 		req_pulse_width_ns = (request->period.sec * NSEC_PER_SEC +
2341f12ae5bSChristian Eggers 				      request->period.nsec) / 2;
2351f12ae5bSChristian Eggers 		pulse_width_ns = min_t(u64, req_pulse_width_ns,
2361f12ae5bSChristian Eggers 				       KSZ_MAX_PULSE_WIDTH);
2371f12ae5bSChristian Eggers 	}
2381f12ae5bSChristian Eggers 
2391f12ae5bSChristian Eggers 	ret = ksz_ptp_tou_pulse_verify(pulse_width_ns);
2401f12ae5bSChristian Eggers 	if (ret)
2411f12ae5bSChristian Eggers 		return ret;
2421f12ae5bSChristian Eggers 
2431f12ae5bSChristian Eggers 	ret = ksz_ptp_configure_perout(dev, cycle_width_ns, pulse_width_ns,
2441f12ae5bSChristian Eggers 				       &ptp_data->perout_target_time_first,
2451f12ae5bSChristian Eggers 				       pin);
2461f12ae5bSChristian Eggers 	if (ret)
2471f12ae5bSChristian Eggers 		return ret;
2481f12ae5bSChristian Eggers 
249168a5940SArun Ramadoss 	ret = ksz_ptp_tou_gpio(dev);
250168a5940SArun Ramadoss 	if (ret)
251168a5940SArun Ramadoss 		return ret;
252168a5940SArun Ramadoss 
2531f12ae5bSChristian Eggers 	ret = ksz_ptp_tou_start(dev, request->index);
2541f12ae5bSChristian Eggers 	if (ret)
2551f12ae5bSChristian Eggers 		return ret;
2561f12ae5bSChristian Eggers 
2571f12ae5bSChristian Eggers 	ptp_data->tou_mode = KSZ_PTP_TOU_PEROUT;
2581f12ae5bSChristian Eggers 
2591f12ae5bSChristian Eggers 	return 0;
2601f12ae5bSChristian Eggers }
2611f12ae5bSChristian Eggers 
ksz_ptp_enable_mode(struct ksz_device * dev)262c2977c61SArun Ramadoss static int ksz_ptp_enable_mode(struct ksz_device *dev)
263c2977c61SArun Ramadoss {
264c2977c61SArun Ramadoss 	struct ksz_tagger_data *tagger_data = ksz_tagger_data(dev->ds);
265bb01ad30SChristian Eggers 	struct ksz_ptp_data *ptp_data = &dev->ptp_data;
266c2977c61SArun Ramadoss 	struct ksz_port *prt;
267c2977c61SArun Ramadoss 	struct dsa_port *dp;
268c2977c61SArun Ramadoss 	bool tag_en = false;
269c2977c61SArun Ramadoss 
270c2977c61SArun Ramadoss 	dsa_switch_for_each_user_port(dp, dev->ds) {
271c2977c61SArun Ramadoss 		prt = &dev->ports[dp->index];
272c2977c61SArun Ramadoss 		if (prt->hwts_tx_en || prt->hwts_rx_en) {
273c2977c61SArun Ramadoss 			tag_en = true;
274c2977c61SArun Ramadoss 			break;
275c2977c61SArun Ramadoss 		}
276c2977c61SArun Ramadoss 	}
277c2977c61SArun Ramadoss 
278bb01ad30SChristian Eggers 	if (tag_en) {
279*242665bdSMartin Whitaker 		ptp_schedule_worker(ptp_data->clock, 0);
280bb01ad30SChristian Eggers 	} else {
281bb01ad30SChristian Eggers 		ptp_cancel_worker_sync(ptp_data->clock);
282bb01ad30SChristian Eggers 	}
283bb01ad30SChristian Eggers 
284c2977c61SArun Ramadoss 	tagger_data->hwtstamp_set_state(dev->ds, tag_en);
285c2977c61SArun Ramadoss 
286c2977c61SArun Ramadoss 	return ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_ENABLE,
287c2977c61SArun Ramadoss 			 tag_en ? PTP_ENABLE : 0);
288c2977c61SArun Ramadoss }
289c2977c61SArun Ramadoss 
290c59e12a1SChristian Eggers /* The function is return back the capability of timestamping feature when
291c59e12a1SChristian Eggers  * requested through ethtool -T <interface> utility
292c59e12a1SChristian Eggers  */
ksz_get_ts_info(struct dsa_switch * ds,int port,struct ethtool_ts_info * ts)293c59e12a1SChristian Eggers int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts)
294c59e12a1SChristian Eggers {
295c59e12a1SChristian Eggers 	struct ksz_device *dev = ds->priv;
296c59e12a1SChristian Eggers 	struct ksz_ptp_data *ptp_data;
297c59e12a1SChristian Eggers 
298c59e12a1SChristian Eggers 	ptp_data = &dev->ptp_data;
299c59e12a1SChristian Eggers 
300c59e12a1SChristian Eggers 	if (!ptp_data->clock)
301c59e12a1SChristian Eggers 		return -ENODEV;
302c59e12a1SChristian Eggers 
303c59e12a1SChristian Eggers 	ts->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
304c59e12a1SChristian Eggers 			      SOF_TIMESTAMPING_RX_HARDWARE |
305c59e12a1SChristian Eggers 			      SOF_TIMESTAMPING_RAW_HARDWARE;
306c59e12a1SChristian Eggers 
307c59e12a1SChristian Eggers 	ts->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ONESTEP_P2P);
308c59e12a1SChristian Eggers 
309d6261f0bSArun Ramadoss 	if (is_lan937x(dev))
310d6261f0bSArun Ramadoss 		ts->tx_types |= BIT(HWTSTAMP_TX_ON);
311d6261f0bSArun Ramadoss 
312c59e12a1SChristian Eggers 	ts->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
313c59e12a1SChristian Eggers 			 BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
314c59e12a1SChristian Eggers 			 BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
315c59e12a1SChristian Eggers 			 BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
316c59e12a1SChristian Eggers 
317c59e12a1SChristian Eggers 	ts->phc_index = ptp_clock_index(ptp_data->clock);
318c59e12a1SChristian Eggers 
319c59e12a1SChristian Eggers 	return 0;
320c59e12a1SChristian Eggers }
321c59e12a1SChristian Eggers 
ksz_hwtstamp_get(struct dsa_switch * ds,int port,struct ifreq * ifr)322c59e12a1SChristian Eggers int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr)
323c59e12a1SChristian Eggers {
324c59e12a1SChristian Eggers 	struct ksz_device *dev = ds->priv;
325c59e12a1SChristian Eggers 	struct hwtstamp_config *config;
326c59e12a1SChristian Eggers 	struct ksz_port *prt;
327c59e12a1SChristian Eggers 
328c59e12a1SChristian Eggers 	prt = &dev->ports[port];
329c59e12a1SChristian Eggers 	config = &prt->tstamp_config;
330c59e12a1SChristian Eggers 
331c59e12a1SChristian Eggers 	return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
332c59e12a1SChristian Eggers 		-EFAULT : 0;
333c59e12a1SChristian Eggers }
334c59e12a1SChristian Eggers 
ksz_set_hwtstamp_config(struct ksz_device * dev,struct ksz_port * prt,struct hwtstamp_config * config)335c59e12a1SChristian Eggers static int ksz_set_hwtstamp_config(struct ksz_device *dev,
336c2977c61SArun Ramadoss 				   struct ksz_port *prt,
337c59e12a1SChristian Eggers 				   struct hwtstamp_config *config)
338c59e12a1SChristian Eggers {
339d6261f0bSArun Ramadoss 	int ret;
340d6261f0bSArun Ramadoss 
341c59e12a1SChristian Eggers 	if (config->flags)
342c59e12a1SChristian Eggers 		return -EINVAL;
343c59e12a1SChristian Eggers 
344c59e12a1SChristian Eggers 	switch (config->tx_type) {
345c59e12a1SChristian Eggers 	case HWTSTAMP_TX_OFF:
346ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en  = false;
347ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = false;
348ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = false;
349c2977c61SArun Ramadoss 		prt->hwts_tx_en = false;
350c2977c61SArun Ramadoss 		break;
351c59e12a1SChristian Eggers 	case HWTSTAMP_TX_ONESTEP_P2P:
352ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en  = false;
353ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = true;
354ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = false;
355c2977c61SArun Ramadoss 		prt->hwts_tx_en = true;
356d6261f0bSArun Ramadoss 
357d6261f0bSArun Ramadoss 		ret = ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_1STEP, PTP_1STEP);
358d6261f0bSArun Ramadoss 		if (ret)
359d6261f0bSArun Ramadoss 			return ret;
360d6261f0bSArun Ramadoss 
361d6261f0bSArun Ramadoss 		break;
362d6261f0bSArun Ramadoss 	case HWTSTAMP_TX_ON:
363d6261f0bSArun Ramadoss 		if (!is_lan937x(dev))
364d6261f0bSArun Ramadoss 			return -ERANGE;
365d6261f0bSArun Ramadoss 
366d6261f0bSArun Ramadoss 		prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en  = true;
367d6261f0bSArun Ramadoss 		prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = true;
368d6261f0bSArun Ramadoss 		prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = true;
369d6261f0bSArun Ramadoss 		prt->hwts_tx_en = true;
370d6261f0bSArun Ramadoss 
371d6261f0bSArun Ramadoss 		ret = ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_1STEP, 0);
372d6261f0bSArun Ramadoss 		if (ret)
373d6261f0bSArun Ramadoss 			return ret;
374d6261f0bSArun Ramadoss 
375c59e12a1SChristian Eggers 		break;
376c59e12a1SChristian Eggers 	default:
377c59e12a1SChristian Eggers 		return -ERANGE;
378c59e12a1SChristian Eggers 	}
379c59e12a1SChristian Eggers 
380c59e12a1SChristian Eggers 	switch (config->rx_filter) {
381c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_NONE:
382c2977c61SArun Ramadoss 		prt->hwts_rx_en = false;
383c59e12a1SChristian Eggers 		break;
384c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
385c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
386c59e12a1SChristian Eggers 		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
387c2977c61SArun Ramadoss 		prt->hwts_rx_en = true;
388c59e12a1SChristian Eggers 		break;
389c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
390c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
391c59e12a1SChristian Eggers 		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
392c2977c61SArun Ramadoss 		prt->hwts_rx_en = true;
393c59e12a1SChristian Eggers 		break;
394c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
395c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
396c59e12a1SChristian Eggers 		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
397c2977c61SArun Ramadoss 		prt->hwts_rx_en = true;
398c59e12a1SChristian Eggers 		break;
399c59e12a1SChristian Eggers 	default:
400c59e12a1SChristian Eggers 		config->rx_filter = HWTSTAMP_FILTER_NONE;
401c59e12a1SChristian Eggers 		return -ERANGE;
402c59e12a1SChristian Eggers 	}
403c59e12a1SChristian Eggers 
404c2977c61SArun Ramadoss 	return ksz_ptp_enable_mode(dev);
405c59e12a1SChristian Eggers }
406c59e12a1SChristian Eggers 
ksz_hwtstamp_set(struct dsa_switch * ds,int port,struct ifreq * ifr)407c59e12a1SChristian Eggers int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
408c59e12a1SChristian Eggers {
409c59e12a1SChristian Eggers 	struct ksz_device *dev = ds->priv;
410c59e12a1SChristian Eggers 	struct hwtstamp_config config;
411c59e12a1SChristian Eggers 	struct ksz_port *prt;
412c59e12a1SChristian Eggers 	int ret;
413c59e12a1SChristian Eggers 
414c59e12a1SChristian Eggers 	prt = &dev->ports[port];
415c59e12a1SChristian Eggers 
416a76e88c2SDan Carpenter 	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
417a76e88c2SDan Carpenter 		return -EFAULT;
418c59e12a1SChristian Eggers 
419c2977c61SArun Ramadoss 	ret = ksz_set_hwtstamp_config(dev, prt, &config);
420c59e12a1SChristian Eggers 	if (ret)
421c59e12a1SChristian Eggers 		return ret;
422c59e12a1SChristian Eggers 
423c59e12a1SChristian Eggers 	memcpy(&prt->tstamp_config, &config, sizeof(config));
424c59e12a1SChristian Eggers 
425a76e88c2SDan Carpenter 	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
426a76e88c2SDan Carpenter 		return -EFAULT;
427a76e88c2SDan Carpenter 
428a76e88c2SDan Carpenter 	return 0;
429c59e12a1SChristian Eggers }
430c59e12a1SChristian Eggers 
ksz_tstamp_reconstruct(struct ksz_device * dev,ktime_t tstamp)43190188fffSChristian Eggers static ktime_t ksz_tstamp_reconstruct(struct ksz_device *dev, ktime_t tstamp)
43290188fffSChristian Eggers {
43390188fffSChristian Eggers 	struct timespec64 ptp_clock_time;
43490188fffSChristian Eggers 	struct ksz_ptp_data *ptp_data;
43590188fffSChristian Eggers 	struct timespec64 diff;
43690188fffSChristian Eggers 	struct timespec64 ts;
43790188fffSChristian Eggers 
43890188fffSChristian Eggers 	ptp_data = &dev->ptp_data;
43990188fffSChristian Eggers 	ts = ktime_to_timespec64(tstamp);
44090188fffSChristian Eggers 
44190188fffSChristian Eggers 	spin_lock_bh(&ptp_data->clock_lock);
44290188fffSChristian Eggers 	ptp_clock_time = ptp_data->clock_time;
44390188fffSChristian Eggers 	spin_unlock_bh(&ptp_data->clock_lock);
44490188fffSChristian Eggers 
44590188fffSChristian Eggers 	/* calculate full time from partial time stamp */
44690188fffSChristian Eggers 	ts.tv_sec = (ptp_clock_time.tv_sec & ~3) | ts.tv_sec;
44790188fffSChristian Eggers 
44890188fffSChristian Eggers 	/* find nearest possible point in time */
44990188fffSChristian Eggers 	diff = timespec64_sub(ts, ptp_clock_time);
45090188fffSChristian Eggers 	if (diff.tv_sec > 2)
45190188fffSChristian Eggers 		ts.tv_sec -= 4;
45290188fffSChristian Eggers 	else if (diff.tv_sec < -2)
45390188fffSChristian Eggers 		ts.tv_sec += 4;
45490188fffSChristian Eggers 
45590188fffSChristian Eggers 	return timespec64_to_ktime(ts);
45690188fffSChristian Eggers }
45790188fffSChristian Eggers 
ksz_port_rxtstamp(struct dsa_switch * ds,int port,struct sk_buff * skb,unsigned int type)45890188fffSChristian Eggers bool ksz_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb,
45990188fffSChristian Eggers 		       unsigned int type)
46090188fffSChristian Eggers {
46190188fffSChristian Eggers 	struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
46290188fffSChristian Eggers 	struct ksz_device *dev = ds->priv;
46390188fffSChristian Eggers 	struct ptp_header *ptp_hdr;
464d6261f0bSArun Ramadoss 	struct ksz_port *prt;
46590188fffSChristian Eggers 	u8 ptp_msg_type;
46690188fffSChristian Eggers 	ktime_t tstamp;
46790188fffSChristian Eggers 	s64 correction;
46890188fffSChristian Eggers 
469d6261f0bSArun Ramadoss 	prt = &dev->ports[port];
470d6261f0bSArun Ramadoss 
47190188fffSChristian Eggers 	tstamp = KSZ_SKB_CB(skb)->tstamp;
47290188fffSChristian Eggers 	memset(hwtstamps, 0, sizeof(*hwtstamps));
47390188fffSChristian Eggers 	hwtstamps->hwtstamp = ksz_tstamp_reconstruct(dev, tstamp);
47490188fffSChristian Eggers 
475d6261f0bSArun Ramadoss 	if (prt->tstamp_config.tx_type != HWTSTAMP_TX_ONESTEP_P2P)
476d6261f0bSArun Ramadoss 		goto out;
477d6261f0bSArun Ramadoss 
47890188fffSChristian Eggers 	ptp_hdr = ptp_parse_header(skb, type);
47990188fffSChristian Eggers 	if (!ptp_hdr)
48090188fffSChristian Eggers 		goto out;
48190188fffSChristian Eggers 
48290188fffSChristian Eggers 	ptp_msg_type = ptp_get_msgtype(ptp_hdr, type);
48390188fffSChristian Eggers 	if (ptp_msg_type != PTP_MSGTYPE_PDELAY_REQ)
48490188fffSChristian Eggers 		goto out;
48590188fffSChristian Eggers 
48690188fffSChristian Eggers 	/* Only subtract the partial time stamp from the correction field.  When
48790188fffSChristian Eggers 	 * the hardware adds the egress time stamp to the correction field of
48890188fffSChristian Eggers 	 * the PDelay_Resp message on tx, also only the partial time stamp will
48990188fffSChristian Eggers 	 * be added.
49090188fffSChristian Eggers 	 */
49190188fffSChristian Eggers 	correction = (s64)get_unaligned_be64(&ptp_hdr->correction);
49290188fffSChristian Eggers 	correction -= ktime_to_ns(tstamp) << 16;
49390188fffSChristian Eggers 
49490188fffSChristian Eggers 	ptp_header_update_correction(skb, type, ptp_hdr, correction);
49590188fffSChristian Eggers 
49690188fffSChristian Eggers out:
49790188fffSChristian Eggers 	return false;
49890188fffSChristian Eggers }
49990188fffSChristian Eggers 
ksz_port_txtstamp(struct dsa_switch * ds,int port,struct sk_buff * skb)500ab32f56aSChristian Eggers void ksz_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
501ab32f56aSChristian Eggers {
502ab32f56aSChristian Eggers 	struct ksz_device *dev = ds->priv;
503ab32f56aSChristian Eggers 	struct ptp_header *hdr;
504ab32f56aSChristian Eggers 	struct sk_buff *clone;
505ab32f56aSChristian Eggers 	struct ksz_port *prt;
506ab32f56aSChristian Eggers 	unsigned int type;
507ab32f56aSChristian Eggers 	u8 ptp_msg_type;
508ab32f56aSChristian Eggers 
509ab32f56aSChristian Eggers 	prt = &dev->ports[port];
510ab32f56aSChristian Eggers 
511ab32f56aSChristian Eggers 	if (!prt->hwts_tx_en)
512ab32f56aSChristian Eggers 		return;
513ab32f56aSChristian Eggers 
514ab32f56aSChristian Eggers 	type = ptp_classify_raw(skb);
515ab32f56aSChristian Eggers 	if (type == PTP_CLASS_NONE)
516ab32f56aSChristian Eggers 		return;
517ab32f56aSChristian Eggers 
518ab32f56aSChristian Eggers 	hdr = ptp_parse_header(skb, type);
519ab32f56aSChristian Eggers 	if (!hdr)
520ab32f56aSChristian Eggers 		return;
521ab32f56aSChristian Eggers 
522ab32f56aSChristian Eggers 	ptp_msg_type = ptp_get_msgtype(hdr, type);
523ab32f56aSChristian Eggers 
524ab32f56aSChristian Eggers 	switch (ptp_msg_type) {
525d6261f0bSArun Ramadoss 	case PTP_MSGTYPE_SYNC:
526d6261f0bSArun Ramadoss 		if (prt->tstamp_config.tx_type == HWTSTAMP_TX_ONESTEP_P2P)
527d6261f0bSArun Ramadoss 			return;
528d6261f0bSArun Ramadoss 		break;
529ab32f56aSChristian Eggers 	case PTP_MSGTYPE_PDELAY_REQ:
530ab32f56aSChristian Eggers 		break;
531a32190b1SChristian Eggers 	case PTP_MSGTYPE_PDELAY_RESP:
532d6261f0bSArun Ramadoss 		if (prt->tstamp_config.tx_type == HWTSTAMP_TX_ONESTEP_P2P) {
533a32190b1SChristian Eggers 			KSZ_SKB_CB(skb)->ptp_type = type;
534a32190b1SChristian Eggers 			KSZ_SKB_CB(skb)->update_correction = true;
535a32190b1SChristian Eggers 			return;
536d6261f0bSArun Ramadoss 		}
537d6261f0bSArun Ramadoss 		break;
538ab32f56aSChristian Eggers 
539ab32f56aSChristian Eggers 	default:
540ab32f56aSChristian Eggers 		return;
541ab32f56aSChristian Eggers 	}
542ab32f56aSChristian Eggers 
543ab32f56aSChristian Eggers 	clone = skb_clone_sk(skb);
544ab32f56aSChristian Eggers 	if (!clone)
545ab32f56aSChristian Eggers 		return;
546ab32f56aSChristian Eggers 
547ab32f56aSChristian Eggers 	/* caching the value to be used in tag_ksz.c */
548ab32f56aSChristian Eggers 	KSZ_SKB_CB(skb)->clone = clone;
549ab32f56aSChristian Eggers }
550ab32f56aSChristian Eggers 
ksz_ptp_txtstamp_skb(struct ksz_device * dev,struct ksz_port * prt,struct sk_buff * skb)551ab32f56aSChristian Eggers static void ksz_ptp_txtstamp_skb(struct ksz_device *dev,
552ab32f56aSChristian Eggers 				 struct ksz_port *prt, struct sk_buff *skb)
553ab32f56aSChristian Eggers {
554ab32f56aSChristian Eggers 	struct skb_shared_hwtstamps hwtstamps = {};
555ab32f56aSChristian Eggers 	int ret;
556ab32f56aSChristian Eggers 
557ab32f56aSChristian Eggers 	/* timeout must include DSA master to transmit data, tstamp latency,
558ab32f56aSChristian Eggers 	 * IRQ latency and time for reading the time stamp.
559ab32f56aSChristian Eggers 	 */
560ab32f56aSChristian Eggers 	ret = wait_for_completion_timeout(&prt->tstamp_msg_comp,
561ab32f56aSChristian Eggers 					  msecs_to_jiffies(100));
562ab32f56aSChristian Eggers 	if (!ret)
563ab32f56aSChristian Eggers 		return;
564ab32f56aSChristian Eggers 
565ab32f56aSChristian Eggers 	hwtstamps.hwtstamp = prt->tstamp_msg;
566ab32f56aSChristian Eggers 	skb_complete_tx_timestamp(skb, &hwtstamps);
567ab32f56aSChristian Eggers }
568ab32f56aSChristian Eggers 
ksz_port_deferred_xmit(struct kthread_work * work)569ab32f56aSChristian Eggers void ksz_port_deferred_xmit(struct kthread_work *work)
570ab32f56aSChristian Eggers {
571ab32f56aSChristian Eggers 	struct ksz_deferred_xmit_work *xmit_work = work_to_xmit_work(work);
572ab32f56aSChristian Eggers 	struct sk_buff *clone, *skb = xmit_work->skb;
573ab32f56aSChristian Eggers 	struct dsa_switch *ds = xmit_work->dp->ds;
574ab32f56aSChristian Eggers 	struct ksz_device *dev = ds->priv;
575ab32f56aSChristian Eggers 	struct ksz_port *prt;
576ab32f56aSChristian Eggers 
577ab32f56aSChristian Eggers 	prt = &dev->ports[xmit_work->dp->index];
578ab32f56aSChristian Eggers 
579ab32f56aSChristian Eggers 	clone = KSZ_SKB_CB(skb)->clone;
580ab32f56aSChristian Eggers 
581ab32f56aSChristian Eggers 	skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
582ab32f56aSChristian Eggers 
583ab32f56aSChristian Eggers 	reinit_completion(&prt->tstamp_msg_comp);
584ab32f56aSChristian Eggers 
585ab32f56aSChristian Eggers 	dsa_enqueue_skb(skb, skb->dev);
586ab32f56aSChristian Eggers 
587ab32f56aSChristian Eggers 	ksz_ptp_txtstamp_skb(dev, prt, clone);
588ab32f56aSChristian Eggers 
589ab32f56aSChristian Eggers 	kfree(xmit_work);
590ab32f56aSChristian Eggers }
591ab32f56aSChristian Eggers 
_ksz_ptp_gettime(struct ksz_device * dev,struct timespec64 * ts)592eac1ea20SChristian Eggers static int _ksz_ptp_gettime(struct ksz_device *dev, struct timespec64 *ts)
593eac1ea20SChristian Eggers {
594eac1ea20SChristian Eggers 	u32 nanoseconds;
595eac1ea20SChristian Eggers 	u32 seconds;
596eac1ea20SChristian Eggers 	u8 phase;
597eac1ea20SChristian Eggers 	int ret;
598eac1ea20SChristian Eggers 
599eac1ea20SChristian Eggers 	/* Copy current PTP clock into shadow registers and read */
600eac1ea20SChristian Eggers 	ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_READ_TIME, PTP_READ_TIME);
601eac1ea20SChristian Eggers 	if (ret)
602eac1ea20SChristian Eggers 		return ret;
603eac1ea20SChristian Eggers 
604eac1ea20SChristian Eggers 	ret = ksz_read8(dev, REG_PTP_RTC_SUB_NANOSEC__2, &phase);
605eac1ea20SChristian Eggers 	if (ret)
606eac1ea20SChristian Eggers 		return ret;
607eac1ea20SChristian Eggers 
608eac1ea20SChristian Eggers 	ret = ksz_read32(dev, REG_PTP_RTC_NANOSEC, &nanoseconds);
609eac1ea20SChristian Eggers 	if (ret)
610eac1ea20SChristian Eggers 		return ret;
611eac1ea20SChristian Eggers 
612eac1ea20SChristian Eggers 	ret = ksz_read32(dev, REG_PTP_RTC_SEC, &seconds);
613eac1ea20SChristian Eggers 	if (ret)
614eac1ea20SChristian Eggers 		return ret;
615eac1ea20SChristian Eggers 
616eac1ea20SChristian Eggers 	ts->tv_sec = seconds;
617eac1ea20SChristian Eggers 	ts->tv_nsec = nanoseconds + phase * 8;
618eac1ea20SChristian Eggers 
619eac1ea20SChristian Eggers 	return 0;
620eac1ea20SChristian Eggers }
621eac1ea20SChristian Eggers 
ksz_ptp_gettime(struct ptp_clock_info * ptp,struct timespec64 * ts)622eac1ea20SChristian Eggers static int ksz_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
623eac1ea20SChristian Eggers {
624eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
625eac1ea20SChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
626eac1ea20SChristian Eggers 	int ret;
627eac1ea20SChristian Eggers 
628eac1ea20SChristian Eggers 	mutex_lock(&ptp_data->lock);
629eac1ea20SChristian Eggers 	ret = _ksz_ptp_gettime(dev, ts);
630eac1ea20SChristian Eggers 	mutex_unlock(&ptp_data->lock);
631eac1ea20SChristian Eggers 
632eac1ea20SChristian Eggers 	return ret;
633eac1ea20SChristian Eggers }
634eac1ea20SChristian Eggers 
ksz_ptp_restart_perout(struct ksz_device * dev)6351f12ae5bSChristian Eggers static int ksz_ptp_restart_perout(struct ksz_device *dev)
6361f12ae5bSChristian Eggers {
6371f12ae5bSChristian Eggers 	struct ksz_ptp_data *ptp_data = &dev->ptp_data;
6381f12ae5bSChristian Eggers 	s64 now_ns, first_ns, period_ns, next_ns;
6391f12ae5bSChristian Eggers 	struct ptp_perout_request request;
6401f12ae5bSChristian Eggers 	struct timespec64 next;
6411f12ae5bSChristian Eggers 	struct timespec64 now;
6421f12ae5bSChristian Eggers 	unsigned int count;
6431f12ae5bSChristian Eggers 	int ret;
6441f12ae5bSChristian Eggers 
6451f12ae5bSChristian Eggers 	dev_info(dev->dev, "Restarting periodic output signal\n");
6461f12ae5bSChristian Eggers 
6471f12ae5bSChristian Eggers 	ret = _ksz_ptp_gettime(dev, &now);
6481f12ae5bSChristian Eggers 	if (ret)
6491f12ae5bSChristian Eggers 		return ret;
6501f12ae5bSChristian Eggers 
6511f12ae5bSChristian Eggers 	now_ns = timespec64_to_ns(&now);
6521f12ae5bSChristian Eggers 	first_ns = timespec64_to_ns(&ptp_data->perout_target_time_first);
6531f12ae5bSChristian Eggers 
6541f12ae5bSChristian Eggers 	/* Calculate next perout event based on start time and period */
6551f12ae5bSChristian Eggers 	period_ns = timespec64_to_ns(&ptp_data->perout_period);
6561f12ae5bSChristian Eggers 
6571f12ae5bSChristian Eggers 	if (first_ns < now_ns) {
6581f12ae5bSChristian Eggers 		count = div_u64(now_ns - first_ns, period_ns);
6591f12ae5bSChristian Eggers 		next_ns = first_ns + count * period_ns;
6601f12ae5bSChristian Eggers 	} else {
6611f12ae5bSChristian Eggers 		next_ns = first_ns;
6621f12ae5bSChristian Eggers 	}
6631f12ae5bSChristian Eggers 
6641f12ae5bSChristian Eggers 	/* Ensure 100 ms guard time prior next event */
6651f12ae5bSChristian Eggers 	while (next_ns < now_ns + 100000000)
6661f12ae5bSChristian Eggers 		next_ns += period_ns;
6671f12ae5bSChristian Eggers 
6681f12ae5bSChristian Eggers 	/* Restart periodic output signal */
6691f12ae5bSChristian Eggers 	next = ns_to_timespec64(next_ns);
6701f12ae5bSChristian Eggers 	request.start.sec  = next.tv_sec;
6711f12ae5bSChristian Eggers 	request.start.nsec = next.tv_nsec;
6721f12ae5bSChristian Eggers 	request.period.sec  = ptp_data->perout_period.tv_sec;
6731f12ae5bSChristian Eggers 	request.period.nsec = ptp_data->perout_period.tv_nsec;
6741f12ae5bSChristian Eggers 	request.index = 0;
6751f12ae5bSChristian Eggers 	request.flags = 0;
6761f12ae5bSChristian Eggers 
6771f12ae5bSChristian Eggers 	return ksz_ptp_enable_perout(dev, &request, 1);
6781f12ae5bSChristian Eggers }
6791f12ae5bSChristian Eggers 
ksz_ptp_settime(struct ptp_clock_info * ptp,const struct timespec64 * ts)680eac1ea20SChristian Eggers static int ksz_ptp_settime(struct ptp_clock_info *ptp,
681eac1ea20SChristian Eggers 			   const struct timespec64 *ts)
682eac1ea20SChristian Eggers {
683eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
684eac1ea20SChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
685eac1ea20SChristian Eggers 	int ret;
686eac1ea20SChristian Eggers 
687eac1ea20SChristian Eggers 	mutex_lock(&ptp_data->lock);
688eac1ea20SChristian Eggers 
689eac1ea20SChristian Eggers 	/* Write to shadow registers and Load PTP clock */
690eac1ea20SChristian Eggers 	ret = ksz_write16(dev, REG_PTP_RTC_SUB_NANOSEC__2, PTP_RTC_0NS);
691eac1ea20SChristian Eggers 	if (ret)
692eac1ea20SChristian Eggers 		goto unlock;
693eac1ea20SChristian Eggers 
694eac1ea20SChristian Eggers 	ret = ksz_write32(dev, REG_PTP_RTC_NANOSEC, ts->tv_nsec);
695eac1ea20SChristian Eggers 	if (ret)
696eac1ea20SChristian Eggers 		goto unlock;
697eac1ea20SChristian Eggers 
698eac1ea20SChristian Eggers 	ret = ksz_write32(dev, REG_PTP_RTC_SEC, ts->tv_sec);
699eac1ea20SChristian Eggers 	if (ret)
700eac1ea20SChristian Eggers 		goto unlock;
701eac1ea20SChristian Eggers 
702eac1ea20SChristian Eggers 	ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_LOAD_TIME, PTP_LOAD_TIME);
703bb01ad30SChristian Eggers 	if (ret)
704bb01ad30SChristian Eggers 		goto unlock;
705bb01ad30SChristian Eggers 
7061f12ae5bSChristian Eggers 	switch (ptp_data->tou_mode) {
7071f12ae5bSChristian Eggers 	case KSZ_PTP_TOU_IDLE:
7081f12ae5bSChristian Eggers 		break;
7091f12ae5bSChristian Eggers 
7101f12ae5bSChristian Eggers 	case KSZ_PTP_TOU_PEROUT:
7111f12ae5bSChristian Eggers 		ret = ksz_ptp_restart_perout(dev);
7121f12ae5bSChristian Eggers 		if (ret)
7131f12ae5bSChristian Eggers 			goto unlock;
7141f12ae5bSChristian Eggers 
7151f12ae5bSChristian Eggers 		break;
7161f12ae5bSChristian Eggers 	}
7171f12ae5bSChristian Eggers 
718bb01ad30SChristian Eggers 	spin_lock_bh(&ptp_data->clock_lock);
719bb01ad30SChristian Eggers 	ptp_data->clock_time = *ts;
720bb01ad30SChristian Eggers 	spin_unlock_bh(&ptp_data->clock_lock);
721eac1ea20SChristian Eggers 
722eac1ea20SChristian Eggers unlock:
723eac1ea20SChristian Eggers 	mutex_unlock(&ptp_data->lock);
724eac1ea20SChristian Eggers 
725eac1ea20SChristian Eggers 	return ret;
726eac1ea20SChristian Eggers }
727eac1ea20SChristian Eggers 
ksz_ptp_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)728eac1ea20SChristian Eggers static int ksz_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
729eac1ea20SChristian Eggers {
730eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
731eac1ea20SChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
732eac1ea20SChristian Eggers 	u64 base, adj;
733eac1ea20SChristian Eggers 	bool negative;
734eac1ea20SChristian Eggers 	u32 data32;
735eac1ea20SChristian Eggers 	int ret;
736eac1ea20SChristian Eggers 
737eac1ea20SChristian Eggers 	mutex_lock(&ptp_data->lock);
738eac1ea20SChristian Eggers 
739eac1ea20SChristian Eggers 	if (scaled_ppm) {
740eac1ea20SChristian Eggers 		base = KSZ_PTP_INC_NS << KSZ_PTP_SUBNS_BITS;
741eac1ea20SChristian Eggers 		negative = diff_by_scaled_ppm(base, scaled_ppm, &adj);
742eac1ea20SChristian Eggers 
743eac1ea20SChristian Eggers 		data32 = (u32)adj;
744eac1ea20SChristian Eggers 		data32 &= PTP_SUBNANOSEC_M;
745eac1ea20SChristian Eggers 		if (!negative)
746eac1ea20SChristian Eggers 			data32 |= PTP_RATE_DIR;
747eac1ea20SChristian Eggers 
748eac1ea20SChristian Eggers 		ret = ksz_write32(dev, REG_PTP_SUBNANOSEC_RATE, data32);
749eac1ea20SChristian Eggers 		if (ret)
750eac1ea20SChristian Eggers 			goto unlock;
751eac1ea20SChristian Eggers 
752eac1ea20SChristian Eggers 		ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ADJ_ENABLE,
753eac1ea20SChristian Eggers 				PTP_CLK_ADJ_ENABLE);
754eac1ea20SChristian Eggers 		if (ret)
755eac1ea20SChristian Eggers 			goto unlock;
756eac1ea20SChristian Eggers 	} else {
757eac1ea20SChristian Eggers 		ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ADJ_ENABLE, 0);
758eac1ea20SChristian Eggers 		if (ret)
759eac1ea20SChristian Eggers 			goto unlock;
760eac1ea20SChristian Eggers 	}
761eac1ea20SChristian Eggers 
762eac1ea20SChristian Eggers unlock:
763eac1ea20SChristian Eggers 	mutex_unlock(&ptp_data->lock);
764eac1ea20SChristian Eggers 	return ret;
765eac1ea20SChristian Eggers }
766eac1ea20SChristian Eggers 
ksz_ptp_adjtime(struct ptp_clock_info * ptp,s64 delta)767eac1ea20SChristian Eggers static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
768eac1ea20SChristian Eggers {
769eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
770eac1ea20SChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
771bb01ad30SChristian Eggers 	struct timespec64 delta64 = ns_to_timespec64(delta);
772eac1ea20SChristian Eggers 	s32 sec, nsec;
773eac1ea20SChristian Eggers 	u16 data16;
774eac1ea20SChristian Eggers 	int ret;
775eac1ea20SChristian Eggers 
776eac1ea20SChristian Eggers 	mutex_lock(&ptp_data->lock);
777eac1ea20SChristian Eggers 
778eac1ea20SChristian Eggers 	/* do not use ns_to_timespec64(),
779eac1ea20SChristian Eggers 	 * both sec and nsec are subtracted by hw
780eac1ea20SChristian Eggers 	 */
781eac1ea20SChristian Eggers 	sec = div_s64_rem(delta, NSEC_PER_SEC, &nsec);
782eac1ea20SChristian Eggers 
783eac1ea20SChristian Eggers 	ret = ksz_write32(dev, REG_PTP_RTC_NANOSEC, abs(nsec));
784eac1ea20SChristian Eggers 	if (ret)
785eac1ea20SChristian Eggers 		goto unlock;
786eac1ea20SChristian Eggers 
787eac1ea20SChristian Eggers 	ret = ksz_write32(dev, REG_PTP_RTC_SEC, abs(sec));
788eac1ea20SChristian Eggers 	if (ret)
789eac1ea20SChristian Eggers 		goto unlock;
790eac1ea20SChristian Eggers 
791eac1ea20SChristian Eggers 	ret = ksz_read16(dev, REG_PTP_CLK_CTRL, &data16);
792eac1ea20SChristian Eggers 	if (ret)
793eac1ea20SChristian Eggers 		goto unlock;
794eac1ea20SChristian Eggers 
795eac1ea20SChristian Eggers 	data16 |= PTP_STEP_ADJ;
796eac1ea20SChristian Eggers 
797eac1ea20SChristian Eggers 	/* PTP_STEP_DIR -- 0: subtract, 1: add */
798eac1ea20SChristian Eggers 	if (delta < 0)
799eac1ea20SChristian Eggers 		data16 &= ~PTP_STEP_DIR;
800eac1ea20SChristian Eggers 	else
801eac1ea20SChristian Eggers 		data16 |= PTP_STEP_DIR;
802eac1ea20SChristian Eggers 
803eac1ea20SChristian Eggers 	ret = ksz_write16(dev, REG_PTP_CLK_CTRL, data16);
804bb01ad30SChristian Eggers 	if (ret)
805bb01ad30SChristian Eggers 		goto unlock;
806bb01ad30SChristian Eggers 
8071f12ae5bSChristian Eggers 	switch (ptp_data->tou_mode) {
8081f12ae5bSChristian Eggers 	case KSZ_PTP_TOU_IDLE:
8091f12ae5bSChristian Eggers 		break;
8101f12ae5bSChristian Eggers 
8111f12ae5bSChristian Eggers 	case KSZ_PTP_TOU_PEROUT:
8121f12ae5bSChristian Eggers 		ret = ksz_ptp_restart_perout(dev);
8131f12ae5bSChristian Eggers 		if (ret)
8141f12ae5bSChristian Eggers 			goto unlock;
8151f12ae5bSChristian Eggers 
8161f12ae5bSChristian Eggers 		break;
8171f12ae5bSChristian Eggers 	}
8181f12ae5bSChristian Eggers 
819bb01ad30SChristian Eggers 	spin_lock_bh(&ptp_data->clock_lock);
820bb01ad30SChristian Eggers 	ptp_data->clock_time = timespec64_add(ptp_data->clock_time, delta64);
821bb01ad30SChristian Eggers 	spin_unlock_bh(&ptp_data->clock_lock);
822eac1ea20SChristian Eggers 
823eac1ea20SChristian Eggers unlock:
824eac1ea20SChristian Eggers 	mutex_unlock(&ptp_data->lock);
825eac1ea20SChristian Eggers 	return ret;
826eac1ea20SChristian Eggers }
827eac1ea20SChristian Eggers 
ksz_ptp_enable(struct ptp_clock_info * ptp,struct ptp_clock_request * req,int on)8281f12ae5bSChristian Eggers static int ksz_ptp_enable(struct ptp_clock_info *ptp,
8291f12ae5bSChristian Eggers 			  struct ptp_clock_request *req, int on)
8301f12ae5bSChristian Eggers {
8311f12ae5bSChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
8321f12ae5bSChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
8331f12ae5bSChristian Eggers 	int ret;
8341f12ae5bSChristian Eggers 
8351f12ae5bSChristian Eggers 	switch (req->type) {
8361f12ae5bSChristian Eggers 	case PTP_CLK_REQ_PEROUT:
8371f12ae5bSChristian Eggers 		mutex_lock(&ptp_data->lock);
8381f12ae5bSChristian Eggers 		ret = ksz_ptp_enable_perout(dev, &req->perout, on);
8391f12ae5bSChristian Eggers 		mutex_unlock(&ptp_data->lock);
8401f12ae5bSChristian Eggers 		break;
8411f12ae5bSChristian Eggers 	default:
8421f12ae5bSChristian Eggers 		return -EOPNOTSUPP;
8431f12ae5bSChristian Eggers 	}
8441f12ae5bSChristian Eggers 
8451f12ae5bSChristian Eggers 	return ret;
8461f12ae5bSChristian Eggers }
8471f12ae5bSChristian Eggers 
ksz_ptp_verify_pin(struct ptp_clock_info * ptp,unsigned int pin,enum ptp_pin_function func,unsigned int chan)848343d3bd8SArun Ramadoss static int ksz_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
849343d3bd8SArun Ramadoss 			      enum ptp_pin_function func, unsigned int chan)
850343d3bd8SArun Ramadoss {
851343d3bd8SArun Ramadoss 	int ret = 0;
852343d3bd8SArun Ramadoss 
853343d3bd8SArun Ramadoss 	switch (func) {
854343d3bd8SArun Ramadoss 	case PTP_PF_NONE:
855343d3bd8SArun Ramadoss 	case PTP_PF_PEROUT:
856343d3bd8SArun Ramadoss 		break;
857343d3bd8SArun Ramadoss 	default:
858343d3bd8SArun Ramadoss 		ret = -1;
859343d3bd8SArun Ramadoss 		break;
860343d3bd8SArun Ramadoss 	}
861343d3bd8SArun Ramadoss 
862343d3bd8SArun Ramadoss 	return ret;
863343d3bd8SArun Ramadoss }
864343d3bd8SArun Ramadoss 
865bb01ad30SChristian Eggers /*  Function is pointer to the do_aux_work in the ptp_clock capability */
ksz_ptp_do_aux_work(struct ptp_clock_info * ptp)866bb01ad30SChristian Eggers static long ksz_ptp_do_aux_work(struct ptp_clock_info *ptp)
867bb01ad30SChristian Eggers {
868bb01ad30SChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
869bb01ad30SChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
870bb01ad30SChristian Eggers 	struct timespec64 ts;
871bb01ad30SChristian Eggers 	int ret;
872bb01ad30SChristian Eggers 
873bb01ad30SChristian Eggers 	mutex_lock(&ptp_data->lock);
874bb01ad30SChristian Eggers 	ret = _ksz_ptp_gettime(dev, &ts);
875bb01ad30SChristian Eggers 	if (ret)
876bb01ad30SChristian Eggers 		goto out;
877bb01ad30SChristian Eggers 
878bb01ad30SChristian Eggers 	spin_lock_bh(&ptp_data->clock_lock);
879bb01ad30SChristian Eggers 	ptp_data->clock_time = ts;
880bb01ad30SChristian Eggers 	spin_unlock_bh(&ptp_data->clock_lock);
881bb01ad30SChristian Eggers 
882bb01ad30SChristian Eggers out:
883bb01ad30SChristian Eggers 	mutex_unlock(&ptp_data->lock);
884bb01ad30SChristian Eggers 
885bb01ad30SChristian Eggers 	return HZ;  /* reschedule in 1 second */
886bb01ad30SChristian Eggers }
887bb01ad30SChristian Eggers 
ksz_ptp_start_clock(struct ksz_device * dev)888eac1ea20SChristian Eggers static int ksz_ptp_start_clock(struct ksz_device *dev)
889eac1ea20SChristian Eggers {
890bb01ad30SChristian Eggers 	struct ksz_ptp_data *ptp_data = &dev->ptp_data;
891bb01ad30SChristian Eggers 	int ret;
892bb01ad30SChristian Eggers 
893bb01ad30SChristian Eggers 	ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ENABLE, PTP_CLK_ENABLE);
894bb01ad30SChristian Eggers 	if (ret)
895bb01ad30SChristian Eggers 		return ret;
896bb01ad30SChristian Eggers 
897bb01ad30SChristian Eggers 	ptp_data->clock_time.tv_sec = 0;
898bb01ad30SChristian Eggers 	ptp_data->clock_time.tv_nsec = 0;
899bb01ad30SChristian Eggers 
900bb01ad30SChristian Eggers 	return 0;
901eac1ea20SChristian Eggers }
902eac1ea20SChristian Eggers 
ksz_ptp_clock_register(struct dsa_switch * ds)903eac1ea20SChristian Eggers int ksz_ptp_clock_register(struct dsa_switch *ds)
904eac1ea20SChristian Eggers {
905eac1ea20SChristian Eggers 	struct ksz_device *dev = ds->priv;
906eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data;
907eac1ea20SChristian Eggers 	int ret;
908343d3bd8SArun Ramadoss 	u8 i;
909eac1ea20SChristian Eggers 
910eac1ea20SChristian Eggers 	ptp_data = &dev->ptp_data;
911eac1ea20SChristian Eggers 	mutex_init(&ptp_data->lock);
912bb01ad30SChristian Eggers 	spin_lock_init(&ptp_data->clock_lock);
913eac1ea20SChristian Eggers 
914eac1ea20SChristian Eggers 	ptp_data->caps.owner		= THIS_MODULE;
915eac1ea20SChristian Eggers 	snprintf(ptp_data->caps.name, 16, "Microchip Clock");
916eac1ea20SChristian Eggers 	ptp_data->caps.max_adj		= KSZ_MAX_DRIFT_CORR;
917eac1ea20SChristian Eggers 	ptp_data->caps.gettime64	= ksz_ptp_gettime;
918eac1ea20SChristian Eggers 	ptp_data->caps.settime64	= ksz_ptp_settime;
919eac1ea20SChristian Eggers 	ptp_data->caps.adjfine		= ksz_ptp_adjfine;
920eac1ea20SChristian Eggers 	ptp_data->caps.adjtime		= ksz_ptp_adjtime;
921bb01ad30SChristian Eggers 	ptp_data->caps.do_aux_work	= ksz_ptp_do_aux_work;
9221f12ae5bSChristian Eggers 	ptp_data->caps.enable		= ksz_ptp_enable;
923343d3bd8SArun Ramadoss 	ptp_data->caps.verify		= ksz_ptp_verify_pin;
924343d3bd8SArun Ramadoss 	ptp_data->caps.n_pins		= KSZ_PTP_N_GPIO;
9251f12ae5bSChristian Eggers 	ptp_data->caps.n_per_out	= 3;
926eac1ea20SChristian Eggers 
927eac1ea20SChristian Eggers 	ret = ksz_ptp_start_clock(dev);
928eac1ea20SChristian Eggers 	if (ret)
929eac1ea20SChristian Eggers 		return ret;
930eac1ea20SChristian Eggers 
931343d3bd8SArun Ramadoss 	for (i = 0; i < KSZ_PTP_N_GPIO; i++) {
932343d3bd8SArun Ramadoss 		struct ptp_pin_desc *ptp_pin = &ptp_data->pin_config[i];
933343d3bd8SArun Ramadoss 
934343d3bd8SArun Ramadoss 		snprintf(ptp_pin->name,
935343d3bd8SArun Ramadoss 			 sizeof(ptp_pin->name), "ksz_ptp_pin_%02d", i);
936343d3bd8SArun Ramadoss 		ptp_pin->index = i;
937343d3bd8SArun Ramadoss 		ptp_pin->func = PTP_PF_NONE;
938343d3bd8SArun Ramadoss 	}
939343d3bd8SArun Ramadoss 
940343d3bd8SArun Ramadoss 	ptp_data->caps.pin_config = ptp_data->pin_config;
941343d3bd8SArun Ramadoss 
942eac1ea20SChristian Eggers 	/* Currently only P2P mode is supported. When 802_1AS bit is set, it
943eac1ea20SChristian Eggers 	 * forwards all PTP packets to host port and none to other ports.
944eac1ea20SChristian Eggers 	 */
945eac1ea20SChristian Eggers 	ret = ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_TC_P2P | PTP_802_1AS,
946eac1ea20SChristian Eggers 			PTP_TC_P2P | PTP_802_1AS);
947eac1ea20SChristian Eggers 	if (ret)
948eac1ea20SChristian Eggers 		return ret;
949eac1ea20SChristian Eggers 
950eac1ea20SChristian Eggers 	ptp_data->clock = ptp_clock_register(&ptp_data->caps, dev->dev);
951eac1ea20SChristian Eggers 	if (IS_ERR_OR_NULL(ptp_data->clock))
952eac1ea20SChristian Eggers 		return PTR_ERR(ptp_data->clock);
953eac1ea20SChristian Eggers 
954eac1ea20SChristian Eggers 	return 0;
955eac1ea20SChristian Eggers }
956eac1ea20SChristian Eggers 
ksz_ptp_clock_unregister(struct dsa_switch * ds)957eac1ea20SChristian Eggers void ksz_ptp_clock_unregister(struct dsa_switch *ds)
958eac1ea20SChristian Eggers {
959eac1ea20SChristian Eggers 	struct ksz_device *dev = ds->priv;
960eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data;
961eac1ea20SChristian Eggers 
962eac1ea20SChristian Eggers 	ptp_data = &dev->ptp_data;
963eac1ea20SChristian Eggers 
964eac1ea20SChristian Eggers 	if (ptp_data->clock)
965eac1ea20SChristian Eggers 		ptp_clock_unregister(ptp_data->clock);
966eac1ea20SChristian Eggers }
967eac1ea20SChristian Eggers 
ksz_ptp_msg_thread_fn(int irq,void * dev_id)968cc13ab18SArun Ramadoss static irqreturn_t ksz_ptp_msg_thread_fn(int irq, void *dev_id)
969cc13ab18SArun Ramadoss {
970ab32f56aSChristian Eggers 	struct ksz_ptp_irq *ptpmsg_irq = dev_id;
971ab32f56aSChristian Eggers 	struct ksz_device *dev;
972ab32f56aSChristian Eggers 	struct ksz_port *port;
973ab32f56aSChristian Eggers 	u32 tstamp_raw;
974ab32f56aSChristian Eggers 	ktime_t tstamp;
975ab32f56aSChristian Eggers 	int ret;
976ab32f56aSChristian Eggers 
977ab32f56aSChristian Eggers 	port = ptpmsg_irq->port;
978ab32f56aSChristian Eggers 	dev = port->ksz_dev;
979ab32f56aSChristian Eggers 
980ab32f56aSChristian Eggers 	if (ptpmsg_irq->ts_en) {
981ab32f56aSChristian Eggers 		ret = ksz_read32(dev, ptpmsg_irq->ts_reg, &tstamp_raw);
982ab32f56aSChristian Eggers 		if (ret)
983cc13ab18SArun Ramadoss 			return IRQ_NONE;
984ab32f56aSChristian Eggers 
985ab32f56aSChristian Eggers 		tstamp = ksz_decode_tstamp(tstamp_raw);
986ab32f56aSChristian Eggers 
987ab32f56aSChristian Eggers 		port->tstamp_msg = ksz_tstamp_reconstruct(dev, tstamp);
988ab32f56aSChristian Eggers 
989ab32f56aSChristian Eggers 		complete(&port->tstamp_msg_comp);
990ab32f56aSChristian Eggers 	}
991ab32f56aSChristian Eggers 
992ab32f56aSChristian Eggers 	return IRQ_HANDLED;
993cc13ab18SArun Ramadoss }
994cc13ab18SArun Ramadoss 
ksz_ptp_irq_thread_fn(int irq,void * dev_id)995cc13ab18SArun Ramadoss static irqreturn_t ksz_ptp_irq_thread_fn(int irq, void *dev_id)
996cc13ab18SArun Ramadoss {
997cc13ab18SArun Ramadoss 	struct ksz_irq *ptpirq = dev_id;
998cc13ab18SArun Ramadoss 	unsigned int nhandled = 0;
999cc13ab18SArun Ramadoss 	struct ksz_device *dev;
1000cc13ab18SArun Ramadoss 	unsigned int sub_irq;
1001cc13ab18SArun Ramadoss 	u16 data;
1002cc13ab18SArun Ramadoss 	int ret;
1003cc13ab18SArun Ramadoss 	u8 n;
1004cc13ab18SArun Ramadoss 
1005cc13ab18SArun Ramadoss 	dev = ptpirq->dev;
1006cc13ab18SArun Ramadoss 
1007cc13ab18SArun Ramadoss 	ret = ksz_read16(dev, ptpirq->reg_status, &data);
1008cc13ab18SArun Ramadoss 	if (ret)
1009cc13ab18SArun Ramadoss 		goto out;
1010cc13ab18SArun Ramadoss 
1011cc13ab18SArun Ramadoss 	/* Clear the interrupts W1C */
1012cc13ab18SArun Ramadoss 	ret = ksz_write16(dev, ptpirq->reg_status, data);
1013cc13ab18SArun Ramadoss 	if (ret)
1014cc13ab18SArun Ramadoss 		return IRQ_NONE;
1015cc13ab18SArun Ramadoss 
1016cc13ab18SArun Ramadoss 	for (n = 0; n < ptpirq->nirqs; ++n) {
1017cc13ab18SArun Ramadoss 		if (data & BIT(n + KSZ_PTP_INT_START)) {
1018cc13ab18SArun Ramadoss 			sub_irq = irq_find_mapping(ptpirq->domain, n);
1019cc13ab18SArun Ramadoss 			handle_nested_irq(sub_irq);
1020cc13ab18SArun Ramadoss 			++nhandled;
1021cc13ab18SArun Ramadoss 		}
1022cc13ab18SArun Ramadoss 	}
1023cc13ab18SArun Ramadoss 
1024cc13ab18SArun Ramadoss out:
1025cc13ab18SArun Ramadoss 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
1026cc13ab18SArun Ramadoss }
1027cc13ab18SArun Ramadoss 
ksz_ptp_irq_mask(struct irq_data * d)1028cc13ab18SArun Ramadoss static void ksz_ptp_irq_mask(struct irq_data *d)
1029cc13ab18SArun Ramadoss {
1030cc13ab18SArun Ramadoss 	struct ksz_irq *kirq = irq_data_get_irq_chip_data(d);
1031cc13ab18SArun Ramadoss 
1032cc13ab18SArun Ramadoss 	kirq->masked &= ~BIT(d->hwirq + KSZ_PTP_INT_START);
1033cc13ab18SArun Ramadoss }
1034cc13ab18SArun Ramadoss 
ksz_ptp_irq_unmask(struct irq_data * d)1035cc13ab18SArun Ramadoss static void ksz_ptp_irq_unmask(struct irq_data *d)
1036cc13ab18SArun Ramadoss {
1037cc13ab18SArun Ramadoss 	struct ksz_irq *kirq = irq_data_get_irq_chip_data(d);
1038cc13ab18SArun Ramadoss 
1039cc13ab18SArun Ramadoss 	kirq->masked |= BIT(d->hwirq + KSZ_PTP_INT_START);
1040cc13ab18SArun Ramadoss }
1041cc13ab18SArun Ramadoss 
ksz_ptp_irq_bus_lock(struct irq_data * d)1042cc13ab18SArun Ramadoss static void ksz_ptp_irq_bus_lock(struct irq_data *d)
1043cc13ab18SArun Ramadoss {
1044cc13ab18SArun Ramadoss 	struct ksz_irq *kirq  = irq_data_get_irq_chip_data(d);
1045cc13ab18SArun Ramadoss 
1046cc13ab18SArun Ramadoss 	mutex_lock(&kirq->dev->lock_irq);
1047cc13ab18SArun Ramadoss }
1048cc13ab18SArun Ramadoss 
ksz_ptp_irq_bus_sync_unlock(struct irq_data * d)1049cc13ab18SArun Ramadoss static void ksz_ptp_irq_bus_sync_unlock(struct irq_data *d)
1050cc13ab18SArun Ramadoss {
1051cc13ab18SArun Ramadoss 	struct ksz_irq *kirq  = irq_data_get_irq_chip_data(d);
1052cc13ab18SArun Ramadoss 	struct ksz_device *dev = kirq->dev;
1053cc13ab18SArun Ramadoss 	int ret;
1054cc13ab18SArun Ramadoss 
1055cc13ab18SArun Ramadoss 	ret = ksz_write16(dev, kirq->reg_mask, kirq->masked);
1056cc13ab18SArun Ramadoss 	if (ret)
1057cc13ab18SArun Ramadoss 		dev_err(dev->dev, "failed to change IRQ mask\n");
1058cc13ab18SArun Ramadoss 
1059cc13ab18SArun Ramadoss 	mutex_unlock(&dev->lock_irq);
1060cc13ab18SArun Ramadoss }
1061cc13ab18SArun Ramadoss 
1062cc13ab18SArun Ramadoss static const struct irq_chip ksz_ptp_irq_chip = {
1063cc13ab18SArun Ramadoss 	.name			= "ksz-irq",
1064cc13ab18SArun Ramadoss 	.irq_mask		= ksz_ptp_irq_mask,
1065cc13ab18SArun Ramadoss 	.irq_unmask		= ksz_ptp_irq_unmask,
1066cc13ab18SArun Ramadoss 	.irq_bus_lock		= ksz_ptp_irq_bus_lock,
1067cc13ab18SArun Ramadoss 	.irq_bus_sync_unlock	= ksz_ptp_irq_bus_sync_unlock,
1068cc13ab18SArun Ramadoss };
1069cc13ab18SArun Ramadoss 
ksz_ptp_irq_domain_map(struct irq_domain * d,unsigned int irq,irq_hw_number_t hwirq)1070cc13ab18SArun Ramadoss static int ksz_ptp_irq_domain_map(struct irq_domain *d,
1071cc13ab18SArun Ramadoss 				  unsigned int irq, irq_hw_number_t hwirq)
1072cc13ab18SArun Ramadoss {
1073cc13ab18SArun Ramadoss 	irq_set_chip_data(irq, d->host_data);
1074cc13ab18SArun Ramadoss 	irq_set_chip_and_handler(irq, &ksz_ptp_irq_chip, handle_level_irq);
1075cc13ab18SArun Ramadoss 	irq_set_noprobe(irq);
1076cc13ab18SArun Ramadoss 
1077cc13ab18SArun Ramadoss 	return 0;
1078cc13ab18SArun Ramadoss }
1079cc13ab18SArun Ramadoss 
1080cc13ab18SArun Ramadoss static const struct irq_domain_ops ksz_ptp_irq_domain_ops = {
1081cc13ab18SArun Ramadoss 	.map	= ksz_ptp_irq_domain_map,
1082cc13ab18SArun Ramadoss 	.xlate	= irq_domain_xlate_twocell,
1083cc13ab18SArun Ramadoss };
1084cc13ab18SArun Ramadoss 
ksz_ptp_msg_irq_free(struct ksz_port * port,u8 n)1085cc13ab18SArun Ramadoss static void ksz_ptp_msg_irq_free(struct ksz_port *port, u8 n)
1086cc13ab18SArun Ramadoss {
1087cc13ab18SArun Ramadoss 	struct ksz_ptp_irq *ptpmsg_irq;
1088cc13ab18SArun Ramadoss 
1089cc13ab18SArun Ramadoss 	ptpmsg_irq = &port->ptpmsg_irq[n];
1090cc13ab18SArun Ramadoss 
1091cc13ab18SArun Ramadoss 	free_irq(ptpmsg_irq->num, ptpmsg_irq);
1092cc13ab18SArun Ramadoss 	irq_dispose_mapping(ptpmsg_irq->num);
1093cc13ab18SArun Ramadoss }
1094cc13ab18SArun Ramadoss 
ksz_ptp_msg_irq_setup(struct ksz_port * port,u8 n)1095cc13ab18SArun Ramadoss static int ksz_ptp_msg_irq_setup(struct ksz_port *port, u8 n)
1096cc13ab18SArun Ramadoss {
1097cc13ab18SArun Ramadoss 	u16 ts_reg[] = {REG_PTP_PORT_PDRESP_TS, REG_PTP_PORT_XDELAY_TS,
1098cc13ab18SArun Ramadoss 			REG_PTP_PORT_SYNC_TS};
1099cc13ab18SArun Ramadoss 	static const char * const name[] = {"pdresp-msg", "xdreq-msg",
1100cc13ab18SArun Ramadoss 					    "sync-msg"};
1101cc13ab18SArun Ramadoss 	const struct ksz_dev_ops *ops = port->ksz_dev->dev_ops;
1102cc13ab18SArun Ramadoss 	struct ksz_ptp_irq *ptpmsg_irq;
1103cc13ab18SArun Ramadoss 
1104cc13ab18SArun Ramadoss 	ptpmsg_irq = &port->ptpmsg_irq[n];
1105cc13ab18SArun Ramadoss 
1106cc13ab18SArun Ramadoss 	ptpmsg_irq->port = port;
1107cc13ab18SArun Ramadoss 	ptpmsg_irq->ts_reg = ops->get_port_addr(port->num, ts_reg[n]);
1108cc13ab18SArun Ramadoss 
1109cc13ab18SArun Ramadoss 	snprintf(ptpmsg_irq->name, sizeof(ptpmsg_irq->name), name[n]);
1110cc13ab18SArun Ramadoss 
1111cc13ab18SArun Ramadoss 	ptpmsg_irq->num = irq_find_mapping(port->ptpirq.domain, n);
1112cc13ab18SArun Ramadoss 	if (ptpmsg_irq->num < 0)
1113cc13ab18SArun Ramadoss 		return ptpmsg_irq->num;
1114cc13ab18SArun Ramadoss 
1115cc13ab18SArun Ramadoss 	return request_threaded_irq(ptpmsg_irq->num, NULL,
1116cc13ab18SArun Ramadoss 				    ksz_ptp_msg_thread_fn, IRQF_ONESHOT,
1117cc13ab18SArun Ramadoss 				    ptpmsg_irq->name, ptpmsg_irq);
1118cc13ab18SArun Ramadoss }
1119cc13ab18SArun Ramadoss 
ksz_ptp_irq_setup(struct dsa_switch * ds,u8 p)1120cc13ab18SArun Ramadoss int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p)
1121cc13ab18SArun Ramadoss {
1122cc13ab18SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1123cc13ab18SArun Ramadoss 	const struct ksz_dev_ops *ops = dev->dev_ops;
1124cc13ab18SArun Ramadoss 	struct ksz_port *port = &dev->ports[p];
1125cc13ab18SArun Ramadoss 	struct ksz_irq *ptpirq = &port->ptpirq;
1126cc13ab18SArun Ramadoss 	int irq;
1127cc13ab18SArun Ramadoss 	int ret;
1128cc13ab18SArun Ramadoss 
1129cc13ab18SArun Ramadoss 	ptpirq->dev = dev;
1130cc13ab18SArun Ramadoss 	ptpirq->masked = 0;
1131cc13ab18SArun Ramadoss 	ptpirq->nirqs = 3;
1132cc13ab18SArun Ramadoss 	ptpirq->reg_mask = ops->get_port_addr(p, REG_PTP_PORT_TX_INT_ENABLE__2);
1133cc13ab18SArun Ramadoss 	ptpirq->reg_status = ops->get_port_addr(p,
1134cc13ab18SArun Ramadoss 						REG_PTP_PORT_TX_INT_STATUS__2);
1135cc13ab18SArun Ramadoss 	snprintf(ptpirq->name, sizeof(ptpirq->name), "ptp-irq-%d", p);
1136cc13ab18SArun Ramadoss 
1137ab32f56aSChristian Eggers 	init_completion(&port->tstamp_msg_comp);
1138ab32f56aSChristian Eggers 
1139cc13ab18SArun Ramadoss 	ptpirq->domain = irq_domain_add_linear(dev->dev->of_node, ptpirq->nirqs,
1140cc13ab18SArun Ramadoss 					       &ksz_ptp_irq_domain_ops, ptpirq);
1141cc13ab18SArun Ramadoss 	if (!ptpirq->domain)
1142cc13ab18SArun Ramadoss 		return -ENOMEM;
1143cc13ab18SArun Ramadoss 
1144cc13ab18SArun Ramadoss 	for (irq = 0; irq < ptpirq->nirqs; irq++)
1145cc13ab18SArun Ramadoss 		irq_create_mapping(ptpirq->domain, irq);
1146cc13ab18SArun Ramadoss 
1147cc13ab18SArun Ramadoss 	ptpirq->irq_num = irq_find_mapping(port->pirq.domain, PORT_SRC_PTP_INT);
1148cc13ab18SArun Ramadoss 	if (ptpirq->irq_num < 0) {
1149cc13ab18SArun Ramadoss 		ret = ptpirq->irq_num;
1150cc13ab18SArun Ramadoss 		goto out;
1151cc13ab18SArun Ramadoss 	}
1152cc13ab18SArun Ramadoss 
1153cc13ab18SArun Ramadoss 	ret = request_threaded_irq(ptpirq->irq_num, NULL, ksz_ptp_irq_thread_fn,
1154cc13ab18SArun Ramadoss 				   IRQF_ONESHOT, ptpirq->name, ptpirq);
1155cc13ab18SArun Ramadoss 	if (ret)
1156cc13ab18SArun Ramadoss 		goto out;
1157cc13ab18SArun Ramadoss 
1158cc13ab18SArun Ramadoss 	for (irq = 0; irq < ptpirq->nirqs; irq++) {
1159cc13ab18SArun Ramadoss 		ret = ksz_ptp_msg_irq_setup(port, irq);
1160cc13ab18SArun Ramadoss 		if (ret)
1161cc13ab18SArun Ramadoss 			goto out_ptp_msg;
1162cc13ab18SArun Ramadoss 	}
1163cc13ab18SArun Ramadoss 
1164cc13ab18SArun Ramadoss 	return 0;
1165cc13ab18SArun Ramadoss 
1166cc13ab18SArun Ramadoss out_ptp_msg:
1167cc13ab18SArun Ramadoss 	free_irq(ptpirq->irq_num, ptpirq);
1168cc13ab18SArun Ramadoss 	while (irq--)
1169cc13ab18SArun Ramadoss 		free_irq(port->ptpmsg_irq[irq].num, &port->ptpmsg_irq[irq]);
1170cc13ab18SArun Ramadoss out:
1171cc13ab18SArun Ramadoss 	for (irq = 0; irq < ptpirq->nirqs; irq++)
1172cc13ab18SArun Ramadoss 		irq_dispose_mapping(port->ptpmsg_irq[irq].num);
1173cc13ab18SArun Ramadoss 
1174cc13ab18SArun Ramadoss 	irq_domain_remove(ptpirq->domain);
1175cc13ab18SArun Ramadoss 
1176cc13ab18SArun Ramadoss 	return ret;
1177cc13ab18SArun Ramadoss }
1178cc13ab18SArun Ramadoss 
ksz_ptp_irq_free(struct dsa_switch * ds,u8 p)1179cc13ab18SArun Ramadoss void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p)
1180cc13ab18SArun Ramadoss {
1181cc13ab18SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1182cc13ab18SArun Ramadoss 	struct ksz_port *port = &dev->ports[p];
1183cc13ab18SArun Ramadoss 	struct ksz_irq *ptpirq = &port->ptpirq;
1184cc13ab18SArun Ramadoss 	u8 n;
1185cc13ab18SArun Ramadoss 
1186cc13ab18SArun Ramadoss 	for (n = 0; n < ptpirq->nirqs; n++)
1187cc13ab18SArun Ramadoss 		ksz_ptp_msg_irq_free(port, n);
1188cc13ab18SArun Ramadoss 
1189cc13ab18SArun Ramadoss 	free_irq(ptpirq->irq_num, ptpirq);
1190cc13ab18SArun Ramadoss 	irq_dispose_mapping(ptpirq->irq_num);
1191cc13ab18SArun Ramadoss 
1192cc13ab18SArun Ramadoss 	irq_domain_remove(ptpirq->domain);
1193cc13ab18SArun Ramadoss }
1194cc13ab18SArun Ramadoss 
1195eac1ea20SChristian Eggers MODULE_AUTHOR("Christian Eggers <ceggers@arri.de>");
1196eac1ea20SChristian Eggers MODULE_AUTHOR("Arun Ramadoss <arun.ramadoss@microchip.com>");
1197eac1ea20SChristian Eggers MODULE_DESCRIPTION("PTP support for KSZ switch");
1198eac1ea20SChristian Eggers MODULE_LICENSE("GPL");
1199