diff options
author | David S. Miller <davem@davemloft.net> | 2019-01-22 20:21:58 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-01-22 20:21:58 -0800 |
commit | a2ff7e49ec5035973776665b5bf491de8f3467ae (patch) | |
tree | 5ca2e10d5a40098d1a2d8efa36fa8ba08f5684d2 | |
parent | ed175d9c6f0d4df0f83f22ff4c887c21b7d021cd (diff) | |
parent | 53deab23c00afbbe491ad58054bbc63517d6232f (diff) | |
download | linux-a2ff7e49ec5035973776665b5bf491de8f3467ae.tar.bz2 |
Merge branch 'ptp_qoriq'
Yangbo Lu says:
====================
External trigger stamp fifo support for ptp_qoriq
This patch-set is to add external trigger stamp fifo support by a new
binding "fsl,extts-fifo", and to add fiper pulse loopback support which
is very useful for validating trigger without external hardware.
Also fixed issues in interrupt enabling/handling.
"fsl,extts-fifo" is required to be added into 1588 timer dts node whose
hardware supports it. The work will be done for some QorIQ platforms dts in
the near future.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/devicetree/bindings/ptp/ptp-qoriq.txt | 2 | ||||
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | arch/arm/boot/dts/ls1021a.dtsi | 1 | ||||
-rw-r--r-- | drivers/ptp/Kconfig | 2 | ||||
-rw-r--r-- | drivers/ptp/Makefile | 4 | ||||
-rw-r--r-- | drivers/ptp/ptp_qoriq.c | 129 | ||||
-rw-r--r-- | drivers/ptp/ptp_qoriq_debugfs.c | 101 | ||||
-rw-r--r-- | include/linux/fsl/ptp_qoriq.h | 15 |
8 files changed, 210 insertions, 45 deletions
diff --git a/Documentation/devicetree/bindings/ptp/ptp-qoriq.txt b/Documentation/devicetree/bindings/ptp/ptp-qoriq.txt index c5d0e7998e2b..8e7f8551d190 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-qoriq.txt +++ b/Documentation/devicetree/bindings/ptp/ptp-qoriq.txt @@ -17,6 +17,8 @@ Clock Properties: - fsl,tmr-fiper1 Fixed interval period pulse generator. - fsl,tmr-fiper2 Fixed interval period pulse generator. - fsl,max-adj Maximum frequency adjustment in parts per billion. + - fsl,extts-fifo The presence of this property indicates hardware + support for the external trigger stamp FIFO. These properties set the operational parameters for the PTP clock. You must choose these carefully for the clock to work right. diff --git a/MAINTAINERS b/MAINTAINERS index 470e5fe50cf2..d5d36cedf0b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6087,6 +6087,7 @@ M: Yangbo Lu <yangbo.lu@nxp.com> L: netdev@vger.kernel.org S: Maintained F: drivers/ptp/ptp_qoriq.c +F: drivers/ptp/ptp_qoriq_debugfs.c F: include/linux/fsl/ptp_qoriq.h F: Documentation/devicetree/bindings/ptp/ptp-qoriq.txt diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index ed0941292172..ad75959b99c1 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -706,6 +706,7 @@ fsl,tmr-fiper1 = <999999995>; fsl,tmr-fiper2 = <99990>; fsl,max-adj = <499999999>; + fsl,extts-fifo; }; enet0: ethernet@2d10000 { diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index d137c480db46..aeb4a8b2e0af 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -53,7 +53,7 @@ config PTP_1588_CLOCK_QORIQ packets using the SO_TIMESTAMPING API. To compile this driver as a module, choose M here: the module - will be called ptp_qoriq. + will be called ptp-qoriq. config PTP_1588_CLOCK_IXP46X tristate "Intel IXP46x as PTP clock" diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile index 19efa9cfa950..677d1d178a3e 100644 --- a/drivers/ptp/Makefile +++ b/drivers/ptp/Makefile @@ -9,4 +9,6 @@ obj-$(CONFIG_PTP_1588_CLOCK_DTE) += ptp_dte.o obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o obj-$(CONFIG_PTP_1588_CLOCK_PCH) += ptp_pch.o obj-$(CONFIG_PTP_1588_CLOCK_KVM) += ptp_kvm.o -obj-$(CONFIG_PTP_1588_CLOCK_QORIQ) += ptp_qoriq.o +obj-$(CONFIG_PTP_1588_CLOCK_QORIQ) += ptp-qoriq.o +ptp-qoriq-y += ptp_qoriq.o +ptp-qoriq-$(CONFIG_DEBUG_FS) += ptp_qoriq_debugfs.o diff --git a/drivers/ptp/ptp_qoriq.c b/drivers/ptp/ptp_qoriq.c index fdd49c26bbcc..43416b2e8a13 100644 --- a/drivers/ptp/ptp_qoriq.c +++ b/drivers/ptp/ptp_qoriq.c @@ -88,6 +88,49 @@ static void set_fipers(struct qoriq_ptp *qoriq_ptp) qoriq_write(®s->fiper_regs->tmr_fiper2, qoriq_ptp->tmr_fiper2); } +static int extts_clean_up(struct qoriq_ptp *qoriq_ptp, int index, + bool update_event) +{ + struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; + struct ptp_clock_event event; + void __iomem *reg_etts_l; + void __iomem *reg_etts_h; + u32 valid, stat, lo, hi; + + switch (index) { + case 0: + valid = ETS1_VLD; + reg_etts_l = ®s->etts_regs->tmr_etts1_l; + reg_etts_h = ®s->etts_regs->tmr_etts1_h; + break; + case 1: + valid = ETS2_VLD; + reg_etts_l = ®s->etts_regs->tmr_etts2_l; + reg_etts_h = ®s->etts_regs->tmr_etts2_h; + break; + default: + return -EINVAL; + } + + event.type = PTP_CLOCK_EXTTS; + event.index = index; + + do { + lo = qoriq_read(reg_etts_l); + hi = qoriq_read(reg_etts_h); + + if (update_event) { + event.timestamp = ((u64) hi) << 32; + event.timestamp |= lo; + ptp_clock_event(qoriq_ptp->clock, &event); + } + + stat = qoriq_read(®s->ctrl_regs->tmr_stat); + } while (qoriq_ptp->extts_fifo_support && (stat & valid)); + + return 0; +} + /* * Interrupt service routine */ @@ -98,33 +141,28 @@ static irqreturn_t isr(int irq, void *priv) struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; struct ptp_clock_event event; u64 ns; - u32 ack = 0, lo, hi, mask, val; + u32 ack = 0, lo, hi, mask, val, irqs; + + spin_lock(&qoriq_ptp->lock); val = qoriq_read(®s->ctrl_regs->tmr_tevent); + mask = qoriq_read(®s->ctrl_regs->tmr_temask); + + spin_unlock(&qoriq_ptp->lock); - if (val & ETS1) { + irqs = val & mask; + + if (irqs & ETS1) { ack |= ETS1; - hi = qoriq_read(®s->etts_regs->tmr_etts1_h); - lo = qoriq_read(®s->etts_regs->tmr_etts1_l); - event.type = PTP_CLOCK_EXTTS; - event.index = 0; - event.timestamp = ((u64) hi) << 32; - event.timestamp |= lo; - ptp_clock_event(qoriq_ptp->clock, &event); + extts_clean_up(qoriq_ptp, 0, true); } - if (val & ETS2) { + if (irqs & ETS2) { ack |= ETS2; - hi = qoriq_read(®s->etts_regs->tmr_etts2_h); - lo = qoriq_read(®s->etts_regs->tmr_etts2_l); - event.type = PTP_CLOCK_EXTTS; - event.index = 1; - event.timestamp = ((u64) hi) << 32; - event.timestamp |= lo; - ptp_clock_event(qoriq_ptp->clock, &event); + extts_clean_up(qoriq_ptp, 1, true); } - if (val & ALM2) { + if (irqs & ALM2) { ack |= ALM2; if (qoriq_ptp->alarm_value) { event.type = PTP_CLOCK_ALARM; @@ -136,13 +174,10 @@ static irqreturn_t isr(int irq, void *priv) ns = qoriq_ptp->alarm_value + qoriq_ptp->alarm_interval; hi = ns >> 32; lo = ns & 0xffffffff; - spin_lock(&qoriq_ptp->lock); qoriq_write(®s->alarm_regs->tmr_alarm2_l, lo); qoriq_write(®s->alarm_regs->tmr_alarm2_h, hi); - spin_unlock(&qoriq_ptp->lock); qoriq_ptp->alarm_value = ns; } else { - qoriq_write(®s->ctrl_regs->tmr_tevent, ALM2); spin_lock(&qoriq_ptp->lock); mask = qoriq_read(®s->ctrl_regs->tmr_temask); mask &= ~ALM2EN; @@ -153,7 +188,7 @@ static irqreturn_t isr(int irq, void *priv) } } - if (val & PP1) { + if (irqs & PP1) { ack |= PP1; event.type = PTP_CLOCK_PPS; ptp_clock_event(qoriq_ptp->clock, &event); @@ -260,7 +295,7 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp, struct qoriq_ptp *qoriq_ptp = container_of(ptp, struct qoriq_ptp, caps); struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; unsigned long flags; - u32 bit, mask; + u32 bit, mask = 0; switch (rq->type) { case PTP_CLK_REQ_EXTTS: @@ -274,32 +309,32 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp, default: return -EINVAL; } - spin_lock_irqsave(&qoriq_ptp->lock, flags); - mask = qoriq_read(®s->ctrl_regs->tmr_temask); - if (on) - mask |= bit; - else - mask &= ~bit; - qoriq_write(®s->ctrl_regs->tmr_temask, mask); - spin_unlock_irqrestore(&qoriq_ptp->lock, flags); - return 0; - case PTP_CLK_REQ_PPS: - spin_lock_irqsave(&qoriq_ptp->lock, flags); - mask = qoriq_read(®s->ctrl_regs->tmr_temask); if (on) - mask |= PP1EN; - else - mask &= ~PP1EN; - qoriq_write(®s->ctrl_regs->tmr_temask, mask); - spin_unlock_irqrestore(&qoriq_ptp->lock, flags); - return 0; + extts_clean_up(qoriq_ptp, rq->extts.index, false); - default: break; + case PTP_CLK_REQ_PPS: + bit = PP1EN; + break; + default: + return -EOPNOTSUPP; + } + + spin_lock_irqsave(&qoriq_ptp->lock, flags); + + mask = qoriq_read(®s->ctrl_regs->tmr_temask); + if (on) { + mask |= bit; + qoriq_write(®s->ctrl_regs->tmr_tevent, bit); + } else { + mask &= ~bit; } - return -EOPNOTSUPP; + qoriq_write(®s->ctrl_regs->tmr_temask, mask); + + spin_unlock_irqrestore(&qoriq_ptp->lock, flags); + return 0; } static const struct ptp_clock_info ptp_qoriq_caps = { @@ -436,11 +471,17 @@ static int qoriq_ptp_probe(struct platform_device *dev) err = -EINVAL; + qoriq_ptp->dev = &dev->dev; qoriq_ptp->caps = ptp_qoriq_caps; if (of_property_read_u32(node, "fsl,cksel", &qoriq_ptp->cksel)) qoriq_ptp->cksel = DEFAULT_CKSEL; + if (of_property_read_bool(node, "fsl,extts-fifo")) + qoriq_ptp->extts_fifo_support = true; + else + qoriq_ptp->extts_fifo_support = false; + if (of_property_read_u32(node, "fsl,tclk-period", &qoriq_ptp->tclk_period) || of_property_read_u32(node, @@ -532,6 +573,7 @@ static int qoriq_ptp_probe(struct platform_device *dev) } qoriq_ptp->phc_index = ptp_clock_index(qoriq_ptp->clock); + ptp_qoriq_create_debugfs(qoriq_ptp); platform_set_drvdata(dev, qoriq_ptp); return 0; @@ -557,6 +599,7 @@ static int qoriq_ptp_remove(struct platform_device *dev) qoriq_write(®s->ctrl_regs->tmr_temask, 0); qoriq_write(®s->ctrl_regs->tmr_ctrl, 0); + ptp_qoriq_remove_debugfs(qoriq_ptp); ptp_clock_unregister(qoriq_ptp->clock); iounmap(qoriq_ptp->base); release_resource(qoriq_ptp->rsrc); diff --git a/drivers/ptp/ptp_qoriq_debugfs.c b/drivers/ptp/ptp_qoriq_debugfs.c new file mode 100644 index 000000000000..d904332b240d --- /dev/null +++ b/drivers/ptp/ptp_qoriq_debugfs.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright 2019 NXP + */ +#include <linux/device.h> +#include <linux/debugfs.h> +#include <linux/fsl/ptp_qoriq.h> + +static int ptp_qoriq_fiper1_lpbk_get(void *data, u64 *val) +{ + struct qoriq_ptp *qoriq_ptp = data; + struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; + u32 ctrl; + + ctrl = qoriq_read(®s->ctrl_regs->tmr_ctrl); + *val = ctrl & PP1L ? 1 : 0; + + return 0; +} + +static int ptp_qoriq_fiper1_lpbk_set(void *data, u64 val) +{ + struct qoriq_ptp *qoriq_ptp = data; + struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; + u32 ctrl; + + ctrl = qoriq_read(®s->ctrl_regs->tmr_ctrl); + if (val == 0) + ctrl &= ~PP1L; + else + ctrl |= PP1L; + + qoriq_write(®s->ctrl_regs->tmr_ctrl, ctrl); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(ptp_qoriq_fiper1_fops, ptp_qoriq_fiper1_lpbk_get, + ptp_qoriq_fiper1_lpbk_set, "%llu\n"); + +static int ptp_qoriq_fiper2_lpbk_get(void *data, u64 *val) +{ + struct qoriq_ptp *qoriq_ptp = data; + struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; + u32 ctrl; + + ctrl = qoriq_read(®s->ctrl_regs->tmr_ctrl); + *val = ctrl & PP2L ? 1 : 0; + + return 0; +} + +static int ptp_qoriq_fiper2_lpbk_set(void *data, u64 val) +{ + struct qoriq_ptp *qoriq_ptp = data; + struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; + u32 ctrl; + + ctrl = qoriq_read(®s->ctrl_regs->tmr_ctrl); + if (val == 0) + ctrl &= ~PP2L; + else + ctrl |= PP2L; + + qoriq_write(®s->ctrl_regs->tmr_ctrl, ctrl); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(ptp_qoriq_fiper2_fops, ptp_qoriq_fiper2_lpbk_get, + ptp_qoriq_fiper2_lpbk_set, "%llu\n"); + +void ptp_qoriq_create_debugfs(struct qoriq_ptp *qoriq_ptp) +{ + struct dentry *root; + + root = debugfs_create_dir(dev_name(qoriq_ptp->dev), NULL); + if (IS_ERR(root)) + return; + if (!root) + goto err_root; + + qoriq_ptp->debugfs_root = root; + + if (!debugfs_create_file("fiper1-loopback", 0600, root, qoriq_ptp, + &ptp_qoriq_fiper1_fops)) + goto err_node; + if (!debugfs_create_file("fiper2-loopback", 0600, root, qoriq_ptp, + &ptp_qoriq_fiper2_fops)) + goto err_node; + return; + +err_node: + debugfs_remove_recursive(root); + qoriq_ptp->debugfs_root = NULL; +err_root: + dev_err(qoriq_ptp->dev, "failed to initialize debugfs\n"); +} + +void ptp_qoriq_remove_debugfs(struct qoriq_ptp *qoriq_ptp) +{ + debugfs_remove_recursive(qoriq_ptp->debugfs_root); + qoriq_ptp->debugfs_root = NULL; +} diff --git a/include/linux/fsl/ptp_qoriq.h b/include/linux/fsl/ptp_qoriq.h index c1f003aadcce..94e9797e434c 100644 --- a/include/linux/fsl/ptp_qoriq.h +++ b/include/linux/fsl/ptp_qoriq.h @@ -120,6 +120,8 @@ struct qoriq_ptp_registers { /* Bit definitions for the TMR_STAT register */ #define STAT_VEC_SHIFT (0) /* Timer general purpose status vector */ #define STAT_VEC_MASK (0x3f) +#define ETS1_VLD (1<<24) +#define ETS2_VLD (1<<25) /* Bit definitions for the TMR_PRSC register */ #define PRSC_OCK_SHIFT (0) /* Output clock division/prescale factor. */ @@ -141,6 +143,9 @@ struct qoriq_ptp { struct ptp_clock *clock; struct ptp_clock_info caps; struct resource *rsrc; + struct dentry *debugfs_root; + struct device *dev; + bool extts_fifo_support; int irq; int phc_index; u64 alarm_interval; /* for periodic alarm */ @@ -166,4 +171,14 @@ static inline void qoriq_write(unsigned __iomem *addr, u32 val) iowrite32be(val, addr); } +#ifdef CONFIG_DEBUG_FS +void ptp_qoriq_create_debugfs(struct qoriq_ptp *qoriq_ptp); +void ptp_qoriq_remove_debugfs(struct qoriq_ptp *qoriq_ptp); +#else +static inline void ptp_qoriq_create_debugfs(struct qoriq_ptp *qoriq_ptp) +{ } +static inline void ptp_qoriq_remove_debugfs(struct qoriq_ptp *qoriq_ptp) +{ } +#endif + #endif |