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>
This commit is contained in:
commit
a2ff7e49ec
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -706,6 +706,7 @@
|
||||
fsl,tmr-fiper1 = <999999995>;
|
||||
fsl,tmr-fiper2 = <99990>;
|
||||
fsl,max-adj = <499999999>;
|
||||
fsl,extts-fifo;
|
||||
};
|
||||
|
||||
enet0: ethernet@2d10000 {
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
if (val & ETS1) {
|
||||
spin_unlock(&qoriq_ptp->lock);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
101
drivers/ptp/ptp_qoriq_debugfs.c
Normal file
101
drivers/ptp/ptp_qoriq_debugfs.c
Normal file
@ -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;
|
||||
}
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user