From 2b49d128b3f8d8fff8972afcbc603802e5e40c6a Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 20 Apr 2020 10:46:45 +0800 Subject: net: mscc: ocelot: move ocelot ptp clock code out of ocelot.c The Ocelot PTP clock driver had been embedded into ocelot.c driver. It had supported basic gettime64/settime64/adjtime/adjfine functions by now which were used by both Ocelot switch and Felix switch. This patch is to move current ptp clock code out of ocelot.c driver maintaining as a single ocelot_ptp.c. For futher new features implementation, the common code could be put in ocelot_ptp.c and the switch specific code should be in specific switch driver. The interrupt implementation in SoC is different between Ocelot and Felix. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 25 ++++ drivers/net/ethernet/mscc/Makefile | 2 +- drivers/net/ethernet/mscc/ocelot.c | 206 ------------------------------- drivers/net/ethernet/mscc/ocelot.h | 3 +- drivers/net/ethernet/mscc/ocelot_board.c | 25 ++++ drivers/net/ethernet/mscc/ocelot_ptp.c | 203 ++++++++++++++++++++++++++++++ drivers/net/ethernet/mscc/ocelot_ptp.h | 41 ------ include/soc/mscc/ocelot.h | 1 - include/soc/mscc/ocelot_ptp.h | 52 ++++++++ 9 files changed, 307 insertions(+), 251 deletions(-) create mode 100644 drivers/net/ethernet/mscc/ocelot_ptp.c delete mode 100644 drivers/net/ethernet/mscc/ocelot_ptp.h create mode 100644 include/soc/mscc/ocelot_ptp.h diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index d0a3764ff0cf..44015a24b087 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -494,6 +495,21 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) return 0; } +static struct ptp_clock_info ocelot_ptp_clock_info = { + .owner = THIS_MODULE, + .name = "felix ptp", + .max_adj = 0x7fffffff, + .n_alarm = 0, + .n_ext_ts = 0, + .n_per_out = 0, + .n_pins = 0, + .pps = 0, + .gettime64 = ocelot_ptp_gettime64, + .settime64 = ocelot_ptp_settime64, + .adjtime = ocelot_ptp_adjtime, + .adjfine = ocelot_ptp_adjfine, +}; + /* Hardware initialization done here so that we can allocate structures with * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing * us to allocate structures twice (leak memory) and map PCI memory twice @@ -510,6 +526,14 @@ static int felix_setup(struct dsa_switch *ds) return err; ocelot_init(ocelot); + if (ocelot->ptp) { + err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info); + if (err) { + dev_err(ocelot->dev, + "Timestamp initialization failed\n"); + ocelot->ptp = 0; + } + } for (port = 0; port < ds->num_ports; port++) { ocelot_init_port(ocelot, port); @@ -548,6 +572,7 @@ static void felix_teardown(struct dsa_switch *ds) if (felix->info->mdio_bus_free) felix->info->mdio_bus_free(ocelot); + ocelot_deinit_timestamp(ocelot); /* stop workqueue thread */ ocelot_deinit(ocelot); } diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile index 9a36c26095c8..91b33b55054e 100644 --- a/drivers/net/ethernet/mscc/Makefile +++ b/drivers/net/ethernet/mscc/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: (GPL-2.0 OR MIT) obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o mscc_ocelot_common-y := ocelot.o ocelot_io.o -mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o ocelot_ace.o ocelot_flower.o +mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o ocelot_ace.o ocelot_flower.o ocelot_ptp.o obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index a8c48a4a708f..7c4165af9f66 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -1991,200 +1990,6 @@ struct notifier_block ocelot_switchdev_blocking_nb __read_mostly = { }; EXPORT_SYMBOL(ocelot_switchdev_blocking_nb); -int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts) -{ - struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); - unsigned long flags; - time64_t s; - u32 val; - s64 ns; - - spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); - - val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); - val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); - val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_SAVE); - ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); - - s = ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN) & 0xffff; - s <<= 32; - s += ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN); - ns = ocelot_read_rix(ocelot, PTP_PIN_TOD_NSEC, TOD_ACC_PIN); - - spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); - - /* Deal with negative values */ - if (ns >= 0x3ffffff0 && ns <= 0x3fffffff) { - s--; - ns &= 0xf; - ns += 999999984; - } - - set_normalized_timespec64(ts, s, ns); - return 0; -} -EXPORT_SYMBOL(ocelot_ptp_gettime64); - -static int ocelot_ptp_settime64(struct ptp_clock_info *ptp, - const struct timespec64 *ts) -{ - struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); - unsigned long flags; - u32 val; - - spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); - - val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); - val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); - val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE); - - ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); - - ocelot_write_rix(ocelot, lower_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_LSB, - TOD_ACC_PIN); - ocelot_write_rix(ocelot, upper_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_MSB, - TOD_ACC_PIN); - ocelot_write_rix(ocelot, ts->tv_nsec, PTP_PIN_TOD_NSEC, TOD_ACC_PIN); - - val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); - val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); - val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_LOAD); - - ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); - - spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); - return 0; -} - -static int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) -{ - if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) { - struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); - unsigned long flags; - u32 val; - - spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); - - val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); - val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); - val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE); - - ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); - - ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN); - ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN); - ocelot_write_rix(ocelot, delta, PTP_PIN_TOD_NSEC, TOD_ACC_PIN); - - val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); - val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); - val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_DELTA); - - ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); - - spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); - } else { - /* Fall back using ocelot_ptp_settime64 which is not exact. */ - struct timespec64 ts; - u64 now; - - ocelot_ptp_gettime64(ptp, &ts); - - now = ktime_to_ns(timespec64_to_ktime(ts)); - ts = ns_to_timespec64(now + delta); - - ocelot_ptp_settime64(ptp, &ts); - } - return 0; -} - -static int ocelot_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) -{ - struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); - u32 unit = 0, direction = 0; - unsigned long flags; - u64 adj = 0; - - spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); - - if (!scaled_ppm) - goto disable_adj; - - if (scaled_ppm < 0) { - direction = PTP_CFG_CLK_ADJ_CFG_DIR; - scaled_ppm = -scaled_ppm; - } - - adj = PSEC_PER_SEC << 16; - do_div(adj, scaled_ppm); - do_div(adj, 1000); - - /* If the adjustment value is too large, use ns instead */ - if (adj >= (1L << 30)) { - unit = PTP_CFG_CLK_ADJ_FREQ_NS; - do_div(adj, 1000); - } - - /* Still too big */ - if (adj >= (1L << 30)) - goto disable_adj; - - ocelot_write(ocelot, unit | adj, PTP_CLK_CFG_ADJ_FREQ); - ocelot_write(ocelot, PTP_CFG_CLK_ADJ_CFG_ENA | direction, - PTP_CLK_CFG_ADJ_CFG); - - spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); - return 0; - -disable_adj: - ocelot_write(ocelot, 0, PTP_CLK_CFG_ADJ_CFG); - - spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); - return 0; -} - -static struct ptp_clock_info ocelot_ptp_clock_info = { - .owner = THIS_MODULE, - .name = "ocelot ptp", - .max_adj = 0x7fffffff, - .n_alarm = 0, - .n_ext_ts = 0, - .n_per_out = 0, - .n_pins = 0, - .pps = 0, - .gettime64 = ocelot_ptp_gettime64, - .settime64 = ocelot_ptp_settime64, - .adjtime = ocelot_ptp_adjtime, - .adjfine = ocelot_ptp_adjfine, -}; - -static int ocelot_init_timestamp(struct ocelot *ocelot) -{ - struct ptp_clock *ptp_clock; - - ocelot->ptp_info = ocelot_ptp_clock_info; - ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev); - if (IS_ERR(ptp_clock)) - return PTR_ERR(ptp_clock); - /* Check if PHC support is missing at the configuration level */ - if (!ptp_clock) - return 0; - - ocelot->ptp_clock = ptp_clock; - - ocelot_write(ocelot, SYS_PTP_CFG_PTP_STAMP_WID(30), SYS_PTP_CFG); - ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_LOW); - ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_HIGH); - - ocelot_write(ocelot, PTP_CFG_MISC_PTP_EN, PTP_CFG_MISC); - - /* There is no device reconfiguration, PTP Rx stamping is always - * enabled. - */ - ocelot->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; - - return 0; -} - /* Configure the maximum SDU (L2 payload) on RX to the value specified in @sdu. * The length of VLAN tags is accounted for automatically via DEV_MAC_TAGS_CFG. * In the special case that it's the NPI port that we're configuring, the @@ -2530,15 +2335,6 @@ int ocelot_init(struct ocelot *ocelot) queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work, OCELOT_STATS_CHECK_DELAY); - if (ocelot->ptp) { - ret = ocelot_init_timestamp(ocelot); - if (ret) { - dev_err(ocelot->dev, - "Timestamp initialization failed\n"); - return ret; - } - } - return 0; } EXPORT_SYMBOL(ocelot_init); @@ -2551,8 +2347,6 @@ void ocelot_deinit(struct ocelot *ocelot) cancel_delayed_work(&ocelot->stats_work); destroy_workqueue(ocelot->stats_queue); mutex_destroy(&ocelot->stats_lock); - if (ocelot->ptp_clock) - ptp_clock_unregister(ocelot->ptp_clock); for (i = 0; i < ocelot->num_phys_ports; i++) { port = ocelot->ports[i]; diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 641af929497f..f0a15aa187f2 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -15,18 +15,17 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include "ocelot_rew.h" #include "ocelot_qs.h" #include "ocelot_tc.h" -#include "ocelot_ptp.h" #define OCELOT_BUFFER_CELL_SZ 60 diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 0ac9fbf77a01..ee016f7ed934 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -366,6 +366,21 @@ static const struct vcap_props vsc7514_vcap_props[] = { }, }; +static struct ptp_clock_info ocelot_ptp_clock_info = { + .owner = THIS_MODULE, + .name = "ocelot ptp", + .max_adj = 0x7fffffff, + .n_alarm = 0, + .n_ext_ts = 0, + .n_per_out = 0, + .n_pins = 0, + .pps = 0, + .gettime64 = ocelot_ptp_gettime64, + .settime64 = ocelot_ptp_settime64, + .adjtime = ocelot_ptp_adjtime, + .adjfine = ocelot_ptp_adjfine, +}; + static int mscc_ocelot_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -469,6 +484,15 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ocelot->vcap = vsc7514_vcap_props; ocelot_init(ocelot); + if (ocelot->ptp) { + err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info); + if (err) { + dev_err(ocelot->dev, + "Timestamp initialization failed\n"); + ocelot->ptp = 0; + } + } + /* No NPI port */ ocelot_configure_cpu(ocelot, -1, OCELOT_TAG_PREFIX_NONE, OCELOT_TAG_PREFIX_NONE); @@ -574,6 +598,7 @@ static int mscc_ocelot_remove(struct platform_device *pdev) { struct ocelot *ocelot = platform_get_drvdata(pdev); + ocelot_deinit_timestamp(ocelot); ocelot_deinit(ocelot); unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb); unregister_switchdev_notifier(&ocelot_switchdev_nb); diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.c b/drivers/net/ethernet/mscc/ocelot_ptp.c new file mode 100644 index 000000000000..69d4e5677343 --- /dev/null +++ b/drivers/net/ethernet/mscc/ocelot_ptp.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* Microsemi Ocelot PTP clock driver + * + * Copyright (c) 2017 Microsemi Corporation + * Copyright 2020 NXP + */ +#include +#include +#include + +int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); + unsigned long flags; + time64_t s; + u32 val; + s64 ns; + + spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); + + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_SAVE); + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); + + s = ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN) & 0xffff; + s <<= 32; + s += ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN); + ns = ocelot_read_rix(ocelot, PTP_PIN_TOD_NSEC, TOD_ACC_PIN); + + spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + + /* Deal with negative values */ + if (ns >= 0x3ffffff0 && ns <= 0x3fffffff) { + s--; + ns &= 0xf; + ns += 999999984; + } + + set_normalized_timespec64(ts, s, ns); + return 0; +} +EXPORT_SYMBOL(ocelot_ptp_gettime64); + +int ocelot_ptp_settime64(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); + + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE); + + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); + + ocelot_write_rix(ocelot, lower_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_LSB, + TOD_ACC_PIN); + ocelot_write_rix(ocelot, upper_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_MSB, + TOD_ACC_PIN); + ocelot_write_rix(ocelot, ts->tv_nsec, PTP_PIN_TOD_NSEC, TOD_ACC_PIN); + + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_LOAD); + + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); + + spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + return 0; +} +EXPORT_SYMBOL(ocelot_ptp_settime64); + +int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) { + struct ocelot *ocelot = container_of(ptp, struct ocelot, + ptp_info); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); + + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | + PTP_PIN_CFG_DOM); + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE); + + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); + + ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN); + ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN); + ocelot_write_rix(ocelot, delta, PTP_PIN_TOD_NSEC, TOD_ACC_PIN); + + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | + PTP_PIN_CFG_DOM); + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_DELTA); + + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); + + spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + } else { + /* Fall back using ocelot_ptp_settime64 which is not exact. */ + struct timespec64 ts; + u64 now; + + ocelot_ptp_gettime64(ptp, &ts); + + now = ktime_to_ns(timespec64_to_ktime(ts)); + ts = ns_to_timespec64(now + delta); + + ocelot_ptp_settime64(ptp, &ts); + } + return 0; +} +EXPORT_SYMBOL(ocelot_ptp_adjtime); + +int ocelot_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); + u32 unit = 0, direction = 0; + unsigned long flags; + u64 adj = 0; + + spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); + + if (!scaled_ppm) + goto disable_adj; + + if (scaled_ppm < 0) { + direction = PTP_CFG_CLK_ADJ_CFG_DIR; + scaled_ppm = -scaled_ppm; + } + + adj = PSEC_PER_SEC << 16; + do_div(adj, scaled_ppm); + do_div(adj, 1000); + + /* If the adjustment value is too large, use ns instead */ + if (adj >= (1L << 30)) { + unit = PTP_CFG_CLK_ADJ_FREQ_NS; + do_div(adj, 1000); + } + + /* Still too big */ + if (adj >= (1L << 30)) + goto disable_adj; + + ocelot_write(ocelot, unit | adj, PTP_CLK_CFG_ADJ_FREQ); + ocelot_write(ocelot, PTP_CFG_CLK_ADJ_CFG_ENA | direction, + PTP_CLK_CFG_ADJ_CFG); + + spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + return 0; + +disable_adj: + ocelot_write(ocelot, 0, PTP_CLK_CFG_ADJ_CFG); + + spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + return 0; +} +EXPORT_SYMBOL(ocelot_ptp_adjfine); + +int ocelot_init_timestamp(struct ocelot *ocelot, struct ptp_clock_info *info) +{ + struct ptp_clock *ptp_clock; + + ocelot->ptp_info = *info; + ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev); + if (IS_ERR(ptp_clock)) + return PTR_ERR(ptp_clock); + /* Check if PHC support is missing at the configuration level */ + if (!ptp_clock) + return 0; + + ocelot->ptp_clock = ptp_clock; + + ocelot_write(ocelot, SYS_PTP_CFG_PTP_STAMP_WID(30), SYS_PTP_CFG); + ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_LOW); + ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_HIGH); + + ocelot_write(ocelot, PTP_CFG_MISC_PTP_EN, PTP_CFG_MISC); + + /* There is no device reconfiguration, PTP Rx stamping is always + * enabled. + */ + ocelot->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + + return 0; +} +EXPORT_SYMBOL(ocelot_init_timestamp); + +int ocelot_deinit_timestamp(struct ocelot *ocelot) +{ + if (ocelot->ptp_clock) + ptp_clock_unregister(ocelot->ptp_clock); + return 0; +} +EXPORT_SYMBOL(ocelot_deinit_timestamp); diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.h b/drivers/net/ethernet/mscc/ocelot_ptp.h deleted file mode 100644 index 9ede14a12573..000000000000 --- a/drivers/net/ethernet/mscc/ocelot_ptp.h +++ /dev/null @@ -1,41 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ -/* - * Microsemi Ocelot Switch driver - * - * License: Dual MIT/GPL - * Copyright (c) 2017 Microsemi Corporation - */ - -#ifndef _MSCC_OCELOT_PTP_H_ -#define _MSCC_OCELOT_PTP_H_ - -#define PTP_PIN_CFG_RSZ 0x20 -#define PTP_PIN_TOD_SEC_MSB_RSZ PTP_PIN_CFG_RSZ -#define PTP_PIN_TOD_SEC_LSB_RSZ PTP_PIN_CFG_RSZ -#define PTP_PIN_TOD_NSEC_RSZ PTP_PIN_CFG_RSZ - -#define PTP_PIN_CFG_DOM BIT(0) -#define PTP_PIN_CFG_SYNC BIT(2) -#define PTP_PIN_CFG_ACTION(x) ((x) << 3) -#define PTP_PIN_CFG_ACTION_MASK PTP_PIN_CFG_ACTION(0x7) - -enum { - PTP_PIN_ACTION_IDLE = 0, - PTP_PIN_ACTION_LOAD, - PTP_PIN_ACTION_SAVE, - PTP_PIN_ACTION_CLOCK, - PTP_PIN_ACTION_DELTA, - PTP_PIN_ACTION_NOSYNC, - PTP_PIN_ACTION_SYNC, -}; - -#define PTP_CFG_MISC_PTP_EN BIT(2) - -#define PSEC_PER_SEC 1000000000000LL - -#define PTP_CFG_CLK_ADJ_CFG_ENA BIT(0) -#define PTP_CFG_CLK_ADJ_CFG_DIR BIT(1) - -#define PTP_CFG_CLK_ADJ_FREQ_NS BIT(30) - -#endif diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 6d6a3947c8b7..6fd88ee622cf 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -620,7 +620,6 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid); int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr); int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr); -int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts); int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port, struct sk_buff *skb); void ocelot_get_txtstamp(struct ocelot *ocelot); diff --git a/include/soc/mscc/ocelot_ptp.h b/include/soc/mscc/ocelot_ptp.h new file mode 100644 index 000000000000..f01b0ce4e4cb --- /dev/null +++ b/include/soc/mscc/ocelot_ptp.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Microsemi Ocelot Switch driver + * + * License: Dual MIT/GPL + * Copyright (c) 2017 Microsemi Corporation + * Copyright 2020 NXP + */ + +#ifndef _MSCC_OCELOT_PTP_H_ +#define _MSCC_OCELOT_PTP_H_ + +#include +#include + +#define PTP_PIN_CFG_RSZ 0x20 +#define PTP_PIN_TOD_SEC_MSB_RSZ PTP_PIN_CFG_RSZ +#define PTP_PIN_TOD_SEC_LSB_RSZ PTP_PIN_CFG_RSZ +#define PTP_PIN_TOD_NSEC_RSZ PTP_PIN_CFG_RSZ + +#define PTP_PIN_CFG_DOM BIT(0) +#define PTP_PIN_CFG_SYNC BIT(2) +#define PTP_PIN_CFG_ACTION(x) ((x) << 3) +#define PTP_PIN_CFG_ACTION_MASK PTP_PIN_CFG_ACTION(0x7) + +enum { + PTP_PIN_ACTION_IDLE = 0, + PTP_PIN_ACTION_LOAD, + PTP_PIN_ACTION_SAVE, + PTP_PIN_ACTION_CLOCK, + PTP_PIN_ACTION_DELTA, + PTP_PIN_ACTION_NOSYNC, + PTP_PIN_ACTION_SYNC, +}; + +#define PTP_CFG_MISC_PTP_EN BIT(2) + +#define PSEC_PER_SEC 1000000000000LL + +#define PTP_CFG_CLK_ADJ_CFG_ENA BIT(0) +#define PTP_CFG_CLK_ADJ_CFG_DIR BIT(1) + +#define PTP_CFG_CLK_ADJ_FREQ_NS BIT(30) + +int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts); +int ocelot_ptp_settime64(struct ptp_clock_info *ptp, + const struct timespec64 *ts); +int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta); +int ocelot_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm); +int ocelot_init_timestamp(struct ocelot *ocelot, struct ptp_clock_info *info); +int ocelot_deinit_timestamp(struct ocelot *ocelot); +#endif -- cgit v1.2.3 From d2b09a8e7bcbfa47e7161b20d6387ac968834c21 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 20 Apr 2020 10:46:46 +0800 Subject: net: mscc: ocelot: fix timestamp info if ptp clock does not work The timestamp info should be only software timestamp capabilities if ptp clock does not work. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 7c4165af9f66..a2b9b85612a4 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1349,6 +1349,12 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port, { info->phc_index = ocelot->ptp_clock ? ptp_clock_index(ocelot->ptp_clock) : -1; + if (info->phc_index == -1) { + info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + return 0; + } info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE | -- cgit v1.2.3 From 3007bc7321e3c37de9d7d965cb9fb95aaa00113b Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 20 Apr 2020 10:46:47 +0800 Subject: net: mscc: ocelot: redefine PTP pins There are 5 PTP_PINS register groups on Ocelot switch. Except the one used for TOD operations, there are still 4 register groups for programmable pins. So redefine the 4 programmable pins. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- include/soc/mscc/ocelot.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 6fd88ee622cf..7d44d3508869 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -440,10 +440,11 @@ enum ocelot_regfield { REGFIELD_MAX }; -enum ocelot_clk_pins { - ALT_PPS_PIN = 1, - EXT_CLK_PIN, - ALT_LDST_PIN, +enum ocelot_ptp_pins { + PTP_PIN_0, + PTP_PIN_1, + PTP_PIN_2, + PTP_PIN_3, TOD_ACC_PIN }; -- cgit v1.2.3 From 94aca0824443d32987b31e656044ff7da425c523 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 20 Apr 2020 10:46:48 +0800 Subject: net: mscc: ocelot: add wave programming registers definitions Add wave programming registers definitions for Ocelot platforms. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 2 ++ drivers/net/ethernet/mscc/ocelot_regs.c | 2 ++ include/soc/mscc/ocelot.h | 2 ++ include/soc/mscc/ocelot_ptp.h | 2 ++ 4 files changed, 8 insertions(+) diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index b4078f3c5c38..4fe707ef54b8 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -313,6 +313,8 @@ static const u32 vsc9959_ptp_regmap[] = { REG(PTP_PIN_TOD_SEC_MSB, 0x000004), REG(PTP_PIN_TOD_SEC_LSB, 0x000008), REG(PTP_PIN_TOD_NSEC, 0x00000c), + REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014), + REG(PTP_PIN_WF_LOW_PERIOD, 0x000018), REG(PTP_CFG_MISC, 0x0000a0), REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4), REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8), diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c index b88b5899b227..ed4dd01a41ad 100644 --- a/drivers/net/ethernet/mscc/ocelot_regs.c +++ b/drivers/net/ethernet/mscc/ocelot_regs.c @@ -239,6 +239,8 @@ static const u32 ocelot_ptp_regmap[] = { REG(PTP_PIN_TOD_SEC_MSB, 0x000004), REG(PTP_PIN_TOD_SEC_LSB, 0x000008), REG(PTP_PIN_TOD_NSEC, 0x00000c), + REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014), + REG(PTP_PIN_WF_LOW_PERIOD, 0x000018), REG(PTP_CFG_MISC, 0x0000a0), REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4), REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8), diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 7d44d3508869..31193ad3a545 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -385,6 +385,8 @@ enum ocelot_reg { PTP_PIN_TOD_SEC_MSB, PTP_PIN_TOD_SEC_LSB, PTP_PIN_TOD_NSEC, + PTP_PIN_WF_HIGH_PERIOD, + PTP_PIN_WF_LOW_PERIOD, PTP_CFG_MISC, PTP_CLK_CFG_ADJ_CFG, PTP_CLK_CFG_ADJ_FREQ, diff --git a/include/soc/mscc/ocelot_ptp.h b/include/soc/mscc/ocelot_ptp.h index f01b0ce4e4cb..aae1570eecb1 100644 --- a/include/soc/mscc/ocelot_ptp.h +++ b/include/soc/mscc/ocelot_ptp.h @@ -17,6 +17,8 @@ #define PTP_PIN_TOD_SEC_MSB_RSZ PTP_PIN_CFG_RSZ #define PTP_PIN_TOD_SEC_LSB_RSZ PTP_PIN_CFG_RSZ #define PTP_PIN_TOD_NSEC_RSZ PTP_PIN_CFG_RSZ +#define PTP_PIN_WF_HIGH_PERIOD_RSZ PTP_PIN_CFG_RSZ +#define PTP_PIN_WF_LOW_PERIOD_RSZ PTP_PIN_CFG_RSZ #define PTP_PIN_CFG_DOM BIT(0) #define PTP_PIN_CFG_SYNC BIT(2) -- cgit v1.2.3 From cc2d87bb83407c7dfb0900d63b3fcfbf6a59202f Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 20 Apr 2020 10:46:49 +0800 Subject: net: mscc: ocelot: support 4 PTP programmable pins Support 4 PTP programmable pins with only PTP_PF_PEROUT function for now. The PTP_PF_EXTTS function will be supported in the future, and it should be implemented separately for Felix and Ocelot, because of different hardware interrupt implementation in them. Since the hardware is not able to support absolute start time, the periodic clock request only allows start time 0 0. But nsec could be accepted for PPS case for phase adjustment. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot_ptp.c | 121 +++++++++++++++++++++++++++++++++ include/soc/mscc/ocelot.h | 3 + include/soc/mscc/ocelot_ptp.h | 4 ++ 3 files changed, 128 insertions(+) diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.c b/drivers/net/ethernet/mscc/ocelot_ptp.c index 69d4e5677343..a3088a1676ed 100644 --- a/drivers/net/ethernet/mscc/ocelot_ptp.c +++ b/drivers/net/ethernet/mscc/ocelot_ptp.c @@ -165,11 +165,132 @@ disable_adj: } EXPORT_SYMBOL(ocelot_ptp_adjfine); +int ocelot_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin, + enum ptp_pin_function func, unsigned int chan) +{ + switch (func) { + case PTP_PF_NONE: + case PTP_PF_PEROUT: + break; + case PTP_PF_EXTTS: + case PTP_PF_PHYSYNC: + return -1; + } + return 0; +} +EXPORT_SYMBOL(ocelot_ptp_verify); + +int ocelot_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); + struct timespec64 ts_start, ts_period; + enum ocelot_ptp_pins ptp_pin; + unsigned long flags; + bool pps = false; + int pin = -1; + u32 val; + s64 ns; + + switch (rq->type) { + case PTP_CLK_REQ_PEROUT: + /* Reject requests with unsupported flags */ + if (rq->perout.flags) + return -EOPNOTSUPP; + + pin = ptp_find_pin(ocelot->ptp_clock, PTP_PF_PEROUT, + rq->perout.index); + if (pin == 0) + ptp_pin = PTP_PIN_0; + else if (pin == 1) + ptp_pin = PTP_PIN_1; + else if (pin == 2) + ptp_pin = PTP_PIN_2; + else if (pin == 3) + ptp_pin = PTP_PIN_3; + else + return -EBUSY; + + ts_start.tv_sec = rq->perout.start.sec; + ts_start.tv_nsec = rq->perout.start.nsec; + ts_period.tv_sec = rq->perout.period.sec; + ts_period.tv_nsec = rq->perout.period.nsec; + + if (ts_period.tv_sec == 1 && ts_period.tv_nsec == 0) + pps = true; + + if (ts_start.tv_sec || (ts_start.tv_nsec && !pps)) { + dev_warn(ocelot->dev, + "Absolute start time not supported!\n"); + dev_warn(ocelot->dev, + "Accept nsec for PPS phase adjustment, otherwise start time should be 0 0.\n"); + return -EINVAL; + } + + /* Handle turning off */ + if (!on) { + spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); + val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE); + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin); + spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + break; + } + + /* Handle PPS request */ + if (pps) { + spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); + /* Pulse generated perout.start.nsec after TOD has + * increased seconds. + * Pulse width is set to 1us. + */ + ocelot_write_rix(ocelot, ts_start.tv_nsec, + PTP_PIN_WF_LOW_PERIOD, ptp_pin); + ocelot_write_rix(ocelot, 1000, + PTP_PIN_WF_HIGH_PERIOD, ptp_pin); + val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_CLOCK); + val |= PTP_PIN_CFG_SYNC; + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin); + spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + break; + } + + /* Handle periodic clock */ + ns = timespec64_to_ns(&ts_period); + ns = ns >> 1; + if (ns > 0x3fffffff || ns <= 0x6) + return -EINVAL; + + spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); + ocelot_write_rix(ocelot, ns, PTP_PIN_WF_LOW_PERIOD, ptp_pin); + ocelot_write_rix(ocelot, ns, PTP_PIN_WF_HIGH_PERIOD, ptp_pin); + val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_CLOCK); + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin); + spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} +EXPORT_SYMBOL(ocelot_ptp_enable); + int ocelot_init_timestamp(struct ocelot *ocelot, struct ptp_clock_info *info) { struct ptp_clock *ptp_clock; + int i; ocelot->ptp_info = *info; + + for (i = 0; i < OCELOT_PTP_PINS_NUM; i++) { + struct ptp_pin_desc *p = &ocelot->ptp_pins[i]; + + snprintf(p->name, sizeof(p->name), "switch_1588_dat%d", i); + p->index = i; + p->func = PTP_PF_NONE; + } + + ocelot->ptp_info.pin_config = &ocelot->ptp_pins[0]; + ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev); if (IS_ERR(ptp_clock)) return PTR_ERR(ptp_clock); diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 31193ad3a545..a025fb798164 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -92,6 +92,8 @@ #define OCELOT_SPEED_100 2 #define OCELOT_SPEED_10 3 +#define OCELOT_PTP_PINS_NUM 4 + #define TARGET_OFFSET 24 #define REG_MASK GENMASK(TARGET_OFFSET - 1, 0) #define REG(reg, offset) [reg & REG_MASK] = offset @@ -552,6 +554,7 @@ struct ocelot { struct mutex ptp_lock; /* Protects the PTP clock */ spinlock_t ptp_clock_lock; + struct ptp_pin_desc ptp_pins[OCELOT_PTP_PINS_NUM]; }; struct ocelot_policer { diff --git a/include/soc/mscc/ocelot_ptp.h b/include/soc/mscc/ocelot_ptp.h index aae1570eecb1..4a6b2f71b6b2 100644 --- a/include/soc/mscc/ocelot_ptp.h +++ b/include/soc/mscc/ocelot_ptp.h @@ -49,6 +49,10 @@ int ocelot_ptp_settime64(struct ptp_clock_info *ptp, const struct timespec64 *ts); int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta); int ocelot_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm); +int ocelot_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin, + enum ptp_pin_function func, unsigned int chan); +int ocelot_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on); int ocelot_init_timestamp(struct ocelot *ocelot, struct ptp_clock_info *info); int ocelot_deinit_timestamp(struct ocelot *ocelot); #endif -- cgit v1.2.3 From aabb2bb07c963c67b8072aafcca3677e2b235be0 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 20 Apr 2020 10:46:50 +0800 Subject: net: mscc: ocelot: enable PTP programmable pin Enable PTP programmable pin. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot_board.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index ee016f7ed934..67a8d61c926a 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -372,13 +372,15 @@ static struct ptp_clock_info ocelot_ptp_clock_info = { .max_adj = 0x7fffffff, .n_alarm = 0, .n_ext_ts = 0, - .n_per_out = 0, - .n_pins = 0, + .n_per_out = OCELOT_PTP_PINS_NUM, + .n_pins = OCELOT_PTP_PINS_NUM, .pps = 0, .gettime64 = ocelot_ptp_gettime64, .settime64 = ocelot_ptp_settime64, .adjtime = ocelot_ptp_adjtime, .adjfine = ocelot_ptp_adjfine, + .verify = ocelot_ptp_verify, + .enable = ocelot_ptp_enable, }; static int mscc_ocelot_probe(struct platform_device *pdev) -- cgit v1.2.3 From 5287be405ca2263a9c524a6b0a7869c59760f4e6 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 20 Apr 2020 10:46:51 +0800 Subject: net: dsa: felix: enable PTP programmable pin Enable PTP programmable pin. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 44015a24b087..9173b95551d1 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -501,13 +501,15 @@ static struct ptp_clock_info ocelot_ptp_clock_info = { .max_adj = 0x7fffffff, .n_alarm = 0, .n_ext_ts = 0, - .n_per_out = 0, - .n_pins = 0, + .n_per_out = OCELOT_PTP_PINS_NUM, + .n_pins = OCELOT_PTP_PINS_NUM, .pps = 0, .gettime64 = ocelot_ptp_gettime64, .settime64 = ocelot_ptp_settime64, .adjtime = ocelot_ptp_adjtime, .adjfine = ocelot_ptp_adjfine, + .verify = ocelot_ptp_verify, + .enable = ocelot_ptp_enable, }; /* Hardware initialization done here so that we can allocate structures with -- cgit v1.2.3