Commit a2ff7e49 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents ed175d9c 53deab23
......@@ -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 @@ ptp_clock@2d10e00 {
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(&regs->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 = &regs->etts_regs->tmr_etts1_l;
reg_etts_h = &regs->etts_regs->tmr_etts1_h;
break;
case 1:
valid = ETS2_VLD;
reg_etts_l = &regs->etts_regs->tmr_etts2_l;
reg_etts_h = &regs->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(&regs->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(&regs->ctrl_regs->tmr_tevent);
mask = qoriq_read(&regs->ctrl_regs->tmr_temask);
spin_unlock(&qoriq_ptp->lock);
if (val & ETS1) {
irqs = val & mask;
if (irqs & ETS1) {
ack |= ETS1;
hi = qoriq_read(&regs->etts_regs->tmr_etts1_h);
lo = qoriq_read(&regs->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(&regs->etts_regs->tmr_etts2_h);
lo = qoriq_read(&regs->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(&regs->alarm_regs->tmr_alarm2_l, lo);
qoriq_write(&regs->alarm_regs->tmr_alarm2_h, hi);
spin_unlock(&qoriq_ptp->lock);
qoriq_ptp->alarm_value = ns;
} else {
qoriq_write(&regs->ctrl_regs->tmr_tevent, ALM2);
spin_lock(&qoriq_ptp->lock);
mask = qoriq_read(&regs->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(&regs->ctrl_regs->tmr_temask);
if (on)
mask |= bit;
else
mask &= ~bit;
qoriq_write(&regs->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(&regs->ctrl_regs->tmr_temask);
if (on)
mask |= PP1EN;
else
mask &= ~PP1EN;
qoriq_write(&regs->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(&regs->ctrl_regs->tmr_temask);
if (on) {
mask |= bit;
qoriq_write(&regs->ctrl_regs->tmr_tevent, bit);
} else {
mask &= ~bit;
}
return -EOPNOTSUPP;
qoriq_write(&regs->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(&regs->ctrl_regs->tmr_temask, 0);
qoriq_write(&regs->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);
......
// 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(&regs->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(&regs->ctrl_regs->tmr_ctrl);
if (val == 0)
ctrl &= ~PP1L;
else
ctrl |= PP1L;
qoriq_write(&regs->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(&regs->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(&regs->ctrl_regs->tmr_ctrl);
if (val == 0)
ctrl &= ~PP2L;
else
ctrl |= PP2L;
qoriq_write(&regs->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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment