Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'ptp-add-pulse-signal-loopback-support-for-debugging'

Wei Fang says:

====================
ptp: add pulse signal loopback support for debugging

Some PTP devices support looping back the periodic pulse signal for
debugging. For example, the PTP device of QorIQ platform and the NETC v4
Timer has the ability to loop back the pulse signal and record the extts
events for the loopback signal. So we can make sure that the pulse
intervals and their phase alignment are correct from the perspective of
the emitting PHC's time base. In addition, we can use this loopback
feature as a built-in extts event generator when we have no external
equipment which does that. Therefore, add the generic debugfs interfaces
to the ptp_clock driver. The first two patch are separated from the
previous patch set [1]. The third patch is new added.

[1]: https://lore.kernel.org/imx/20250827063332.1217664-1-wei.fang@nxp.com/ #patch 3 and 9
====================

Link: https://patch.msgid.link/20250905030711.1509648-1-wei.fang@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+128 -118
-1
MAINTAINERS
··· 9817 9817 F: drivers/net/ethernet/freescale/dpaa2/dprtc* 9818 9818 F: drivers/net/ethernet/freescale/enetc/enetc_ptp.c 9819 9819 F: drivers/ptp/ptp_qoriq.c 9820 - F: drivers/ptp/ptp_qoriq_debugfs.c 9821 9820 F: include/linux/fsl/ptp_qoriq.h 9822 9821 9823 9822 FREESCALE QUAD SPI DRIVER
+1 -1
drivers/ptp/Kconfig
··· 67 67 packets using the SO_TIMESTAMPING API. 68 68 69 69 To compile this driver as a module, choose M here: the module 70 - will be called ptp-qoriq. 70 + will be called ptp_qoriq. 71 71 72 72 comment "Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks." 73 73 depends on PHYLIB=n || NETWORK_PHY_TIMESTAMPING=n
+1 -3
drivers/ptp/Makefile
··· 12 12 obj-$(CONFIG_PTP_1588_CLOCK_PCH) += ptp_pch.o 13 13 obj-$(CONFIG_PTP_1588_CLOCK_KVM) += ptp_kvm.o 14 14 obj-$(CONFIG_PTP_1588_CLOCK_VMCLOCK) += ptp_vmclock.o 15 - obj-$(CONFIG_PTP_1588_CLOCK_QORIQ) += ptp-qoriq.o 16 - ptp-qoriq-y += ptp_qoriq.o 17 - ptp-qoriq-$(CONFIG_DEBUG_FS) += ptp_qoriq_debugfs.o 15 + obj-$(CONFIG_PTP_1588_CLOCK_QORIQ) += ptp_qoriq.o 18 16 obj-$(CONFIG_PTP_1588_CLOCK_IDTCM) += ptp_clockmatrix.o 19 17 obj-$(CONFIG_PTP_1588_CLOCK_FC3W) += ptp_fc3.o 20 18 obj-$(CONFIG_PTP_1588_CLOCK_IDT82P33) += ptp_idt82p33.o
+69
drivers/ptp/ptp_clock.c
··· 248 248 kthread_queue_delayed_work(ptp->kworker, &ptp->aux_work, delay); 249 249 } 250 250 251 + static ssize_t ptp_n_perout_loopback_read(struct file *filep, 252 + char __user *buffer, 253 + size_t count, loff_t *pos) 254 + { 255 + struct ptp_clock *ptp = filep->private_data; 256 + char buf[12] = {}; 257 + 258 + snprintf(buf, sizeof(buf), "%d\n", ptp->info->n_per_lp); 259 + 260 + return simple_read_from_buffer(buffer, count, pos, buf, strlen(buf)); 261 + } 262 + 263 + static const struct file_operations ptp_n_perout_loopback_fops = { 264 + .owner = THIS_MODULE, 265 + .open = simple_open, 266 + .read = ptp_n_perout_loopback_read, 267 + }; 268 + 269 + static ssize_t ptp_perout_loopback_write(struct file *filep, 270 + const char __user *buffer, 271 + size_t count, loff_t *ppos) 272 + { 273 + struct ptp_clock *ptp = filep->private_data; 274 + struct ptp_clock_info *ops = ptp->info; 275 + unsigned int index, enable; 276 + int len, cnt, err; 277 + char buf[32] = {}; 278 + 279 + if (*ppos || !count) 280 + return -EINVAL; 281 + 282 + if (count >= sizeof(buf)) 283 + return -ENOSPC; 284 + 285 + len = simple_write_to_buffer(buf, sizeof(buf) - 1, 286 + ppos, buffer, count); 287 + if (len < 0) 288 + return len; 289 + 290 + buf[len] = '\0'; 291 + cnt = sscanf(buf, "%u %u", &index, &enable); 292 + if (cnt != 2) 293 + return -EINVAL; 294 + 295 + if (index >= ops->n_per_lp) 296 + return -EINVAL; 297 + 298 + if (enable != 0 && enable != 1) 299 + return -EINVAL; 300 + 301 + err = ops->perout_loopback(ops, index, enable); 302 + if (err) 303 + return err; 304 + 305 + return count; 306 + } 307 + 308 + static const struct file_operations ptp_perout_loopback_ops = { 309 + .owner = THIS_MODULE, 310 + .open = simple_open, 311 + .write = ptp_perout_loopback_write, 312 + }; 313 + 251 314 /* public interface */ 252 315 253 316 struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, ··· 452 389 /* Debugfs initialization */ 453 390 snprintf(debugfsname, sizeof(debugfsname), "ptp%d", ptp->index); 454 391 ptp->debugfs_root = debugfs_create_dir(debugfsname, NULL); 392 + if (info->n_per_lp > 0 && info->perout_loopback) { 393 + debugfs_create_file("n_perout_loopback", 0400, ptp->debugfs_root, 394 + ptp, &ptp_n_perout_loopback_fops); 395 + debugfs_create_file("perout_loopback", 0200, ptp->debugfs_root, 396 + ptp, &ptp_perout_loopback_ops); 397 + } 455 398 456 399 return ptp; 457 400
+25
drivers/ptp/ptp_netc.c
··· 21 21 #define TMR_ETEP(i) BIT(8 + (i)) 22 22 #define TMR_COMP_MODE BIT(15) 23 23 #define TMR_CTRL_TCLK_PERIOD GENMASK(25, 16) 24 + #define TMR_CTRL_PPL(i) BIT(27 - (i)) 24 25 #define TMR_CTRL_FS BIT(28) 25 26 26 27 #define NETC_TMR_TEVENT 0x0084 ··· 610 609 } 611 610 } 612 611 612 + static int netc_timer_perout_loopback(struct ptp_clock_info *ptp, 613 + unsigned int index, int on) 614 + { 615 + struct netc_timer *priv = ptp_to_netc_timer(ptp); 616 + unsigned long flags; 617 + u32 tmr_ctrl; 618 + 619 + spin_lock_irqsave(&priv->lock, flags); 620 + 621 + tmr_ctrl = netc_timer_rd(priv, NETC_TMR_CTRL); 622 + if (on) 623 + tmr_ctrl |= TMR_CTRL_PPL(index); 624 + else 625 + tmr_ctrl &= ~TMR_CTRL_PPL(index); 626 + 627 + netc_timer_wr(priv, NETC_TMR_CTRL, tmr_ctrl); 628 + 629 + spin_unlock_irqrestore(&priv->lock, flags); 630 + 631 + return 0; 632 + } 633 + 613 634 static void netc_timer_adjust_period(struct netc_timer *priv, u64 period) 614 635 { 615 636 u32 fractional_period = lower_32_bits(period); ··· 740 717 .pps = 1, 741 718 .n_per_out = 3, 742 719 .n_ext_ts = 2, 720 + .n_per_lp = 2, 743 721 .supported_extts_flags = PTP_RISING_EDGE | PTP_FALLING_EDGE | 744 722 PTP_STRICT_FLAGS, 745 723 .adjfine = netc_timer_adjfine, ··· 748 724 .gettimex64 = netc_timer_gettimex64, 749 725 .settime64 = netc_timer_settime64, 750 726 .enable = netc_timer_enable, 727 + .perout_loopback = netc_timer_perout_loopback, 751 728 }; 752 729 753 730 static void netc_timer_init(struct netc_timer *priv)
+22 -2
drivers/ptp/ptp_qoriq.c
··· 465 465 return 0; 466 466 } 467 467 468 + static int ptp_qoriq_perout_loopback(struct ptp_clock_info *ptp, 469 + unsigned int index, int on) 470 + { 471 + struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); 472 + struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; 473 + u32 loopback_bit = index ? PP2L : PP1L; 474 + u32 tmr_ctrl; 475 + 476 + tmr_ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl); 477 + if (on) 478 + tmr_ctrl |= loopback_bit; 479 + else 480 + tmr_ctrl &= ~loopback_bit; 481 + 482 + ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl, tmr_ctrl); 483 + 484 + return 0; 485 + } 486 + 468 487 int ptp_qoriq_init(struct ptp_qoriq *ptp_qoriq, void __iomem *base, 469 488 const struct ptp_clock_info *caps) 470 489 { ··· 498 479 499 480 ptp_qoriq->base = base; 500 481 ptp_qoriq->caps = *caps; 482 + ptp_qoriq->caps.n_per_lp = 2; 483 + ptp_qoriq->caps.perout_loopback = ptp_qoriq_perout_loopback; 501 484 502 485 if (of_property_read_u32(node, "fsl,cksel", &ptp_qoriq->cksel)) 503 486 ptp_qoriq->cksel = DEFAULT_CKSEL; ··· 589 568 return PTR_ERR(ptp_qoriq->clock); 590 569 591 570 ptp_qoriq->phc_index = ptp_clock_index(ptp_qoriq->clock); 592 - ptp_qoriq_create_debugfs(ptp_qoriq); 571 + 593 572 return 0; 594 573 } 595 574 EXPORT_SYMBOL_GPL(ptp_qoriq_init); ··· 601 580 ptp_qoriq->write(&regs->ctrl_regs->tmr_temask, 0); 602 581 ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl, 0); 603 582 604 - ptp_qoriq_remove_debugfs(ptp_qoriq); 605 583 ptp_clock_unregister(ptp_qoriq->clock); 606 584 iounmap(ptp_qoriq->base); 607 585 free_irq(ptp_qoriq->irq, ptp_qoriq);
-101
drivers/ptp/ptp_qoriq_debugfs.c
··· 1 - // SPDX-License-Identifier: GPL-2.0+ 2 - /* Copyright 2019 NXP 3 - */ 4 - #include <linux/device.h> 5 - #include <linux/debugfs.h> 6 - #include <linux/fsl/ptp_qoriq.h> 7 - 8 - static int ptp_qoriq_fiper1_lpbk_get(void *data, u64 *val) 9 - { 10 - struct ptp_qoriq *ptp_qoriq = data; 11 - struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; 12 - u32 ctrl; 13 - 14 - ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl); 15 - *val = ctrl & PP1L ? 1 : 0; 16 - 17 - return 0; 18 - } 19 - 20 - static int ptp_qoriq_fiper1_lpbk_set(void *data, u64 val) 21 - { 22 - struct ptp_qoriq *ptp_qoriq = data; 23 - struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; 24 - u32 ctrl; 25 - 26 - ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl); 27 - if (val == 0) 28 - ctrl &= ~PP1L; 29 - else 30 - ctrl |= PP1L; 31 - 32 - ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl, ctrl); 33 - return 0; 34 - } 35 - 36 - DEFINE_DEBUGFS_ATTRIBUTE(ptp_qoriq_fiper1_fops, ptp_qoriq_fiper1_lpbk_get, 37 - ptp_qoriq_fiper1_lpbk_set, "%llu\n"); 38 - 39 - static int ptp_qoriq_fiper2_lpbk_get(void *data, u64 *val) 40 - { 41 - struct ptp_qoriq *ptp_qoriq = data; 42 - struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; 43 - u32 ctrl; 44 - 45 - ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl); 46 - *val = ctrl & PP2L ? 1 : 0; 47 - 48 - return 0; 49 - } 50 - 51 - static int ptp_qoriq_fiper2_lpbk_set(void *data, u64 val) 52 - { 53 - struct ptp_qoriq *ptp_qoriq = data; 54 - struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; 55 - u32 ctrl; 56 - 57 - ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl); 58 - if (val == 0) 59 - ctrl &= ~PP2L; 60 - else 61 - ctrl |= PP2L; 62 - 63 - ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl, ctrl); 64 - return 0; 65 - } 66 - 67 - DEFINE_DEBUGFS_ATTRIBUTE(ptp_qoriq_fiper2_fops, ptp_qoriq_fiper2_lpbk_get, 68 - ptp_qoriq_fiper2_lpbk_set, "%llu\n"); 69 - 70 - void ptp_qoriq_create_debugfs(struct ptp_qoriq *ptp_qoriq) 71 - { 72 - struct dentry *root; 73 - 74 - root = debugfs_create_dir(dev_name(ptp_qoriq->dev), NULL); 75 - if (IS_ERR(root)) 76 - return; 77 - if (!root) 78 - goto err_root; 79 - 80 - ptp_qoriq->debugfs_root = root; 81 - 82 - if (!debugfs_create_file_unsafe("fiper1-loopback", 0600, root, 83 - ptp_qoriq, &ptp_qoriq_fiper1_fops)) 84 - goto err_node; 85 - if (!debugfs_create_file_unsafe("fiper2-loopback", 0600, root, 86 - ptp_qoriq, &ptp_qoriq_fiper2_fops)) 87 - goto err_node; 88 - return; 89 - 90 - err_node: 91 - debugfs_remove_recursive(root); 92 - ptp_qoriq->debugfs_root = NULL; 93 - err_root: 94 - dev_err(ptp_qoriq->dev, "failed to initialize debugfs\n"); 95 - } 96 - 97 - void ptp_qoriq_remove_debugfs(struct ptp_qoriq *ptp_qoriq) 98 - { 99 - debugfs_remove_recursive(ptp_qoriq->debugfs_root); 100 - ptp_qoriq->debugfs_root = NULL; 101 - }
-10
include/linux/fsl/ptp_qoriq.h
··· 145 145 struct ptp_clock *clock; 146 146 struct ptp_clock_info caps; 147 147 struct resource *rsrc; 148 - struct dentry *debugfs_root; 149 148 struct device *dev; 150 149 bool extts_fifo_support; 151 150 bool fiper3_support; ··· 194 195 int ptp_qoriq_enable(struct ptp_clock_info *ptp, 195 196 struct ptp_clock_request *rq, int on); 196 197 int extts_clean_up(struct ptp_qoriq *ptp_qoriq, int index, bool update_event); 197 - #ifdef CONFIG_DEBUG_FS 198 - void ptp_qoriq_create_debugfs(struct ptp_qoriq *ptp_qoriq); 199 - void ptp_qoriq_remove_debugfs(struct ptp_qoriq *ptp_qoriq); 200 - #else 201 - static inline void ptp_qoriq_create_debugfs(struct ptp_qoriq *ptp_qoriq) 202 - { } 203 - static inline void ptp_qoriq_remove_debugfs(struct ptp_qoriq *ptp_qoriq) 204 - { } 205 - #endif 206 198 207 199 #endif
+10
include/linux/ptp_clock_kernel.h
··· 67 67 * @n_ext_ts: The number of external time stamp channels. 68 68 * @n_per_out: The number of programmable periodic signals. 69 69 * @n_pins: The number of programmable pins. 70 + * @n_per_lp: The number of channels that support loopback the periodic 71 + * output signal. 70 72 * @pps: Indicates whether the clock supports a PPS callback. 71 73 * 72 74 * @supported_perout_flags: The set of flags the driver supports for the ··· 177 175 * scheduling time (>=0) or negative value in case further 178 176 * scheduling is not required. 179 177 * 178 + * @perout_loopback: Request driver to enable or disable the periodic output 179 + * signal loopback. 180 + * parameter index: index of the periodic output signal channel. 181 + * parameter on: caller passes one to enable or zero to disable. 182 + * 180 183 * Drivers should embed their ptp_clock_info within a private 181 184 * structure, obtaining a reference to it using container_of(). 182 185 * ··· 196 189 int n_ext_ts; 197 190 int n_per_out; 198 191 int n_pins; 192 + int n_per_lp; 199 193 int pps; 200 194 unsigned int supported_perout_flags; 201 195 unsigned int supported_extts_flags; ··· 221 213 int (*verify)(struct ptp_clock_info *ptp, unsigned int pin, 222 214 enum ptp_pin_function func, unsigned int chan); 223 215 long (*do_aux_work)(struct ptp_clock_info *ptp); 216 + int (*perout_loopback)(struct ptp_clock_info *ptp, unsigned int index, 217 + int on); 224 218 }; 225 219 226 220 struct ptp_clock;