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;
269bb01ad30SChristian Eggers 	int ret;
270c2977c61SArun Ramadoss 
271c2977c61SArun Ramadoss 	dsa_switch_for_each_user_port(dp, dev->ds) {
272c2977c61SArun Ramadoss 		prt = &dev->ports[dp->index];
273c2977c61SArun Ramadoss 		if (prt->hwts_tx_en || prt->hwts_rx_en) {
274c2977c61SArun Ramadoss 			tag_en = true;
275c2977c61SArun Ramadoss 			break;
276c2977c61SArun Ramadoss 		}
277c2977c61SArun Ramadoss 	}
278c2977c61SArun Ramadoss 
279bb01ad30SChristian Eggers 	if (tag_en) {
280bb01ad30SChristian Eggers 		ret = ptp_schedule_worker(ptp_data->clock, 0);
281bb01ad30SChristian Eggers 		if (ret)
282bb01ad30SChristian Eggers 			return ret;
283bb01ad30SChristian Eggers 	} else {
284bb01ad30SChristian Eggers 		ptp_cancel_worker_sync(ptp_data->clock);
285bb01ad30SChristian Eggers 	}
286bb01ad30SChristian Eggers 
287c2977c61SArun Ramadoss 	tagger_data->hwtstamp_set_state(dev->ds, tag_en);
288c2977c61SArun Ramadoss 
289c2977c61SArun Ramadoss 	return ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_ENABLE,
290c2977c61SArun Ramadoss 			 tag_en ? PTP_ENABLE : 0);
291c2977c61SArun Ramadoss }
292c2977c61SArun Ramadoss 
293c59e12a1SChristian Eggers /* The function is return back the capability of timestamping feature when
294c59e12a1SChristian Eggers  * requested through ethtool -T <interface> utility
295c59e12a1SChristian Eggers  */
ksz_get_ts_info(struct dsa_switch * ds,int port,struct ethtool_ts_info * ts)296c59e12a1SChristian Eggers int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts)
297c59e12a1SChristian Eggers {
298c59e12a1SChristian Eggers 	struct ksz_device *dev = ds->priv;
299c59e12a1SChristian Eggers 	struct ksz_ptp_data *ptp_data;
300c59e12a1SChristian Eggers 
301c59e12a1SChristian Eggers 	ptp_data = &dev->ptp_data;
302c59e12a1SChristian Eggers 
303c59e12a1SChristian Eggers 	if (!ptp_data->clock)
304c59e12a1SChristian Eggers 		return -ENODEV;
305c59e12a1SChristian Eggers 
306c59e12a1SChristian Eggers 	ts->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
307c59e12a1SChristian Eggers 			      SOF_TIMESTAMPING_RX_HARDWARE |
308c59e12a1SChristian Eggers 			      SOF_TIMESTAMPING_RAW_HARDWARE;
309c59e12a1SChristian Eggers 
310c59e12a1SChristian Eggers 	ts->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ONESTEP_P2P);
311c59e12a1SChristian Eggers 
312d6261f0bSArun Ramadoss 	if (is_lan937x(dev))
313d6261f0bSArun Ramadoss 		ts->tx_types |= BIT(HWTSTAMP_TX_ON);
314d6261f0bSArun Ramadoss 
315c59e12a1SChristian Eggers 	ts->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
316c59e12a1SChristian Eggers 			 BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
317c59e12a1SChristian Eggers 			 BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
318c59e12a1SChristian Eggers 			 BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
319c59e12a1SChristian Eggers 
320c59e12a1SChristian Eggers 	ts->phc_index = ptp_clock_index(ptp_data->clock);
321c59e12a1SChristian Eggers 
322c59e12a1SChristian Eggers 	return 0;
323c59e12a1SChristian Eggers }
324c59e12a1SChristian Eggers 
ksz_hwtstamp_get(struct dsa_switch * ds,int port,struct ifreq * ifr)325c59e12a1SChristian Eggers int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr)
326c59e12a1SChristian Eggers {
327c59e12a1SChristian Eggers 	struct ksz_device *dev = ds->priv;
328c59e12a1SChristian Eggers 	struct hwtstamp_config *config;
329c59e12a1SChristian Eggers 	struct ksz_port *prt;
330c59e12a1SChristian Eggers 
331c59e12a1SChristian Eggers 	prt = &dev->ports[port];
332c59e12a1SChristian Eggers 	config = &prt->tstamp_config;
333c59e12a1SChristian Eggers 
334c59e12a1SChristian Eggers 	return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
335c59e12a1SChristian Eggers 		-EFAULT : 0;
336c59e12a1SChristian Eggers }
337c59e12a1SChristian Eggers 
ksz_set_hwtstamp_config(struct ksz_device * dev,struct ksz_port * prt,struct hwtstamp_config * config)338c59e12a1SChristian Eggers static int ksz_set_hwtstamp_config(struct ksz_device *dev,
339c2977c61SArun Ramadoss 				   struct ksz_port *prt,
340c59e12a1SChristian Eggers 				   struct hwtstamp_config *config)
341c59e12a1SChristian Eggers {
342d6261f0bSArun Ramadoss 	int ret;
343d6261f0bSArun Ramadoss 
344c59e12a1SChristian Eggers 	if (config->flags)
345c59e12a1SChristian Eggers 		return -EINVAL;
346c59e12a1SChristian Eggers 
347c59e12a1SChristian Eggers 	switch (config->tx_type) {
348c59e12a1SChristian Eggers 	case HWTSTAMP_TX_OFF:
349ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en  = false;
350ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = false;
351ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = false;
352c2977c61SArun Ramadoss 		prt->hwts_tx_en = false;
353c2977c61SArun Ramadoss 		break;
354c59e12a1SChristian Eggers 	case HWTSTAMP_TX_ONESTEP_P2P:
355ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en  = false;
356ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = true;
357ab32f56aSChristian Eggers 		prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = false;
358c2977c61SArun Ramadoss 		prt->hwts_tx_en = true;
359d6261f0bSArun Ramadoss 
360d6261f0bSArun Ramadoss 		ret = ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_1STEP, PTP_1STEP);
361d6261f0bSArun Ramadoss 		if (ret)
362d6261f0bSArun Ramadoss 			return ret;
363d6261f0bSArun Ramadoss 
364d6261f0bSArun Ramadoss 		break;
365d6261f0bSArun Ramadoss 	case HWTSTAMP_TX_ON:
366d6261f0bSArun Ramadoss 		if (!is_lan937x(dev))
367d6261f0bSArun Ramadoss 			return -ERANGE;
368d6261f0bSArun Ramadoss 
369d6261f0bSArun Ramadoss 		prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en  = true;
370d6261f0bSArun Ramadoss 		prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = true;
371d6261f0bSArun Ramadoss 		prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = true;
372d6261f0bSArun Ramadoss 		prt->hwts_tx_en = true;
373d6261f0bSArun Ramadoss 
374d6261f0bSArun Ramadoss 		ret = ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_1STEP, 0);
375d6261f0bSArun Ramadoss 		if (ret)
376d6261f0bSArun Ramadoss 			return ret;
377d6261f0bSArun Ramadoss 
378c59e12a1SChristian Eggers 		break;
379c59e12a1SChristian Eggers 	default:
380c59e12a1SChristian Eggers 		return -ERANGE;
381c59e12a1SChristian Eggers 	}
382c59e12a1SChristian Eggers 
383c59e12a1SChristian Eggers 	switch (config->rx_filter) {
384c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_NONE:
385c2977c61SArun Ramadoss 		prt->hwts_rx_en = false;
386c59e12a1SChristian Eggers 		break;
387c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
388c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
389c59e12a1SChristian Eggers 		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
390c2977c61SArun Ramadoss 		prt->hwts_rx_en = true;
391c59e12a1SChristian Eggers 		break;
392c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
393c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
394c59e12a1SChristian Eggers 		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
395c2977c61SArun Ramadoss 		prt->hwts_rx_en = true;
396c59e12a1SChristian Eggers 		break;
397c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
398c59e12a1SChristian Eggers 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
399c59e12a1SChristian Eggers 		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
400c2977c61SArun Ramadoss 		prt->hwts_rx_en = true;
401c59e12a1SChristian Eggers 		break;
402c59e12a1SChristian Eggers 	default:
403c59e12a1SChristian Eggers 		config->rx_filter = HWTSTAMP_FILTER_NONE;
404c59e12a1SChristian Eggers 		return -ERANGE;
405c59e12a1SChristian Eggers 	}
406c59e12a1SChristian Eggers 
407c2977c61SArun Ramadoss 	return ksz_ptp_enable_mode(dev);
408c59e12a1SChristian Eggers }
409c59e12a1SChristian Eggers 
ksz_hwtstamp_set(struct dsa_switch * ds,int port,struct ifreq * ifr)410c59e12a1SChristian Eggers int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
411c59e12a1SChristian Eggers {
412c59e12a1SChristian Eggers 	struct ksz_device *dev = ds->priv;
413c59e12a1SChristian Eggers 	struct hwtstamp_config config;
414c59e12a1SChristian Eggers 	struct ksz_port *prt;
415c59e12a1SChristian Eggers 	int ret;
416c59e12a1SChristian Eggers 
417c59e12a1SChristian Eggers 	prt = &dev->ports[port];
418c59e12a1SChristian Eggers 
419*a76e88c2SDan Carpenter 	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
420*a76e88c2SDan Carpenter 		return -EFAULT;
421c59e12a1SChristian Eggers 
422c2977c61SArun Ramadoss 	ret = ksz_set_hwtstamp_config(dev, prt, &config);
423c59e12a1SChristian Eggers 	if (ret)
424c59e12a1SChristian Eggers 		return ret;
425c59e12a1SChristian Eggers 
426c59e12a1SChristian Eggers 	memcpy(&prt->tstamp_config, &config, sizeof(config));
427c59e12a1SChristian Eggers 
428*a76e88c2SDan Carpenter 	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
429*a76e88c2SDan Carpenter 		return -EFAULT;
430*a76e88c2SDan Carpenter 
431*a76e88c2SDan Carpenter 	return 0;
432c59e12a1SChristian Eggers }
433c59e12a1SChristian Eggers 
ksz_tstamp_reconstruct(struct ksz_device * dev,ktime_t tstamp)43490188fffSChristian Eggers static ktime_t ksz_tstamp_reconstruct(struct ksz_device *dev, ktime_t tstamp)
43590188fffSChristian Eggers {
43690188fffSChristian Eggers 	struct timespec64 ptp_clock_time;
43790188fffSChristian Eggers 	struct ksz_ptp_data *ptp_data;
43890188fffSChristian Eggers 	struct timespec64 diff;
43990188fffSChristian Eggers 	struct timespec64 ts;
44090188fffSChristian Eggers 
44190188fffSChristian Eggers 	ptp_data = &dev->ptp_data;
44290188fffSChristian Eggers 	ts = ktime_to_timespec64(tstamp);
44390188fffSChristian Eggers 
44490188fffSChristian Eggers 	spin_lock_bh(&ptp_data->clock_lock);
44590188fffSChristian Eggers 	ptp_clock_time = ptp_data->clock_time;
44690188fffSChristian Eggers 	spin_unlock_bh(&ptp_data->clock_lock);
44790188fffSChristian Eggers 
44890188fffSChristian Eggers 	/* calculate full time from partial time stamp */
44990188fffSChristian Eggers 	ts.tv_sec = (ptp_clock_time.tv_sec & ~3) | ts.tv_sec;
45090188fffSChristian Eggers 
45190188fffSChristian Eggers 	/* find nearest possible point in time */
45290188fffSChristian Eggers 	diff = timespec64_sub(ts, ptp_clock_time);
45390188fffSChristian Eggers 	if (diff.tv_sec > 2)
45490188fffSChristian Eggers 		ts.tv_sec -= 4;
45590188fffSChristian Eggers 	else if (diff.tv_sec < -2)
45690188fffSChristian Eggers 		ts.tv_sec += 4;
45790188fffSChristian Eggers 
45890188fffSChristian Eggers 	return timespec64_to_ktime(ts);
45990188fffSChristian Eggers }
46090188fffSChristian Eggers 
ksz_port_rxtstamp(struct dsa_switch * ds,int port,struct sk_buff * skb,unsigned int type)46190188fffSChristian Eggers bool ksz_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb,
46290188fffSChristian Eggers 		       unsigned int type)
46390188fffSChristian Eggers {
46490188fffSChristian Eggers 	struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
46590188fffSChristian Eggers 	struct ksz_device *dev = ds->priv;
46690188fffSChristian Eggers 	struct ptp_header *ptp_hdr;
467d6261f0bSArun Ramadoss 	struct ksz_port *prt;
46890188fffSChristian Eggers 	u8 ptp_msg_type;
46990188fffSChristian Eggers 	ktime_t tstamp;
47090188fffSChristian Eggers 	s64 correction;
47190188fffSChristian Eggers 
472d6261f0bSArun Ramadoss 	prt = &dev->ports[port];
473d6261f0bSArun Ramadoss 
47490188fffSChristian Eggers 	tstamp = KSZ_SKB_CB(skb)->tstamp;
47590188fffSChristian Eggers 	memset(hwtstamps, 0, sizeof(*hwtstamps));
47690188fffSChristian Eggers 	hwtstamps->hwtstamp = ksz_tstamp_reconstruct(dev, tstamp);
47790188fffSChristian Eggers 
478d6261f0bSArun Ramadoss 	if (prt->tstamp_config.tx_type != HWTSTAMP_TX_ONESTEP_P2P)
479d6261f0bSArun Ramadoss 		goto out;
480d6261f0bSArun Ramadoss 
48190188fffSChristian Eggers 	ptp_hdr = ptp_parse_header(skb, type);
48290188fffSChristian Eggers 	if (!ptp_hdr)
48390188fffSChristian Eggers 		goto out;
48490188fffSChristian Eggers 
48590188fffSChristian Eggers 	ptp_msg_type = ptp_get_msgtype(ptp_hdr, type);
48690188fffSChristian Eggers 	if (ptp_msg_type != PTP_MSGTYPE_PDELAY_REQ)
48790188fffSChristian Eggers 		goto out;
48890188fffSChristian Eggers 
48990188fffSChristian Eggers 	/* Only subtract the partial time stamp from the correction field.  When
49090188fffSChristian Eggers 	 * the hardware adds the egress time stamp to the correction field of
49190188fffSChristian Eggers 	 * the PDelay_Resp message on tx, also only the partial time stamp will
49290188fffSChristian Eggers 	 * be added.
49390188fffSChristian Eggers 	 */
49490188fffSChristian Eggers 	correction = (s64)get_unaligned_be64(&ptp_hdr->correction);
49590188fffSChristian Eggers 	correction -= ktime_to_ns(tstamp) << 16;
49690188fffSChristian Eggers 
49790188fffSChristian Eggers 	ptp_header_update_correction(skb, type, ptp_hdr, correction);
49890188fffSChristian Eggers 
49990188fffSChristian Eggers out:
50090188fffSChristian Eggers 	return false;
50190188fffSChristian Eggers }
50290188fffSChristian Eggers 
ksz_port_txtstamp(struct dsa_switch * ds,int port,struct sk_buff * skb)503ab32f56aSChristian Eggers void ksz_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
504ab32f56aSChristian Eggers {
505ab32f56aSChristian Eggers 	struct ksz_device *dev = ds->priv;
506ab32f56aSChristian Eggers 	struct ptp_header *hdr;
507ab32f56aSChristian Eggers 	struct sk_buff *clone;
508ab32f56aSChristian Eggers 	struct ksz_port *prt;
509ab32f56aSChristian Eggers 	unsigned int type;
510ab32f56aSChristian Eggers 	u8 ptp_msg_type;
511ab32f56aSChristian Eggers 
512ab32f56aSChristian Eggers 	prt = &dev->ports[port];
513ab32f56aSChristian Eggers 
514ab32f56aSChristian Eggers 	if (!prt->hwts_tx_en)
515ab32f56aSChristian Eggers 		return;
516ab32f56aSChristian Eggers 
517ab32f56aSChristian Eggers 	type = ptp_classify_raw(skb);
518ab32f56aSChristian Eggers 	if (type == PTP_CLASS_NONE)
519ab32f56aSChristian Eggers 		return;
520ab32f56aSChristian Eggers 
521ab32f56aSChristian Eggers 	hdr = ptp_parse_header(skb, type);
522ab32f56aSChristian Eggers 	if (!hdr)
523ab32f56aSChristian Eggers 		return;
524ab32f56aSChristian Eggers 
525ab32f56aSChristian Eggers 	ptp_msg_type = ptp_get_msgtype(hdr, type);
526ab32f56aSChristian Eggers 
527ab32f56aSChristian Eggers 	switch (ptp_msg_type) {
528d6261f0bSArun Ramadoss 	case PTP_MSGTYPE_SYNC:
529d6261f0bSArun Ramadoss 		if (prt->tstamp_config.tx_type == HWTSTAMP_TX_ONESTEP_P2P)
530d6261f0bSArun Ramadoss 			return;
531d6261f0bSArun Ramadoss 		break;
532ab32f56aSChristian Eggers 	case PTP_MSGTYPE_PDELAY_REQ:
533ab32f56aSChristian Eggers 		break;
534a32190b1SChristian Eggers 	case PTP_MSGTYPE_PDELAY_RESP:
535d6261f0bSArun Ramadoss 		if (prt->tstamp_config.tx_type == HWTSTAMP_TX_ONESTEP_P2P) {
536a32190b1SChristian Eggers 			KSZ_SKB_CB(skb)->ptp_type = type;
537a32190b1SChristian Eggers 			KSZ_SKB_CB(skb)->update_correction = true;
538a32190b1SChristian Eggers 			return;
539d6261f0bSArun Ramadoss 		}
540d6261f0bSArun Ramadoss 		break;
541ab32f56aSChristian Eggers 
542ab32f56aSChristian Eggers 	default:
543ab32f56aSChristian Eggers 		return;
544ab32f56aSChristian Eggers 	}
545ab32f56aSChristian Eggers 
546ab32f56aSChristian Eggers 	clone = skb_clone_sk(skb);
547ab32f56aSChristian Eggers 	if (!clone)
548ab32f56aSChristian Eggers 		return;
549ab32f56aSChristian Eggers 
550ab32f56aSChristian Eggers 	/* caching the value to be used in tag_ksz.c */
551ab32f56aSChristian Eggers 	KSZ_SKB_CB(skb)->clone = clone;
552ab32f56aSChristian Eggers }
553ab32f56aSChristian Eggers 
ksz_ptp_txtstamp_skb(struct ksz_device * dev,struct ksz_port * prt,struct sk_buff * skb)554ab32f56aSChristian Eggers static void ksz_ptp_txtstamp_skb(struct ksz_device *dev,
555ab32f56aSChristian Eggers 				 struct ksz_port *prt, struct sk_buff *skb)
556ab32f56aSChristian Eggers {
557ab32f56aSChristian Eggers 	struct skb_shared_hwtstamps hwtstamps = {};
558ab32f56aSChristian Eggers 	int ret;
559ab32f56aSChristian Eggers 
560ab32f56aSChristian Eggers 	/* timeout must include DSA master to transmit data, tstamp latency,
561ab32f56aSChristian Eggers 	 * IRQ latency and time for reading the time stamp.
562ab32f56aSChristian Eggers 	 */
563ab32f56aSChristian Eggers 	ret = wait_for_completion_timeout(&prt->tstamp_msg_comp,
564ab32f56aSChristian Eggers 					  msecs_to_jiffies(100));
565ab32f56aSChristian Eggers 	if (!ret)
566ab32f56aSChristian Eggers 		return;
567ab32f56aSChristian Eggers 
568ab32f56aSChristian Eggers 	hwtstamps.hwtstamp = prt->tstamp_msg;
569ab32f56aSChristian Eggers 	skb_complete_tx_timestamp(skb, &hwtstamps);
570ab32f56aSChristian Eggers }
571ab32f56aSChristian Eggers 
ksz_port_deferred_xmit(struct kthread_work * work)572ab32f56aSChristian Eggers void ksz_port_deferred_xmit(struct kthread_work *work)
573ab32f56aSChristian Eggers {
574ab32f56aSChristian Eggers 	struct ksz_deferred_xmit_work *xmit_work = work_to_xmit_work(work);
575ab32f56aSChristian Eggers 	struct sk_buff *clone, *skb = xmit_work->skb;
576ab32f56aSChristian Eggers 	struct dsa_switch *ds = xmit_work->dp->ds;
577ab32f56aSChristian Eggers 	struct ksz_device *dev = ds->priv;
578ab32f56aSChristian Eggers 	struct ksz_port *prt;
579ab32f56aSChristian Eggers 
580ab32f56aSChristian Eggers 	prt = &dev->ports[xmit_work->dp->index];
581ab32f56aSChristian Eggers 
582ab32f56aSChristian Eggers 	clone = KSZ_SKB_CB(skb)->clone;
583ab32f56aSChristian Eggers 
584ab32f56aSChristian Eggers 	skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
585ab32f56aSChristian Eggers 
586ab32f56aSChristian Eggers 	reinit_completion(&prt->tstamp_msg_comp);
587ab32f56aSChristian Eggers 
588ab32f56aSChristian Eggers 	dsa_enqueue_skb(skb, skb->dev);
589ab32f56aSChristian Eggers 
590ab32f56aSChristian Eggers 	ksz_ptp_txtstamp_skb(dev, prt, clone);
591ab32f56aSChristian Eggers 
592ab32f56aSChristian Eggers 	kfree(xmit_work);
593ab32f56aSChristian Eggers }
594ab32f56aSChristian Eggers 
_ksz_ptp_gettime(struct ksz_device * dev,struct timespec64 * ts)595eac1ea20SChristian Eggers static int _ksz_ptp_gettime(struct ksz_device *dev, struct timespec64 *ts)
596eac1ea20SChristian Eggers {
597eac1ea20SChristian Eggers 	u32 nanoseconds;
598eac1ea20SChristian Eggers 	u32 seconds;
599eac1ea20SChristian Eggers 	u8 phase;
600eac1ea20SChristian Eggers 	int ret;
601eac1ea20SChristian Eggers 
602eac1ea20SChristian Eggers 	/* Copy current PTP clock into shadow registers and read */
603eac1ea20SChristian Eggers 	ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_READ_TIME, PTP_READ_TIME);
604eac1ea20SChristian Eggers 	if (ret)
605eac1ea20SChristian Eggers 		return ret;
606eac1ea20SChristian Eggers 
607eac1ea20SChristian Eggers 	ret = ksz_read8(dev, REG_PTP_RTC_SUB_NANOSEC__2, &phase);
608eac1ea20SChristian Eggers 	if (ret)
609eac1ea20SChristian Eggers 		return ret;
610eac1ea20SChristian Eggers 
611eac1ea20SChristian Eggers 	ret = ksz_read32(dev, REG_PTP_RTC_NANOSEC, &nanoseconds);
612eac1ea20SChristian Eggers 	if (ret)
613eac1ea20SChristian Eggers 		return ret;
614eac1ea20SChristian Eggers 
615eac1ea20SChristian Eggers 	ret = ksz_read32(dev, REG_PTP_RTC_SEC, &seconds);
616eac1ea20SChristian Eggers 	if (ret)
617eac1ea20SChristian Eggers 		return ret;
618eac1ea20SChristian Eggers 
619eac1ea20SChristian Eggers 	ts->tv_sec = seconds;
620eac1ea20SChristian Eggers 	ts->tv_nsec = nanoseconds + phase * 8;
621eac1ea20SChristian Eggers 
622eac1ea20SChristian Eggers 	return 0;
623eac1ea20SChristian Eggers }
624eac1ea20SChristian Eggers 
ksz_ptp_gettime(struct ptp_clock_info * ptp,struct timespec64 * ts)625eac1ea20SChristian Eggers static int ksz_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
626eac1ea20SChristian Eggers {
627eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
628eac1ea20SChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
629eac1ea20SChristian Eggers 	int ret;
630eac1ea20SChristian Eggers 
631eac1ea20SChristian Eggers 	mutex_lock(&ptp_data->lock);
632eac1ea20SChristian Eggers 	ret = _ksz_ptp_gettime(dev, ts);
633eac1ea20SChristian Eggers 	mutex_unlock(&ptp_data->lock);
634eac1ea20SChristian Eggers 
635eac1ea20SChristian Eggers 	return ret;
636eac1ea20SChristian Eggers }
637eac1ea20SChristian Eggers 
ksz_ptp_restart_perout(struct ksz_device * dev)6381f12ae5bSChristian Eggers static int ksz_ptp_restart_perout(struct ksz_device *dev)
6391f12ae5bSChristian Eggers {
6401f12ae5bSChristian Eggers 	struct ksz_ptp_data *ptp_data = &dev->ptp_data;
6411f12ae5bSChristian Eggers 	s64 now_ns, first_ns, period_ns, next_ns;
6421f12ae5bSChristian Eggers 	struct ptp_perout_request request;
6431f12ae5bSChristian Eggers 	struct timespec64 next;
6441f12ae5bSChristian Eggers 	struct timespec64 now;
6451f12ae5bSChristian Eggers 	unsigned int count;
6461f12ae5bSChristian Eggers 	int ret;
6471f12ae5bSChristian Eggers 
6481f12ae5bSChristian Eggers 	dev_info(dev->dev, "Restarting periodic output signal\n");
6491f12ae5bSChristian Eggers 
6501f12ae5bSChristian Eggers 	ret = _ksz_ptp_gettime(dev, &now);
6511f12ae5bSChristian Eggers 	if (ret)
6521f12ae5bSChristian Eggers 		return ret;
6531f12ae5bSChristian Eggers 
6541f12ae5bSChristian Eggers 	now_ns = timespec64_to_ns(&now);
6551f12ae5bSChristian Eggers 	first_ns = timespec64_to_ns(&ptp_data->perout_target_time_first);
6561f12ae5bSChristian Eggers 
6571f12ae5bSChristian Eggers 	/* Calculate next perout event based on start time and period */
6581f12ae5bSChristian Eggers 	period_ns = timespec64_to_ns(&ptp_data->perout_period);
6591f12ae5bSChristian Eggers 
6601f12ae5bSChristian Eggers 	if (first_ns < now_ns) {
6611f12ae5bSChristian Eggers 		count = div_u64(now_ns - first_ns, period_ns);
6621f12ae5bSChristian Eggers 		next_ns = first_ns + count * period_ns;
6631f12ae5bSChristian Eggers 	} else {
6641f12ae5bSChristian Eggers 		next_ns = first_ns;
6651f12ae5bSChristian Eggers 	}
6661f12ae5bSChristian Eggers 
6671f12ae5bSChristian Eggers 	/* Ensure 100 ms guard time prior next event */
6681f12ae5bSChristian Eggers 	while (next_ns < now_ns + 100000000)
6691f12ae5bSChristian Eggers 		next_ns += period_ns;
6701f12ae5bSChristian Eggers 
6711f12ae5bSChristian Eggers 	/* Restart periodic output signal */
6721f12ae5bSChristian Eggers 	next = ns_to_timespec64(next_ns);
6731f12ae5bSChristian Eggers 	request.start.sec  = next.tv_sec;
6741f12ae5bSChristian Eggers 	request.start.nsec = next.tv_nsec;
6751f12ae5bSChristian Eggers 	request.period.sec  = ptp_data->perout_period.tv_sec;
6761f12ae5bSChristian Eggers 	request.period.nsec = ptp_data->perout_period.tv_nsec;
6771f12ae5bSChristian Eggers 	request.index = 0;
6781f12ae5bSChristian Eggers 	request.flags = 0;
6791f12ae5bSChristian Eggers 
6801f12ae5bSChristian Eggers 	return ksz_ptp_enable_perout(dev, &request, 1);
6811f12ae5bSChristian Eggers }
6821f12ae5bSChristian Eggers 
ksz_ptp_settime(struct ptp_clock_info * ptp,const struct timespec64 * ts)683eac1ea20SChristian Eggers static int ksz_ptp_settime(struct ptp_clock_info *ptp,
684eac1ea20SChristian Eggers 			   const struct timespec64 *ts)
685eac1ea20SChristian Eggers {
686eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
687eac1ea20SChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
688eac1ea20SChristian Eggers 	int ret;
689eac1ea20SChristian Eggers 
690eac1ea20SChristian Eggers 	mutex_lock(&ptp_data->lock);
691eac1ea20SChristian Eggers 
692eac1ea20SChristian Eggers 	/* Write to shadow registers and Load PTP clock */
693eac1ea20SChristian Eggers 	ret = ksz_write16(dev, REG_PTP_RTC_SUB_NANOSEC__2, PTP_RTC_0NS);
694eac1ea20SChristian Eggers 	if (ret)
695eac1ea20SChristian Eggers 		goto unlock;
696eac1ea20SChristian Eggers 
697eac1ea20SChristian Eggers 	ret = ksz_write32(dev, REG_PTP_RTC_NANOSEC, ts->tv_nsec);
698eac1ea20SChristian Eggers 	if (ret)
699eac1ea20SChristian Eggers 		goto unlock;
700eac1ea20SChristian Eggers 
701eac1ea20SChristian Eggers 	ret = ksz_write32(dev, REG_PTP_RTC_SEC, ts->tv_sec);
702eac1ea20SChristian Eggers 	if (ret)
703eac1ea20SChristian Eggers 		goto unlock;
704eac1ea20SChristian Eggers 
705eac1ea20SChristian Eggers 	ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_LOAD_TIME, PTP_LOAD_TIME);
706bb01ad30SChristian Eggers 	if (ret)
707bb01ad30SChristian Eggers 		goto unlock;
708bb01ad30SChristian Eggers 
7091f12ae5bSChristian Eggers 	switch (ptp_data->tou_mode) {
7101f12ae5bSChristian Eggers 	case KSZ_PTP_TOU_IDLE:
7111f12ae5bSChristian Eggers 		break;
7121f12ae5bSChristian Eggers 
7131f12ae5bSChristian Eggers 	case KSZ_PTP_TOU_PEROUT:
7141f12ae5bSChristian Eggers 		ret = ksz_ptp_restart_perout(dev);
7151f12ae5bSChristian Eggers 		if (ret)
7161f12ae5bSChristian Eggers 			goto unlock;
7171f12ae5bSChristian Eggers 
7181f12ae5bSChristian Eggers 		break;
7191f12ae5bSChristian Eggers 	}
7201f12ae5bSChristian Eggers 
721bb01ad30SChristian Eggers 	spin_lock_bh(&ptp_data->clock_lock);
722bb01ad30SChristian Eggers 	ptp_data->clock_time = *ts;
723bb01ad30SChristian Eggers 	spin_unlock_bh(&ptp_data->clock_lock);
724eac1ea20SChristian Eggers 
725eac1ea20SChristian Eggers unlock:
726eac1ea20SChristian Eggers 	mutex_unlock(&ptp_data->lock);
727eac1ea20SChristian Eggers 
728eac1ea20SChristian Eggers 	return ret;
729eac1ea20SChristian Eggers }
730eac1ea20SChristian Eggers 
ksz_ptp_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)731eac1ea20SChristian Eggers static int ksz_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
732eac1ea20SChristian Eggers {
733eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
734eac1ea20SChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
735eac1ea20SChristian Eggers 	u64 base, adj;
736eac1ea20SChristian Eggers 	bool negative;
737eac1ea20SChristian Eggers 	u32 data32;
738eac1ea20SChristian Eggers 	int ret;
739eac1ea20SChristian Eggers 
740eac1ea20SChristian Eggers 	mutex_lock(&ptp_data->lock);
741eac1ea20SChristian Eggers 
742eac1ea20SChristian Eggers 	if (scaled_ppm) {
743eac1ea20SChristian Eggers 		base = KSZ_PTP_INC_NS << KSZ_PTP_SUBNS_BITS;
744eac1ea20SChristian Eggers 		negative = diff_by_scaled_ppm(base, scaled_ppm, &adj);
745eac1ea20SChristian Eggers 
746eac1ea20SChristian Eggers 		data32 = (u32)adj;
747eac1ea20SChristian Eggers 		data32 &= PTP_SUBNANOSEC_M;
748eac1ea20SChristian Eggers 		if (!negative)
749eac1ea20SChristian Eggers 			data32 |= PTP_RATE_DIR;
750eac1ea20SChristian Eggers 
751eac1ea20SChristian Eggers 		ret = ksz_write32(dev, REG_PTP_SUBNANOSEC_RATE, data32);
752eac1ea20SChristian Eggers 		if (ret)
753eac1ea20SChristian Eggers 			goto unlock;
754eac1ea20SChristian Eggers 
755eac1ea20SChristian Eggers 		ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ADJ_ENABLE,
756eac1ea20SChristian Eggers 				PTP_CLK_ADJ_ENABLE);
757eac1ea20SChristian Eggers 		if (ret)
758eac1ea20SChristian Eggers 			goto unlock;
759eac1ea20SChristian Eggers 	} else {
760eac1ea20SChristian Eggers 		ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ADJ_ENABLE, 0);
761eac1ea20SChristian Eggers 		if (ret)
762eac1ea20SChristian Eggers 			goto unlock;
763eac1ea20SChristian Eggers 	}
764eac1ea20SChristian Eggers 
765eac1ea20SChristian Eggers unlock:
766eac1ea20SChristian Eggers 	mutex_unlock(&ptp_data->lock);
767eac1ea20SChristian Eggers 	return ret;
768eac1ea20SChristian Eggers }
769eac1ea20SChristian Eggers 
ksz_ptp_adjtime(struct ptp_clock_info * ptp,s64 delta)770eac1ea20SChristian Eggers static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
771eac1ea20SChristian Eggers {
772eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
773eac1ea20SChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
774bb01ad30SChristian Eggers 	struct timespec64 delta64 = ns_to_timespec64(delta);
775eac1ea20SChristian Eggers 	s32 sec, nsec;
776eac1ea20SChristian Eggers 	u16 data16;
777eac1ea20SChristian Eggers 	int ret;
778eac1ea20SChristian Eggers 
779eac1ea20SChristian Eggers 	mutex_lock(&ptp_data->lock);
780eac1ea20SChristian Eggers 
781eac1ea20SChristian Eggers 	/* do not use ns_to_timespec64(),
782eac1ea20SChristian Eggers 	 * both sec and nsec are subtracted by hw
783eac1ea20SChristian Eggers 	 */
784eac1ea20SChristian Eggers 	sec = div_s64_rem(delta, NSEC_PER_SEC, &nsec);
785eac1ea20SChristian Eggers 
786eac1ea20SChristian Eggers 	ret = ksz_write32(dev, REG_PTP_RTC_NANOSEC, abs(nsec));
787eac1ea20SChristian Eggers 	if (ret)
788eac1ea20SChristian Eggers 		goto unlock;
789eac1ea20SChristian Eggers 
790eac1ea20SChristian Eggers 	ret = ksz_write32(dev, REG_PTP_RTC_SEC, abs(sec));
791eac1ea20SChristian Eggers 	if (ret)
792eac1ea20SChristian Eggers 		goto unlock;
793eac1ea20SChristian Eggers 
794eac1ea20SChristian Eggers 	ret = ksz_read16(dev, REG_PTP_CLK_CTRL, &data16);
795eac1ea20SChristian Eggers 	if (ret)
796eac1ea20SChristian Eggers 		goto unlock;
797eac1ea20SChristian Eggers 
798eac1ea20SChristian Eggers 	data16 |= PTP_STEP_ADJ;
799eac1ea20SChristian Eggers 
800eac1ea20SChristian Eggers 	/* PTP_STEP_DIR -- 0: subtract, 1: add */
801eac1ea20SChristian Eggers 	if (delta < 0)
802eac1ea20SChristian Eggers 		data16 &= ~PTP_STEP_DIR;
803eac1ea20SChristian Eggers 	else
804eac1ea20SChristian Eggers 		data16 |= PTP_STEP_DIR;
805eac1ea20SChristian Eggers 
806eac1ea20SChristian Eggers 	ret = ksz_write16(dev, REG_PTP_CLK_CTRL, data16);
807bb01ad30SChristian Eggers 	if (ret)
808bb01ad30SChristian Eggers 		goto unlock;
809bb01ad30SChristian Eggers 
8101f12ae5bSChristian Eggers 	switch (ptp_data->tou_mode) {
8111f12ae5bSChristian Eggers 	case KSZ_PTP_TOU_IDLE:
8121f12ae5bSChristian Eggers 		break;
8131f12ae5bSChristian Eggers 
8141f12ae5bSChristian Eggers 	case KSZ_PTP_TOU_PEROUT:
8151f12ae5bSChristian Eggers 		ret = ksz_ptp_restart_perout(dev);
8161f12ae5bSChristian Eggers 		if (ret)
8171f12ae5bSChristian Eggers 			goto unlock;
8181f12ae5bSChristian Eggers 
8191f12ae5bSChristian Eggers 		break;
8201f12ae5bSChristian Eggers 	}
8211f12ae5bSChristian Eggers 
822bb01ad30SChristian Eggers 	spin_lock_bh(&ptp_data->clock_lock);
823bb01ad30SChristian Eggers 	ptp_data->clock_time = timespec64_add(ptp_data->clock_time, delta64);
824bb01ad30SChristian Eggers 	spin_unlock_bh(&ptp_data->clock_lock);
825eac1ea20SChristian Eggers 
826eac1ea20SChristian Eggers unlock:
827eac1ea20SChristian Eggers 	mutex_unlock(&ptp_data->lock);
828eac1ea20SChristian Eggers 	return ret;
829eac1ea20SChristian Eggers }
830eac1ea20SChristian Eggers 
ksz_ptp_enable(struct ptp_clock_info * ptp,struct ptp_clock_request * req,int on)8311f12ae5bSChristian Eggers static int ksz_ptp_enable(struct ptp_clock_info *ptp,
8321f12ae5bSChristian Eggers 			  struct ptp_clock_request *req, int on)
8331f12ae5bSChristian Eggers {
8341f12ae5bSChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
8351f12ae5bSChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
8361f12ae5bSChristian Eggers 	int ret;
8371f12ae5bSChristian Eggers 
8381f12ae5bSChristian Eggers 	switch (req->type) {
8391f12ae5bSChristian Eggers 	case PTP_CLK_REQ_PEROUT:
8401f12ae5bSChristian Eggers 		mutex_lock(&ptp_data->lock);
8411f12ae5bSChristian Eggers 		ret = ksz_ptp_enable_perout(dev, &req->perout, on);
8421f12ae5bSChristian Eggers 		mutex_unlock(&ptp_data->lock);
8431f12ae5bSChristian Eggers 		break;
8441f12ae5bSChristian Eggers 	default:
8451f12ae5bSChristian Eggers 		return -EOPNOTSUPP;
8461f12ae5bSChristian Eggers 	}
8471f12ae5bSChristian Eggers 
8481f12ae5bSChristian Eggers 	return ret;
8491f12ae5bSChristian Eggers }
8501f12ae5bSChristian Eggers 
ksz_ptp_verify_pin(struct ptp_clock_info * ptp,unsigned int pin,enum ptp_pin_function func,unsigned int chan)851343d3bd8SArun Ramadoss static int ksz_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
852343d3bd8SArun Ramadoss 			      enum ptp_pin_function func, unsigned int chan)
853343d3bd8SArun Ramadoss {
854343d3bd8SArun Ramadoss 	int ret = 0;
855343d3bd8SArun Ramadoss 
856343d3bd8SArun Ramadoss 	switch (func) {
857343d3bd8SArun Ramadoss 	case PTP_PF_NONE:
858343d3bd8SArun Ramadoss 	case PTP_PF_PEROUT:
859343d3bd8SArun Ramadoss 		break;
860343d3bd8SArun Ramadoss 	default:
861343d3bd8SArun Ramadoss 		ret = -1;
862343d3bd8SArun Ramadoss 		break;
863343d3bd8SArun Ramadoss 	}
864343d3bd8SArun Ramadoss 
865343d3bd8SArun Ramadoss 	return ret;
866343d3bd8SArun Ramadoss }
867343d3bd8SArun Ramadoss 
868bb01ad30SChristian Eggers /*  Function is pointer to the do_aux_work in the ptp_clock capability */
ksz_ptp_do_aux_work(struct ptp_clock_info * ptp)869bb01ad30SChristian Eggers static long ksz_ptp_do_aux_work(struct ptp_clock_info *ptp)
870bb01ad30SChristian Eggers {
871bb01ad30SChristian Eggers 	struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
872bb01ad30SChristian Eggers 	struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
873bb01ad30SChristian Eggers 	struct timespec64 ts;
874bb01ad30SChristian Eggers 	int ret;
875bb01ad30SChristian Eggers 
876bb01ad30SChristian Eggers 	mutex_lock(&ptp_data->lock);
877bb01ad30SChristian Eggers 	ret = _ksz_ptp_gettime(dev, &ts);
878bb01ad30SChristian Eggers 	if (ret)
879bb01ad30SChristian Eggers 		goto out;
880bb01ad30SChristian Eggers 
881bb01ad30SChristian Eggers 	spin_lock_bh(&ptp_data->clock_lock);
882bb01ad30SChristian Eggers 	ptp_data->clock_time = ts;
883bb01ad30SChristian Eggers 	spin_unlock_bh(&ptp_data->clock_lock);
884bb01ad30SChristian Eggers 
885bb01ad30SChristian Eggers out:
886bb01ad30SChristian Eggers 	mutex_unlock(&ptp_data->lock);
887bb01ad30SChristian Eggers 
888bb01ad30SChristian Eggers 	return HZ;  /* reschedule in 1 second */
889bb01ad30SChristian Eggers }
890bb01ad30SChristian Eggers 
ksz_ptp_start_clock(struct ksz_device * dev)891eac1ea20SChristian Eggers static int ksz_ptp_start_clock(struct ksz_device *dev)
892eac1ea20SChristian Eggers {
893bb01ad30SChristian Eggers 	struct ksz_ptp_data *ptp_data = &dev->ptp_data;
894bb01ad30SChristian Eggers 	int ret;
895bb01ad30SChristian Eggers 
896bb01ad30SChristian Eggers 	ret = ksz_rmw16(dev, REG_PTP_CLK_CTRL, PTP_CLK_ENABLE, PTP_CLK_ENABLE);
897bb01ad30SChristian Eggers 	if (ret)
898bb01ad30SChristian Eggers 		return ret;
899bb01ad30SChristian Eggers 
900bb01ad30SChristian Eggers 	ptp_data->clock_time.tv_sec = 0;
901bb01ad30SChristian Eggers 	ptp_data->clock_time.tv_nsec = 0;
902bb01ad30SChristian Eggers 
903bb01ad30SChristian Eggers 	return 0;
904eac1ea20SChristian Eggers }
905eac1ea20SChristian Eggers 
ksz_ptp_clock_register(struct dsa_switch * ds)906eac1ea20SChristian Eggers int ksz_ptp_clock_register(struct dsa_switch *ds)
907eac1ea20SChristian Eggers {
908eac1ea20SChristian Eggers 	struct ksz_device *dev = ds->priv;
909eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data;
910eac1ea20SChristian Eggers 	int ret;
911343d3bd8SArun Ramadoss 	u8 i;
912eac1ea20SChristian Eggers 
913eac1ea20SChristian Eggers 	ptp_data = &dev->ptp_data;
914eac1ea20SChristian Eggers 	mutex_init(&ptp_data->lock);
915bb01ad30SChristian Eggers 	spin_lock_init(&ptp_data->clock_lock);
916eac1ea20SChristian Eggers 
917eac1ea20SChristian Eggers 	ptp_data->caps.owner		= THIS_MODULE;
918eac1ea20SChristian Eggers 	snprintf(ptp_data->caps.name, 16, "Microchip Clock");
919eac1ea20SChristian Eggers 	ptp_data->caps.max_adj		= KSZ_MAX_DRIFT_CORR;
920eac1ea20SChristian Eggers 	ptp_data->caps.gettime64	= ksz_ptp_gettime;
921eac1ea20SChristian Eggers 	ptp_data->caps.settime64	= ksz_ptp_settime;
922eac1ea20SChristian Eggers 	ptp_data->caps.adjfine		= ksz_ptp_adjfine;
923eac1ea20SChristian Eggers 	ptp_data->caps.adjtime		= ksz_ptp_adjtime;
924bb01ad30SChristian Eggers 	ptp_data->caps.do_aux_work	= ksz_ptp_do_aux_work;
9251f12ae5bSChristian Eggers 	ptp_data->caps.enable		= ksz_ptp_enable;
926343d3bd8SArun Ramadoss 	ptp_data->caps.verify		= ksz_ptp_verify_pin;
927343d3bd8SArun Ramadoss 	ptp_data->caps.n_pins		= KSZ_PTP_N_GPIO;
9281f12ae5bSChristian Eggers 	ptp_data->caps.n_per_out	= 3;
929eac1ea20SChristian Eggers 
930eac1ea20SChristian Eggers 	ret = ksz_ptp_start_clock(dev);
931eac1ea20SChristian Eggers 	if (ret)
932eac1ea20SChristian Eggers 		return ret;
933eac1ea20SChristian Eggers 
934343d3bd8SArun Ramadoss 	for (i = 0; i < KSZ_PTP_N_GPIO; i++) {
935343d3bd8SArun Ramadoss 		struct ptp_pin_desc *ptp_pin = &ptp_data->pin_config[i];
936343d3bd8SArun Ramadoss 
937343d3bd8SArun Ramadoss 		snprintf(ptp_pin->name,
938343d3bd8SArun Ramadoss 			 sizeof(ptp_pin->name), "ksz_ptp_pin_%02d", i);
939343d3bd8SArun Ramadoss 		ptp_pin->index = i;
940343d3bd8SArun Ramadoss 		ptp_pin->func = PTP_PF_NONE;
941343d3bd8SArun Ramadoss 	}
942343d3bd8SArun Ramadoss 
943343d3bd8SArun Ramadoss 	ptp_data->caps.pin_config = ptp_data->pin_config;
944343d3bd8SArun Ramadoss 
945eac1ea20SChristian Eggers 	/* Currently only P2P mode is supported. When 802_1AS bit is set, it
946eac1ea20SChristian Eggers 	 * forwards all PTP packets to host port and none to other ports.
947eac1ea20SChristian Eggers 	 */
948eac1ea20SChristian Eggers 	ret = ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_TC_P2P | PTP_802_1AS,
949eac1ea20SChristian Eggers 			PTP_TC_P2P | PTP_802_1AS);
950eac1ea20SChristian Eggers 	if (ret)
951eac1ea20SChristian Eggers 		return ret;
952eac1ea20SChristian Eggers 
953eac1ea20SChristian Eggers 	ptp_data->clock = ptp_clock_register(&ptp_data->caps, dev->dev);
954eac1ea20SChristian Eggers 	if (IS_ERR_OR_NULL(ptp_data->clock))
955eac1ea20SChristian Eggers 		return PTR_ERR(ptp_data->clock);
956eac1ea20SChristian Eggers 
957eac1ea20SChristian Eggers 	return 0;
958eac1ea20SChristian Eggers }
959eac1ea20SChristian Eggers 
ksz_ptp_clock_unregister(struct dsa_switch * ds)960eac1ea20SChristian Eggers void ksz_ptp_clock_unregister(struct dsa_switch *ds)
961eac1ea20SChristian Eggers {
962eac1ea20SChristian Eggers 	struct ksz_device *dev = ds->priv;
963eac1ea20SChristian Eggers 	struct ksz_ptp_data *ptp_data;
964eac1ea20SChristian Eggers 
965eac1ea20SChristian Eggers 	ptp_data = &dev->ptp_data;
966eac1ea20SChristian Eggers 
967eac1ea20SChristian Eggers 	if (ptp_data->clock)
968eac1ea20SChristian Eggers 		ptp_clock_unregister(ptp_data->clock);
969eac1ea20SChristian Eggers }
970eac1ea20SChristian Eggers 
ksz_ptp_msg_thread_fn(int irq,void * dev_id)971cc13ab18SArun Ramadoss static irqreturn_t ksz_ptp_msg_thread_fn(int irq, void *dev_id)
972cc13ab18SArun Ramadoss {
973ab32f56aSChristian Eggers 	struct ksz_ptp_irq *ptpmsg_irq = dev_id;
974ab32f56aSChristian Eggers 	struct ksz_device *dev;
975ab32f56aSChristian Eggers 	struct ksz_port *port;
976ab32f56aSChristian Eggers 	u32 tstamp_raw;
977ab32f56aSChristian Eggers 	ktime_t tstamp;
978ab32f56aSChristian Eggers 	int ret;
979ab32f56aSChristian Eggers 
980ab32f56aSChristian Eggers 	port = ptpmsg_irq->port;
981ab32f56aSChristian Eggers 	dev = port->ksz_dev;
982ab32f56aSChristian Eggers 
983ab32f56aSChristian Eggers 	if (ptpmsg_irq->ts_en) {
984ab32f56aSChristian Eggers 		ret = ksz_read32(dev, ptpmsg_irq->ts_reg, &tstamp_raw);
985ab32f56aSChristian Eggers 		if (ret)
986cc13ab18SArun Ramadoss 			return IRQ_NONE;
987ab32f56aSChristian Eggers 
988ab32f56aSChristian Eggers 		tstamp = ksz_decode_tstamp(tstamp_raw);
989ab32f56aSChristian Eggers 
990ab32f56aSChristian Eggers 		port->tstamp_msg = ksz_tstamp_reconstruct(dev, tstamp);
991ab32f56aSChristian Eggers 
992ab32f56aSChristian Eggers 		complete(&port->tstamp_msg_comp);
993ab32f56aSChristian Eggers 	}
994ab32f56aSChristian Eggers 
995ab32f56aSChristian Eggers 	return IRQ_HANDLED;
996cc13ab18SArun Ramadoss }
997cc13ab18SArun Ramadoss 
ksz_ptp_irq_thread_fn(int irq,void * dev_id)998cc13ab18SArun Ramadoss static irqreturn_t ksz_ptp_irq_thread_fn(int irq, void *dev_id)
999cc13ab18SArun Ramadoss {
1000cc13ab18SArun Ramadoss 	struct ksz_irq *ptpirq = dev_id;
1001cc13ab18SArun Ramadoss 	unsigned int nhandled = 0;
1002cc13ab18SArun Ramadoss 	struct ksz_device *dev;
1003cc13ab18SArun Ramadoss 	unsigned int sub_irq;
1004cc13ab18SArun Ramadoss 	u16 data;
1005cc13ab18SArun Ramadoss 	int ret;
1006cc13ab18SArun Ramadoss 	u8 n;
1007cc13ab18SArun Ramadoss 
1008cc13ab18SArun Ramadoss 	dev = ptpirq->dev;
1009cc13ab18SArun Ramadoss 
1010cc13ab18SArun Ramadoss 	ret = ksz_read16(dev, ptpirq->reg_status, &data);
1011cc13ab18SArun Ramadoss 	if (ret)
1012cc13ab18SArun Ramadoss 		goto out;
1013cc13ab18SArun Ramadoss 
1014cc13ab18SArun Ramadoss 	/* Clear the interrupts W1C */
1015cc13ab18SArun Ramadoss 	ret = ksz_write16(dev, ptpirq->reg_status, data);
1016cc13ab18SArun Ramadoss 	if (ret)
1017cc13ab18SArun Ramadoss 		return IRQ_NONE;
1018cc13ab18SArun Ramadoss 
1019cc13ab18SArun Ramadoss 	for (n = 0; n < ptpirq->nirqs; ++n) {
1020cc13ab18SArun Ramadoss 		if (data & BIT(n + KSZ_PTP_INT_START)) {
1021cc13ab18SArun Ramadoss 			sub_irq = irq_find_mapping(ptpirq->domain, n);
1022cc13ab18SArun Ramadoss 			handle_nested_irq(sub_irq);
1023cc13ab18SArun Ramadoss 			++nhandled;
1024cc13ab18SArun Ramadoss 		}
1025cc13ab18SArun Ramadoss 	}
1026cc13ab18SArun Ramadoss 
1027cc13ab18SArun Ramadoss out:
1028cc13ab18SArun Ramadoss 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
1029cc13ab18SArun Ramadoss }
1030cc13ab18SArun Ramadoss 
ksz_ptp_irq_mask(struct irq_data * d)1031cc13ab18SArun Ramadoss static void ksz_ptp_irq_mask(struct irq_data *d)
1032cc13ab18SArun Ramadoss {
1033cc13ab18SArun Ramadoss 	struct ksz_irq *kirq = irq_data_get_irq_chip_data(d);
1034cc13ab18SArun Ramadoss 
1035cc13ab18SArun Ramadoss 	kirq->masked &= ~BIT(d->hwirq + KSZ_PTP_INT_START);
1036cc13ab18SArun Ramadoss }
1037cc13ab18SArun Ramadoss 
ksz_ptp_irq_unmask(struct irq_data * d)1038cc13ab18SArun Ramadoss static void ksz_ptp_irq_unmask(struct irq_data *d)
1039cc13ab18SArun Ramadoss {
1040cc13ab18SArun Ramadoss 	struct ksz_irq *kirq = irq_data_get_irq_chip_data(d);
1041cc13ab18SArun Ramadoss 
1042cc13ab18SArun Ramadoss 	kirq->masked |= BIT(d->hwirq + KSZ_PTP_INT_START);
1043cc13ab18SArun Ramadoss }
1044cc13ab18SArun Ramadoss 
ksz_ptp_irq_bus_lock(struct irq_data * d)1045cc13ab18SArun Ramadoss static void ksz_ptp_irq_bus_lock(struct irq_data *d)
1046cc13ab18SArun Ramadoss {
1047cc13ab18SArun Ramadoss 	struct ksz_irq *kirq  = irq_data_get_irq_chip_data(d);
1048cc13ab18SArun Ramadoss 
1049cc13ab18SArun Ramadoss 	mutex_lock(&kirq->dev->lock_irq);
1050cc13ab18SArun Ramadoss }
1051cc13ab18SArun Ramadoss 
ksz_ptp_irq_bus_sync_unlock(struct irq_data * d)1052cc13ab18SArun Ramadoss static void ksz_ptp_irq_bus_sync_unlock(struct irq_data *d)
1053cc13ab18SArun Ramadoss {
1054cc13ab18SArun Ramadoss 	struct ksz_irq *kirq  = irq_data_get_irq_chip_data(d);
1055cc13ab18SArun Ramadoss 	struct ksz_device *dev = kirq->dev;
1056cc13ab18SArun Ramadoss 	int ret;
1057cc13ab18SArun Ramadoss 
1058cc13ab18SArun Ramadoss 	ret = ksz_write16(dev, kirq->reg_mask, kirq->masked);
1059cc13ab18SArun Ramadoss 	if (ret)
1060cc13ab18SArun Ramadoss 		dev_err(dev->dev, "failed to change IRQ mask\n");
1061cc13ab18SArun Ramadoss 
1062cc13ab18SArun Ramadoss 	mutex_unlock(&dev->lock_irq);
1063cc13ab18SArun Ramadoss }
1064cc13ab18SArun Ramadoss 
1065cc13ab18SArun Ramadoss static const struct irq_chip ksz_ptp_irq_chip = {
1066cc13ab18SArun Ramadoss 	.name			= "ksz-irq",
1067cc13ab18SArun Ramadoss 	.irq_mask		= ksz_ptp_irq_mask,
1068cc13ab18SArun Ramadoss 	.irq_unmask		= ksz_ptp_irq_unmask,
1069cc13ab18SArun Ramadoss 	.irq_bus_lock		= ksz_ptp_irq_bus_lock,
1070cc13ab18SArun Ramadoss 	.irq_bus_sync_unlock	= ksz_ptp_irq_bus_sync_unlock,
1071cc13ab18SArun Ramadoss };
1072cc13ab18SArun Ramadoss 
ksz_ptp_irq_domain_map(struct irq_domain * d,unsigned int irq,irq_hw_number_t hwirq)1073cc13ab18SArun Ramadoss static int ksz_ptp_irq_domain_map(struct irq_domain *d,
1074cc13ab18SArun Ramadoss 				  unsigned int irq, irq_hw_number_t hwirq)
1075cc13ab18SArun Ramadoss {
1076cc13ab18SArun Ramadoss 	irq_set_chip_data(irq, d->host_data);
1077cc13ab18SArun Ramadoss 	irq_set_chip_and_handler(irq, &ksz_ptp_irq_chip, handle_level_irq);
1078cc13ab18SArun Ramadoss 	irq_set_noprobe(irq);
1079cc13ab18SArun Ramadoss 
1080cc13ab18SArun Ramadoss 	return 0;
1081cc13ab18SArun Ramadoss }
1082cc13ab18SArun Ramadoss 
1083cc13ab18SArun Ramadoss static const struct irq_domain_ops ksz_ptp_irq_domain_ops = {
1084cc13ab18SArun Ramadoss 	.map	= ksz_ptp_irq_domain_map,
1085cc13ab18SArun Ramadoss 	.xlate	= irq_domain_xlate_twocell,
1086cc13ab18SArun Ramadoss };
1087cc13ab18SArun Ramadoss 
ksz_ptp_msg_irq_free(struct ksz_port * port,u8 n)1088cc13ab18SArun Ramadoss static void ksz_ptp_msg_irq_free(struct ksz_port *port, u8 n)
1089cc13ab18SArun Ramadoss {
1090cc13ab18SArun Ramadoss 	struct ksz_ptp_irq *ptpmsg_irq;
1091cc13ab18SArun Ramadoss 
1092cc13ab18SArun Ramadoss 	ptpmsg_irq = &port->ptpmsg_irq[n];
1093cc13ab18SArun Ramadoss 
1094cc13ab18SArun Ramadoss 	free_irq(ptpmsg_irq->num, ptpmsg_irq);
1095cc13ab18SArun Ramadoss 	irq_dispose_mapping(ptpmsg_irq->num);
1096cc13ab18SArun Ramadoss }
1097cc13ab18SArun Ramadoss 
ksz_ptp_msg_irq_setup(struct ksz_port * port,u8 n)1098cc13ab18SArun Ramadoss static int ksz_ptp_msg_irq_setup(struct ksz_port *port, u8 n)
1099cc13ab18SArun Ramadoss {
1100cc13ab18SArun Ramadoss 	u16 ts_reg[] = {REG_PTP_PORT_PDRESP_TS, REG_PTP_PORT_XDELAY_TS,
1101cc13ab18SArun Ramadoss 			REG_PTP_PORT_SYNC_TS};
1102cc13ab18SArun Ramadoss 	static const char * const name[] = {"pdresp-msg", "xdreq-msg",
1103cc13ab18SArun Ramadoss 					    "sync-msg"};
1104cc13ab18SArun Ramadoss 	const struct ksz_dev_ops *ops = port->ksz_dev->dev_ops;
1105cc13ab18SArun Ramadoss 	struct ksz_ptp_irq *ptpmsg_irq;
1106cc13ab18SArun Ramadoss 
1107cc13ab18SArun Ramadoss 	ptpmsg_irq = &port->ptpmsg_irq[n];
1108cc13ab18SArun Ramadoss 
1109cc13ab18SArun Ramadoss 	ptpmsg_irq->port = port;
1110cc13ab18SArun Ramadoss 	ptpmsg_irq->ts_reg = ops->get_port_addr(port->num, ts_reg[n]);
1111cc13ab18SArun Ramadoss 
1112cc13ab18SArun Ramadoss 	snprintf(ptpmsg_irq->name, sizeof(ptpmsg_irq->name), name[n]);
1113cc13ab18SArun Ramadoss 
1114cc13ab18SArun Ramadoss 	ptpmsg_irq->num = irq_find_mapping(port->ptpirq.domain, n);
1115cc13ab18SArun Ramadoss 	if (ptpmsg_irq->num < 0)
1116cc13ab18SArun Ramadoss 		return ptpmsg_irq->num;
1117cc13ab18SArun Ramadoss 
1118cc13ab18SArun Ramadoss 	return request_threaded_irq(ptpmsg_irq->num, NULL,
1119cc13ab18SArun Ramadoss 				    ksz_ptp_msg_thread_fn, IRQF_ONESHOT,
1120cc13ab18SArun Ramadoss 				    ptpmsg_irq->name, ptpmsg_irq);
1121cc13ab18SArun Ramadoss }
1122cc13ab18SArun Ramadoss 
ksz_ptp_irq_setup(struct dsa_switch * ds,u8 p)1123cc13ab18SArun Ramadoss int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p)
1124cc13ab18SArun Ramadoss {
1125cc13ab18SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1126cc13ab18SArun Ramadoss 	const struct ksz_dev_ops *ops = dev->dev_ops;
1127cc13ab18SArun Ramadoss 	struct ksz_port *port = &dev->ports[p];
1128cc13ab18SArun Ramadoss 	struct ksz_irq *ptpirq = &port->ptpirq;
1129cc13ab18SArun Ramadoss 	int irq;
1130cc13ab18SArun Ramadoss 	int ret;
1131cc13ab18SArun Ramadoss 
1132cc13ab18SArun Ramadoss 	ptpirq->dev = dev;
1133cc13ab18SArun Ramadoss 	ptpirq->masked = 0;
1134cc13ab18SArun Ramadoss 	ptpirq->nirqs = 3;
1135cc13ab18SArun Ramadoss 	ptpirq->reg_mask = ops->get_port_addr(p, REG_PTP_PORT_TX_INT_ENABLE__2);
1136cc13ab18SArun Ramadoss 	ptpirq->reg_status = ops->get_port_addr(p,
1137cc13ab18SArun Ramadoss 						REG_PTP_PORT_TX_INT_STATUS__2);
1138cc13ab18SArun Ramadoss 	snprintf(ptpirq->name, sizeof(ptpirq->name), "ptp-irq-%d", p);
1139cc13ab18SArun Ramadoss 
1140ab32f56aSChristian Eggers 	init_completion(&port->tstamp_msg_comp);
1141ab32f56aSChristian Eggers 
1142cc13ab18SArun Ramadoss 	ptpirq->domain = irq_domain_add_linear(dev->dev->of_node, ptpirq->nirqs,
1143cc13ab18SArun Ramadoss 					       &ksz_ptp_irq_domain_ops, ptpirq);
1144cc13ab18SArun Ramadoss 	if (!ptpirq->domain)
1145cc13ab18SArun Ramadoss 		return -ENOMEM;
1146cc13ab18SArun Ramadoss 
1147cc13ab18SArun Ramadoss 	for (irq = 0; irq < ptpirq->nirqs; irq++)
1148cc13ab18SArun Ramadoss 		irq_create_mapping(ptpirq->domain, irq);
1149cc13ab18SArun Ramadoss 
1150cc13ab18SArun Ramadoss 	ptpirq->irq_num = irq_find_mapping(port->pirq.domain, PORT_SRC_PTP_INT);
1151cc13ab18SArun Ramadoss 	if (ptpirq->irq_num < 0) {
1152cc13ab18SArun Ramadoss 		ret = ptpirq->irq_num;
1153cc13ab18SArun Ramadoss 		goto out;
1154cc13ab18SArun Ramadoss 	}
1155cc13ab18SArun Ramadoss 
1156cc13ab18SArun Ramadoss 	ret = request_threaded_irq(ptpirq->irq_num, NULL, ksz_ptp_irq_thread_fn,
1157cc13ab18SArun Ramadoss 				   IRQF_ONESHOT, ptpirq->name, ptpirq);
1158cc13ab18SArun Ramadoss 	if (ret)
1159cc13ab18SArun Ramadoss 		goto out;
1160cc13ab18SArun Ramadoss 
1161cc13ab18SArun Ramadoss 	for (irq = 0; irq < ptpirq->nirqs; irq++) {
1162cc13ab18SArun Ramadoss 		ret = ksz_ptp_msg_irq_setup(port, irq);
1163cc13ab18SArun Ramadoss 		if (ret)
1164cc13ab18SArun Ramadoss 			goto out_ptp_msg;
1165cc13ab18SArun Ramadoss 	}
1166cc13ab18SArun Ramadoss 
1167cc13ab18SArun Ramadoss 	return 0;
1168cc13ab18SArun Ramadoss 
1169cc13ab18SArun Ramadoss out_ptp_msg:
1170cc13ab18SArun Ramadoss 	free_irq(ptpirq->irq_num, ptpirq);
1171cc13ab18SArun Ramadoss 	while (irq--)
1172cc13ab18SArun Ramadoss 		free_irq(port->ptpmsg_irq[irq].num, &port->ptpmsg_irq[irq]);
1173cc13ab18SArun Ramadoss out:
1174cc13ab18SArun Ramadoss 	for (irq = 0; irq < ptpirq->nirqs; irq++)
1175cc13ab18SArun Ramadoss 		irq_dispose_mapping(port->ptpmsg_irq[irq].num);
1176cc13ab18SArun Ramadoss 
1177cc13ab18SArun Ramadoss 	irq_domain_remove(ptpirq->domain);
1178cc13ab18SArun Ramadoss 
1179cc13ab18SArun Ramadoss 	return ret;
1180cc13ab18SArun Ramadoss }
1181cc13ab18SArun Ramadoss 
ksz_ptp_irq_free(struct dsa_switch * ds,u8 p)1182cc13ab18SArun Ramadoss void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p)
1183cc13ab18SArun Ramadoss {
1184cc13ab18SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1185cc13ab18SArun Ramadoss 	struct ksz_port *port = &dev->ports[p];
1186cc13ab18SArun Ramadoss 	struct ksz_irq *ptpirq = &port->ptpirq;
1187cc13ab18SArun Ramadoss 	u8 n;
1188cc13ab18SArun Ramadoss 
1189cc13ab18SArun Ramadoss 	for (n = 0; n < ptpirq->nirqs; n++)
1190cc13ab18SArun Ramadoss 		ksz_ptp_msg_irq_free(port, n);
1191cc13ab18SArun Ramadoss 
1192cc13ab18SArun Ramadoss 	free_irq(ptpirq->irq_num, ptpirq);
1193cc13ab18SArun Ramadoss 	irq_dispose_mapping(ptpirq->irq_num);
1194cc13ab18SArun Ramadoss 
1195cc13ab18SArun Ramadoss 	irq_domain_remove(ptpirq->domain);
1196cc13ab18SArun Ramadoss }
1197cc13ab18SArun Ramadoss 
1198eac1ea20SChristian Eggers MODULE_AUTHOR("Christian Eggers <ceggers@arri.de>");
1199eac1ea20SChristian Eggers MODULE_AUTHOR("Arun Ramadoss <arun.ramadoss@microchip.com>");
1200eac1ea20SChristian Eggers MODULE_DESCRIPTION("PTP support for KSZ switch");
1201eac1ea20SChristian Eggers MODULE_LICENSE("GPL");
1202