Commit f67bf662 authored by Jonathan Lemon's avatar Jonathan Lemon Committed by David S. Miller

ptp: ocp: Add debugfs entry for timecard

Provide a view into the timecard internals for debugging.
Signed-off-by: default avatarJonathan Lemon <jonathan.lemon@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 065efcc5
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
...@@ -208,6 +209,7 @@ struct ptp_ocp { ...@@ -208,6 +209,7 @@ struct ptp_ocp {
struct tod_reg __iomem *tod; struct tod_reg __iomem *tod;
struct pps_reg __iomem *pps_to_ext; struct pps_reg __iomem *pps_to_ext;
struct pps_reg __iomem *pps_to_clk; struct pps_reg __iomem *pps_to_clk;
struct gpio_reg __iomem *pps_select;
struct gpio_reg __iomem *sma; struct gpio_reg __iomem *sma;
struct irig_master_reg __iomem *irig_out; struct irig_master_reg __iomem *irig_out;
struct irig_slave_reg __iomem *irig_in; struct irig_slave_reg __iomem *irig_in;
...@@ -224,6 +226,7 @@ struct ptp_ocp { ...@@ -224,6 +226,7 @@ struct ptp_ocp {
struct platform_device *spi_flash; struct platform_device *spi_flash;
struct clk_hw *i2c_clk; struct clk_hw *i2c_clk;
struct timer_list watchdog; struct timer_list watchdog;
struct dentry *debug_root;
time64_t gnss_lost; time64_t gnss_lost;
int id; int id;
int n_irqs; int n_irqs;
...@@ -354,6 +357,10 @@ static struct ocp_resource ocp_fb_resource[] = { ...@@ -354,6 +357,10 @@ static struct ocp_resource ocp_fb_resource[] = {
OCP_MEM_RESOURCE(image), OCP_MEM_RESOURCE(image),
.offset = 0x00020000, .size = 0x1000, .offset = 0x00020000, .size = 0x1000,
}, },
{
OCP_MEM_RESOURCE(pps_select),
.offset = 0x00130000, .size = 0x1000,
},
{ {
OCP_MEM_RESOURCE(sma), OCP_MEM_RESOURCE(sma),
.offset = 0x00140000, .size = 0x1000, .offset = 0x00140000, .size = 0x1000,
...@@ -1815,6 +1822,225 @@ static struct attribute *timecard_attrs[] = { ...@@ -1815,6 +1822,225 @@ static struct attribute *timecard_attrs[] = {
}; };
ATTRIBUTE_GROUPS(timecard); ATTRIBUTE_GROUPS(timecard);
static const char *
gpio_map(u32 gpio, u32 bit, const char *pri, const char *sec, const char *def)
{
const char *ans;
if (gpio & (1 << bit))
ans = pri;
else if (gpio & (1 << (bit + 16)))
ans = sec;
else
ans = def;
return ans;
}
static void
gpio_multi_map(char *buf, u32 gpio, u32 bit,
const char *pri, const char *sec, const char *def)
{
char *ans = buf;
strcpy(ans, def);
if (gpio & (1 << bit))
ans += sprintf(ans, "%s ", pri);
if (gpio & (1 << (bit + 16)))
ans += sprintf(ans, "%s ", sec);
}
static int
ptp_ocp_summary_show(struct seq_file *s, void *data)
{
struct device *dev = s->private;
struct ptp_system_timestamp sts;
u32 sma_in, sma_out, ctrl, val;
struct ts_reg __iomem *ts_reg;
struct timespec64 ts;
struct ptp_ocp *bp;
const char *src;
char *buf;
bool on;
buf = (char *)__get_free_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
bp = dev_get_drvdata(dev);
sma_in = ioread32(&bp->sma->gpio1);
sma_out = ioread32(&bp->sma->gpio2);
seq_printf(s, "%7s: /dev/ptp%d\n", "PTP", ptp_clock_index(bp->ptp));
sma1_show(dev, NULL, buf);
seq_printf(s, " sma1: %s", buf);
sma2_show(dev, NULL, buf);
seq_printf(s, " sma2: %s", buf);
sma3_show(dev, NULL, buf);
seq_printf(s, " sma3: %s", buf);
sma4_show(dev, NULL, buf);
seq_printf(s, " sma4: %s", buf);
if (bp->ts0) {
ts_reg = bp->ts0->mem;
on = ioread32(&ts_reg->enable);
src = "GNSS";
seq_printf(s, "%7s: %s, src: %s\n", "TS0",
on ? " ON" : "OFF", src);
}
if (bp->ts1) {
ts_reg = bp->ts1->mem;
on = ioread32(&ts_reg->enable);
src = gpio_map(sma_in, 2, "sma1", "sma2", "----");
seq_printf(s, "%7s: %s, src: %s\n", "TS1",
on ? " ON" : "OFF", src);
}
if (bp->ts2) {
ts_reg = bp->ts2->mem;
on = ioread32(&ts_reg->enable);
src = gpio_map(sma_in, 3, "sma1", "sma2", "----");
seq_printf(s, "%7s: %s, src: %s\n", "TS2",
on ? " ON" : "OFF", src);
}
if (bp->irig_out) {
ctrl = ioread32(&bp->irig_out->ctrl);
on = ctrl & IRIG_M_CTRL_ENABLE;
val = ioread32(&bp->irig_out->status);
gpio_multi_map(buf, sma_out, 4, "sma3", "sma4", "----");
seq_printf(s, "%7s: %s, error: %d, mode %d, out: %s\n", "IRIG",
on ? " ON" : "OFF", val, (ctrl >> 16), buf);
}
if (bp->irig_in) {
on = ioread32(&bp->irig_in->ctrl) & IRIG_S_CTRL_ENABLE;
val = ioread32(&bp->irig_in->status);
src = gpio_map(sma_in, 4, "sma1", "sma2", "----");
seq_printf(s, "%7s: %s, error: %d, src: %s\n", "IRIG in",
on ? " ON" : "OFF", val, src);
}
if (bp->dcf_out) {
on = ioread32(&bp->dcf_out->ctrl) & DCF_M_CTRL_ENABLE;
val = ioread32(&bp->dcf_out->status);
gpio_multi_map(buf, sma_out, 5, "sma3", "sma4", "----");
seq_printf(s, "%7s: %s, error: %d, out: %s\n", "DCF",
on ? " ON" : "OFF", val, buf);
}
if (bp->dcf_in) {
on = ioread32(&bp->dcf_in->ctrl) & DCF_S_CTRL_ENABLE;
val = ioread32(&bp->dcf_in->status);
src = gpio_map(sma_in, 5, "sma1", "sma2", "----");
seq_printf(s, "%7s: %s, error: %d, src: %s\n", "DCF in",
on ? " ON" : "OFF", val, src);
}
/* compute src for PPS1, used below. */
if (bp->pps_select) {
val = ioread32(&bp->pps_select->gpio1);
if (val & 0x01)
src = gpio_map(sma_in, 0, "sma1", "sma2", "----");
else if (val & 0x02)
src = "MAC";
else if (val & 0x04)
src = "GNSS";
else
src = "----";
} else {
src = "?";
}
/* assumes automatic switchover/selection */
val = ioread32(&bp->reg->select);
switch (val >> 16) {
case 0:
sprintf(buf, "----");
break;
case 2:
sprintf(buf, "IRIG");
break;
case 3:
sprintf(buf, "%s via PPS1", src);
break;
case 6:
sprintf(buf, "DCF");
break;
default:
strcpy(buf, "unknown");
break;
}
val = ioread32(&bp->reg->status);
seq_printf(s, "%7s: %s, state: %s\n", "PHC src", buf,
val & OCP_STATUS_IN_SYNC ? "sync" : "unsynced");
/* reuses PPS1 src from earlier */
seq_printf(s, "MAC PPS1 src: %s\n", src);
src = gpio_map(sma_in, 1, "sma1", "sma2", "GNSS2");
seq_printf(s, "MAC PPS2 src: %s\n", src);
if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, &sts)) {
struct timespec64 sys_ts;
s64 pre_ns, post_ns, ns;
pre_ns = timespec64_to_ns(&sts.pre_ts);
post_ns = timespec64_to_ns(&sts.post_ts);
ns = (pre_ns + post_ns) / 2;
ns += (s64)bp->utc_tai_offset * NSEC_PER_SEC;
sys_ts = ns_to_timespec64(ns);
seq_printf(s, "%7s: %lld.%ld == %ptT TAI\n", "PHC",
ts.tv_sec, ts.tv_nsec, &ts);
seq_printf(s, "%7s: %lld.%ld == %ptT UTC offset %d\n", "SYS",
sys_ts.tv_sec, sys_ts.tv_nsec, &sys_ts,
bp->utc_tai_offset);
seq_printf(s, "%7s: PHC:SYS offset: %lld window: %lld\n", "",
timespec64_to_ns(&ts) - ns,
post_ns - pre_ns);
}
free_page((unsigned long)buf);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(ptp_ocp_summary);
static struct dentry *ptp_ocp_debugfs_root;
static void
ptp_ocp_debugfs_add_device(struct ptp_ocp *bp)
{
struct dentry *d;
d = debugfs_create_dir(dev_name(&bp->dev), ptp_ocp_debugfs_root);
bp->debug_root = d;
debugfs_create_file("summary", 0444, bp->debug_root,
&bp->dev, &ptp_ocp_summary_fops);
}
static void
ptp_ocp_debugfs_remove_device(struct ptp_ocp *bp)
{
debugfs_remove_recursive(bp->debug_root);
}
static void
ptp_ocp_debugfs_init(void)
{
ptp_ocp_debugfs_root = debugfs_create_dir("timecard", NULL);
}
static void
ptp_ocp_debugfs_fini(void)
{
debugfs_remove_recursive(ptp_ocp_debugfs_root);
}
static void static void
ptp_ocp_dev_release(struct device *dev) ptp_ocp_dev_release(struct device *dev)
{ {
...@@ -1918,6 +2144,8 @@ ptp_ocp_complete(struct ptp_ocp *bp) ...@@ -1918,6 +2144,8 @@ ptp_ocp_complete(struct ptp_ocp *bp)
if (device_add_groups(&bp->dev, timecard_groups)) if (device_add_groups(&bp->dev, timecard_groups))
pr_err("device add groups failed\n"); pr_err("device add groups failed\n");
ptp_ocp_debugfs_add_device(bp);
return 0; return 0;
} }
...@@ -1988,6 +2216,7 @@ ptp_ocp_detach_sysfs(struct ptp_ocp *bp) ...@@ -1988,6 +2216,7 @@ ptp_ocp_detach_sysfs(struct ptp_ocp *bp)
static void static void
ptp_ocp_detach(struct ptp_ocp *bp) ptp_ocp_detach(struct ptp_ocp *bp)
{ {
ptp_ocp_debugfs_remove_device(bp);
ptp_ocp_detach_sysfs(bp); ptp_ocp_detach_sysfs(bp);
if (timer_pending(&bp->watchdog)) if (timer_pending(&bp->watchdog))
del_timer_sync(&bp->watchdog); del_timer_sync(&bp->watchdog);
...@@ -2157,6 +2386,8 @@ ptp_ocp_init(void) ...@@ -2157,6 +2386,8 @@ ptp_ocp_init(void)
const char *what; const char *what;
int err; int err;
ptp_ocp_debugfs_init();
what = "timecard class"; what = "timecard class";
err = class_register(&timecard_class); err = class_register(&timecard_class);
if (err) if (err)
...@@ -2179,6 +2410,7 @@ ptp_ocp_init(void) ...@@ -2179,6 +2410,7 @@ ptp_ocp_init(void)
out_notifier: out_notifier:
class_unregister(&timecard_class); class_unregister(&timecard_class);
out: out:
ptp_ocp_debugfs_fini();
pr_err(KBUILD_MODNAME ": failed to register %s: %d\n", what, err); pr_err(KBUILD_MODNAME ": failed to register %s: %d\n", what, err);
return err; return err;
} }
...@@ -2189,6 +2421,7 @@ ptp_ocp_fini(void) ...@@ -2189,6 +2421,7 @@ ptp_ocp_fini(void)
bus_unregister_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier); bus_unregister_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier);
pci_unregister_driver(&ptp_ocp_driver); pci_unregister_driver(&ptp_ocp_driver);
class_unregister(&timecard_class); class_unregister(&timecard_class);
ptp_ocp_debugfs_fini();
} }
module_init(ptp_ocp_init); module_init(ptp_ocp_init);
......
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