* [PATCH net-next v2 00/10] ptp: ocp: support for new firmware
@ 2022-03-10 20:19 Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 01/10] ptp: ocp: Add support for selectable SMA directions Jonathan Lemon
` (10 more replies)
0 siblings, 11 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
This series contains support for new firmware features for
the timecard.
v1 -> v2: roundup() is not 32-bit safe, use DIV_ROUND_UP_ULL
Jonathan Lemon (10):
ptp: ocp: Add support for selectable SMA directions.
ptp: ocp: Add ability to disable input selectors.
ptp: ocp: Rename output selector 'GNSS' to 'GNSS1'
ptp: ocp: Add GND and VCC output selectors
ptp: ocp: Add firmware capability bits for feature gating
ptp: ocp: Add signal generators and update sysfs nodes
ptp: ocp: Program the signal generators via PTP_CLK_REQ_PEROUT
ptp: ocp: Add 4 frequency counters
ptp: ocp: Add 2 more timestampers
docs: ABI: Document new timecard sysfs nodes.
Documentation/ABI/testing/sysfs-timecard | 94 +-
drivers/ptp/ptp_ocp.c | 1212 +++++++++++++++++++---
2 files changed, 1147 insertions(+), 159 deletions(-)
--
2.31.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH net-next v2 01/10] ptp: ocp: Add support for selectable SMA directions.
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
@ 2022-03-10 20:19 ` Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 02/10] ptp: ocp: Add ability to disable input selectors Jonathan Lemon
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
Assuming the firmware allows it, the direction of each SMA connector
is no longer fixed. Handle remapping directions for each pin.
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
drivers/ptp/ptp_ocp.c | 332 +++++++++++++++++++++++++++---------------
1 file changed, 213 insertions(+), 119 deletions(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 98b3f01e76c9..b776b4f02a2b 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -206,6 +206,17 @@ struct ptp_ocp_ext_src {
int irq_vec;
};
+enum ptp_ocp_sma_mode {
+ SMA_MODE_IN,
+ SMA_MODE_OUT,
+};
+
+struct ptp_ocp_sma_connector {
+ enum ptp_ocp_sma_mode mode;
+ bool fixed_fcn;
+ bool fixed_dir;
+};
+
#define OCP_BOARD_ID_LEN 13
#define OCP_SERIAL_LEN 6
@@ -218,7 +229,8 @@ struct ptp_ocp {
struct pps_reg __iomem *pps_to_ext;
struct pps_reg __iomem *pps_to_clk;
struct gpio_reg __iomem *pps_select;
- struct gpio_reg __iomem *sma;
+ struct gpio_reg __iomem *sma_map1;
+ struct gpio_reg __iomem *sma_map2;
struct irig_master_reg __iomem *irig_out;
struct irig_slave_reg __iomem *irig_in;
struct dcf_master_reg __iomem *dcf_out;
@@ -252,6 +264,7 @@ struct ptp_ocp {
int flash_start;
u32 utc_tai_offset;
u32 ts_window_adjust;
+ struct ptp_ocp_sma_connector sma[4];
};
#define OCP_REQ_TIMESTAMP BIT(0)
@@ -417,9 +430,13 @@ static struct ocp_resource ocp_fb_resource[] = {
.offset = 0x00130000, .size = 0x1000,
},
{
- OCP_MEM_RESOURCE(sma),
+ OCP_MEM_RESOURCE(sma_map1),
.offset = 0x00140000, .size = 0x1000,
},
+ {
+ OCP_MEM_RESOURCE(sma_map2),
+ .offset = 0x00220000, .size = 0x1000,
+ },
{
OCP_I2C_RESOURCE(i2c_ctrl),
.offset = 0x00150000, .size = 0x10000, .irq_vec = 7,
@@ -502,6 +519,9 @@ static struct ocp_selector ptp_ocp_clock[] = {
{ }
};
+#define SMA_ENABLE BIT(15)
+#define SMA_SELECT_MASK ((1U << 15) - 1)
+
static struct ocp_selector ptp_ocp_sma_in[] = {
{ .name = "10Mhz", .value = 0x00 },
{ .name = "PPS1", .value = 0x01 },
@@ -1455,6 +1475,45 @@ ptp_ocp_nmea_out_init(struct ptp_ocp *bp)
iowrite32(1, &bp->nmea_out->ctrl); /* enable */
}
+static void
+ptp_ocp_sma_init(struct ptp_ocp *bp)
+{
+ u32 reg;
+ int i;
+
+ /* defaults */
+ bp->sma[0].mode = SMA_MODE_IN;
+ bp->sma[1].mode = SMA_MODE_IN;
+ bp->sma[2].mode = SMA_MODE_OUT;
+ bp->sma[3].mode = SMA_MODE_OUT;
+
+ /* If no SMA1 map, the pin functions and directions are fixed. */
+ if (!bp->sma_map1) {
+ for (i = 0; i < 4; i++) {
+ bp->sma[i].fixed_fcn = true;
+ bp->sma[i].fixed_dir = true;
+ }
+ return;
+ }
+
+ /* If SMA2 GPIO output map is all 1, it is not present.
+ * This indicates the firmware has fixed direction SMA pins.
+ */
+ reg = ioread32(&bp->sma_map2->gpio2);
+ if (reg == 0xffffffff) {
+ for (i = 0; i < 4; i++)
+ bp->sma[i].fixed_dir = true;
+ } else {
+ reg = ioread32(&bp->sma_map1->gpio1);
+ bp->sma[0].mode = reg & BIT(15) ? SMA_MODE_IN : SMA_MODE_OUT;
+ bp->sma[1].mode = reg & BIT(31) ? SMA_MODE_IN : SMA_MODE_OUT;
+
+ reg = ioread32(&bp->sma_map1->gpio2);
+ bp->sma[2].mode = reg & BIT(15) ? SMA_MODE_OUT : SMA_MODE_IN;
+ bp->sma[3].mode = reg & BIT(31) ? SMA_MODE_OUT : SMA_MODE_IN;
+ }
+}
+
/* FB specific board initializers; last "resource" registered. */
static int
ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
@@ -1465,6 +1524,7 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
ptp_ocp_tod_init(bp);
ptp_ocp_nmea_out_init(bp);
+ ptp_ocp_sma_init(bp);
return ptp_ocp_init_clock(bp);
}
@@ -1566,36 +1626,6 @@ __handle_signal_inputs(struct ptp_ocp *bp, u32 val)
* ANT4 == sma4 (out)
*/
-enum ptp_ocp_sma_mode {
- SMA_MODE_IN,
- SMA_MODE_OUT,
-};
-
-static struct ptp_ocp_sma_connector {
- enum ptp_ocp_sma_mode mode;
- bool fixed_mode;
- u16 default_out_idx;
-} ptp_ocp_sma_map[4] = {
- {
- .mode = SMA_MODE_IN,
- .fixed_mode = true,
- },
- {
- .mode = SMA_MODE_IN,
- .fixed_mode = true,
- },
- {
- .mode = SMA_MODE_OUT,
- .fixed_mode = true,
- .default_out_idx = 0, /* 10Mhz */
- },
- {
- .mode = SMA_MODE_OUT,
- .fixed_mode = true,
- .default_out_idx = 1, /* PHC */
- },
-};
-
static ssize_t
ptp_ocp_show_output(u32 val, char *buf, int default_idx)
{
@@ -1611,7 +1641,7 @@ ptp_ocp_show_output(u32 val, char *buf, int default_idx)
}
static ssize_t
-ptp_ocp_show_inputs(u32 val, char *buf, const char *zero_in)
+ptp_ocp_show_inputs(u32 val, char *buf, int default_idx)
{
const char *name;
ssize_t count;
@@ -1624,8 +1654,9 @@ ptp_ocp_show_inputs(u32 val, char *buf, const char *zero_in)
count += sysfs_emit_at(buf, count, "%s ", name);
}
}
- if (!val && zero_in)
- count += sysfs_emit_at(buf, count, "%s ", zero_in);
+ if (!val && default_idx >= 0)
+ count += sysfs_emit_at(buf, count, "%s ",
+ ptp_ocp_sma_in[default_idx].name);
if (count)
count--;
count += sysfs_emit_at(buf, count, "\n");
@@ -1650,7 +1681,7 @@ sma_parse_inputs(const char *buf, enum ptp_ocp_sma_mode *mode)
idx = 0;
dir = *mode == SMA_MODE_IN ? 0 : 1;
- if (!strcasecmp("IN:", argv[idx])) {
+ if (!strcasecmp("IN:", argv[0])) {
dir = 0;
idx++;
}
@@ -1671,102 +1702,123 @@ sma_parse_inputs(const char *buf, enum ptp_ocp_sma_mode *mode)
return ret;
}
-static ssize_t
-ptp_ocp_sma_show(struct ptp_ocp *bp, int sma_nr, u32 val, char *buf,
- const char *zero_in)
+static u32
+ptp_ocp_sma_get(struct ptp_ocp *bp, int sma_nr, enum ptp_ocp_sma_mode mode)
{
- struct ptp_ocp_sma_connector *sma = &ptp_ocp_sma_map[sma_nr - 1];
+ u32 __iomem *gpio;
+ u32 shift;
+
+ if (bp->sma[sma_nr - 1].fixed_fcn)
+ return (sma_nr - 1) & 1;
+
+ if (mode == SMA_MODE_IN)
+ gpio = sma_nr > 2 ? &bp->sma_map2->gpio1 : &bp->sma_map1->gpio1;
+ else
+ gpio = sma_nr > 2 ? &bp->sma_map1->gpio2 : &bp->sma_map2->gpio2;
+ shift = sma_nr & 1 ? 0 : 16;
+
+ return (ioread32(gpio) >> shift) & 0xffff;
+}
+
+static ssize_t
+ptp_ocp_sma_show(struct ptp_ocp *bp, int sma_nr, char *buf,
+ int default_in_idx, int default_out_idx)
+{
+ struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1];
+ u32 val;
+
+ val = ptp_ocp_sma_get(bp, sma_nr, sma->mode) & SMA_SELECT_MASK;
if (sma->mode == SMA_MODE_IN)
- return ptp_ocp_show_inputs(val, buf, zero_in);
+ return ptp_ocp_show_inputs(val, buf, default_in_idx);
- return ptp_ocp_show_output(val, buf, sma->default_out_idx);
+ return ptp_ocp_show_output(val, buf, default_out_idx);
}
static ssize_t
sma1_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ptp_ocp *bp = dev_get_drvdata(dev);
- u32 val;
- val = ioread32(&bp->sma->gpio1) & 0x3f;
- return ptp_ocp_sma_show(bp, 1, val, buf, ptp_ocp_sma_in[0].name);
+ return ptp_ocp_sma_show(bp, 1, buf, 0, 1);
}
static ssize_t
sma2_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ptp_ocp *bp = dev_get_drvdata(dev);
- u32 val;
- val = (ioread32(&bp->sma->gpio1) >> 16) & 0x3f;
- return ptp_ocp_sma_show(bp, 2, val, buf, NULL);
+ return ptp_ocp_sma_show(bp, 2, buf, -1, 1);
}
static ssize_t
sma3_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ptp_ocp *bp = dev_get_drvdata(dev);
- u32 val;
- val = ioread32(&bp->sma->gpio2) & 0x3f;
- return ptp_ocp_sma_show(bp, 3, val, buf, NULL);
+ return ptp_ocp_sma_show(bp, 3, buf, -1, 0);
}
static ssize_t
sma4_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ptp_ocp *bp = dev_get_drvdata(dev);
- u32 val;
- val = (ioread32(&bp->sma->gpio2) >> 16) & 0x3f;
- return ptp_ocp_sma_show(bp, 4, val, buf, NULL);
+ return ptp_ocp_sma_show(bp, 4, buf, -1, 1);
}
static void
-ptp_ocp_sma_store_output(struct ptp_ocp *bp, u32 val, u32 shift)
+ptp_ocp_sma_store_output(struct ptp_ocp *bp, int sma_nr, u32 val)
{
+ u32 reg, mask, shift;
unsigned long flags;
- u32 gpio, mask;
+ u32 __iomem *gpio;
+
+ gpio = sma_nr > 2 ? &bp->sma_map1->gpio2 : &bp->sma_map2->gpio2;
+ shift = sma_nr & 1 ? 0 : 16;
mask = 0xffff << (16 - shift);
spin_lock_irqsave(&bp->lock, flags);
- gpio = ioread32(&bp->sma->gpio2);
- gpio = (gpio & mask) | (val << shift);
+ reg = ioread32(gpio);
+ reg = (reg & mask) | (val << shift);
- __handle_signal_outputs(bp, gpio);
+ __handle_signal_outputs(bp, reg);
- iowrite32(gpio, &bp->sma->gpio2);
+ iowrite32(reg, gpio);
spin_unlock_irqrestore(&bp->lock, flags);
}
static void
-ptp_ocp_sma_store_inputs(struct ptp_ocp *bp, u32 val, u32 shift)
+ptp_ocp_sma_store_inputs(struct ptp_ocp *bp, int sma_nr, u32 val)
{
+ u32 reg, mask, shift;
unsigned long flags;
- u32 gpio, mask;
+ u32 __iomem *gpio;
+
+ gpio = sma_nr > 2 ? &bp->sma_map2->gpio1 : &bp->sma_map1->gpio1;
+ shift = sma_nr & 1 ? 0 : 16;
mask = 0xffff << (16 - shift);
spin_lock_irqsave(&bp->lock, flags);
- gpio = ioread32(&bp->sma->gpio1);
- gpio = (gpio & mask) | (val << shift);
+ reg = ioread32(gpio);
+ reg = (reg & mask) | (val << shift);
- __handle_signal_inputs(bp, gpio);
+ __handle_signal_inputs(bp, reg);
- iowrite32(gpio, &bp->sma->gpio1);
+ iowrite32(reg, gpio);
spin_unlock_irqrestore(&bp->lock, flags);
}
-static ssize_t
-ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr, u32 shift)
+static int
+ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
{
- struct ptp_ocp_sma_connector *sma = &ptp_ocp_sma_map[sma_nr - 1];
+ struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1];
enum ptp_ocp_sma_mode mode;
int val;
@@ -1775,18 +1827,30 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr, u32 shift)
if (val < 0)
return val;
- if (mode != sma->mode && sma->fixed_mode)
+ if (mode != sma->mode && sma->fixed_dir)
return -EOPNOTSUPP;
- if (mode != sma->mode) {
- pr_err("Mode changes not supported yet.\n");
- return -EOPNOTSUPP;
+ if (sma->fixed_fcn) {
+ if (val != ((sma_nr - 1) & 1))
+ return -EOPNOTSUPP;
+ return 0;
}
- if (sma->mode == SMA_MODE_IN)
- ptp_ocp_sma_store_inputs(bp, val, shift);
+ if (mode != sma->mode) {
+ if (mode == SMA_MODE_IN)
+ ptp_ocp_sma_store_output(bp, sma_nr, 0);
+ else
+ ptp_ocp_sma_store_inputs(bp, sma_nr, 0);
+ sma->mode = mode;
+ }
+
+ if (!sma->fixed_dir)
+ val |= SMA_ENABLE; /* add enable bit */
+
+ if (mode == SMA_MODE_IN)
+ ptp_ocp_sma_store_inputs(bp, sma_nr, val);
else
- ptp_ocp_sma_store_output(bp, val, shift);
+ ptp_ocp_sma_store_output(bp, sma_nr, val);
return 0;
}
@@ -1798,7 +1862,7 @@ sma1_store(struct device *dev, struct device_attribute *attr,
struct ptp_ocp *bp = dev_get_drvdata(dev);
int err;
- err = ptp_ocp_sma_store(bp, buf, 1, 0);
+ err = ptp_ocp_sma_store(bp, buf, 1);
return err ? err : count;
}
@@ -1809,7 +1873,7 @@ sma2_store(struct device *dev, struct device_attribute *attr,
struct ptp_ocp *bp = dev_get_drvdata(dev);
int err;
- err = ptp_ocp_sma_store(bp, buf, 2, 16);
+ err = ptp_ocp_sma_store(bp, buf, 2);
return err ? err : count;
}
@@ -1820,7 +1884,7 @@ sma3_store(struct device *dev, struct device_attribute *attr,
struct ptp_ocp *bp = dev_get_drvdata(dev);
int err;
- err = ptp_ocp_sma_store(bp, buf, 3, 0);
+ err = ptp_ocp_sma_store(bp, buf, 3);
return err ? err : count;
}
@@ -1831,7 +1895,7 @@ sma4_store(struct device *dev, struct device_attribute *attr,
struct ptp_ocp *bp = dev_get_drvdata(dev);
int err;
- err = ptp_ocp_sma_store(bp, buf, 4, 16);
+ err = ptp_ocp_sma_store(bp, buf, 4);
return err ? err : count;
}
static DEVICE_ATTR_RW(sma1);
@@ -2110,31 +2174,38 @@ static struct attribute *timecard_attrs[] = {
};
ATTRIBUTE_GROUPS(timecard);
-static const char *
-gpio_map(u32 gpio, u32 bit, const char *pri, const char *sec, const char *def)
+static void
+gpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit,
+ const char *def)
{
- const char *ans;
+ int i;
- if (gpio & (1 << bit))
- ans = pri;
- else if (gpio & (1 << (bit + 16)))
- ans = sec;
- else
- ans = def;
- return ans;
+ for (i = 0; i < 4; i++) {
+ if (bp->sma[i].mode != SMA_MODE_IN)
+ continue;
+ if (map[i][0] & (1 << bit)) {
+ sprintf(buf, "sma%d", i + 1);
+ return;
+ }
+ }
+ if (!def)
+ def = "----";
+ strcpy(buf, def);
}
static void
-gpio_multi_map(char *buf, u32 gpio, u32 bit,
- const char *pri, const char *sec, const char *def)
+gpio_output_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit)
{
char *ans = buf;
+ int i;
- strcpy(ans, def);
- if (gpio & (1 << bit))
- ans += sprintf(ans, "%s ", pri);
- if (gpio & (1 << (bit + 16)))
- ans += sprintf(ans, "%s ", sec);
+ strcpy(ans, "----");
+ for (i = 0; i < 4; i++) {
+ if (bp->sma[i].mode != SMA_MODE_OUT)
+ continue;
+ if (map[i][1] & (1 << bit))
+ ans += sprintf(ans, "sma%d ", i + 1);
+ }
}
static int
@@ -2142,21 +2213,18 @@ 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;
+ u16 sma_val[4][2], ctrl, val;
struct ts_reg __iomem *ts_reg;
struct timespec64 ts;
struct ptp_ocp *bp;
- const char *src;
+ char *src, *buf;
bool on, map;
- char *buf;
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));
if (bp->gnss_port != -1)
@@ -2168,17 +2236,42 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
if (bp->nmea_port != -1)
seq_printf(s, "%7s: /dev/ttyS%d\n", "NMEA", bp->nmea_port);
+ memset(sma_val, 0xff, sizeof(sma_val));
+ if (bp->sma_map1) {
+ u32 reg;
+
+ reg = ioread32(&bp->sma_map1->gpio1);
+ sma_val[0][0] = reg & 0xffff;
+ sma_val[1][0] = reg >> 16;
+
+ reg = ioread32(&bp->sma_map1->gpio2);
+ sma_val[2][1] = reg & 0xffff;
+ sma_val[3][1] = reg >> 16;
+
+ reg = ioread32(&bp->sma_map2->gpio1);
+ sma_val[2][0] = reg & 0xffff;
+ sma_val[3][0] = reg >> 16;
+
+ reg = ioread32(&bp->sma_map2->gpio2);
+ sma_val[0][1] = reg & 0xffff;
+ sma_val[1][1] = reg >> 16;
+ }
+
sma1_show(dev, NULL, buf);
- seq_printf(s, " sma1: %s", buf);
+ seq_printf(s, " sma1: %04x,%04x %s",
+ sma_val[0][0], sma_val[0][1], buf);
sma2_show(dev, NULL, buf);
- seq_printf(s, " sma2: %s", buf);
+ seq_printf(s, " sma2: %04x,%04x %s",
+ sma_val[1][0], sma_val[1][1], buf);
sma3_show(dev, NULL, buf);
- seq_printf(s, " sma3: %s", buf);
+ seq_printf(s, " sma3: %04x,%04x %s",
+ sma_val[2][0], sma_val[2][1], buf);
sma4_show(dev, NULL, buf);
- seq_printf(s, " sma4: %s", buf);
+ seq_printf(s, " sma4: %04x,%04x %s",
+ sma_val[3][0], sma_val[3][1], buf);
if (bp->ts0) {
ts_reg = bp->ts0->mem;
@@ -2191,17 +2284,17 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
if (bp->ts1) {
ts_reg = bp->ts1->mem;
on = ioread32(&ts_reg->enable);
- src = gpio_map(sma_in, 2, "sma1", "sma2", "----");
+ gpio_input_map(buf, bp, sma_val, 2, NULL);
seq_printf(s, "%7s: %s, src: %s\n", "TS1",
- on ? " ON" : "OFF", src);
+ on ? " ON" : "OFF", buf);
}
if (bp->ts2) {
ts_reg = bp->ts2->mem;
on = ioread32(&ts_reg->enable);
- src = gpio_map(sma_in, 3, "sma1", "sma2", "----");
+ gpio_input_map(buf, bp, sma_val, 3, NULL);
seq_printf(s, "%7s: %s, src: %s\n", "TS2",
- on ? " ON" : "OFF", src);
+ on ? " ON" : "OFF", buf);
}
if (bp->pps) {
@@ -2221,7 +2314,7 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
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", "----");
+ gpio_output_map(buf, bp, sma_val, 4);
seq_printf(s, "%7s: %s, error: %d, mode %d, out: %s\n", "IRIG",
on ? " ON" : "OFF", val, (ctrl >> 16), buf);
}
@@ -2229,15 +2322,15 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
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", "----");
+ gpio_input_map(buf, bp, sma_val, 4, NULL);
seq_printf(s, "%7s: %s, error: %d, src: %s\n", "IRIG in",
- on ? " ON" : "OFF", val, src);
+ on ? " ON" : "OFF", val, buf);
}
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", "----");
+ gpio_output_map(buf, bp, sma_val, 5);
seq_printf(s, "%7s: %s, error: %d, out: %s\n", "DCF",
on ? " ON" : "OFF", val, buf);
}
@@ -2245,9 +2338,9 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
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", "----");
+ gpio_input_map(buf, bp, sma_val, 5, NULL);
seq_printf(s, "%7s: %s, error: %d, src: %s\n", "DCF in",
- on ? " ON" : "OFF", val, src);
+ on ? " ON" : "OFF", val, buf);
}
if (bp->nmea_out) {
@@ -2260,8 +2353,9 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
/* compute src for PPS1, used below. */
if (bp->pps_select) {
val = ioread32(&bp->pps_select->gpio1);
+ src = &buf[80];
if (val & 0x01)
- src = gpio_map(sma_in, 0, "sma1", "sma2", "----");
+ gpio_input_map(src, bp, sma_val, 0, NULL);
else if (val & 0x02)
src = "MAC";
else if (val & 0x04)
@@ -2298,8 +2392,8 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
/* 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);
+ gpio_input_map(buf, bp, sma_val, 1, "GNSS2");
+ seq_printf(s, "MAC PPS2 src: %s\n", buf);
if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, &sts)) {
struct timespec64 sys_ts;
--
2.31.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 02/10] ptp: ocp: Add ability to disable input selectors.
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 01/10] ptp: ocp: Add support for selectable SMA directions Jonathan Lemon
@ 2022-03-10 20:19 ` Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 03/10] ptp: ocp: Rename output selector 'GNSS' to 'GNSS1' Jonathan Lemon
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
This adds support for the "IN: None" selector, which disables
the input on a sma pin. This should be compatible with old firmware
(the firmware will ignore it if not supported).
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
drivers/ptp/ptp_ocp.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index b776b4f02a2b..53b11c7f8fa0 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -215,6 +215,7 @@ struct ptp_ocp_sma_connector {
enum ptp_ocp_sma_mode mode;
bool fixed_fcn;
bool fixed_dir;
+ bool disabled;
};
#define OCP_BOARD_ID_LEN 13
@@ -521,6 +522,7 @@ static struct ocp_selector ptp_ocp_clock[] = {
#define SMA_ENABLE BIT(15)
#define SMA_SELECT_MASK ((1U << 15) - 1)
+#define SMA_DISABLE 0x10000
static struct ocp_selector ptp_ocp_sma_in[] = {
{ .name = "10Mhz", .value = 0x00 },
@@ -530,6 +532,7 @@ static struct ocp_selector ptp_ocp_sma_in[] = {
{ .name = "TS2", .value = 0x08 },
{ .name = "IRIG", .value = 0x10 },
{ .name = "DCF", .value = 0x20 },
+ { .name = "None", .value = SMA_DISABLE },
{ }
};
@@ -1627,7 +1630,7 @@ __handle_signal_inputs(struct ptp_ocp *bp, u32 val)
*/
static ssize_t
-ptp_ocp_show_output(u32 val, char *buf, int default_idx)
+ptp_ocp_show_output(u32 val, char *buf, int def_val)
{
const char *name;
ssize_t count;
@@ -1635,13 +1638,13 @@ ptp_ocp_show_output(u32 val, char *buf, int default_idx)
count = sysfs_emit(buf, "OUT: ");
name = ptp_ocp_select_name_from_val(ptp_ocp_sma_out, val);
if (!name)
- name = ptp_ocp_sma_out[default_idx].name;
+ name = ptp_ocp_select_name_from_val(ptp_ocp_sma_out, def_val);
count += sysfs_emit_at(buf, count, "%s\n", name);
return count;
}
static ssize_t
-ptp_ocp_show_inputs(u32 val, char *buf, int default_idx)
+ptp_ocp_show_inputs(u32 val, char *buf, int def_val)
{
const char *name;
ssize_t count;
@@ -1654,9 +1657,10 @@ ptp_ocp_show_inputs(u32 val, char *buf, int default_idx)
count += sysfs_emit_at(buf, count, "%s ", name);
}
}
- if (!val && default_idx >= 0)
- count += sysfs_emit_at(buf, count, "%s ",
- ptp_ocp_sma_in[default_idx].name);
+ if (!val && def_val >= 0) {
+ name = ptp_ocp_select_name_from_val(ptp_ocp_sma_in, def_val);
+ count += sysfs_emit_at(buf, count, "%s ", name);
+ }
if (count)
count--;
count += sysfs_emit_at(buf, count, "\n");
@@ -1722,17 +1726,20 @@ ptp_ocp_sma_get(struct ptp_ocp *bp, int sma_nr, enum ptp_ocp_sma_mode mode)
static ssize_t
ptp_ocp_sma_show(struct ptp_ocp *bp, int sma_nr, char *buf,
- int default_in_idx, int default_out_idx)
+ int default_in_val, int default_out_val)
{
struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1];
u32 val;
val = ptp_ocp_sma_get(bp, sma_nr, sma->mode) & SMA_SELECT_MASK;
- if (sma->mode == SMA_MODE_IN)
- return ptp_ocp_show_inputs(val, buf, default_in_idx);
+ if (sma->mode == SMA_MODE_IN) {
+ if (sma->disabled)
+ val = SMA_DISABLE;
+ return ptp_ocp_show_inputs(val, buf, default_in_val);
+ }
- return ptp_ocp_show_output(val, buf, default_out_idx);
+ return ptp_ocp_show_output(val, buf, default_out_val);
}
static ssize_t
@@ -1827,7 +1834,7 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
if (val < 0)
return val;
- if (mode != sma->mode && sma->fixed_dir)
+ if (sma->fixed_dir && (mode != sma->mode || val & SMA_DISABLE))
return -EOPNOTSUPP;
if (sma->fixed_fcn) {
@@ -1836,6 +1843,8 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
return 0;
}
+ sma->disabled = !!(val & SMA_DISABLE);
+
if (mode != sma->mode) {
if (mode == SMA_MODE_IN)
ptp_ocp_sma_store_output(bp, sma_nr, 0);
@@ -1847,6 +1856,9 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
if (!sma->fixed_dir)
val |= SMA_ENABLE; /* add enable bit */
+ if (sma->disabled)
+ val = 0;
+
if (mode == SMA_MODE_IN)
ptp_ocp_sma_store_inputs(bp, sma_nr, val);
else
--
2.31.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 03/10] ptp: ocp: Rename output selector 'GNSS' to 'GNSS1'
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 01/10] ptp: ocp: Add support for selectable SMA directions Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 02/10] ptp: ocp: Add ability to disable input selectors Jonathan Lemon
@ 2022-03-10 20:19 ` Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 04/10] ptp: ocp: Add GND and VCC output selectors Jonathan Lemon
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
As there are may be 2 GNSS outputs, rename the first one for clarity.
This also works around a parsing issue when specifying selectors.
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
drivers/ptp/ptp_ocp.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 53b11c7f8fa0..c85ba3812b25 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -339,7 +339,7 @@ static struct ptp_ocp_eeprom_map fb_eeprom_map[] = {
* 0: TS3 (and PPS)
* 1: TS0
* 2: TS1
- * 3: GNSS
+ * 3: GNSS1
* 4: GNSS2
* 5: MAC
* 6: TS2
@@ -540,7 +540,7 @@ static struct ocp_selector ptp_ocp_sma_out[] = {
{ .name = "10Mhz", .value = 0x00 },
{ .name = "PHC", .value = 0x01 },
{ .name = "MAC", .value = 0x02 },
- { .name = "GNSS", .value = 0x04 },
+ { .name = "GNSS1", .value = 0x04 },
{ .name = "GNSS2", .value = 0x08 },
{ .name = "IRIG", .value = 0x10 },
{ .name = "DCF", .value = 0x20 },
@@ -2288,7 +2288,7 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
if (bp->ts0) {
ts_reg = bp->ts0->mem;
on = ioread32(&ts_reg->enable);
- src = "GNSS";
+ src = "GNSS1";
seq_printf(s, "%7s: %s, src: %s\n", "TS0",
on ? " ON" : "OFF", src);
}
@@ -2371,7 +2371,7 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
else if (val & 0x02)
src = "MAC";
else if (val & 0x04)
- src = "GNSS";
+ src = "GNSS1";
else
src = "----";
} else {
--
2.31.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 04/10] ptp: ocp: Add GND and VCC output selectors
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
` (2 preceding siblings ...)
2022-03-10 20:19 ` [PATCH net-next v2 03/10] ptp: ocp: Rename output selector 'GNSS' to 'GNSS1' Jonathan Lemon
@ 2022-03-10 20:19 ` Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 05/10] ptp: ocp: Add firmware capability bits for feature gating Jonathan Lemon
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
These will provide constant outputs.
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
drivers/ptp/ptp_ocp.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index c85ba3812b25..d2df28a52926 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -544,6 +544,8 @@ static struct ocp_selector ptp_ocp_sma_out[] = {
{ .name = "GNSS2", .value = 0x08 },
{ .name = "IRIG", .value = 0x10 },
{ .name = "DCF", .value = 0x20 },
+ { .name = "GND", .value = 0x2000 },
+ { .name = "VCC", .value = 0x4000 },
{ }
};
--
2.31.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 05/10] ptp: ocp: Add firmware capability bits for feature gating
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
` (3 preceding siblings ...)
2022-03-10 20:19 ` [PATCH net-next v2 04/10] ptp: ocp: Add GND and VCC output selectors Jonathan Lemon
@ 2022-03-10 20:19 ` Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 06/10] ptp: ocp: Add signal generators and update sysfs nodes Jonathan Lemon
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
Add the ability to group sysfs nodes behind a firmware feature
check. This way non-present sysfs attributes are omitted on
older firmware, which does not have newer features.
This will be used in the upcoming patches which adds more
features to the timecard.
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
drivers/ptp/ptp_ocp.c | 38 +++++++++++++++++++++++++++++++++-----
1 file changed, 33 insertions(+), 5 deletions(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index d2df28a52926..e55dc9586ec0 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -218,6 +218,13 @@ struct ptp_ocp_sma_connector {
bool disabled;
};
+struct ocp_attr_group {
+ u64 cap;
+ const struct attribute_group *group;
+};
+
+#define OCP_CAP_BASIC BIT(0)
+
#define OCP_BOARD_ID_LEN 13
#define OCP_SERIAL_LEN 6
@@ -248,6 +255,7 @@ struct ptp_ocp {
struct platform_device *spi_flash;
struct clk_hw *i2c_clk;
struct timer_list watchdog;
+ const struct ocp_attr_group *attr_tbl;
const struct ptp_ocp_eeprom_map *eeprom_map;
struct dentry *debug_root;
time64_t gnss_lost;
@@ -265,6 +273,7 @@ struct ptp_ocp {
int flash_start;
u32 utc_tai_offset;
u32 ts_window_adjust;
+ u64 fw_cap;
struct ptp_ocp_sma_connector sma[4];
};
@@ -290,6 +299,8 @@ static int ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
static irqreturn_t ptp_ocp_ts_irq(int irq, void *priv);
static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
+static const struct ocp_attr_group fb_timecard_groups[];
+
struct ptp_ocp_eeprom_map {
u16 off;
u16 len;
@@ -1526,6 +1537,8 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
bp->flash_start = 1024 * 4096;
bp->eeprom_map = fb_eeprom_map;
bp->fw_version = ioread32(&bp->image->version);
+ bp->attr_tbl = fb_timecard_groups;
+ bp->fw_cap = OCP_CAP_BASIC;
ptp_ocp_tod_init(bp);
ptp_ocp_nmea_out_init(bp);
@@ -2167,7 +2180,7 @@ tod_correction_store(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RW(tod_correction);
-static struct attribute *timecard_attrs[] = {
+static struct attribute *fb_timecard_attrs[] = {
&dev_attr_serialnum.attr,
&dev_attr_gnss_sync.attr,
&dev_attr_clock_source.attr,
@@ -2186,7 +2199,13 @@ static struct attribute *timecard_attrs[] = {
&dev_attr_tod_correction.attr,
NULL,
};
-ATTRIBUTE_GROUPS(timecard);
+static const struct attribute_group fb_timecard_group = {
+ .attrs = fb_timecard_attrs,
+};
+static const struct ocp_attr_group fb_timecard_groups[] = {
+ { .cap = OCP_CAP_BASIC, .group = &fb_timecard_group },
+ { },
+};
static void
gpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit,
@@ -2605,6 +2624,7 @@ ptp_ocp_complete(struct ptp_ocp *bp)
{
struct pps_device *pps;
char buf[32];
+ int i, err;
if (bp->gnss_port != -1) {
sprintf(buf, "ttyS%d", bp->gnss_port);
@@ -2629,8 +2649,13 @@ ptp_ocp_complete(struct ptp_ocp *bp)
if (pps)
ptp_ocp_symlink(bp, pps->dev, "pps");
- if (device_add_groups(&bp->dev, timecard_groups))
- pr_err("device add groups failed\n");
+ for (i = 0; bp->attr_tbl[i].cap; i++) {
+ if (!(bp->attr_tbl[i].cap & bp->fw_cap))
+ continue;
+ err = sysfs_create_group(&bp->dev.kobj, bp->attr_tbl[i].group);
+ if (err)
+ return err;
+ }
ptp_ocp_debugfs_add_device(bp);
@@ -2703,12 +2728,15 @@ static void
ptp_ocp_detach_sysfs(struct ptp_ocp *bp)
{
struct device *dev = &bp->dev;
+ int i;
sysfs_remove_link(&dev->kobj, "ttyGNSS");
sysfs_remove_link(&dev->kobj, "ttyMAC");
sysfs_remove_link(&dev->kobj, "ptp");
sysfs_remove_link(&dev->kobj, "pps");
- device_remove_groups(dev, timecard_groups);
+ if (bp->attr_tbl)
+ for (i = 0; bp->attr_tbl[i].cap; i++)
+ sysfs_remove_group(&dev->kobj, bp->attr_tbl[i].group);
}
static void
--
2.31.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 06/10] ptp: ocp: Add signal generators and update sysfs nodes
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
` (4 preceding siblings ...)
2022-03-10 20:19 ` [PATCH net-next v2 05/10] ptp: ocp: Add firmware capability bits for feature gating Jonathan Lemon
@ 2022-03-10 20:19 ` Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 07/10] ptp: ocp: Program the signal generators via PTP_CLK_REQ_PEROUT Jonathan Lemon
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
Newer firmware provides 4 programmable signal generators, add
support for those here. The signal generators provide the
ability to set the period, duty cycle, phase offset, and polarity,
with new values defaulting to prior values.
The period and phase offset are specified in nanoseconds.
E.g: period [duty [phase [polarity]]]
echo 500000000 > signal # 1/2 second period
echo 1000000 40 100 > signal # 1ms period, 40% on, offset 100ns
echo 0 > signal # turn off generator
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
drivers/ptp/ptp_ocp.c | 486 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 476 insertions(+), 10 deletions(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index e55dc9586ec0..397e3e6b840f 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -179,6 +179,26 @@ struct dcf_slave_reg {
#define DCF_S_CTRL_ENABLE BIT(0)
+struct signal_reg {
+ u32 enable;
+ u32 status;
+ u32 polarity;
+ u32 version;
+ u32 __pad0[4];
+ u32 cable_delay;
+ u32 __pad1[3];
+ u32 intr;
+ u32 intr_mask;
+ u32 __pad2[2];
+ u32 start_ns;
+ u32 start_sec;
+ u32 pulse_ns;
+ u32 pulse_sec;
+ u32 period_ns;
+ u32 period_sec;
+ u32 repeat_count;
+};
+
struct ptp_ocp_flash_info {
const char *name;
int pci_offset;
@@ -224,6 +244,17 @@ struct ocp_attr_group {
};
#define OCP_CAP_BASIC BIT(0)
+#define OCP_CAP_SIGNAL BIT(1)
+
+struct ptp_ocp_signal {
+ ktime_t period;
+ ktime_t pulse;
+ ktime_t phase;
+ ktime_t start;
+ int duty;
+ bool polarity;
+ bool running;
+};
#define OCP_BOARD_ID_LEN 13
#define OCP_SERIAL_LEN 6
@@ -244,6 +275,7 @@ struct ptp_ocp {
struct dcf_master_reg __iomem *dcf_out;
struct dcf_slave_reg __iomem *dcf_in;
struct tod_reg __iomem *nmea_out;
+ struct ptp_ocp_ext_src *signal_out[4];
struct ptp_ocp_ext_src *pps;
struct ptp_ocp_ext_src *ts0;
struct ptp_ocp_ext_src *ts1;
@@ -274,6 +306,7 @@ struct ptp_ocp {
u32 utc_tai_offset;
u32 ts_window_adjust;
u64 fw_cap;
+ struct ptp_ocp_signal signal[4];
struct ptp_ocp_sma_connector sma[4];
};
@@ -297,7 +330,10 @@ static int ptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r);
static int ptp_ocp_register_ext(struct ptp_ocp *bp, struct ocp_resource *r);
static int ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
static irqreturn_t ptp_ocp_ts_irq(int irq, void *priv);
+static irqreturn_t ptp_ocp_signal_irq(int irq, void *priv);
static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
+static int ptp_ocp_signal_enable(void *priv, u32 req, bool enable);
+static int ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr);
static const struct ocp_attr_group fb_timecard_groups[];
@@ -358,6 +394,10 @@ static struct ptp_ocp_eeprom_map fb_eeprom_map[] = {
* 8: HWICAP (notused)
* 9: SPI Flash
* 10: NMEA
+ * 11: Signal Generator 1
+ * 12: Signal Generator 2
+ * 13: Signal Generator 3
+ * 14: Signal Generator 4
*/
static struct ocp_resource ocp_fb_resource[] = {
@@ -401,6 +441,42 @@ static struct ocp_resource ocp_fb_resource[] = {
.enable = ptp_ocp_ts_enable,
},
},
+ {
+ OCP_EXT_RESOURCE(signal_out[0]),
+ .offset = 0x010D0000, .size = 0x10000, .irq_vec = 11,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 1,
+ .irq_fcn = ptp_ocp_signal_irq,
+ .enable = ptp_ocp_signal_enable,
+ },
+ },
+ {
+ OCP_EXT_RESOURCE(signal_out[1]),
+ .offset = 0x010E0000, .size = 0x10000, .irq_vec = 12,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 2,
+ .irq_fcn = ptp_ocp_signal_irq,
+ .enable = ptp_ocp_signal_enable,
+ },
+ },
+ {
+ OCP_EXT_RESOURCE(signal_out[2]),
+ .offset = 0x010F0000, .size = 0x10000, .irq_vec = 13,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 3,
+ .irq_fcn = ptp_ocp_signal_irq,
+ .enable = ptp_ocp_signal_enable,
+ },
+ },
+ {
+ OCP_EXT_RESOURCE(signal_out[3]),
+ .offset = 0x01100000, .size = 0x10000, .irq_vec = 14,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 4,
+ .irq_fcn = ptp_ocp_signal_irq,
+ .enable = ptp_ocp_signal_enable,
+ },
+ },
{
OCP_MEM_RESOURCE(pps_to_ext),
.offset = 0x01030000, .size = 0x10000,
@@ -548,15 +624,19 @@ static struct ocp_selector ptp_ocp_sma_in[] = {
};
static struct ocp_selector ptp_ocp_sma_out[] = {
- { .name = "10Mhz", .value = 0x00 },
- { .name = "PHC", .value = 0x01 },
- { .name = "MAC", .value = 0x02 },
- { .name = "GNSS1", .value = 0x04 },
- { .name = "GNSS2", .value = 0x08 },
- { .name = "IRIG", .value = 0x10 },
- { .name = "DCF", .value = 0x20 },
- { .name = "GND", .value = 0x2000 },
- { .name = "VCC", .value = 0x4000 },
+ { .name = "10Mhz", .value = 0x0000 },
+ { .name = "PHC", .value = 0x0001 },
+ { .name = "MAC", .value = 0x0002 },
+ { .name = "GNSS1", .value = 0x0004 },
+ { .name = "GNSS2", .value = 0x0008 },
+ { .name = "IRIG", .value = 0x0010 },
+ { .name = "DCF", .value = 0x0020 },
+ { .name = "GEN1", .value = 0x0040 },
+ { .name = "GEN2", .value = 0x0080 },
+ { .name = "GEN3", .value = 0x0100 },
+ { .name = "GEN4", .value = 0x0200 },
+ { .name = "GND", .value = 0x2000 },
+ { .name = "VCC", .value = 0x4000 },
{ }
};
@@ -1319,6 +1399,113 @@ ptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r)
return 0;
}
+/* The expectation is that this is triggered only on error. */
+static irqreturn_t
+ptp_ocp_signal_irq(int irq, void *priv)
+{
+ struct ptp_ocp_ext_src *ext = priv;
+ struct signal_reg __iomem *reg = ext->mem;
+ struct ptp_ocp *bp = ext->bp;
+ u32 enable, status;
+ int gen;
+
+ gen = ext->info->index - 1;
+
+ enable = ioread32(®->enable);
+ status = ioread32(®->status);
+
+ /* disable generator on error */
+ if (status || !enable) {
+ iowrite32(0, ®->intr_mask);
+ iowrite32(0, ®->enable);
+ bp->signal[gen].running = false;
+ }
+
+ iowrite32(0, ®->intr); /* ack interrupt */
+
+ return IRQ_HANDLED;
+}
+
+static int
+ptp_ocp_signal_set(struct ptp_ocp *bp, int gen, struct ptp_ocp_signal *s)
+{
+ struct ptp_system_timestamp sts;
+ struct timespec64 ts;
+ ktime_t start_ns;
+ int err;
+
+ if (!s->period)
+ return 0;
+
+ if (!s->pulse)
+ s->pulse = ktime_divns(s->period * s->duty, 100);
+
+ err = ptp_ocp_gettimex(&bp->ptp_info, &ts, &sts);
+ if (err)
+ return err;
+
+ start_ns = ktime_set(ts.tv_sec, ts.tv_nsec) + NSEC_PER_MSEC;
+ if (!s->start) {
+ /* roundup() does not work on 32-bit systems */
+ s->start = DIV_ROUND_UP_ULL(start_ns, s->period);
+ s->start = ktime_add(s->start, s->phase);
+ }
+
+ if (s->duty < 1 || s->duty > 99)
+ return -EINVAL;
+
+ if (s->pulse < 1 || s->pulse > s->period)
+ return -EINVAL;
+
+ if (s->start < start_ns)
+ return -EINVAL;
+
+ bp->signal[gen] = *s;
+
+ return 0;
+}
+
+static int
+ptp_ocp_signal_enable(void *priv, u32 req, bool enable)
+{
+ struct ptp_ocp_ext_src *ext = priv;
+ struct signal_reg __iomem *reg = ext->mem;
+ struct ptp_ocp *bp = ext->bp;
+ struct timespec64 ts;
+ int gen;
+
+ gen = ext->info->index - 1;
+
+ iowrite32(0, ®->intr_mask);
+ iowrite32(0, ®->enable);
+ bp->signal[gen].running = false;
+ if (!enable)
+ return 0;
+
+ ts = ktime_to_timespec64(bp->signal[gen].start);
+ iowrite32(ts.tv_sec, ®->start_sec);
+ iowrite32(ts.tv_nsec, ®->start_ns);
+
+ ts = ktime_to_timespec64(bp->signal[gen].period);
+ iowrite32(ts.tv_sec, ®->period_sec);
+ iowrite32(ts.tv_nsec, ®->period_ns);
+
+ ts = ktime_to_timespec64(bp->signal[gen].pulse);
+ iowrite32(ts.tv_sec, ®->pulse_sec);
+ iowrite32(ts.tv_nsec, ®->pulse_ns);
+
+ iowrite32(bp->signal[gen].polarity, ®->polarity);
+ iowrite32(0, ®->repeat_count);
+
+ iowrite32(0, ®->intr); /* clear interrupt state */
+ iowrite32(1, ®->intr_mask); /* enable interrupt */
+ iowrite32(3, ®->enable); /* valid & enable */
+
+ bp->signal[gen].running = true;
+
+ return 0;
+}
+
static irqreturn_t
ptp_ocp_ts_irq(int irq, void *priv)
{
@@ -1491,6 +1678,29 @@ ptp_ocp_nmea_out_init(struct ptp_ocp *bp)
iowrite32(1, &bp->nmea_out->ctrl); /* enable */
}
+static void
+_ptp_ocp_signal_init(struct ptp_ocp_signal *s, struct signal_reg __iomem *reg)
+{
+ u32 val;
+
+ iowrite32(0, ®->enable); /* disable */
+
+ val = ioread32(®->polarity);
+ s->polarity = val ? true : false;
+ s->duty = 50;
+}
+
+static void
+ptp_ocp_signal_init(struct ptp_ocp *bp)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ if (bp->signal_out[i])
+ _ptp_ocp_signal_init(&bp->signal[i],
+ bp->signal_out[i]->mem);
+}
+
static void
ptp_ocp_sma_init(struct ptp_ocp *bp)
{
@@ -1534,15 +1744,22 @@ ptp_ocp_sma_init(struct ptp_ocp *bp)
static int
ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
{
+ int ver;
+
bp->flash_start = 1024 * 4096;
bp->eeprom_map = fb_eeprom_map;
bp->fw_version = ioread32(&bp->image->version);
bp->attr_tbl = fb_timecard_groups;
bp->fw_cap = OCP_CAP_BASIC;
+ ver = bp->fw_version & 0xffff;
+ if (ver >= 19)
+ bp->fw_cap |= OCP_CAP_SIGNAL;
+
ptp_ocp_tod_init(bp);
ptp_ocp_nmea_out_init(bp);
ptp_ocp_sma_init(bp);
+ ptp_ocp_signal_init(bp);
return ptp_ocp_init_clock(bp);
}
@@ -1946,6 +2163,189 @@ available_sma_outputs_show(struct device *dev,
}
static DEVICE_ATTR_RO(available_sma_outputs);
+#define EXT_ATTR_RO(_group, _name, _val) \
+ struct dev_ext_attribute dev_attr_##_group##_val##_##_name = \
+ { __ATTR_RO(_name), (void *)_val }
+#define EXT_ATTR_RW(_group, _name, _val) \
+ struct dev_ext_attribute dev_attr_##_group##_val##_##_name = \
+ { __ATTR_RW(_name), (void *)_val }
+#define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr)
+
+/* period [duty [phase [polarity]]] */
+static ssize_t
+signal_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ struct ptp_ocp_signal s = { };
+ int gen = (uintptr_t)ea->var;
+ int argc, err;
+ char **argv;
+
+ argv = argv_split(GFP_KERNEL, buf, &argc);
+ if (!argv)
+ return -ENOMEM;
+
+ err = -EINVAL;
+ s.duty = bp->signal[gen].duty;
+ s.phase = bp->signal[gen].phase;
+ s.period = bp->signal[gen].period;
+ s.polarity = bp->signal[gen].polarity;
+
+ switch (argc) {
+ case 4:
+ argc--;
+ err = kstrtobool(argv[argc], &s.polarity);
+ if (err)
+ goto out;
+ fallthrough;
+ case 3:
+ argc--;
+ err = kstrtou64(argv[argc], 0, &s.phase);
+ if (err)
+ goto out;
+ fallthrough;
+ case 2:
+ argc--;
+ err = kstrtoint(argv[argc], 0, &s.duty);
+ if (err)
+ goto out;
+ fallthrough;
+ case 1:
+ argc--;
+ err = kstrtou64(argv[argc], 0, &s.period);
+ if (err)
+ goto out;
+ break;
+ default:
+ goto out;
+ }
+
+ err = ptp_ocp_signal_set(bp, gen, &s);
+ if (err)
+ goto out;
+
+ err = ptp_ocp_signal_enable(bp->signal_out[gen], gen, s.period != 0);
+
+out:
+ argv_free(argv);
+ return err ? err : count;
+}
+
+static ssize_t
+signal_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ struct ptp_ocp_signal *signal;
+ struct timespec64 ts;
+ ssize_t count;
+ int i;
+
+ i = (uintptr_t)ea->var;
+ signal = &bp->signal[i];
+
+ count = sysfs_emit(buf, "%llu %d %llu %d", signal->period,
+ signal->duty, signal->phase, signal->polarity);
+
+ ts = ktime_to_timespec64(signal->start);
+ count += sysfs_emit_at(buf, count, " %ptT TAI\n", &ts);
+
+ return count;
+}
+static EXT_ATTR_RW(signal, signal, 0);
+static EXT_ATTR_RW(signal, signal, 1);
+static EXT_ATTR_RW(signal, signal, 2);
+static EXT_ATTR_RW(signal, signal, 3);
+
+static ssize_t
+duty_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ int i = (uintptr_t)ea->var;
+
+ return sysfs_emit(buf, "%d\n", bp->signal[i].duty);
+}
+static EXT_ATTR_RO(signal, duty, 0);
+static EXT_ATTR_RO(signal, duty, 1);
+static EXT_ATTR_RO(signal, duty, 2);
+static EXT_ATTR_RO(signal, duty, 3);
+
+static ssize_t
+period_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ int i = (uintptr_t)ea->var;
+
+ return sysfs_emit(buf, "%llu\n", bp->signal[i].period);
+}
+static EXT_ATTR_RO(signal, period, 0);
+static EXT_ATTR_RO(signal, period, 1);
+static EXT_ATTR_RO(signal, period, 2);
+static EXT_ATTR_RO(signal, period, 3);
+
+static ssize_t
+phase_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ int i = (uintptr_t)ea->var;
+
+ return sysfs_emit(buf, "%llu\n", bp->signal[i].phase);
+}
+static EXT_ATTR_RO(signal, phase, 0);
+static EXT_ATTR_RO(signal, phase, 1);
+static EXT_ATTR_RO(signal, phase, 2);
+static EXT_ATTR_RO(signal, phase, 3);
+
+static ssize_t
+polarity_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ int i = (uintptr_t)ea->var;
+
+ return sysfs_emit(buf, "%d\n", bp->signal[i].polarity);
+}
+static EXT_ATTR_RO(signal, polarity, 0);
+static EXT_ATTR_RO(signal, polarity, 1);
+static EXT_ATTR_RO(signal, polarity, 2);
+static EXT_ATTR_RO(signal, polarity, 3);
+
+static ssize_t
+running_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ int i = (uintptr_t)ea->var;
+
+ return sysfs_emit(buf, "%d\n", bp->signal[i].running);
+}
+static EXT_ATTR_RO(signal, running, 0);
+static EXT_ATTR_RO(signal, running, 1);
+static EXT_ATTR_RO(signal, running, 2);
+static EXT_ATTR_RO(signal, running, 3);
+
+static ssize_t
+start_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ int i = (uintptr_t)ea->var;
+ struct timespec64 ts;
+
+ ts = ktime_to_timespec64(bp->signal[i].start);
+ return sysfs_emit(buf, "%llu.%lu\n", ts.tv_sec, ts.tv_nsec);
+}
+static EXT_ATTR_RO(signal, start, 0);
+static EXT_ATTR_RO(signal, start, 1);
+static EXT_ATTR_RO(signal, start, 2);
+static EXT_ATTR_RO(signal, start, 3);
+
static ssize_t
serialnum_show(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -2180,6 +2580,31 @@ tod_correction_store(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RW(tod_correction);
+#define _DEVICE_SIGNAL_GROUP_ATTRS(_nr) \
+ static struct attribute *fb_timecard_signal##_nr##_attrs[] = { \
+ &dev_attr_signal##_nr##_signal.attr.attr, \
+ &dev_attr_signal##_nr##_duty.attr.attr, \
+ &dev_attr_signal##_nr##_phase.attr.attr, \
+ &dev_attr_signal##_nr##_period.attr.attr, \
+ &dev_attr_signal##_nr##_polarity.attr.attr, \
+ &dev_attr_signal##_nr##_running.attr.attr, \
+ &dev_attr_signal##_nr##_start.attr.attr, \
+ NULL, \
+ }
+
+#define DEVICE_SIGNAL_GROUP(_name, _nr) \
+ _DEVICE_SIGNAL_GROUP_ATTRS(_nr); \
+ static const struct attribute_group \
+ fb_timecard_signal##_nr##_group = { \
+ .name = #_name, \
+ .attrs = fb_timecard_signal##_nr##_attrs, \
+}
+
+DEVICE_SIGNAL_GROUP(gen1, 0);
+DEVICE_SIGNAL_GROUP(gen2, 1);
+DEVICE_SIGNAL_GROUP(gen3, 2);
+DEVICE_SIGNAL_GROUP(gen4, 3);
+
static struct attribute *fb_timecard_attrs[] = {
&dev_attr_serialnum.attr,
&dev_attr_gnss_sync.attr,
@@ -2204,6 +2629,10 @@ static const struct attribute_group fb_timecard_group = {
};
static const struct ocp_attr_group fb_timecard_groups[] = {
{ .cap = OCP_CAP_BASIC, .group = &fb_timecard_group },
+ { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal0_group },
+ { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal1_group },
+ { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal2_group },
+ { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal3_group },
{ },
};
@@ -2241,6 +2670,33 @@ gpio_output_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit)
}
}
+static void
+_signal_summary_show(struct seq_file *s, struct ptp_ocp *bp, int nr)
+{
+ struct signal_reg __iomem *reg = bp->signal_out[nr]->mem;
+ struct ptp_ocp_signal *signal = &bp->signal[nr];
+ char label[8];
+ bool on;
+ u32 val;
+
+ if (!signal)
+ return;
+
+ on = signal->running;
+ sprintf(label, "GEN%d", nr);
+ seq_printf(s, "%7s: %s, period:%llu duty:%d%% phase:%llu pol:%d",
+ label, on ? " ON" : "OFF",
+ signal->period, signal->duty, signal->phase,
+ signal->polarity);
+
+ val = ioread32(®->enable);
+ seq_printf(s, " [%x", val);
+ val = ioread32(®->status);
+ seq_printf(s, " %x]", val);
+
+ seq_printf(s, " start:%llu\n", signal->start);
+}
+
static int
ptp_ocp_summary_show(struct seq_file *s, void *data)
{
@@ -2252,6 +2708,7 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
struct ptp_ocp *bp;
char *src, *buf;
bool on, map;
+ int i;
buf = (char *)__get_free_page(GFP_KERNEL);
if (!buf)
@@ -2343,6 +2800,10 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
on && map ? " ON" : "OFF", src);
}
+ if (bp->fw_cap & OCP_CAP_SIGNAL)
+ for (i = 0; i < 4; i++)
+ _signal_summary_show(s, bp, i);
+
if (bp->irig_out) {
ctrl = ioread32(&bp->irig_out->ctrl);
on = ctrl & IRIG_M_CTRL_ENABLE;
@@ -2742,6 +3203,8 @@ ptp_ocp_detach_sysfs(struct ptp_ocp *bp)
static void
ptp_ocp_detach(struct ptp_ocp *bp)
{
+ int i;
+
ptp_ocp_debugfs_remove_device(bp);
ptp_ocp_detach_sysfs(bp);
if (timer_pending(&bp->watchdog))
@@ -2754,6 +3217,9 @@ ptp_ocp_detach(struct ptp_ocp *bp)
ptp_ocp_unregister_ext(bp->ts2);
if (bp->pps)
ptp_ocp_unregister_ext(bp->pps);
+ for (i = 0; i < 4; i++)
+ if (bp->signal_out[i])
+ ptp_ocp_unregister_ext(bp->signal_out[i]);
if (bp->gnss_port != -1)
serial8250_unregister_port(bp->gnss_port);
if (bp->gnss2_port != -1)
@@ -2804,7 +3270,7 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
* allow this - if not all of the IRQ's are returned, skip the
* extra devices and just register the clock.
*/
- err = pci_alloc_irq_vectors(pdev, 1, 11, PCI_IRQ_MSI | PCI_IRQ_MSIX);
+ err = pci_alloc_irq_vectors(pdev, 1, 15, PCI_IRQ_MSI | PCI_IRQ_MSIX);
if (err < 0) {
dev_err(&pdev->dev, "alloc_irq_vectors err: %d\n", err);
goto out;
--
2.31.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 07/10] ptp: ocp: Program the signal generators via PTP_CLK_REQ_PEROUT
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
` (5 preceding siblings ...)
2022-03-10 20:19 ` [PATCH net-next v2 06/10] ptp: ocp: Add signal generators and update sysfs nodes Jonathan Lemon
@ 2022-03-10 20:19 ` Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 08/10] ptp: ocp: Add 4 frequency counters Jonathan Lemon
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
The signal generators can be programmed either via the sysfs
file or through a PTP_CLK_REQ_PEROUT ioctl request.
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
drivers/ptp/ptp_ocp.c | 103 ++++++++++++++++++++++++++++++++++++++----
1 file changed, 94 insertions(+), 9 deletions(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 397e3e6b840f..002b3d00996e 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -332,6 +332,8 @@ static int ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
static irqreturn_t ptp_ocp_ts_irq(int irq, void *priv);
static irqreturn_t ptp_ocp_signal_irq(int irq, void *priv);
static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
+static int ptp_ocp_signal_from_perout(struct ptp_ocp *bp, int gen,
+ struct ptp_perout_request *req);
static int ptp_ocp_signal_enable(void *priv, u32 req, bool enable);
static int ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr);
@@ -867,13 +869,27 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
ext = bp->pps;
break;
case PTP_CLK_REQ_PEROUT:
- if (on &&
- (rq->perout.period.sec != 1 || rq->perout.period.nsec != 0))
- return -EINVAL;
- /* This is a request for 1PPS on an output SMA.
- * Allow, but assume manual configuration.
- */
- return 0;
+ switch (rq->perout.index) {
+ case 0:
+ /* This is a request for 1PPS on an output SMA.
+ * Allow, but assume manual configuration.
+ */
+ if (on && (rq->perout.period.sec != 1 ||
+ rq->perout.period.nsec != 0))
+ return -EINVAL;
+ return 0;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ req = rq->perout.index - 1;
+ ext = bp->signal_out[req];
+ err = ptp_ocp_signal_from_perout(bp, req, &rq->perout);
+ if (err)
+ return err;
+ break;
+ }
+ break;
default:
return -EOPNOTSUPP;
}
@@ -885,6 +901,24 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
return err;
}
+static int
+ptp_ocp_verify(struct ptp_clock_info *ptp_info, unsigned pin,
+ enum ptp_pin_function func, unsigned chan)
+{
+ struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
+ char buf[16];
+
+ if (func != PTP_PF_PEROUT)
+ return -EOPNOTSUPP;
+
+ if (chan)
+ sprintf(buf, "OUT: GEN%d", chan);
+ else
+ sprintf(buf, "OUT: PHC");
+
+ return ptp_ocp_sma_store(bp, buf, pin + 1);
+}
+
static const struct ptp_clock_info ptp_ocp_clock_info = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
@@ -895,9 +929,10 @@ static const struct ptp_clock_info ptp_ocp_clock_info = {
.adjfine = ptp_ocp_null_adjfine,
.adjphase = ptp_ocp_null_adjphase,
.enable = ptp_ocp_enable,
+ .verify = ptp_ocp_verify,
.pps = true,
.n_ext_ts = 4,
- .n_per_out = 1,
+ .n_per_out = 5,
};
static void
@@ -1465,6 +1500,30 @@ ptp_ocp_signal_set(struct ptp_ocp *bp, int gen, struct ptp_ocp_signal *s)
return 0;
}
+static int
+ptp_ocp_signal_from_perout(struct ptp_ocp *bp, int gen,
+ struct ptp_perout_request *req)
+{
+ struct ptp_ocp_signal s = { };
+
+ s.polarity = bp->signal[gen].polarity;
+ s.period = ktime_set(req->period.sec, req->period.nsec);
+ if (!s.period)
+ return 0;
+
+ if (req->flags & PTP_PEROUT_DUTY_CYCLE) {
+ s.pulse = ktime_set(req->on.sec, req->on.nsec);
+ s.duty = ktime_divns(s.pulse * 100, s.period);
+ }
+
+ if (req->flags & PTP_PEROUT_PHASE)
+ s.phase = ktime_set(req->phase.sec, req->phase.nsec);
+ else
+ s.start = ktime_set(req->start.sec, req->start.nsec);
+
+ return ptp_ocp_signal_set(bp, gen, &s);
+}
+
static int
ptp_ocp_signal_enable(void *priv, u32 req, bool enable)
{
@@ -1740,11 +1799,32 @@ ptp_ocp_sma_init(struct ptp_ocp *bp)
}
}
+static int
+ptp_ocp_fb_set_pins(struct ptp_ocp *bp)
+{
+ struct ptp_pin_desc *config;
+ int i;
+
+ config = kzalloc(sizeof(*config) * 4, GFP_KERNEL);
+ if (!config)
+ return -ENOMEM;
+
+ for (i = 0; i < 4; i++) {
+ sprintf(config[i].name, "sma%d", i + 1);
+ config[i].index = i;
+ }
+
+ bp->ptp_info.n_pins = 4;
+ bp->ptp_info.pin_config = config;
+
+ return 0;
+}
+
/* FB specific board initializers; last "resource" registered. */
static int
ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
{
- int ver;
+ int ver, err;
bp->flash_start = 1024 * 4096;
bp->eeprom_map = fb_eeprom_map;
@@ -1761,6 +1841,10 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
ptp_ocp_sma_init(bp);
ptp_ocp_signal_init(bp);
+ err = ptp_ocp_fb_set_pins(bp);
+ if (err)
+ return err;
+
return ptp_ocp_init_clock(bp);
}
@@ -3238,6 +3322,7 @@ ptp_ocp_detach(struct ptp_ocp *bp)
pci_free_irq_vectors(bp->pdev);
if (bp->ptp)
ptp_clock_unregister(bp->ptp);
+ kfree(bp->ptp_info.pin_config);
device_unregister(&bp->dev);
}
--
2.31.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 08/10] ptp: ocp: Add 4 frequency counters
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
` (6 preceding siblings ...)
2022-03-10 20:19 ` [PATCH net-next v2 07/10] ptp: ocp: Program the signal generators via PTP_CLK_REQ_PEROUT Jonathan Lemon
@ 2022-03-10 20:19 ` Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 09/10] ptp: ocp: Add 2 more timestampers Jonathan Lemon
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
Input signals can be steered to any of the frequency counters.
The counter measures the frequency over a number of seconds:
echo 0 > freq1/seconds = turns off measurement
echo 1 > freq1/seconds = sets period & turns on measurment.
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
drivers/ptp/ptp_ocp.c | 172 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 165 insertions(+), 7 deletions(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 002b3d00996e..d2ef4e7fcc47 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -199,6 +199,15 @@ struct signal_reg {
u32 repeat_count;
};
+struct frequency_reg {
+ u32 ctrl;
+ u32 status;
+};
+#define FREQ_STATUS_VALID BIT(31)
+#define FREQ_STATUS_ERROR BIT(30)
+#define FREQ_STATUS_OVERRUN BIT(29)
+#define FREQ_STATUS_MASK (BIT(24) - 1)
+
struct ptp_ocp_flash_info {
const char *name;
int pci_offset;
@@ -245,6 +254,7 @@ struct ocp_attr_group {
#define OCP_CAP_BASIC BIT(0)
#define OCP_CAP_SIGNAL BIT(1)
+#define OCP_CAP_FREQ BIT(2)
struct ptp_ocp_signal {
ktime_t period;
@@ -275,6 +285,7 @@ struct ptp_ocp {
struct dcf_master_reg __iomem *dcf_out;
struct dcf_slave_reg __iomem *dcf_in;
struct tod_reg __iomem *nmea_out;
+ struct frequency_reg __iomem *freq_in[4];
struct ptp_ocp_ext_src *signal_out[4];
struct ptp_ocp_ext_src *pps;
struct ptp_ocp_ext_src *ts0;
@@ -576,6 +587,22 @@ static struct ocp_resource ocp_fb_resource[] = {
},
},
},
+ {
+ OCP_MEM_RESOURCE(freq_in[0]),
+ .offset = 0x01200000, .size = 0x10000,
+ },
+ {
+ OCP_MEM_RESOURCE(freq_in[1]),
+ .offset = 0x01210000, .size = 0x10000,
+ },
+ {
+ OCP_MEM_RESOURCE(freq_in[2]),
+ .offset = 0x01220000, .size = 0x10000,
+ },
+ {
+ OCP_MEM_RESOURCE(freq_in[3]),
+ .offset = 0x01230000, .size = 0x10000,
+ },
{
.setup = ptp_ocp_fb_board_init,
},
@@ -614,13 +641,17 @@ static struct ocp_selector ptp_ocp_clock[] = {
#define SMA_DISABLE 0x10000
static struct ocp_selector ptp_ocp_sma_in[] = {
- { .name = "10Mhz", .value = 0x00 },
- { .name = "PPS1", .value = 0x01 },
- { .name = "PPS2", .value = 0x02 },
- { .name = "TS1", .value = 0x04 },
- { .name = "TS2", .value = 0x08 },
- { .name = "IRIG", .value = 0x10 },
- { .name = "DCF", .value = 0x20 },
+ { .name = "10Mhz", .value = 0x0000 },
+ { .name = "PPS1", .value = 0x0001 },
+ { .name = "PPS2", .value = 0x0002 },
+ { .name = "TS1", .value = 0x0004 },
+ { .name = "TS2", .value = 0x0008 },
+ { .name = "IRIG", .value = 0x0010 },
+ { .name = "DCF", .value = 0x0020 },
+ { .name = "FREQ1", .value = 0x0100 },
+ { .name = "FREQ2", .value = 0x0200 },
+ { .name = "FREQ3", .value = 0x0400 },
+ { .name = "FREQ4", .value = 0x0800 },
{ .name = "None", .value = SMA_DISABLE },
{ }
};
@@ -1835,6 +1866,8 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
ver = bp->fw_version & 0xffff;
if (ver >= 19)
bp->fw_cap |= OCP_CAP_SIGNAL;
+ if (ver >= 20)
+ bp->fw_cap |= OCP_CAP_FREQ;
ptp_ocp_tod_init(bp);
ptp_ocp_nmea_out_init(bp);
@@ -2430,6 +2463,73 @@ static EXT_ATTR_RO(signal, start, 1);
static EXT_ATTR_RO(signal, start, 2);
static EXT_ATTR_RO(signal, start, 3);
+static ssize_t
+seconds_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ int idx = (uintptr_t)ea->var;
+ u32 val;
+ int err;
+
+ err = kstrtou32(buf, 0, &val);
+ if (err)
+ return err;
+ if (val > 0xff)
+ return -EINVAL;
+
+ if (val)
+ val = (val << 8) | 0x1;
+
+ iowrite32(val, &bp->freq_in[idx]->ctrl);
+
+ return count;
+}
+
+static ssize_t
+seconds_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ int idx = (uintptr_t)ea->var;
+ u32 val;
+
+ val = ioread32(&bp->freq_in[idx]->ctrl);
+ if (val & 1)
+ val = (val >> 8) & 0xff;
+ else
+ val = 0;
+
+ return sysfs_emit(buf, "%u\n", val);
+}
+static EXT_ATTR_RW(freq, seconds, 0);
+static EXT_ATTR_RW(freq, seconds, 1);
+static EXT_ATTR_RW(freq, seconds, 2);
+static EXT_ATTR_RW(freq, seconds, 3);
+
+static ssize_t
+frequency_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ int idx = (uintptr_t)ea->var;
+ u32 val;
+
+ val = ioread32(&bp->freq_in[idx]->status);
+ if (val & FREQ_STATUS_ERROR)
+ return sysfs_emit(buf, "error\n");
+ if (val & FREQ_STATUS_OVERRUN)
+ return sysfs_emit(buf, "overrun\n");
+ if (val & FREQ_STATUS_VALID)
+ return sysfs_emit(buf, "%lu\n", val & FREQ_STATUS_MASK);
+ return 0;
+}
+static EXT_ATTR_RO(freq, frequency, 0);
+static EXT_ATTR_RO(freq, frequency, 1);
+static EXT_ATTR_RO(freq, frequency, 2);
+static EXT_ATTR_RO(freq, frequency, 3);
+
static ssize_t
serialnum_show(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -2689,6 +2789,26 @@ DEVICE_SIGNAL_GROUP(gen2, 1);
DEVICE_SIGNAL_GROUP(gen3, 2);
DEVICE_SIGNAL_GROUP(gen4, 3);
+#define _DEVICE_FREQ_GROUP_ATTRS(_nr) \
+ static struct attribute *fb_timecard_freq##_nr##_attrs[] = { \
+ &dev_attr_freq##_nr##_seconds.attr.attr, \
+ &dev_attr_freq##_nr##_frequency.attr.attr, \
+ NULL, \
+ }
+
+#define DEVICE_FREQ_GROUP(_name, _nr) \
+ _DEVICE_FREQ_GROUP_ATTRS(_nr); \
+ static const struct attribute_group \
+ fb_timecard_freq##_nr##_group = { \
+ .name = #_name, \
+ .attrs = fb_timecard_freq##_nr##_attrs, \
+}
+
+DEVICE_FREQ_GROUP(freq1, 0);
+DEVICE_FREQ_GROUP(freq2, 1);
+DEVICE_FREQ_GROUP(freq3, 2);
+DEVICE_FREQ_GROUP(freq4, 3);
+
static struct attribute *fb_timecard_attrs[] = {
&dev_attr_serialnum.attr,
&dev_attr_gnss_sync.attr,
@@ -2717,6 +2837,10 @@ static const struct ocp_attr_group fb_timecard_groups[] = {
{ .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal1_group },
{ .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal2_group },
{ .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal3_group },
+ { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq0_group },
+ { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq1_group },
+ { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq2_group },
+ { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq3_group },
{ },
};
@@ -2781,6 +2905,36 @@ _signal_summary_show(struct seq_file *s, struct ptp_ocp *bp, int nr)
seq_printf(s, " start:%llu\n", signal->start);
}
+static void
+_frequency_summary_show(struct seq_file *s, int nr,
+ struct frequency_reg __iomem *reg)
+{
+ char label[8];
+ bool on;
+ u32 val;
+
+ if (!reg)
+ return;
+
+ sprintf(label, "FREQ%d", nr);
+ val = ioread32(®->ctrl);
+ on = val & 1;
+ val = (val >> 8) & 0xff;
+ seq_printf(s, "%7s: %s, sec:%u",
+ label,
+ on ? " ON" : "OFF",
+ val);
+
+ val = ioread32(®->status);
+ if (val & FREQ_STATUS_ERROR)
+ seq_printf(s, ", error");
+ if (val & FREQ_STATUS_OVERRUN)
+ seq_printf(s, ", overrun");
+ if (val & FREQ_STATUS_VALID)
+ seq_printf(s, ", freq %lu Hz", val & FREQ_STATUS_MASK);
+ seq_printf(s, " reg:%x\n", val);
+}
+
static int
ptp_ocp_summary_show(struct seq_file *s, void *data)
{
@@ -2888,6 +3042,10 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
for (i = 0; i < 4; i++)
_signal_summary_show(s, bp, i);
+ if (bp->fw_cap & OCP_CAP_FREQ)
+ for (i = 0; i < 4; i++)
+ _frequency_summary_show(s, i, bp->freq_in[i]);
+
if (bp->irig_out) {
ctrl = ioread32(&bp->irig_out->ctrl);
on = ctrl & IRIG_M_CTRL_ENABLE;
--
2.31.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 09/10] ptp: ocp: Add 2 more timestampers
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
` (7 preceding siblings ...)
2022-03-10 20:19 ` [PATCH net-next v2 08/10] ptp: ocp: Add 4 frequency counters Jonathan Lemon
@ 2022-03-10 20:19 ` Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 10/10] docs: ABI: Document new timecard sysfs nodes Jonathan Lemon
2022-03-11 12:00 ` [PATCH net-next v2 00/10] ptp: ocp: support for new firmware patchwork-bot+netdevbpf
10 siblings, 0 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
The timecard now has 4 general purpose timestampers.
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
drivers/ptp/ptp_ocp.c | 61 +++++++++++++++++++++++++++++++++++++++----
1 file changed, 56 insertions(+), 5 deletions(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index d2ef4e7fcc47..fc1864c988e4 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -291,6 +291,8 @@ struct ptp_ocp {
struct ptp_ocp_ext_src *ts0;
struct ptp_ocp_ext_src *ts1;
struct ptp_ocp_ext_src *ts2;
+ struct ptp_ocp_ext_src *ts3;
+ struct ptp_ocp_ext_src *ts4;
struct img_reg __iomem *image;
struct ptp_clock *ptp;
struct ptp_clock_info ptp_info;
@@ -396,7 +398,7 @@ static struct ptp_ocp_eeprom_map fb_eeprom_map[] = {
OCP_RES_LOCATION(member), .setup = ptp_ocp_register_ext
/* This is the MSI vector mapping used.
- * 0: TS3 (and PPS)
+ * 0: PPS (TS5)
* 1: TS0
* 2: TS1
* 3: GNSS1
@@ -411,6 +413,8 @@ static struct ptp_ocp_eeprom_map fb_eeprom_map[] = {
* 12: Signal Generator 2
* 13: Signal Generator 3
* 14: Signal Generator 4
+ * 15: TS3
+ * 16: TS4
*/
static struct ocp_resource ocp_fb_resource[] = {
@@ -445,11 +449,30 @@ static struct ocp_resource ocp_fb_resource[] = {
.enable = ptp_ocp_ts_enable,
},
},
+ {
+ OCP_EXT_RESOURCE(ts3),
+ .offset = 0x01110000, .size = 0x10000, .irq_vec = 15,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 3,
+ .irq_fcn = ptp_ocp_ts_irq,
+ .enable = ptp_ocp_ts_enable,
+ },
+ },
+ {
+ OCP_EXT_RESOURCE(ts4),
+ .offset = 0x01120000, .size = 0x10000, .irq_vec = 16,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 4,
+ .irq_fcn = ptp_ocp_ts_irq,
+ .enable = ptp_ocp_ts_enable,
+ },
+ },
+ /* Timestamp for PHC and/or PPS generator */
{
OCP_EXT_RESOURCE(pps),
.offset = 0x010C0000, .size = 0x10000, .irq_vec = 0,
.extra = &(struct ptp_ocp_ext_info) {
- .index = 3,
+ .index = 5,
.irq_fcn = ptp_ocp_ts_irq,
.enable = ptp_ocp_ts_enable,
},
@@ -648,6 +671,8 @@ static struct ocp_selector ptp_ocp_sma_in[] = {
{ .name = "TS2", .value = 0x0008 },
{ .name = "IRIG", .value = 0x0010 },
{ .name = "DCF", .value = 0x0020 },
+ { .name = "TS3", .value = 0x0040 },
+ { .name = "TS4", .value = 0x0080 },
{ .name = "FREQ1", .value = 0x0100 },
{ .name = "FREQ2", .value = 0x0200 },
{ .name = "FREQ3", .value = 0x0400 },
@@ -891,6 +916,12 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
ext = bp->ts2;
break;
case 3:
+ ext = bp->ts3;
+ break;
+ case 4:
+ ext = bp->ts4;
+ break;
+ case 5:
ext = bp->pps;
break;
}
@@ -962,7 +993,7 @@ static const struct ptp_clock_info ptp_ocp_clock_info = {
.enable = ptp_ocp_enable,
.verify = ptp_ocp_verify,
.pps = true,
- .n_ext_ts = 4,
+ .n_ext_ts = 6,
.n_per_out = 5,
};
@@ -3025,12 +3056,28 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
on ? " ON" : "OFF", buf);
}
+ if (bp->ts3) {
+ ts_reg = bp->ts3->mem;
+ on = ioread32(&ts_reg->enable);
+ gpio_input_map(buf, bp, sma_val, 6, NULL);
+ seq_printf(s, "%7s: %s, src: %s\n", "TS3",
+ on ? " ON" : "OFF", buf);
+ }
+
+ if (bp->ts4) {
+ ts_reg = bp->ts4->mem;
+ on = ioread32(&ts_reg->enable);
+ gpio_input_map(buf, bp, sma_val, 7, NULL);
+ seq_printf(s, "%7s: %s, src: %s\n", "TS4",
+ on ? " ON" : "OFF", buf);
+ }
+
if (bp->pps) {
ts_reg = bp->pps->mem;
src = "PHC";
on = ioread32(&ts_reg->enable);
map = !!(bp->pps_req_map & OCP_REQ_TIMESTAMP);
- seq_printf(s, "%7s: %s, src: %s\n", "TS3",
+ seq_printf(s, "%7s: %s, src: %s\n", "TS5",
on && map ? " ON" : "OFF", src);
map = !!(bp->pps_req_map & OCP_REQ_PPS);
@@ -3457,6 +3504,10 @@ ptp_ocp_detach(struct ptp_ocp *bp)
ptp_ocp_unregister_ext(bp->ts1);
if (bp->ts2)
ptp_ocp_unregister_ext(bp->ts2);
+ if (bp->ts3)
+ ptp_ocp_unregister_ext(bp->ts3);
+ if (bp->ts4)
+ ptp_ocp_unregister_ext(bp->ts4);
if (bp->pps)
ptp_ocp_unregister_ext(bp->pps);
for (i = 0; i < 4; i++)
@@ -3513,7 +3564,7 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
* allow this - if not all of the IRQ's are returned, skip the
* extra devices and just register the clock.
*/
- err = pci_alloc_irq_vectors(pdev, 1, 15, PCI_IRQ_MSI | PCI_IRQ_MSIX);
+ err = pci_alloc_irq_vectors(pdev, 1, 17, PCI_IRQ_MSI | PCI_IRQ_MSIX);
if (err < 0) {
dev_err(&pdev->dev, "alloc_irq_vectors err: %d\n", err);
goto out;
--
2.31.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 10/10] docs: ABI: Document new timecard sysfs nodes.
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
` (8 preceding siblings ...)
2022-03-10 20:19 ` [PATCH net-next v2 09/10] ptp: ocp: Add 2 more timestampers Jonathan Lemon
@ 2022-03-10 20:19 ` Jonathan Lemon
2022-03-11 12:00 ` [PATCH net-next v2 00/10] ptp: ocp: support for new firmware patchwork-bot+netdevbpf
10 siblings, 0 replies; 12+ messages in thread
From: Jonathan Lemon @ 2022-03-10 20:19 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, richardcochran, kernel-team
Add sysfs nodes for the frequency generator and signal counters.
Update SMA selector lists for these, and also add the new
'None', 'VCC' 'GND' selectors.
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
Documentation/ABI/testing/sysfs-timecard | 94 +++++++++++++++++++++++-
1 file changed, 93 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/sysfs-timecard b/Documentation/ABI/testing/sysfs-timecard
index 5bf78486a469..220478156297 100644
--- a/Documentation/ABI/testing/sysfs-timecard
+++ b/Documentation/ABI/testing/sysfs-timecard
@@ -37,8 +37,15 @@ Description: (RO) Set of available destinations (sinks) for a SMA
PPS2 signal is sent to the PPS2 selector
TS1 signal is sent to timestamper 1
TS2 signal is sent to timestamper 2
+ TS3 signal is sent to timestamper 3
+ TS4 signal is sent to timestamper 4
IRIG signal is sent to the IRIG-B module
DCF signal is sent to the DCF module
+ FREQ1 signal is sent to frequency counter 1
+ FREQ2 signal is sent to frequency counter 2
+ FREQ3 signal is sent to frequency counter 3
+ FREQ4 signal is sent to frequency counter 4
+ None signal input is disabled
===== ================================================
What: /sys/class/timecard/ocpN/available_sma_outputs
@@ -50,10 +57,16 @@ Description: (RO) Set of available sources for a SMA output signal.
10Mhz output is from the 10Mhz reference clock
PHC output PPS is from the PHC clock
MAC output PPS is from the Miniature Atomic Clock
- GNSS output PPS is from the GNSS module
+ GNSS1 output PPS is from the first GNSS module
GNSS2 output PPS is from the second GNSS module
IRIG output is from the PHC, in IRIG-B format
DCF output is from the PHC, in DCF format
+ GEN1 output is from frequency generator 1
+ GEN2 output is from frequency generator 2
+ GEN3 output is from frequency generator 3
+ GEN4 output is from frequency generator 4
+ GND output is GND
+ VCC output is VCC
===== ================================================
What: /sys/class/timecard/ocpN/clock_source
@@ -75,6 +88,85 @@ Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
Description: (RO) Contains the current offset value used by the firmware
for internal disciplining of the atomic clock.
+What: /sys/class/timecard/ocpN/freqX
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RO) Optional directory containing the sysfs nodes for
+ frequency counter <X>.
+
+What: /sys/class/timecard/ocpN/freqX/frequency
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RO) Contains the measured frequency over the specified
+ measurement period.
+
+What: /sys/class/timecard/ocpN/freqX/seconds
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RW) Specifies the number of seconds from 0-255 that the
+ frequency should be measured over. Write 0 to disable.
+
+What: /sys/class/timecard/ocpN/genX
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RO) Optional directory containing the sysfs nodes for
+ frequency generator <X>.
+
+What: /sys/class/timecard/ocpN/genX/duty
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RO) Specifies the signal duty cycle as a percentage from 1-99.
+
+What: /sys/class/timecard/ocpN/genX/period
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RO) Specifies the signal period in nanoseconds.
+
+What: /sys/class/timecard/ocpN/genX/phase
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RO) Specifies the signal phase offset in nanoseconds.
+
+What: /sys/class/timecard/ocpN/genX/polarity
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RO) Specifies the signal polarity, either 1 or 0.
+
+What: /sys/class/timecard/ocpN/genX/running
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RO) Either 0 or 1, showing if the signal generator is running.
+
+What: /sys/class/timecard/ocpN/genX/start
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RO) Shows the time in <sec>.<nsec> that the signal generator
+ started running.
+
+What: /sys/class/timecard/ocpN/genX/signal
+Date: March 2022
+Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
+Description: (RW) Used to start the signal generator, and summarize
+ the current status.
+
+ The signal generator may be started by writing the signal
+ period, followed by the optional signal values. If the
+ optional values are not provided, they default to the current
+ settings, which may be obtained from the other sysfs nodes.
+
+ period [duty [phase [polarity]]]
+
+ echo 500000000 > signal # 1/2 second period
+ echo 1000000 40 100 > signal
+ echo 0 > signal # turn off generator
+
+ Period and phase are specified in nanoseconds. Duty cycle is
+ a percentage from 1-99. Polarity is 1 or 0.
+
+ Reading this node will return:
+
+ period duty phase polarity start_time
+
What: /sys/class/timecard/ocpN/gnss_sync
Date: September 2021
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
--
2.31.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH net-next v2 00/10] ptp: ocp: support for new firmware
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
` (9 preceding siblings ...)
2022-03-10 20:19 ` [PATCH net-next v2 10/10] docs: ABI: Document new timecard sysfs nodes Jonathan Lemon
@ 2022-03-11 12:00 ` patchwork-bot+netdevbpf
10 siblings, 0 replies; 12+ messages in thread
From: patchwork-bot+netdevbpf @ 2022-03-11 12:00 UTC (permalink / raw)
To: Jonathan Lemon; +Cc: netdev, kuba, davem, richardcochran, kernel-team
Hello:
This series was applied to netdev/net-next.git (master)
by David S. Miller <davem@davemloft.net>:
On Thu, 10 Mar 2022 12:19:02 -0800 you wrote:
> This series contains support for new firmware features for
> the timecard.
>
> v1 -> v2: roundup() is not 32-bit safe, use DIV_ROUND_UP_ULL
>
> Jonathan Lemon (10):
> ptp: ocp: Add support for selectable SMA directions.
> ptp: ocp: Add ability to disable input selectors.
> ptp: ocp: Rename output selector 'GNSS' to 'GNSS1'
> ptp: ocp: Add GND and VCC output selectors
> ptp: ocp: Add firmware capability bits for feature gating
> ptp: ocp: Add signal generators and update sysfs nodes
> ptp: ocp: Program the signal generators via PTP_CLK_REQ_PEROUT
> ptp: ocp: Add 4 frequency counters
> ptp: ocp: Add 2 more timestampers
> docs: ABI: Document new timecard sysfs nodes.
>
> [...]
Here is the summary with links:
- [net-next,v2,01/10] ptp: ocp: Add support for selectable SMA directions.
(no matching commit)
- [net-next,v2,02/10] ptp: ocp: Add ability to disable input selectors.
https://git.kernel.org/netdev/net-next/c/b2c4f0ac53f3
- [net-next,v2,03/10] ptp: ocp: Rename output selector 'GNSS' to 'GNSS1'
https://git.kernel.org/netdev/net-next/c/be69087ce675
- [net-next,v2,04/10] ptp: ocp: Add GND and VCC output selectors
https://git.kernel.org/netdev/net-next/c/cd09193ffbf8
- [net-next,v2,05/10] ptp: ocp: Add firmware capability bits for feature gating
https://git.kernel.org/netdev/net-next/c/c205d53c4923
- [net-next,v2,06/10] ptp: ocp: Add signal generators and update sysfs nodes
https://git.kernel.org/netdev/net-next/c/b325af3cfab9
- [net-next,v2,07/10] ptp: ocp: Program the signal generators via PTP_CLK_REQ_PEROUT
https://git.kernel.org/netdev/net-next/c/1aa66a3a135a
- [net-next,v2,08/10] ptp: ocp: Add 4 frequency counters
https://git.kernel.org/netdev/net-next/c/2407f5d62017
- [net-next,v2,09/10] ptp: ocp: Add 2 more timestampers
https://git.kernel.org/netdev/net-next/c/0fa3ff7eb02a
- [net-next,v2,10/10] docs: ABI: Document new timecard sysfs nodes.
https://git.kernel.org/netdev/net-next/c/ff1d56cb2653
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2022-03-11 12:00 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-10 20:19 [PATCH net-next v2 00/10] ptp: ocp: support for new firmware Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 01/10] ptp: ocp: Add support for selectable SMA directions Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 02/10] ptp: ocp: Add ability to disable input selectors Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 03/10] ptp: ocp: Rename output selector 'GNSS' to 'GNSS1' Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 04/10] ptp: ocp: Add GND and VCC output selectors Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 05/10] ptp: ocp: Add firmware capability bits for feature gating Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 06/10] ptp: ocp: Add signal generators and update sysfs nodes Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 07/10] ptp: ocp: Program the signal generators via PTP_CLK_REQ_PEROUT Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 08/10] ptp: ocp: Add 4 frequency counters Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 09/10] ptp: ocp: Add 2 more timestampers Jonathan Lemon
2022-03-10 20:19 ` [PATCH net-next v2 10/10] docs: ABI: Document new timecard sysfs nodes Jonathan Lemon
2022-03-11 12:00 ` [PATCH net-next v2 00/10] ptp: ocp: support for new firmware patchwork-bot+netdevbpf
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.