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