All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 00/18] timecard updates for v13 firmware
@ 2021-09-15  2:16 Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 01/18] ptp: ocp: parameterize the i2c driver used Jonathan Lemon
                   ` (18 more replies)
  0 siblings, 19 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

This update mainly deals with features for the TimeCard v13 firmware.

The signals provided from the external SMA connectors can be steered
to different locations, and the generated SMA signals can be chosen.

Future timecard revisions will allow selectable I/O on any of the 
SMA connectors, so name the attributes appropriately, and set up 
the ABI in preparation for the new features.

The update also adds support for IRIG-B and DCF formats, as well
as NMEA output.

A ts_window_adjust tunable is also provided to fine-tune the 
PHC:SYS time mapping.
--
v1: Earlier reviewed series was for v10 firmware, this is expanded to
    include the v13 features.

Jonathan Lemon (18):
  ptp: ocp: parameterize the i2c driver used
  ptp: ocp: Parameterize the TOD information display.
  ptp: ocp: Skip I2C flash read when there is no controller.
  ptp: ocp: Skip resources with out of range irqs
  ptp: ocp: Report error if resource registration fails.
  ptp: ocp: Add third timestamper
  ptp: ocp: Add SMA selector and controls
  ptp: ocp: Add IRIG-B and DCF blocks
  ptp: ocp: Add IRIG-B output mode control
  ptp: ocp: Add sysfs attribute utc_tai_offset
  ptp: ocp: Separate the init and info logic
  ptp: ocp: Add debugfs entry for timecard
  ptp: ocp: Add NMEA output
  ptp: ocp: Add second GNSS device
  ptp: ocp: Enable 4th timestamper / PPS generator
  ptp: ocp: Have FPGA fold in ns adjustment for adjtime.
  ptp: ocp: Add timestamp window adjustment
  docs: ABI: Add sysfs documentation for timecard

 Documentation/ABI/testing/sysfs-timecard |  174 +++
 drivers/ptp/ptp_ocp.c                    | 1305 +++++++++++++++++++---
 2 files changed, 1343 insertions(+), 136 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-timecard

-- 
2.31.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH net-next 01/18] ptp: ocp: parameterize the i2c driver used
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 02/18] ptp: ocp: Parameterize the TOD information display Jonathan Lemon
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

Move the xilinx i2c driver parameters to the resource block instead
of hardcoding things in the registration functions.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index caf9b37c5eb1..d37eac69150a 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -131,6 +131,13 @@ struct ptp_ocp_flash_info {
 	void *data;
 };
 
+struct ptp_ocp_i2c_info {
+	const char *name;
+	unsigned long fixed_rate;
+	size_t data_size;
+	void *data;
+};
+
 struct ptp_ocp_ext_info {
 	const char *name;
 	int index;
@@ -269,6 +276,10 @@ static struct ocp_resource ocp_fb_resource[] = {
 	{
 		OCP_I2C_RESOURCE(i2c_ctrl),
 		.offset = 0x00150000, .size = 0x10000, .irq_vec = 7,
+		.extra = &(struct ptp_ocp_i2c_info) {
+			.name = "xiic-i2c",
+			.fixed_rate = 50000000,
+		},
 	},
 	{
 		OCP_SERIAL_RESOURCE(gnss_port),
@@ -944,21 +955,25 @@ ptp_ocp_register_spi(struct ptp_ocp *bp, struct ocp_resource *r)
 static struct platform_device *
 ptp_ocp_i2c_bus(struct pci_dev *pdev, struct ocp_resource *r, int id)
 {
+	struct ptp_ocp_i2c_info *info;
 	struct resource res[2];
 	unsigned long start;
 
+	info = r->extra;
 	start = pci_resource_start(pdev, 0) + r->offset;
 	ptp_ocp_set_mem_resource(&res[0], start, r->size);
 	ptp_ocp_set_irq_resource(&res[1], pci_irq_vector(pdev, r->irq_vec));
 
-	return platform_device_register_resndata(&pdev->dev, "xiic-i2c",
-						 id, res, 2, NULL, 0);
+	return platform_device_register_resndata(&pdev->dev, info->name,
+						 id, res, 2,
+						 info->data, info->data_size);
 }
 
 static int
 ptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r)
 {
 	struct pci_dev *pdev = bp->pdev;
+	struct ptp_ocp_i2c_info *info;
 	struct platform_device *p;
 	struct clk_hw *clk;
 	char buf[32];
@@ -970,15 +985,17 @@ ptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r)
 		return 0;
 	}
 
+	info = r->extra;
 	id = pci_dev_id(bp->pdev);
 
 	sprintf(buf, "AXI.%d", id);
-	clk = clk_hw_register_fixed_rate(&pdev->dev, buf, NULL, 0, 50000000);
+	clk = clk_hw_register_fixed_rate(&pdev->dev, buf, NULL, 0,
+					 info->fixed_rate);
 	if (IS_ERR(clk))
 		return PTR_ERR(clk);
 	bp->i2c_clk = clk;
 
-	sprintf(buf, "xiic-i2c.%d", id);
+	sprintf(buf, "%s.%d", info->name, id);
 	devm_clk_hw_register_clkdev(&pdev->dev, clk, NULL, buf);
 	p = ptp_ocp_i2c_bus(bp->pdev, r, id);
 	if (IS_ERR(p))
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 02/18] ptp: ocp: Parameterize the TOD information display.
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 01/18] ptp: ocp: parameterize the i2c driver used Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 03/18] ptp: ocp: Skip I2C flash read when there is no controller Jonathan Lemon
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

Only display the TOD information if there is a corresponding
TOD resource.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index d37eac69150a..2a6cc762c60e 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -743,7 +743,8 @@ ptp_ocp_info(struct ptp_ocp *bp)
 		 ptp_ocp_clock_name_from_val(select >> 16),
 		 ptp_clock_index(bp->ptp));
 
-	ptp_ocp_tod_info(bp);
+	if (bp->tod)
+		ptp_ocp_tod_info(bp);
 }
 
 static struct device *
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 03/18] ptp: ocp: Skip I2C flash read when there is no controller.
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 01/18] ptp: ocp: parameterize the i2c driver used Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 02/18] ptp: ocp: Parameterize the TOD information display Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 04/18] ptp: ocp: Skip resources with out of range irqs Jonathan Lemon
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

If an I2C controller isn't present, don't try and read the I2C flash.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 2a6cc762c60e..196a457929f0 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -228,8 +228,8 @@ static int ptp_ocp_ts_enable(void *priv, bool enable);
  * 3: GPS
  * 4: GPS2 (n/c)
  * 5: MAC
- * 6: SPI IMU (inertial measurement unit)
- * 7: I2C oscillator
+ * 6: N/C
+ * 7: I2C controller
  * 8: HWICAP
  * 9: SPI Flash
  */
@@ -706,6 +706,9 @@ ptp_ocp_get_serial_number(struct ptp_ocp *bp)
 	struct device *dev;
 	int err;
 
+	if (!bp->i2c_ctrl)
+		return;
+
 	dev = device_find_child(&bp->i2c_ctrl->dev, NULL, ptp_ocp_firstchild);
 	if (!dev) {
 		dev_err(&bp->pdev->dev, "Can't find I2C adapter\n");
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 04/18] ptp: ocp: Skip resources with out of range irqs
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (2 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 03/18] ptp: ocp: Skip I2C flash read when there is no controller Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 05/18] ptp: ocp: Report error if resource registration fails Jonathan Lemon
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

The TimeCard exposes different resources, which may have their
own irqs.  Space for the irqs is allocated through a MSI or MSI-X
interrupt vector.  On some platforms, the interrupt allocation
fails.

Rather than making this fatal, just skip exposing those resources.

The main timecard functionality (that of a PTP clock) will work
without the additional resources.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 47 +++++++++++++++++--------------------------
 1 file changed, 18 insertions(+), 29 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 196a457929f0..ad8b794fa7e6 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -139,7 +139,6 @@ struct ptp_ocp_i2c_info {
 };
 
 struct ptp_ocp_ext_info {
-	const char *name;
 	int index;
 	irqreturn_t (*irq_fcn)(int irq, void *priv);
 	int (*enable)(void *priv, bool enable);
@@ -187,6 +186,7 @@ struct ocp_resource {
 	int (*setup)(struct ptp_ocp *bp, struct ocp_resource *r);
 	void *extra;
 	unsigned long bp_offset;
+	const char * const name;
 };
 
 static int ptp_ocp_register_mem(struct ptp_ocp *bp, struct ocp_resource *r);
@@ -204,7 +204,7 @@ static int ptp_ocp_ts_enable(void *priv, bool enable);
 })
 
 #define OCP_RES_LOCATION(member) \
-	.bp_offset = offsetof(struct ptp_ocp, member)
+	.name = #member, .bp_offset = offsetof(struct ptp_ocp, member)
 
 #define OCP_MEM_RESOURCE(member) \
 	OCP_RES_LOCATION(member), .setup = ptp_ocp_register_mem
@@ -243,7 +243,7 @@ static struct ocp_resource ocp_fb_resource[] = {
 		OCP_EXT_RESOURCE(ts0),
 		.offset = 0x01010000, .size = 0x10000, .irq_vec = 1,
 		.extra = &(struct ptp_ocp_ext_info) {
-			.name = "ts0", .index = 0,
+			.index = 0,
 			.irq_fcn = ptp_ocp_ts_irq,
 			.enable = ptp_ocp_ts_enable,
 		},
@@ -252,7 +252,7 @@ static struct ocp_resource ocp_fb_resource[] = {
 		OCP_EXT_RESOURCE(ts1),
 		.offset = 0x01020000, .size = 0x10000, .irq_vec = 2,
 		.extra = &(struct ptp_ocp_ext_info) {
-			.name = "ts1", .index = 1,
+			.index = 1,
 			.irq_fcn = ptp_ocp_ts_irq,
 			.enable = ptp_ocp_ts_enable,
 		},
@@ -925,18 +925,6 @@ ptp_ocp_register_spi(struct ptp_ocp *bp, struct ocp_resource *r)
 	unsigned long start;
 	int id;
 
-	/* XXX hack to work around old FPGA */
-	if (bp->n_irqs < 10) {
-		dev_err(&bp->pdev->dev, "FPGA does not have SPI devices\n");
-		return 0;
-	}
-
-	if (r->irq_vec > bp->n_irqs) {
-		dev_err(&bp->pdev->dev, "spi device irq %d out of range\n",
-			r->irq_vec);
-		return 0;
-	}
-
 	start = pci_resource_start(pdev, 0) + r->offset;
 	ptp_ocp_set_mem_resource(&res[0], start, r->size);
 	ptp_ocp_set_irq_resource(&res[1], pci_irq_vector(pdev, r->irq_vec));
@@ -983,12 +971,6 @@ ptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r)
 	char buf[32];
 	int id;
 
-	if (r->irq_vec > bp->n_irqs) {
-		dev_err(&bp->pdev->dev, "i2c device irq %d out of range\n",
-			r->irq_vec);
-		return 0;
-	}
-
 	info = r->extra;
 	id = pci_dev_id(bp->pdev);
 
@@ -1080,7 +1062,7 @@ ptp_ocp_register_ext(struct ptp_ocp *bp, struct ocp_resource *r)
 	ext->irq_vec = r->irq_vec;
 
 	err = pci_request_irq(pdev, r->irq_vec, ext->info->irq_fcn, NULL,
-			      ext, "ocp%d.%s", bp->id, ext->info->name);
+			      ext, "ocp%d.%s", bp->id, r->name);
 	if (err) {
 		dev_err(&pdev->dev, "Could not get irq %d\n", r->irq_vec);
 		goto out;
@@ -1122,12 +1104,6 @@ ptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r)
 {
 	int port;
 
-	if (r->irq_vec > bp->n_irqs) {
-		dev_err(&bp->pdev->dev, "serial device irq %d out of range\n",
-			r->irq_vec);
-		return 0;
-	}
-
 	port = ptp_ocp_serial_line(bp, r);
 	if (port < 0)
 		return port;
@@ -1160,6 +1136,17 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
 	return ptp_ocp_init_clock(bp);
 }
 
+static bool
+ptp_ocp_allow_irq(struct ptp_ocp *bp, struct ocp_resource *r)
+{
+	bool allow = !r->irq_vec || r->irq_vec < bp->n_irqs;
+
+	if (!allow)
+		dev_err(&bp->pdev->dev, "irq %d out of range, skipping %s\n",
+			r->irq_vec, r->name);
+	return allow;
+}
+
 static int
 ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data)
 {
@@ -1168,6 +1155,8 @@ ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data)
 
 	table = (struct ocp_resource *)driver_data;
 	for (r = table; r->setup; r++) {
+		if (!ptp_ocp_allow_irq(bp, r))
+			continue;
 		err = r->setup(bp, r);
 		if (err)
 			break;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 05/18] ptp: ocp: Report error if resource registration fails.
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (3 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 04/18] ptp: ocp: Skip resources with out of range irqs Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 06/18] ptp: ocp: Add third timestamper Jonathan Lemon
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

If a resource could not be registered, report the name of
the resource and the error code.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index ad8b794fa7e6..1f86e878ccba 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -1158,8 +1158,12 @@ ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data)
 		if (!ptp_ocp_allow_irq(bp, r))
 			continue;
 		err = r->setup(bp, r);
-		if (err)
+		if (err) {
+			dev_err(&bp->pdev->dev,
+				"Could not register %s: err %d\n",
+				r->name, err);
 			break;
+		}
 	}
 	return err;
 }
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 06/18] ptp: ocp: Add third timestamper
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (4 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 05/18] ptp: ocp: Report error if resource registration fails Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 07/18] ptp: ocp: Add SMA selector and controls Jonathan Lemon
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

The firmware may provide a third signal timestamper, so make it
available for use.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 1f86e878ccba..23d5f20f43f8 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -162,6 +162,7 @@ struct ptp_ocp {
 	struct ptp_ocp_ext_src	*pps;
 	struct ptp_ocp_ext_src	*ts0;
 	struct ptp_ocp_ext_src	*ts1;
+	struct ptp_ocp_ext_src	*ts2;
 	struct img_reg __iomem	*image;
 	struct ptp_clock	*ptp;
 	struct ptp_clock_info	ptp_info;
@@ -228,7 +229,7 @@ static int ptp_ocp_ts_enable(void *priv, bool enable);
  * 3: GPS
  * 4: GPS2 (n/c)
  * 5: MAC
- * 6: N/C
+ * 6: TS2
  * 7: I2C controller
  * 8: HWICAP
  * 9: SPI Flash
@@ -257,6 +258,15 @@ static struct ocp_resource ocp_fb_resource[] = {
 			.enable = ptp_ocp_ts_enable,
 		},
 	},
+	{
+		OCP_EXT_RESOURCE(ts2),
+		.offset = 0x01060000, .size = 0x10000, .irq_vec = 6,
+		.extra = &(struct ptp_ocp_ext_info) {
+			.index = 2,
+			.irq_fcn = ptp_ocp_ts_irq,
+			.enable = ptp_ocp_ts_enable,
+		},
+	},
 	{
 		OCP_MEM_RESOURCE(pps_to_ext),
 		.offset = 0x01030000, .size = 0x10000,
@@ -497,6 +507,9 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
 		case 1:
 			ext = bp->ts1;
 			break;
+		case 2:
+			ext = bp->ts2;
+			break;
 		}
 		break;
 	case PTP_CLK_REQ_PPS:
@@ -524,7 +537,7 @@ static const struct ptp_clock_info ptp_ocp_clock_info = {
 	.adjphase	= ptp_ocp_adjphase,
 	.enable		= ptp_ocp_enable,
 	.pps		= true,
-	.n_ext_ts	= 2,
+	.n_ext_ts	= 3,
 };
 
 static void
@@ -1407,6 +1420,8 @@ ptp_ocp_detach(struct ptp_ocp *bp)
 		ptp_ocp_unregister_ext(bp->ts0);
 	if (bp->ts1)
 		ptp_ocp_unregister_ext(bp->ts1);
+	if (bp->ts2)
+		ptp_ocp_unregister_ext(bp->ts2);
 	if (bp->pps)
 		ptp_ocp_unregister_ext(bp->pps);
 	if (bp->gnss_port != -1)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 07/18] ptp: ocp: Add SMA selector and controls
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (5 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 06/18] ptp: ocp: Add third timestamper Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 08/18] ptp: ocp: Add IRIG-B and DCF blocks Jonathan Lemon
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

The latest firmware for the TimeCard adds selectable signals for
the SMA input/outputs.  Add support for SMA selectors, and the
GPIO controls needed for steering signals.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 389 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 361 insertions(+), 28 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 23d5f20f43f8..7441dac4e9c5 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -124,6 +124,13 @@ struct img_reg {
 	u32	version;
 };
 
+struct gpio_reg {
+	u32	gpio1;
+	u32	__pad0;
+	u32	gpio2;
+	u32	__pad1;
+};
+
 struct ptp_ocp_flash_info {
 	const char *name;
 	int pci_offset;
@@ -159,6 +166,7 @@ struct ptp_ocp {
 	struct tod_reg __iomem	*tod;
 	struct pps_reg __iomem	*pps_to_ext;
 	struct pps_reg __iomem	*pps_to_clk;
+	struct gpio_reg __iomem	*sma;
 	struct ptp_ocp_ext_src	*pps;
 	struct ptp_ocp_ext_src	*ts0;
 	struct ptp_ocp_ext_src	*ts1;
@@ -283,6 +291,10 @@ static struct ocp_resource ocp_fb_resource[] = {
 		OCP_MEM_RESOURCE(image),
 		.offset = 0x00020000, .size = 0x1000,
 	},
+	{
+		OCP_MEM_RESOURCE(sma),
+		.offset = 0x00140000, .size = 0x1000,
+	},
 	{
 		OCP_I2C_RESOURCE(i2c_ctrl),
 		.offset = 0x00150000, .size = 0x10000, .irq_vec = 7,
@@ -330,10 +342,12 @@ MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id);
 static DEFINE_MUTEX(ptp_ocp_lock);
 static DEFINE_IDR(ptp_ocp_idr);
 
-static struct {
+struct ocp_selector {
 	const char *name;
 	int value;
-} ptp_ocp_clock[] = {
+};
+
+static struct ocp_selector ptp_ocp_clock[] = {
 	{ .name = "NONE",	.value = 0 },
 	{ .name = "TOD",	.value = 1 },
 	{ .name = "IRIG",	.value = 2 },
@@ -343,33 +357,67 @@ static struct {
 	{ .name = "DCF",	.value = 6 },
 	{ .name = "REGS",	.value = 0xfe },
 	{ .name = "EXT",	.value = 0xff },
+	{ }
+};
+
+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 },
+	{ }
+};
+
+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 = "GNSS2",	.value = 0x08 },
+	{ }
 };
 
 static const char *
-ptp_ocp_clock_name_from_val(int val)
+ptp_ocp_select_name_from_val(struct ocp_selector *tbl, int val)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(ptp_ocp_clock); i++)
-		if (ptp_ocp_clock[i].value == val)
-			return ptp_ocp_clock[i].name;
+	for (i = 0; tbl[i].name; i++)
+		if (tbl[i].value == val)
+			return tbl[i].name;
 	return NULL;
 }
 
 static int
-ptp_ocp_clock_val_from_name(const char *name)
+ptp_ocp_select_val_from_name(struct ocp_selector *tbl, const char *name)
 {
-	const char *clk;
+	const char *select;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(ptp_ocp_clock); i++) {
-		clk = ptp_ocp_clock[i].name;
-		if (!strncasecmp(name, clk, strlen(clk)))
-			return ptp_ocp_clock[i].value;
+	for (i = 0; tbl[i].name; i++) {
+		select = tbl[i].name;
+		if (!strncasecmp(name, select, strlen(select)))
+			return tbl[i].value;
 	}
 	return -EINVAL;
 }
 
+static ssize_t
+ptp_ocp_select_table_show(struct ocp_selector *tbl, char *buf)
+{
+	ssize_t count;
+	int i;
+
+	count = 0;
+	for (i = 0; tbl[i].name; i++)
+		count += sysfs_emit_at(buf, count, "%s ", tbl[i].name);
+	if (count)
+		count--;
+	count += sysfs_emit_at(buf, count, "\n");
+	return count;
+}
+
 static int
 __ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts,
 			 struct ptp_system_timestamp *sts)
@@ -756,7 +804,7 @@ ptp_ocp_info(struct ptp_ocp *bp)
 	select = ioread32(&bp->reg->select);
 	dev_info(&bp->pdev->dev, "Version %d.%d.%d, clock %s, device ptp%d\n",
 		 version >> 24, (version >> 16) & 0xff, version & 0xffff,
-		 ptp_ocp_clock_name_from_val(select >> 16),
+		 ptp_ocp_select_name_from_val(ptp_ocp_clock, select >> 16),
 		 ptp_clock_index(bp->ptp));
 
 	if (bp->tod)
@@ -1181,6 +1229,297 @@ ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data)
 	return err;
 }
 
+/*
+ * ANT0 == gps	(in)
+ * ANT1 == sma1 (in)
+ * ANT2 == sma2 (in)
+ * ANT3 == sma3 (out)
+ * 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)
+{
+	const char *name;
+	ssize_t count;
+
+	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;
+	count += sysfs_emit_at(buf, count, "%s\n", name);
+	return count;
+}
+
+static ssize_t
+ptp_ocp_show_inputs(u32 val, char *buf, const char *zero_in)
+{
+	const char *name;
+	ssize_t count;
+	int i;
+
+	count = sysfs_emit(buf, "IN: ");
+	for (i = 0; i < ARRAY_SIZE(ptp_ocp_sma_in); i++) {
+		if (val & ptp_ocp_sma_in[i].value) {
+			name = ptp_ocp_sma_in[i].name;
+			count += sysfs_emit_at(buf, count, "%s ", name);
+		}
+	}
+	if (!val && zero_in)
+		count += sysfs_emit_at(buf, count, "%s ", zero_in);
+	if (count)
+		count--;
+	count += sysfs_emit_at(buf, count, "\n");
+	return count;
+}
+
+static int
+sma_parse_inputs(const char *buf, enum ptp_ocp_sma_mode *mode)
+{
+	struct ocp_selector *tbl[] = { ptp_ocp_sma_in, ptp_ocp_sma_out };
+	int idx, count, dir;
+	char **argv;
+	int ret;
+
+	argv = argv_split(GFP_KERNEL, buf, &count);
+	if (!argv)
+		return -ENOMEM;
+
+	ret = -EINVAL;
+	if (!count)
+		goto out;
+
+	idx = 0;
+	dir = *mode == SMA_MODE_IN ? 0 : 1;
+	if (!strcasecmp("IN:", argv[idx])) {
+		dir = 0;
+		idx++;
+	}
+	if (!strcasecmp("OUT:", argv[0])) {
+		dir = 1;
+		idx++;
+	}
+	*mode = dir == 0 ? SMA_MODE_IN : SMA_MODE_OUT;
+
+	ret = 0;
+	for (; idx < count; idx++)
+		ret |= ptp_ocp_select_val_from_name(tbl[dir], argv[idx]);
+	if (ret < 0)
+		ret = -EINVAL;
+
+out:
+	argv_free(argv);
+	return ret;
+}
+
+static ssize_t
+ptp_ocp_sma_show(struct ptp_ocp *bp, int sma_nr, u32 val, char *buf,
+		 const char *zero_in)
+{
+	struct ptp_ocp_sma_connector *sma = &ptp_ocp_sma_map[sma_nr - 1];
+
+	if (sma->mode == SMA_MODE_IN)
+		return ptp_ocp_show_inputs(val, buf, zero_in);
+
+	return ptp_ocp_show_output(val, buf, sma->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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+static void
+ptp_ocp_sma_store_output(struct ptp_ocp *bp, u32 val, u32 shift)
+{
+	unsigned long flags;
+	u32 gpio, mask;
+
+	mask = 0xffff << (16 - shift);
+
+	spin_lock_irqsave(&bp->lock, flags);
+
+	gpio = ioread32(&bp->sma->gpio2);
+	gpio = (gpio & mask) | (val << shift);
+	iowrite32(gpio, &bp->sma->gpio2);
+
+	spin_unlock_irqrestore(&bp->lock, flags);
+}
+
+static void
+ptp_ocp_sma_store_inputs(struct ptp_ocp *bp, u32 val, u32 shift)
+{
+	unsigned long flags;
+	u32 gpio, mask;
+
+	mask = 0xffff << (16 - shift);
+
+	spin_lock_irqsave(&bp->lock, flags);
+
+	gpio = ioread32(&bp->sma->gpio1);
+	gpio = (gpio & mask) | (val << shift);
+	iowrite32(gpio, &bp->sma->gpio1);
+
+	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)
+{
+	struct ptp_ocp_sma_connector *sma = &ptp_ocp_sma_map[sma_nr - 1];
+	enum ptp_ocp_sma_mode mode;
+	int val;
+
+	mode = sma->mode;
+	val = sma_parse_inputs(buf, &mode);
+	if (val < 0)
+		return val;
+
+	if (mode != sma->mode && sma->fixed_mode)
+		return -EOPNOTSUPP;
+
+	if (mode != sma->mode) {
+		pr_err("Mode changes not supported yet.\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (sma->mode == SMA_MODE_IN)
+		ptp_ocp_sma_store_inputs(bp, val, shift);
+	else
+		ptp_ocp_sma_store_output(bp, val, shift);
+
+	return 0;
+}
+
+static ssize_t
+sma1_store(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	int err;
+
+	err = ptp_ocp_sma_store(bp, buf, 1, 0);
+	return err ? err : count;
+}
+
+static ssize_t
+sma2_store(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	int err;
+
+	err = ptp_ocp_sma_store(bp, buf, 2, 16);
+	return err ? err : count;
+}
+
+static ssize_t
+sma3_store(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	int err;
+
+	err = ptp_ocp_sma_store(bp, buf, 3, 0);
+	return err ? err : count;
+}
+
+static ssize_t
+sma4_store(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	int err;
+
+	err = ptp_ocp_sma_store(bp, buf, 4, 16);
+	return err ? err : count;
+}
+static DEVICE_ATTR_RW(sma1);
+static DEVICE_ATTR_RW(sma2);
+static DEVICE_ATTR_RW(sma3);
+static DEVICE_ATTR_RW(sma4);
+
+static ssize_t
+available_sma_inputs_show(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	return ptp_ocp_select_table_show(ptp_ocp_sma_in, buf);
+}
+static DEVICE_ATTR_RO(available_sma_inputs);
+
+static ssize_t
+available_sma_outputs_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	return ptp_ocp_select_table_show(ptp_ocp_sma_out, buf);
+}
+static DEVICE_ATTR_RO(available_sma_outputs);
+
 static ssize_t
 serialnum_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -1216,7 +1555,7 @@ clock_source_show(struct device *dev, struct device_attribute *attr, char *buf)
 	u32 select;
 
 	select = ioread32(&bp->reg->select);
-	p = ptp_ocp_clock_name_from_val(select >> 16);
+	p = ptp_ocp_select_name_from_val(ptp_ocp_clock, select >> 16);
 
 	return sysfs_emit(buf, "%s\n", p);
 }
@@ -1229,7 +1568,7 @@ clock_source_store(struct device *dev, struct device_attribute *attr,
 	unsigned long flags;
 	int val;
 
-	val = ptp_ocp_clock_val_from_name(buf);
+	val = ptp_ocp_select_val_from_name(ptp_ocp_clock, buf);
 	if (val < 0)
 		return val;
 
@@ -1245,19 +1584,7 @@ static ssize_t
 available_clock_sources_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
-	const char *clk;
-	ssize_t count;
-	int i;
-
-	count = 0;
-	for (i = 0; i < ARRAY_SIZE(ptp_ocp_clock); i++) {
-		clk = ptp_ocp_clock[i].name;
-		count += sysfs_emit_at(buf, count, "%s ", clk);
-	}
-	if (count)
-		count--;
-	count += sysfs_emit_at(buf, count, "\n");
-	return count;
+	return ptp_ocp_select_table_show(ptp_ocp_clock, buf);
 }
 static DEVICE_ATTR_RO(available_clock_sources);
 
@@ -1266,6 +1593,12 @@ static struct attribute *timecard_attrs[] = {
 	&dev_attr_gnss_sync.attr,
 	&dev_attr_clock_source.attr,
 	&dev_attr_available_clock_sources.attr,
+	&dev_attr_sma1.attr,
+	&dev_attr_sma2.attr,
+	&dev_attr_sma3.attr,
+	&dev_attr_sma4.attr,
+	&dev_attr_available_sma_inputs.attr,
+	&dev_attr_available_sma_outputs.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(timecard);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 08/18] ptp: ocp: Add IRIG-B and DCF blocks
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (6 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 07/18] ptp: ocp: Add SMA selector and controls Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 09/18] ptp: ocp: Add IRIG-B output mode control Jonathan Lemon
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

IRIG (Inter-range Instrumentation Group) timecode format on
one of the SMA output channels is provided by the IRIG master
FPGA block.  Enable the master when the IRIG output format is
selected on either one of the output channels.

By default, the output is in B007 format.

DCF output format is provided by the DCF master block.

Also enable the IRIG and DCF slaves, which parse an incoming
signal from the external SMA connectors, and may be used to
adjust the PHC.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 129 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 129 insertions(+)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 7441dac4e9c5..1a210b77744c 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -131,6 +131,48 @@ struct gpio_reg {
 	u32	__pad1;
 };
 
+struct irig_master_reg {
+	u32	ctrl;
+	u32	status;
+	u32	__pad0;
+	u32	version;
+	u32	adj_sec;
+	u32	mode_ctrl;
+};
+
+#define IRIG_M_CTRL_ENABLE	BIT(0)
+
+struct irig_slave_reg {
+	u32	ctrl;
+	u32	status;
+	u32	__pad0;
+	u32	version;
+	u32	adj_sec;
+	u32	mode_ctrl;
+};
+
+#define IRIG_S_CTRL_ENABLE	BIT(0)
+
+struct dcf_master_reg {
+	u32	ctrl;
+	u32	status;
+	u32	__pad0;
+	u32	version;
+	u32	adj_sec;
+};
+
+#define DCF_M_CTRL_ENABLE	BIT(0)
+
+struct dcf_slave_reg {
+	u32	ctrl;
+	u32	status;
+	u32	__pad0;
+	u32	version;
+	u32	adj_sec;
+};
+
+#define DCF_S_CTRL_ENABLE	BIT(0)
+
 struct ptp_ocp_flash_info {
 	const char *name;
 	int pci_offset;
@@ -167,6 +209,10 @@ struct ptp_ocp {
 	struct pps_reg __iomem	*pps_to_ext;
 	struct pps_reg __iomem	*pps_to_clk;
 	struct gpio_reg __iomem	*sma;
+	struct irig_master_reg	__iomem *irig_out;
+	struct irig_slave_reg	__iomem *irig_in;
+	struct dcf_master_reg	__iomem *dcf_out;
+	struct dcf_slave_reg	__iomem *dcf_in;
 	struct ptp_ocp_ext_src	*pps;
 	struct ptp_ocp_ext_src	*ts0;
 	struct ptp_ocp_ext_src	*ts1;
@@ -287,6 +333,22 @@ static struct ocp_resource ocp_fb_resource[] = {
 		OCP_MEM_RESOURCE(tod),
 		.offset = 0x01050000, .size = 0x10000,
 	},
+	{
+		OCP_MEM_RESOURCE(irig_in),
+		.offset = 0x01070000, .size = 0x10000,
+	},
+	{
+		OCP_MEM_RESOURCE(irig_out),
+		.offset = 0x01080000, .size = 0x10000,
+	},
+	{
+		OCP_MEM_RESOURCE(dcf_in),
+		.offset = 0x01090000, .size = 0x10000,
+	},
+	{
+		OCP_MEM_RESOURCE(dcf_out),
+		.offset = 0x010A0000, .size = 0x10000,
+	},
 	{
 		OCP_MEM_RESOURCE(image),
 		.offset = 0x00020000, .size = 0x1000,
@@ -366,6 +428,8 @@ static struct ocp_selector ptp_ocp_sma_in[] = {
 	{ .name = "PPS2",	.value = 0x02 },
 	{ .name = "TS1",	.value = 0x04 },
 	{ .name = "TS2",	.value = 0x08 },
+	{ .name = "IRIG",	.value = 0x10 },
+	{ .name = "DCF",	.value = 0x20 },
 	{ }
 };
 
@@ -375,6 +439,8 @@ static struct ocp_selector ptp_ocp_sma_out[] = {
 	{ .name = "MAC",	.value = 0x02 },
 	{ .name = "GNSS",	.value = 0x04 },
 	{ .name = "GNSS2",	.value = 0x08 },
+	{ .name = "IRIG",	.value = 0x10 },
+	{ .name = "DCF",	.value = 0x20 },
 	{ }
 };
 
@@ -1229,6 +1295,63 @@ ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data)
 	return err;
 }
 
+static void
+ptp_ocp_enable_fpga(u32 __iomem *reg, u32 bit, bool enable)
+{
+	u32 ctrl;
+	bool on;
+
+	ctrl = ioread32(reg);
+	on = ctrl & bit;
+	if (on ^ enable) {
+		ctrl &= ~bit;
+		ctrl |= enable ? bit : 0;
+		iowrite32(ctrl, reg);
+	}
+}
+
+static void
+ptp_ocp_irig_out(struct ptp_ocp *bp, bool enable)
+{
+	return ptp_ocp_enable_fpga(&bp->irig_out->ctrl,
+				   IRIG_M_CTRL_ENABLE, enable);
+}
+
+static void
+ptp_ocp_irig_in(struct ptp_ocp *bp, bool enable)
+{
+	return ptp_ocp_enable_fpga(&bp->irig_in->ctrl,
+				   IRIG_S_CTRL_ENABLE, enable);
+}
+
+static void
+ptp_ocp_dcf_out(struct ptp_ocp *bp, bool enable)
+{
+	return ptp_ocp_enable_fpga(&bp->dcf_out->ctrl,
+				   DCF_M_CTRL_ENABLE, enable);
+}
+
+static void
+ptp_ocp_dcf_in(struct ptp_ocp *bp, bool enable)
+{
+	return ptp_ocp_enable_fpga(&bp->dcf_in->ctrl,
+				   DCF_S_CTRL_ENABLE, enable);
+}
+
+static void
+__handle_signal_outputs(struct ptp_ocp *bp, u32 val)
+{
+	ptp_ocp_irig_out(bp, val & 0x00100010);
+	ptp_ocp_dcf_out(bp, val & 0x00200020);
+}
+
+static void
+__handle_signal_inputs(struct ptp_ocp *bp, u32 val)
+{
+	ptp_ocp_irig_in(bp, val & 0x00100010);
+	ptp_ocp_dcf_in(bp, val & 0x00200020);
+}
+
 /*
  * ANT0 == gps	(in)
  * ANT1 == sma1 (in)
@@ -1406,6 +1529,9 @@ ptp_ocp_sma_store_output(struct ptp_ocp *bp, u32 val, u32 shift)
 
 	gpio = ioread32(&bp->sma->gpio2);
 	gpio = (gpio & mask) | (val << shift);
+
+	__handle_signal_outputs(bp, gpio);
+
 	iowrite32(gpio, &bp->sma->gpio2);
 
 	spin_unlock_irqrestore(&bp->lock, flags);
@@ -1423,6 +1549,9 @@ ptp_ocp_sma_store_inputs(struct ptp_ocp *bp, u32 val, u32 shift)
 
 	gpio = ioread32(&bp->sma->gpio1);
 	gpio = (gpio & mask) | (val << shift);
+
+	__handle_signal_inputs(bp, gpio);
+
 	iowrite32(gpio, &bp->sma->gpio1);
 
 	spin_unlock_irqrestore(&bp->lock, flags);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 09/18] ptp: ocp: Add IRIG-B output mode control
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (7 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 08/18] ptp: ocp: Add IRIG-B and DCF blocks Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 10/18] ptp: ocp: Add sysfs attribute utc_tai_offset Jonathan Lemon
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

IRIG-B has several different output formats, the timecard defaults
to using B007.  Add a control which selects different output modes.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 1a210b77744c..2b3d4282d77a 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -1676,6 +1676,46 @@ gnss_sync_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR_RO(gnss_sync);
 
+static ssize_t
+irig_b_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	u32 val;
+
+	val = ioread32(&bp->irig_out->ctrl);
+	val = (val >> 16) & 0x07;
+	return sysfs_emit(buf, "%d\n", val);
+}
+
+static ssize_t
+irig_b_mode_store(struct device *dev,
+		  struct device_attribute *attr,
+		  const char *buf, size_t count)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	unsigned long flags;
+	int err;
+	u32 reg;
+	u8 val;
+
+	err = kstrtou8(buf, 0, &val);
+	if (err)
+		return err;
+	if (val > 7)
+		return -EINVAL;
+
+	reg = ((val & 0x7) << 16);
+
+	spin_lock_irqsave(&bp->lock, flags);
+	iowrite32(0, &bp->irig_out->ctrl);		/* disable */
+	iowrite32(reg, &bp->irig_out->ctrl);		/* change mode */
+	iowrite32(reg | IRIG_M_CTRL_ENABLE, &bp->irig_out->ctrl);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	return count;
+}
+static DEVICE_ATTR_RW(irig_b_mode);
+
 static ssize_t
 clock_source_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -1728,6 +1768,7 @@ static struct attribute *timecard_attrs[] = {
 	&dev_attr_sma4.attr,
 	&dev_attr_available_sma_inputs.attr,
 	&dev_attr_available_sma_outputs.attr,
+	&dev_attr_irig_b_mode.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(timecard);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 10/18] ptp: ocp: Add sysfs attribute utc_tai_offset
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (8 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 09/18] ptp: ocp: Add IRIG-B output mode control Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 11/18] ptp: ocp: Separate the init and info logic Jonathan Lemon
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

IRIG and DCF output time in UTC, but the timecard operates
on TAI internally.  Add an attribute node which allows adding
an offset to these modes before output.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 49 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 2b3d4282d77a..2c3af3c9def7 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -230,8 +230,9 @@ struct ptp_ocp {
 	int			gnss_port;
 	int			mac_port;	/* miniature atomic clock */
 	u8			serial[6];
-	int			flash_start;
 	bool			has_serial;
+	int			flash_start;
+	u32			utc_tai_offset;
 };
 
 struct ocp_resource {
@@ -741,6 +742,23 @@ ptp_ocp_init_clock(struct ptp_ocp *bp)
 	return 0;
 }
 
+static void
+ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&bp->lock, flags);
+
+	bp->utc_tai_offset = val;
+
+	if (bp->irig_out)
+		iowrite32(val, &bp->irig_out->adj_sec);
+	if (bp->dcf_out)
+		iowrite32(val, &bp->dcf_out->adj_sec);
+
+	spin_unlock_irqrestore(&bp->lock, flags);
+}
+
 static void
 ptp_ocp_tod_info(struct ptp_ocp *bp)
 {
@@ -1676,6 +1694,34 @@ gnss_sync_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR_RO(gnss_sync);
 
+static ssize_t
+utc_tai_offset_show(struct device *dev,
+		    struct device_attribute *attr, char *buf)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+
+	return sysfs_emit(buf, "%d\n", bp->utc_tai_offset);
+}
+
+static ssize_t
+utc_tai_offset_store(struct device *dev,
+		     struct device_attribute *attr,
+		     const char *buf, size_t count)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	int err;
+	u32 val;
+
+	err = kstrtou32(buf, 0, &val);
+	if (err)
+		return err;
+
+	ptp_ocp_utc_distribute(bp, val);
+
+	return count;
+}
+static DEVICE_ATTR_RW(utc_tai_offset);
+
 static ssize_t
 irig_b_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -1769,6 +1815,7 @@ static struct attribute *timecard_attrs[] = {
 	&dev_attr_available_sma_inputs.attr,
 	&dev_attr_available_sma_outputs.attr,
 	&dev_attr_irig_b_mode.attr,
+	&dev_attr_utc_tai_offset.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(timecard);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 11/18] ptp: ocp: Separate the init and info logic
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (9 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 10/18] ptp: ocp: Add sysfs attribute utc_tai_offset Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 12/18] ptp: ocp: Add debugfs entry for timecard Jonathan Lemon
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

On startup, parts of the FPGA need to be initialized - break these
out into their own functions, separate from the purely informational
blocks.

On startup, distrbute the UTC:TAI offset from the NMEA GNSS parser,
if it is available.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 96 +++++++++++++++++++++++++++----------------
 1 file changed, 60 insertions(+), 36 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 2c3af3c9def7..ea12f685edf6 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -72,7 +72,7 @@ struct tod_reg {
 	u32	status;
 	u32	uart_polarity;
 	u32	version;
-	u32	correction_sec;
+	u32	adj_sec;
 	u32	__pad0[3];
 	u32	uart_baud;
 	u32	__pad1[3];
@@ -728,16 +728,15 @@ ptp_ocp_init_clock(struct ptp_ocp *bp)
 
 	sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
 	if (!sync) {
-		ktime_get_real_ts64(&ts);
+		ktime_get_clocktai_ts64(&ts);
 		ptp_ocp_settime(&bp->ptp_info, &ts);
 	}
-	if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL))
-		dev_info(&bp->pdev->dev, "Time: %lld.%ld, %s\n",
-			 ts.tv_sec, ts.tv_nsec,
-			 sync ? "in-sync" : "UNSYNCED");
 
-	timer_setup(&bp->watchdog, ptp_ocp_watchdog, 0);
-	mod_timer(&bp->watchdog, jiffies + HZ);
+	/* If there is a clock supervisor, then enable the watchdog */
+	if (bp->pps_to_clk) {
+		timer_setup(&bp->watchdog, ptp_ocp_watchdog, 0);
+		mod_timer(&bp->watchdog, jiffies + HZ);
+	}
 
 	return 0;
 }
@@ -759,6 +758,21 @@ ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val)
 	spin_unlock_irqrestore(&bp->lock, flags);
 }
 
+static void
+ptp_ocp_tod_init(struct ptp_ocp *bp)
+{
+	u32 ctrl, reg;
+
+	ctrl = ioread32(&bp->tod->ctrl);
+	ctrl |= TOD_CTRL_PROTOCOL | TOD_CTRL_ENABLE;
+	ctrl &= ~(TOD_CTRL_DISABLE_FMT_A | TOD_CTRL_DISABLE_FMT_B);
+	iowrite32(ctrl, &bp->tod->ctrl);
+
+	reg = ioread32(&bp->tod->utc_status);
+	if (reg & TOD_STATUS_UTC_VALID)
+		ptp_ocp_utc_distribute(bp, reg & TOD_STATUS_UTC_MASK);
+}
+
 static void
 ptp_ocp_tod_info(struct ptp_ocp *bp)
 {
@@ -776,11 +790,6 @@ ptp_ocp_tod_info(struct ptp_ocp *bp)
 	dev_info(&bp->pdev->dev, "TOD Version %d.%d.%d\n",
 		 version >> 24, (version >> 16) & 0xff, version & 0xffff);
 
-	ctrl = ioread32(&bp->tod->ctrl);
-	ctrl |= TOD_CTRL_PROTOCOL | TOD_CTRL_ENABLE;
-	ctrl &= ~(TOD_CTRL_DISABLE_FMT_A | TOD_CTRL_DISABLE_FMT_B);
-	iowrite32(ctrl, &bp->tod->ctrl);
-
 	ctrl = ioread32(&bp->tod->ctrl);
 	idx = ctrl & TOD_CTRL_PROTOCOL ? 4 : 0;
 	idx += (ctrl >> 16) & 3;
@@ -795,7 +804,7 @@ ptp_ocp_tod_info(struct ptp_ocp *bp)
 	reg = ioread32(&bp->tod->status);
 	dev_info(&bp->pdev->dev, "status: %x\n", reg);
 
-	reg = ioread32(&bp->tod->correction_sec);
+	reg = ioread32(&bp->tod->adj_sec);
 	dev_info(&bp->pdev->dev, "correction: %d\n", reg);
 
 	reg = ioread32(&bp->tod->utc_status);
@@ -879,22 +888,6 @@ ptp_ocp_get_serial_number(struct ptp_ocp *bp)
 	put_device(dev);
 }
 
-static void
-ptp_ocp_info(struct ptp_ocp *bp)
-{
-	u32 version, select;
-
-	version = ioread32(&bp->reg->version);
-	select = ioread32(&bp->reg->select);
-	dev_info(&bp->pdev->dev, "Version %d.%d.%d, clock %s, device ptp%d\n",
-		 version >> 24, (version >> 16) & 0xff, version & 0xffff,
-		 ptp_ocp_select_name_from_val(ptp_ocp_clock, select >> 16),
-		 ptp_clock_index(bp->ptp));
-
-	if (bp->tod)
-		ptp_ocp_tod_info(bp);
-}
-
 static struct device *
 ptp_ocp_find_flash(struct ptp_ocp *bp)
 {
@@ -1278,6 +1271,8 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
 {
 	bp->flash_start = 1024 * 4096;
 
+	ptp_ocp_tod_init(bp);
+
 	return ptp_ocp_init_clock(bp);
 }
 
@@ -1927,10 +1922,42 @@ ptp_ocp_complete(struct ptp_ocp *bp)
 }
 
 static void
-ptp_ocp_resource_summary(struct ptp_ocp *bp)
+ptp_ocp_phc_info(struct ptp_ocp *bp)
+{
+	struct timespec64 ts;
+	u32 version, select;
+	bool sync;
+
+	version = ioread32(&bp->reg->version);
+	select = ioread32(&bp->reg->select);
+	dev_info(&bp->pdev->dev, "Version %d.%d.%d, clock %s, device ptp%d\n",
+		 version >> 24, (version >> 16) & 0xff, version & 0xffff,
+		 ptp_ocp_select_name_from_val(ptp_ocp_clock, select >> 16),
+		 ptp_clock_index(bp->ptp));
+
+	sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
+	if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL))
+		dev_info(&bp->pdev->dev, "Time: %lld.%ld, %s\n",
+			 ts.tv_sec, ts.tv_nsec,
+			 sync ? "in-sync" : "UNSYNCED");
+}
+
+static void
+ptp_ocp_serial_info(struct device *dev, const char *name, int port, int baud)
+{
+	if (port != -1)
+		dev_info(dev, "%5s: /dev/ttyS%-2d @ %6d\n", name, port, baud);
+}
+
+static void
+ptp_ocp_info(struct ptp_ocp *bp)
 {
 	struct device *dev = &bp->pdev->dev;
 
+	ptp_ocp_phc_info(bp);
+	if (bp->tod)
+		ptp_ocp_tod_info(bp);
+
 	if (bp->image) {
 		u32 ver = ioread32(&bp->image->version);
 
@@ -1942,10 +1969,8 @@ ptp_ocp_resource_summary(struct ptp_ocp *bp)
 			dev_info(dev, "golden image, version %d\n",
 				 ver >> 16);
 	}
-	if (bp->gnss_port != -1)
-		dev_info(dev, "GNSS @ /dev/ttyS%d 115200\n", bp->gnss_port);
-	if (bp->mac_port != -1)
-		dev_info(dev, "MAC @ /dev/ttyS%d   57600\n", bp->mac_port);
+	ptp_ocp_serial_info(dev, "GNSS", bp->gnss_port, 115200);
+	ptp_ocp_serial_info(dev, "MAC", bp->mac_port, 57600);
 }
 
 static void
@@ -2049,7 +2074,6 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto out;
 
 	ptp_ocp_info(bp);
-	ptp_ocp_resource_summary(bp);
 
 	return 0;
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 12/18] ptp: ocp: Add debugfs entry for timecard
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (10 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 11/18] ptp: ocp: Separate the init and info logic Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 13/18] ptp: ocp: Add NMEA output Jonathan Lemon
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

Provide a view into the timecard internals for debugging.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 233 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 233 insertions(+)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index ea12f685edf6..36924423444e 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -4,6 +4,7 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/debugfs.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/serial_8250.h>
@@ -208,6 +209,7 @@ struct ptp_ocp {
 	struct tod_reg __iomem	*tod;
 	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 irig_master_reg	__iomem *irig_out;
 	struct irig_slave_reg	__iomem *irig_in;
@@ -224,6 +226,7 @@ struct ptp_ocp {
 	struct platform_device	*spi_flash;
 	struct clk_hw		*i2c_clk;
 	struct timer_list	watchdog;
+	struct dentry		*debug_root;
 	time64_t		gnss_lost;
 	int			id;
 	int			n_irqs;
@@ -354,6 +357,10 @@ static struct ocp_resource ocp_fb_resource[] = {
 		OCP_MEM_RESOURCE(image),
 		.offset = 0x00020000, .size = 0x1000,
 	},
+	{
+		OCP_MEM_RESOURCE(pps_select),
+		.offset = 0x00130000, .size = 0x1000,
+	},
 	{
 		OCP_MEM_RESOURCE(sma),
 		.offset = 0x00140000, .size = 0x1000,
@@ -1815,6 +1822,225 @@ 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)
+{
+	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
 ptp_ocp_dev_release(struct device *dev)
 {
@@ -1918,6 +2144,8 @@ ptp_ocp_complete(struct ptp_ocp *bp)
 	if (device_add_groups(&bp->dev, timecard_groups))
 		pr_err("device add groups failed\n");
 
+	ptp_ocp_debugfs_add_device(bp);
+
 	return 0;
 }
 
@@ -1988,6 +2216,7 @@ ptp_ocp_detach_sysfs(struct ptp_ocp *bp)
 static void
 ptp_ocp_detach(struct ptp_ocp *bp)
 {
+	ptp_ocp_debugfs_remove_device(bp);
 	ptp_ocp_detach_sysfs(bp);
 	if (timer_pending(&bp->watchdog))
 		del_timer_sync(&bp->watchdog);
@@ -2157,6 +2386,8 @@ ptp_ocp_init(void)
 	const char *what;
 	int err;
 
+	ptp_ocp_debugfs_init();
+
 	what = "timecard class";
 	err = class_register(&timecard_class);
 	if (err)
@@ -2179,6 +2410,7 @@ ptp_ocp_init(void)
 out_notifier:
 	class_unregister(&timecard_class);
 out:
+	ptp_ocp_debugfs_fini();
 	pr_err(KBUILD_MODNAME ": failed to register %s: %d\n", what, err);
 	return err;
 }
@@ -2189,6 +2421,7 @@ ptp_ocp_fini(void)
 	bus_unregister_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier);
 	pci_unregister_driver(&ptp_ocp_driver);
 	class_unregister(&timecard_class);
+	ptp_ocp_debugfs_fini();
 }
 
 module_init(ptp_ocp_init);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 13/18] ptp: ocp: Add NMEA output
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (11 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 12/18] ptp: ocp: Add debugfs entry for timecard Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 14/18] ptp: ocp: Add second GNSS device Jonathan Lemon
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

The timecard can provide a NMEA-1083 ZDA (time and date) output
string on a serial port, which can be used to drive other devices.

Add the NMEA resources, and the serial port as a sysfs attribute.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 57 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 55 insertions(+), 2 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 36924423444e..74b5561fbdae 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -215,6 +215,7 @@ struct ptp_ocp {
 	struct irig_slave_reg	__iomem *irig_in;
 	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	*pps;
 	struct ptp_ocp_ext_src	*ts0;
 	struct ptp_ocp_ext_src	*ts1;
@@ -232,6 +233,7 @@ struct ptp_ocp {
 	int			n_irqs;
 	int			gnss_port;
 	int			mac_port;	/* miniature atomic clock */
+	int			nmea_port;
 	u8			serial[6];
 	bool			has_serial;
 	int			flash_start;
@@ -289,8 +291,9 @@ static int ptp_ocp_ts_enable(void *priv, bool enable);
  * 5: MAC
  * 6: TS2
  * 7: I2C controller
- * 8: HWICAP
+ * 8: HWICAP (notused)
  * 9: SPI Flash
+ * 10: NMEA
  */
 
 static struct ocp_resource ocp_fb_resource[] = {
@@ -353,6 +356,10 @@ static struct ocp_resource ocp_fb_resource[] = {
 		OCP_MEM_RESOURCE(dcf_out),
 		.offset = 0x010A0000, .size = 0x10000,
 	},
+	{
+		OCP_MEM_RESOURCE(nmea_out),
+		.offset = 0x010B0000, .size = 0x10000,
+	},
 	{
 		OCP_MEM_RESOURCE(image),
 		.offset = 0x00020000, .size = 0x1000,
@@ -381,6 +388,10 @@ static struct ocp_resource ocp_fb_resource[] = {
 		OCP_SERIAL_RESOURCE(mac_port),
 		.offset = 0x00180000 + 0x1000, .irq_vec = 5,
 	},
+	{
+		OCP_SERIAL_RESOURCE(nmea_port),
+		.offset = 0x00190000 + 0x1000, .irq_vec = 10,
+	},
 	{
 		OCP_SPI_RESOURCE(spi_flash),
 		.offset = 0x00310000, .size = 0x10000, .irq_vec = 9,
@@ -761,6 +772,8 @@ ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val)
 		iowrite32(val, &bp->irig_out->adj_sec);
 	if (bp->dcf_out)
 		iowrite32(val, &bp->dcf_out->adj_sec);
+	if (bp->nmea_out)
+		iowrite32(val, &bp->nmea_out->adj_sec);
 
 	spin_unlock_irqrestore(&bp->lock, flags);
 }
@@ -1272,6 +1285,17 @@ ptp_ocp_register_mem(struct ptp_ocp *bp, struct ocp_resource *r)
 	return 0;
 }
 
+static void
+ptp_ocp_nmea_out_init(struct ptp_ocp *bp)
+{
+	if (!bp->nmea_out)
+		return;
+
+	iowrite32(0, &bp->nmea_out->ctrl);		/* disable */
+	iowrite32(7, &bp->nmea_out->uart_baud);		/* 115200 */
+	iowrite32(1, &bp->nmea_out->ctrl);		/* enable */
+}
+
 /* FB specific board initializers; last "resource" registered. */
 static int
 ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
@@ -1279,6 +1303,7 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
 	bp->flash_start = 1024 * 4096;
 
 	ptp_ocp_tod_init(bp);
+	ptp_ocp_nmea_out_init(bp);
 
 	return ptp_ocp_init_clock(bp);
 }
@@ -1941,6 +1966,13 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
 			   on ? " ON" : "OFF", val, src);
 	}
 
+	if (bp->nmea_out) {
+		on = ioread32(&bp->nmea_out->ctrl) & 1;
+		val = ioread32(&bp->nmea_out->status);
+		seq_printf(s, "%7s: %s, error: %d\n", "NMEA",
+			   on ? " ON" : "OFF", val);
+	}
+
 	/* compute src for PPS1, used below. */
 	if (bp->pps_select) {
 		val = ioread32(&bp->pps_select->gpio1);
@@ -2069,6 +2101,7 @@ ptp_ocp_device_init(struct ptp_ocp *bp, struct pci_dev *pdev)
 	spin_lock_init(&bp->lock);
 	bp->gnss_port = -1;
 	bp->mac_port = -1;
+	bp->nmea_port = -1;
 	bp->pdev = pdev;
 
 	device_initialize(&bp->dev);
@@ -2134,6 +2167,10 @@ ptp_ocp_complete(struct ptp_ocp *bp)
 		sprintf(buf, "ttyS%d", bp->mac_port);
 		ptp_ocp_link_child(bp, buf, "ttyMAC");
 	}
+	if (bp->nmea_port != -1) {
+		sprintf(buf, "ttyS%d", bp->nmea_port);
+		ptp_ocp_link_child(bp, buf, "ttyNMEA");
+	}
 	sprintf(buf, "ptp%d", ptp_clock_index(bp->ptp));
 	ptp_ocp_link_child(bp, buf, "ptp");
 
@@ -2180,7 +2217,13 @@ ptp_ocp_serial_info(struct device *dev, const char *name, int port, int baud)
 static void
 ptp_ocp_info(struct ptp_ocp *bp)
 {
+	static int nmea_baud[] = {
+		1200, 2400, 4800, 9600, 19200, 38400,
+		57600, 115200, 230400, 460800, 921600,
+		1000000, 2000000
+	};
 	struct device *dev = &bp->pdev->dev;
+	u32 reg;
 
 	ptp_ocp_phc_info(bp);
 	if (bp->tod)
@@ -2199,6 +2242,14 @@ ptp_ocp_info(struct ptp_ocp *bp)
 	}
 	ptp_ocp_serial_info(dev, "GNSS", bp->gnss_port, 115200);
 	ptp_ocp_serial_info(dev, "MAC", bp->mac_port, 57600);
+	if (bp->nmea_out && bp->nmea_port != -1) {
+		int baud = -1;
+
+		reg = ioread32(&bp->nmea_out->uart_baud);
+		if (reg < ARRAY_SIZE(nmea_baud))
+			baud = nmea_baud[reg];
+		ptp_ocp_serial_info(dev, "NMEA", bp->nmea_port, baud);
+	}
 }
 
 static void
@@ -2232,6 +2283,8 @@ ptp_ocp_detach(struct ptp_ocp *bp)
 		serial8250_unregister_port(bp->gnss_port);
 	if (bp->mac_port != -1)
 		serial8250_unregister_port(bp->mac_port);
+	if (bp->nmea_port != -1)
+		serial8250_unregister_port(bp->nmea_port);
 	if (bp->spi_flash)
 		platform_device_unregister(bp->spi_flash);
 	if (bp->i2c_ctrl)
@@ -2278,7 +2331,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, 10, PCI_IRQ_MSI | PCI_IRQ_MSIX);
+	err = pci_alloc_irq_vectors(pdev, 1, 11, 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] 22+ messages in thread

* [PATCH net-next 14/18] ptp: ocp: Add second GNSS device
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (12 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 13/18] ptp: ocp: Add NMEA output Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 15/18] ptp: ocp: Enable 4th timestamper / PPS generator Jonathan Lemon
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

Upcoming boards may have a second GNSS receiver, getting information
from a different constellation than the first receiver, which provides
some measure of anti-spoofing.

Expose the sysfs attribute for this device, if detected.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 74b5561fbdae..d0e3096f53f6 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -232,6 +232,7 @@ struct ptp_ocp {
 	int			id;
 	int			n_irqs;
 	int			gnss_port;
+	int			gnss2_port;
 	int			mac_port;	/* miniature atomic clock */
 	int			nmea_port;
 	u8			serial[6];
@@ -286,8 +287,8 @@ static int ptp_ocp_ts_enable(void *priv, bool enable);
  * 0: N/C
  * 1: TS0
  * 2: TS1
- * 3: GPS
- * 4: GPS2 (n/c)
+ * 3: GNSS
+ * 4: GNSS2
  * 5: MAC
  * 6: TS2
  * 7: I2C controller
@@ -384,6 +385,10 @@ static struct ocp_resource ocp_fb_resource[] = {
 		OCP_SERIAL_RESOURCE(gnss_port),
 		.offset = 0x00160000 + 0x1000, .irq_vec = 3,
 	},
+	{
+		OCP_SERIAL_RESOURCE(gnss2_port),
+		.offset = 0x00170000 + 0x1000, .irq_vec = 4,
+	},
 	{
 		OCP_SERIAL_RESOURCE(mac_port),
 		.offset = 0x00180000 + 0x1000, .irq_vec = 5,
@@ -2100,6 +2105,7 @@ ptp_ocp_device_init(struct ptp_ocp *bp, struct pci_dev *pdev)
 	bp->ptp_info = ptp_ocp_clock_info;
 	spin_lock_init(&bp->lock);
 	bp->gnss_port = -1;
+	bp->gnss2_port = -1;
 	bp->mac_port = -1;
 	bp->nmea_port = -1;
 	bp->pdev = pdev;
@@ -2163,6 +2169,10 @@ ptp_ocp_complete(struct ptp_ocp *bp)
 		sprintf(buf, "ttyS%d", bp->gnss_port);
 		ptp_ocp_link_child(bp, buf, "ttyGNSS");
 	}
+	if (bp->gnss2_port != -1) {
+		sprintf(buf, "ttyS%d", bp->gnss2_port);
+		ptp_ocp_link_child(bp, buf, "ttyGNSS2");
+	}
 	if (bp->mac_port != -1) {
 		sprintf(buf, "ttyS%d", bp->mac_port);
 		ptp_ocp_link_child(bp, buf, "ttyMAC");
@@ -2241,6 +2251,7 @@ ptp_ocp_info(struct ptp_ocp *bp)
 				 ver >> 16);
 	}
 	ptp_ocp_serial_info(dev, "GNSS", bp->gnss_port, 115200);
+	ptp_ocp_serial_info(dev, "GNSS2", bp->gnss2_port, 115200);
 	ptp_ocp_serial_info(dev, "MAC", bp->mac_port, 57600);
 	if (bp->nmea_out && bp->nmea_port != -1) {
 		int baud = -1;
@@ -2281,6 +2292,8 @@ ptp_ocp_detach(struct ptp_ocp *bp)
 		ptp_ocp_unregister_ext(bp->pps);
 	if (bp->gnss_port != -1)
 		serial8250_unregister_port(bp->gnss_port);
+	if (bp->gnss2_port != -1)
+		serial8250_unregister_port(bp->gnss2_port);
 	if (bp->mac_port != -1)
 		serial8250_unregister_port(bp->mac_port);
 	if (bp->nmea_port != -1)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 15/18] ptp: ocp: Enable 4th timestamper / PPS generator
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (13 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 14/18] ptp: ocp: Add second GNSS device Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-11-06 22:25     ` kernel test robot
  2021-09-15  2:16 ` [PATCH net-next 16/18] ptp: ocp: Have FPGA fold in ns adjustment for adjtime Jonathan Lemon
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

A 4th timestamper is added which timestamps the output of the PHC.

The clock nanosecond offset is not always zero, so when compared
to other timestampers, this provides precise measurements.

Also, the timestamper interrupt from the PHC can be used to generate
a PPS signal for /dev/pps.

Also allow PTP_CLK_REQ_PEROUT requests for a 1PPS output, but do
not actually configure any output pins, this is done via sysfs.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 82 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 74 insertions(+), 8 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index d0e3096f53f6..be8ab727a4ef 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -191,7 +191,7 @@ struct ptp_ocp_i2c_info {
 struct ptp_ocp_ext_info {
 	int index;
 	irqreturn_t (*irq_fcn)(int irq, void *priv);
-	int (*enable)(void *priv, bool enable);
+	int (*enable)(void *priv, u32 req, bool enable);
 };
 
 struct ptp_ocp_ext_src {
@@ -237,10 +237,14 @@ struct ptp_ocp {
 	int			nmea_port;
 	u8			serial[6];
 	bool			has_serial;
+	u32			pps_req_map;
 	int			flash_start;
 	u32			utc_tai_offset;
 };
 
+#define OCP_REQ_TIMESTAMP	BIT(0)
+#define OCP_REQ_PPS		BIT(1)
+
 struct ocp_resource {
 	unsigned long offset;
 	int size;
@@ -258,7 +262,7 @@ 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 int ptp_ocp_ts_enable(void *priv, bool enable);
+static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
 
 #define bp_assign_entry(bp, res, val) ({				\
 	uintptr_t addr = (uintptr_t)(bp) + (res)->bp_offset;		\
@@ -284,7 +288,7 @@ static int ptp_ocp_ts_enable(void *priv, bool enable);
 	OCP_RES_LOCATION(member), .setup = ptp_ocp_register_ext
 
 /* This is the MSI vector mapping used.
- * 0: N/C
+ * 0: TS3 (and PPS)
  * 1: TS0
  * 2: TS1
  * 3: GNSS
@@ -329,6 +333,15 @@ static struct ocp_resource ocp_fb_resource[] = {
 			.enable = ptp_ocp_ts_enable,
 		},
 	},
+	{
+		OCP_EXT_RESOURCE(pps),
+		.offset = 0x010C0000, .size = 0x10000, .irq_vec = 0,
+		.extra = &(struct ptp_ocp_ext_info) {
+			.index = 3,
+			.irq_fcn = ptp_ocp_ts_irq,
+			.enable = ptp_ocp_ts_enable,
+		},
+	},
 	{
 		OCP_MEM_RESOURCE(pps_to_ext),
 		.offset = 0x01030000, .size = 0x10000,
@@ -634,10 +647,12 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
 {
 	struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
 	struct ptp_ocp_ext_src *ext = NULL;
+	u32 req;
 	int err;
 
 	switch (rq->type) {
 	case PTP_CLK_REQ_EXTTS:
+		req = OCP_REQ_TIMESTAMP;
 		switch (rq->extts.index) {
 		case 0:
 			ext = bp->ts0;
@@ -648,18 +663,30 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
 		case 2:
 			ext = bp->ts2;
 			break;
+		case 3:
+			ext = bp->pps;
+			break;
 		}
 		break;
 	case PTP_CLK_REQ_PPS:
+		req = OCP_REQ_PPS;
 		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;
 	default:
 		return -EOPNOTSUPP;
 	}
 
 	err = -ENXIO;
 	if (ext)
-		err = ext->info->enable(ext, on);
+		err = ext->info->enable(ext, req, on);
 
 	return err;
 }
@@ -675,7 +702,8 @@ static const struct ptp_clock_info ptp_ocp_clock_info = {
 	.adjphase	= ptp_ocp_adjphase,
 	.enable		= ptp_ocp_enable,
 	.pps		= true,
-	.n_ext_ts	= 3,
+	.n_ext_ts	= 4,
+	.n_per_out	= 1,
 };
 
 static void
@@ -1163,6 +1191,16 @@ ptp_ocp_ts_irq(int irq, void *priv)
 	struct ptp_clock_event ev;
 	u32 sec, nsec;
 
+	if (ext == ext->bp->pps) {
+		if (ext->bp->pps_req_map & OCP_REQ_PPS) {
+			ev.type = PTP_CLOCK_PPS;
+			ptp_clock_event(ext->bp->ptp, &ev);
+		}
+
+		if ((ext->bp->pps_req_map & ~OCP_REQ_PPS) == 0)
+			goto out;
+	}
+
 	/* XXX should fix API - this converts s/ns -> ts -> s/ns */
 	sec = ioread32(&reg->time_sec);
 	nsec = ioread32(&reg->time_ns);
@@ -1173,16 +1211,31 @@ ptp_ocp_ts_irq(int irq, void *priv)
 
 	ptp_clock_event(ext->bp->ptp, &ev);
 
+out:
 	iowrite32(1, &reg->intr);	/* write 1 to ack */
 
 	return IRQ_HANDLED;
 }
 
 static int
-ptp_ocp_ts_enable(void *priv, bool enable)
+ptp_ocp_ts_enable(void *priv, u32 req, bool enable)
 {
 	struct ptp_ocp_ext_src *ext = priv;
 	struct ts_reg __iomem *reg = ext->mem;
+	struct ptp_ocp *bp = ext->bp;
+
+	if (ext == bp->pps) {
+		u32 old_map = bp->pps_req_map;
+
+		if (enable)
+			bp->pps_req_map |= req;
+		else
+			bp->pps_req_map &= ~req;
+
+		/* if no state change, just return */
+		if ((!!old_map ^ !!bp->pps_req_map) == 0)
+			return 0;
+	}
 
 	if (enable) {
 		iowrite32(1, &reg->enable);
@@ -1199,7 +1252,7 @@ ptp_ocp_ts_enable(void *priv, bool enable)
 static void
 ptp_ocp_unregister_ext(struct ptp_ocp_ext_src *ext)
 {
-	ext->info->enable(ext, false);
+	ext->info->enable(ext, ~0, false);
 	pci_free_irq(ext->bp->pdev, ext->irq_vec, ext);
 	kfree(ext);
 }
@@ -1889,8 +1942,8 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
 	struct timespec64 ts;
 	struct ptp_ocp *bp;
 	const char *src;
+	bool on, map;
 	char *buf;
-	bool on;
 
 	buf = (char *)__get_free_page(GFP_KERNEL);
 	if (!buf)
@@ -1938,6 +1991,19 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
 			   on ? " ON" : "OFF", src);
 	}
 
+	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",
+			   on & map ? " ON" : "OFF", src);
+
+		map = !!(bp->pps_req_map & OCP_REQ_PPS);
+		seq_printf(s, "%7s: %s, src: %s\n", "PPS",
+			   on & map ? " ON" : "OFF", src);
+	}
+
 	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] 22+ messages in thread

* [PATCH net-next 16/18] ptp: ocp: Have FPGA fold in ns adjustment for adjtime.
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (14 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 15/18] ptp: ocp: Enable 4th timestamper / PPS generator Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 17/18] ptp: ocp: Add timestamp window adjustment Jonathan Lemon
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

The current implementation of adjtime uses gettime/settime to
perform nanosecond adjustments.  This introduces addtional phase
errors due to delays.

Instead, use the FPGA's ability to just apply the nanosecond
adjustment to the clock directly.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 40 +++++++++++++++++++++++++---------------
 1 file changed, 25 insertions(+), 15 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index be8ab727a4ef..e6779a712bbb 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -594,9 +594,6 @@ ptp_ocp_settime(struct ptp_clock_info *ptp_info, const struct timespec64 *ts)
 	struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
 	unsigned long flags;
 
-	if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC)
-		return 0;
-
 	spin_lock_irqsave(&bp->lock, flags);
 	__ptp_ocp_settime_locked(bp, ts);
 	spin_unlock_irqrestore(&bp->lock, flags);
@@ -604,26 +601,39 @@ ptp_ocp_settime(struct ptp_clock_info *ptp_info, const struct timespec64 *ts)
 	return 0;
 }
 
+static void
+__ptp_ocp_adjtime_locked(struct ptp_ocp *bp, u64 adj_val)
+{
+	u32 select, ctrl;
+
+	select = ioread32(&bp->reg->select);
+	iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select);
+
+	iowrite32(adj_val, &bp->reg->offset_ns);
+	iowrite32(adj_val & 0x7f, &bp->reg->offset_window_ns);
+
+	ctrl = OCP_CTRL_ADJUST_OFFSET | OCP_CTRL_ENABLE;
+	iowrite32(ctrl, &bp->reg->ctrl);
+
+	/* restore clock selection */
+	iowrite32(select >> 16, &bp->reg->select);
+}
+
 static int
 ptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns)
 {
 	struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
-	struct timespec64 ts;
 	unsigned long flags;
-	int err;
+	u32 adj_ns, sign;
 
-	if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC)
-		return 0;
+	sign = delta_ns < 0 ? BIT(31) : 0;
+	adj_ns = sign ? -delta_ns : delta_ns;
 
 	spin_lock_irqsave(&bp->lock, flags);
-	err = __ptp_ocp_gettime_locked(bp, &ts, NULL);
-	if (likely(!err)) {
-		timespec64_add_ns(&ts, delta_ns);
-		__ptp_ocp_settime_locked(bp, &ts);
-	}
+	__ptp_ocp_adjtime_locked(bp, sign | adj_ns);
 	spin_unlock_irqrestore(&bp->lock, flags);
 
-	return err;
+	return 0;
 }
 
 static int
@@ -636,7 +646,7 @@ ptp_ocp_null_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
 }
 
 static int
-ptp_ocp_adjphase(struct ptp_clock_info *ptp_info, s32 phase_ns)
+ptp_ocp_null_adjphase(struct ptp_clock_info *ptp_info, s32 phase_ns)
 {
 	return -EOPNOTSUPP;
 }
@@ -699,7 +709,7 @@ static const struct ptp_clock_info ptp_ocp_clock_info = {
 	.settime64	= ptp_ocp_settime,
 	.adjtime	= ptp_ocp_adjtime,
 	.adjfine	= ptp_ocp_null_adjfine,
-	.adjphase	= ptp_ocp_adjphase,
+	.adjphase	= ptp_ocp_null_adjphase,
 	.enable		= ptp_ocp_enable,
 	.pps		= true,
 	.n_ext_ts	= 4,
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 17/18] ptp: ocp: Add timestamp window adjustment
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (15 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 16/18] ptp: ocp: Have FPGA fold in ns adjustment for adjtime Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15  2:16 ` [PATCH net-next 18/18] docs: ABI: Add sysfs documentation for timecard Jonathan Lemon
  2021-09-15 10:30 ` [PATCH net-next 00/18] timecard updates for v13 firmware patchwork-bot+netdevbpf
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

The following process is used to read the PHC clock and correlate
the reading with the "correct" system time.

- get starting timestamp
- issue PCI write command
- issue PCI read command
- get ending timestamp
- read latched sec/nsec registers

The write command is posted to PCI bus and returns.  When the write
arrives at the FPGA, the PHC time is latched into the sec/nsec registers,
and a flag is set indicating the registers are valid.  The read command
returns this flag, and the time retrieval proceeds.

Below is a non-scaled picture of the timing diagram involved.  The
PHC time corresponds to some SYS time between [start, end].  Userspace
usually uses the midpoint between [start, end] to estimate the PCI
delay and match this with the PHC time.

 [start] |                |
   write |-------+        |
	 |        \       |
    read |----+    +----->|
	 |     \          * PHC time latched into register
	 |      \         |
midpoint |       +------->|
	 |                |
	 |                |
	 |           +----|
	 |          /     |
	 |<--------+      |
   [end] |                |

As the diagram indicates, the PHC time is latched before the midpoint,
so the system clock time is slightly off the real PHC time.  This shows
up as a phase error with an oscilliscope.

The workaround here is to provide a tunable which reduces (shrinks)
the end time in the above diagram.  This in turn moves the calculated
midpoint so the system time and PHC time are in agreemment.

Currently, the adjustment reduces the end time by 3/16th of the entire
window.  E.g.:  [start, end] ==> [start, (end - (3/16 * end)], which
produces reasonably good results.

Also reduce delays by just writing to the clock control register
instead of performing a read/modify/write sequence, as the contents
of the control register are known.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 77 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 66 insertions(+), 11 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index e6779a712bbb..844b1401cc5d 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -240,6 +240,7 @@ struct ptp_ocp {
 	u32			pps_req_map;
 	int			flash_start;
 	u32			utc_tai_offset;
+	u32			ts_window_adjust;
 };
 
 #define OCP_REQ_TIMESTAMP	BIT(0)
@@ -528,10 +529,9 @@ __ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts,
 	u32 ctrl, time_sec, time_ns;
 	int i;
 
-	ctrl = ioread32(&bp->reg->ctrl);
-	ctrl |= OCP_CTRL_READ_TIME_REQ;
-
 	ptp_read_system_prets(sts);
+
+	ctrl = OCP_CTRL_READ_TIME_REQ | OCP_CTRL_ENABLE;
 	iowrite32(ctrl, &bp->reg->ctrl);
 
 	for (i = 0; i < 100; i++) {
@@ -541,6 +541,12 @@ __ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts,
 	}
 	ptp_read_system_postts(sts);
 
+	if (sts && bp->ts_window_adjust) {
+		s64 ns = timespec64_to_ns(&sts->post_ts);
+
+		sts->post_ts = ns_to_timespec64(ns - bp->ts_window_adjust);
+	}
+
 	time_ns = ioread32(&bp->reg->time_ns);
 	time_sec = ioread32(&bp->reg->time_sec);
 
@@ -580,8 +586,7 @@ __ptp_ocp_settime_locked(struct ptp_ocp *bp, const struct timespec64 *ts)
 	iowrite32(time_ns, &bp->reg->adjust_ns);
 	iowrite32(time_sec, &bp->reg->adjust_sec);
 
-	ctrl = ioread32(&bp->reg->ctrl);
-	ctrl |= OCP_CTRL_ADJUST_TIME;
+	ctrl = OCP_CTRL_ADJUST_TIME | OCP_CTRL_ENABLE;
 	iowrite32(ctrl, &bp->reg->ctrl);
 
 	/* restore clock selection */
@@ -726,8 +731,7 @@ __ptp_ocp_clear_drift_locked(struct ptp_ocp *bp)
 
 	iowrite32(0, &bp->reg->drift_ns);
 
-	ctrl = ioread32(&bp->reg->ctrl);
-	ctrl |= OCP_CTRL_ADJUST_DRIFT;
+	ctrl = OCP_CTRL_ADJUST_DRIFT | OCP_CTRL_ENABLE;
 	iowrite32(ctrl, &bp->reg->ctrl);
 
 	/* restore clock selection */
@@ -759,6 +763,28 @@ ptp_ocp_watchdog(struct timer_list *t)
 	mod_timer(&bp->watchdog, jiffies + HZ);
 }
 
+static void
+ptp_ocp_estimate_pci_timing(struct ptp_ocp *bp)
+{
+	ktime_t start, end;
+	ktime_t delay;
+	u32 ctrl;
+
+	ctrl = ioread32(&bp->reg->ctrl);
+	ctrl = OCP_CTRL_READ_TIME_REQ | OCP_CTRL_ENABLE;
+
+	iowrite32(ctrl, &bp->reg->ctrl);
+
+	start = ktime_get_ns();
+
+	ctrl = ioread32(&bp->reg->ctrl);
+
+	end = ktime_get_ns();
+
+	delay = end - start;
+	bp->ts_window_adjust = (delay >> 5) * 3;
+}
+
 static int
 ptp_ocp_init_clock(struct ptp_ocp *bp)
 {
@@ -766,9 +792,7 @@ ptp_ocp_init_clock(struct ptp_ocp *bp)
 	bool sync;
 	u32 ctrl;
 
-	/* make sure clock is enabled */
-	ctrl = ioread32(&bp->reg->ctrl);
-	ctrl |= OCP_CTRL_ENABLE;
+	ctrl = OCP_CTRL_ENABLE;
 	iowrite32(ctrl, &bp->reg->ctrl);
 
 	/* NO DRIFT Correction */
@@ -787,6 +811,8 @@ ptp_ocp_init_clock(struct ptp_ocp *bp)
 		return -ENODEV;
 	}
 
+	ptp_ocp_estimate_pci_timing(bp);
+
 	sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
 	if (!sync) {
 		ktime_get_clocktai_ts64(&ts);
@@ -1217,7 +1243,7 @@ ptp_ocp_ts_irq(int irq, void *priv)
 
 	ev.type = PTP_CLOCK_EXTTS;
 	ev.index = ext->info->index;
-	ev.timestamp = sec * 1000000000ULL + nsec;
+	ev.timestamp = sec * NSEC_PER_SEC + nsec;
 
 	ptp_clock_event(ext->bp->ptp, &ev);
 
@@ -1817,6 +1843,34 @@ utc_tai_offset_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(utc_tai_offset);
 
+static ssize_t
+ts_window_adjust_show(struct device *dev,
+		      struct device_attribute *attr, char *buf)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+
+	return sysfs_emit(buf, "%d\n", bp->ts_window_adjust);
+}
+
+static ssize_t
+ts_window_adjust_store(struct device *dev,
+		       struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	int err;
+	u32 val;
+
+	err = kstrtou32(buf, 0, &val);
+	if (err)
+		return err;
+
+	bp->ts_window_adjust = val;
+
+	return count;
+}
+static DEVICE_ATTR_RW(ts_window_adjust);
+
 static ssize_t
 irig_b_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -1911,6 +1965,7 @@ static struct attribute *timecard_attrs[] = {
 	&dev_attr_available_sma_outputs.attr,
 	&dev_attr_irig_b_mode.attr,
 	&dev_attr_utc_tai_offset.attr,
+	&dev_attr_ts_window_adjust.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(timecard);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 18/18] docs: ABI: Add sysfs documentation for timecard
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (16 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 17/18] ptp: ocp: Add timestamp window adjustment Jonathan Lemon
@ 2021-09-15  2:16 ` Jonathan Lemon
  2021-09-15 10:30 ` [PATCH net-next 00/18] timecard updates for v13 firmware patchwork-bot+netdevbpf
  18 siblings, 0 replies; 22+ messages in thread
From: Jonathan Lemon @ 2021-09-15  2:16 UTC (permalink / raw)
  To: kuba, davem, richardcochran; +Cc: netdev, kernel-team

This patch describes the sysfs interface implemented by the
ptp_ocp driver, under /sys/class/timecard.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 Documentation/ABI/testing/sysfs-timecard | 174 +++++++++++++++++++++++
 1 file changed, 174 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-timecard

diff --git a/Documentation/ABI/testing/sysfs-timecard b/Documentation/ABI/testing/sysfs-timecard
new file mode 100644
index 000000000000..97f6773794a5
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-timecard
@@ -0,0 +1,174 @@
+What:		/sys/class/timecard/
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	This directory contains files and directories
+		providing a standardized interface to the ancillary
+		features of the OpenCompute timecard.
+
+What:		/sys/class/timecard/ocpN/
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	This directory contains the attributes of the Nth timecard
+		registered.
+
+What:		/sys/class/timecard/ocpN/available_clock_sources
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RO) The list of available time sources that the PHC
+		uses for clock adjustments.
+
+		====  =================================================
+                NONE  no adjustments
+                PPS   adjustments come from the PPS1 selector (default)
+                TOD   adjustments from the GNSS/TOD module
+                IRIG  adjustments from external IRIG-B signal
+                DCF   adjustments from external DCF signal
+                ====  =================================================
+
+What:		/sys/class/timecard/ocpN/available_sma_inputs
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RO) Set of available destinations (sinks) for a SMA
+		input signal.
+
+                =====  ================================================
+                10Mhz  signal is used as the 10Mhz reference clock
+                PPS1   signal is sent to the PPS1 selector
+                PPS2   signal is sent to the PPS2 selector
+                TS1    signal is sent to timestamper 1
+                TS2    signal is sent to timestamper 2
+                IRIG   signal is sent to the IRIG-B module
+                DCF    signal is sent to the DCF module
+                =====  ================================================
+
+What:		/sys/class/timecard/ocpN/available_sma_outputs
+Date:		May 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+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
+                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
+                =====  ================================================
+
+What:		/sys/class/timecard/ocpN/clock_source
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RW) Contains the current synchronization source used by
+		the PHC.  May be changed by writing one of the listed
+		values from the available_clock_sources attribute set.
+
+What:		/sys/class/timecard/ocpN/gnss_sync
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RO) Indicates whether a valid GNSS signal is received,
+		or when the signal was lost.
+
+What:		/sys/class/timecard/ocpN/i2c
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	This optional attribute links to the associated i2c device.
+
+What:		/sys/class/timecard/ocpN/irig_b_mode
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RW) An integer from 0-7 indicating the timecode format
+		of the IRIG-B output signal: B00<n>
+
+What:		/sys/class/timecard/ocpN/pps
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	This optional attribute links to the associated PPS device.
+
+What:		/sys/class/timecard/ocpN/ptp
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	This attribute links to the associated PTP device.
+
+What:		/sys/class/timecard/ocpN/serialnum
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RO) Provides the serial number of the timecard.
+
+What:		/sys/class/timecard/ocpN/sma1
+What:		/sys/class/timecard/ocpN/sma2
+What:		/sys/class/timecard/ocpN/sma3
+What:		/sys/class/timecard/ocpN/sma4
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RW) These attributes specify the direction of the signal
+		on the associated SMA connectors, and also the signal sink
+		or source.
+
+		The display format of the attribute is a space separated
+		list of signals, prefixed by the input/output direction.
+
+		The signal direction may be changed (if supported) by
+		prefixing the signal list with either "in:" or "out:".
+		If neither prefix is present, then the direction is unchanged.
+
+		The output signal may be changed by writing one of the listed
+		values from the available_sma_outputs attribute set.
+
+		The input destinations may be changed by writing multiple
+		values from the available_sma_inputs attribute set,
+		separated by spaces.  If there are duplicated input
+		destinations between connectors, the lowest numbered SMA
+		connector is given priority.
+
+		Note that not all input combinations may make sense.
+
+		The 10Mhz reference clock input is currently only valid
+		on SMA1 and may not be combined with other destination sinks.
+
+What:		/sys/class/timecard/ocpN/ts_window_adjust
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RW) When retrieving the PHC with the PTP SYS_OFFSET_EXTENDED
+		ioctl, a system timestamp is made before and after the PHC
+		time is retrieved.  The midpoint between the two system
+		timestamps is usually taken to be the SYS time associated
+		with the PHC time.  This estimate may be wrong, as it depends
+		on PCI latencies, and when the PHC time was latched
+
+		The attribute value reduces the end timestamp by the given
+		number of nanoseconds, so the computed midpoint matches the
+		retrieved PHC time.
+
+		The initial value is set based on measured PCI latency and
+		the estimated point where the FPGA latches the PHC time.  This
+		value may be changed by writing an unsigned integer.
+
+What:		/sys/class/timecard/ocpN/ttyGNSS
+What:		/sys/class/timecard/ocpN/ttyGNSS2
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	These optional attributes link to the TTY serial ports
+		associated with the GNSS devices.
+
+What:		/sys/class/timecard/ocpN/ttyMAC
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	This optional attribute links to the TTY serial port
+		associated with the Miniature Atomic Clock.
+
+What:		/sys/class/timecard/ocpN/ttyNMEA
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	This optional attribute links to the TTY serial port
+		which outputs the PHC time in NMEA ZDA format.
+
+What:		/sys/class/timecard/ocpN/utc_tai_offset
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RW) The DCF and IRIG output signals are in UTC, while the
+		TimeCard operates on TAI.  This attribute allows setting the
+		offset in seconds, which is added to the TAI timebase for
+		these formats.
+
+		The offset may be changed by writing an unsigned integer.
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH net-next 00/18] timecard updates for v13 firmware
  2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
                   ` (17 preceding siblings ...)
  2021-09-15  2:16 ` [PATCH net-next 18/18] docs: ABI: Add sysfs documentation for timecard Jonathan Lemon
@ 2021-09-15 10:30 ` patchwork-bot+netdevbpf
  18 siblings, 0 replies; 22+ messages in thread
From: patchwork-bot+netdevbpf @ 2021-09-15 10:30 UTC (permalink / raw)
  To: Jonathan Lemon; +Cc: kuba, davem, richardcochran, netdev, kernel-team

Hello:

This series was applied to netdev/net-next.git (refs/heads/master):

On Tue, 14 Sep 2021 19:16:18 -0700 you wrote:
> This update mainly deals with features for the TimeCard v13 firmware.
> 
> The signals provided from the external SMA connectors can be steered
> to different locations, and the generated SMA signals can be chosen.
> 
> Future timecard revisions will allow selectable I/O on any of the
> SMA connectors, so name the attributes appropriately, and set up
> the ABI in preparation for the new features.
> 
> [...]

Here is the summary with links:
  - [net-next,01/18] ptp: ocp: parameterize the i2c driver used
    https://git.kernel.org/netdev/net-next/c/1618df6afab2
  - [net-next,02/18] ptp: ocp: Parameterize the TOD information display.
    https://git.kernel.org/netdev/net-next/c/498ad3f4389a
  - [net-next,03/18] ptp: ocp: Skip I2C flash read when there is no controller.
    https://git.kernel.org/netdev/net-next/c/1447149d6539
  - [net-next,04/18] ptp: ocp: Skip resources with out of range irqs
    https://git.kernel.org/netdev/net-next/c/56ec44033cd7
  - [net-next,05/18] ptp: ocp: Report error if resource registration fails.
    https://git.kernel.org/netdev/net-next/c/bceff2905eff
  - [net-next,06/18] ptp: ocp: Add third timestamper
    https://git.kernel.org/netdev/net-next/c/dcf614692c6c
  - [net-next,07/18] ptp: ocp: Add SMA selector and controls
    https://git.kernel.org/netdev/net-next/c/e1daf0ec73b2
  - [net-next,08/18] ptp: ocp: Add IRIG-B and DCF blocks
    https://git.kernel.org/netdev/net-next/c/6baf2925424a
  - [net-next,09/18] ptp: ocp: Add IRIG-B output mode control
    https://git.kernel.org/netdev/net-next/c/d14ee2525d38
  - [net-next,10/18] ptp: ocp: Add sysfs attribute utc_tai_offset
    https://git.kernel.org/netdev/net-next/c/89260d878253
  - [net-next,11/18] ptp: ocp: Separate the init and info logic
    https://git.kernel.org/netdev/net-next/c/065efcc5e976
  - [net-next,12/18] ptp: ocp: Add debugfs entry for timecard
    https://git.kernel.org/netdev/net-next/c/f67bf662d2cf
  - [net-next,13/18] ptp: ocp: Add NMEA output
    https://git.kernel.org/netdev/net-next/c/e3516bb45078
  - [net-next,14/18] ptp: ocp: Add second GNSS device
    https://git.kernel.org/netdev/net-next/c/71d7e0850476
  - [net-next,15/18] ptp: ocp: Enable 4th timestamper / PPS generator
    https://git.kernel.org/netdev/net-next/c/a62a56d04e63
  - [net-next,16/18] ptp: ocp: Have FPGA fold in ns adjustment for adjtime.
    https://git.kernel.org/netdev/net-next/c/6d59d4fa1789
  - [net-next,17/18] ptp: ocp: Add timestamp window adjustment
    https://git.kernel.org/netdev/net-next/c/1acffc6e09ed
  - [net-next,18/18] docs: ABI: Add sysfs documentation for timecard
    https://git.kernel.org/netdev/net-next/c/d7050a2b85ff

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] 22+ messages in thread

* Re: [PATCH net-next 15/18] ptp: ocp: Enable 4th timestamper / PPS generator
  2021-09-15  2:16 ` [PATCH net-next 15/18] ptp: ocp: Enable 4th timestamper / PPS generator Jonathan Lemon
@ 2021-11-06 22:25     ` kernel test robot
  0 siblings, 0 replies; 22+ messages in thread
From: kernel test robot @ 2021-11-06 22:25 UTC (permalink / raw)
  To: Jonathan Lemon; +Cc: llvm, kbuild-all

[-- Attachment #1: Type: text/plain, Size: 9347 bytes --]

Hi Jonathan,

I love your patch! Perhaps something to improve:

[auto build test WARNING on net/master]
[also build test WARNING on horms-ipvs/master v5.15]
[cannot apply to net-next/master linus/master next-20211106]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jonathan-Lemon/timecard-updates-for-v13-firmware/20210929-111346
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git 4ccb9f03fee7b20484187ba7e25a7b9b79fe63d5
config: i386-randconfig-a001-20210928 (attached as .config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project dc6e8dfdfe7efecfda318d43a06fae18b40eb498)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/e0ae415a29dcf1eaa46cf3ffde625d87339216b7
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jonathan-Lemon/timecard-updates-for-v13-firmware/20210929-111346
        git checkout e0ae415a29dcf1eaa46cf3ffde625d87339216b7
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/ptp/ptp_ocp.c:2000:16: warning: operator '?:' has lower precedence than '&'; '&' will be evaluated first [-Wbitwise-conditional-parentheses]
                              on & map ? " ON" : "OFF", src);
                              ~~~~~~~~ ^
   drivers/ptp/ptp_ocp.c:2000:16: note: place parentheses around the '&' expression to silence this warning
                              on & map ? " ON" : "OFF", src);
                                       ^
                              (       )
   drivers/ptp/ptp_ocp.c:2000:16: note: place parentheses around the '?:' expression to evaluate it first
                              on & map ? " ON" : "OFF", src);
                                       ^
                                   (                  )
   drivers/ptp/ptp_ocp.c:2004:16: warning: operator '?:' has lower precedence than '&'; '&' will be evaluated first [-Wbitwise-conditional-parentheses]
                              on & map ? " ON" : "OFF", src);
                              ~~~~~~~~ ^
   drivers/ptp/ptp_ocp.c:2004:16: note: place parentheses around the '&' expression to silence this warning
                              on & map ? " ON" : "OFF", src);
                                       ^
                              (       )
   drivers/ptp/ptp_ocp.c:2004:16: note: place parentheses around the '?:' expression to evaluate it first
                              on & map ? " ON" : "OFF", src);
                                       ^
                                   (                  )
   2 warnings generated.


vim +2000 drivers/ptp/ptp_ocp.c

  1934	
  1935	static int
  1936	ptp_ocp_summary_show(struct seq_file *s, void *data)
  1937	{
  1938		struct device *dev = s->private;
  1939		struct ptp_system_timestamp sts;
  1940		u32 sma_in, sma_out, ctrl, val;
  1941		struct ts_reg __iomem *ts_reg;
  1942		struct timespec64 ts;
  1943		struct ptp_ocp *bp;
  1944		const char *src;
  1945		bool on, map;
  1946		char *buf;
  1947	
  1948		buf = (char *)__get_free_page(GFP_KERNEL);
  1949		if (!buf)
  1950			return -ENOMEM;
  1951	
  1952		bp = dev_get_drvdata(dev);
  1953		sma_in = ioread32(&bp->sma->gpio1);
  1954		sma_out = ioread32(&bp->sma->gpio2);
  1955	
  1956		seq_printf(s, "%7s: /dev/ptp%d\n", "PTP", ptp_clock_index(bp->ptp));
  1957	
  1958		sma1_show(dev, NULL, buf);
  1959		seq_printf(s, "   sma1: %s", buf);
  1960	
  1961		sma2_show(dev, NULL, buf);
  1962		seq_printf(s, "   sma2: %s", buf);
  1963	
  1964		sma3_show(dev, NULL, buf);
  1965		seq_printf(s, "   sma3: %s", buf);
  1966	
  1967		sma4_show(dev, NULL, buf);
  1968		seq_printf(s, "   sma4: %s", buf);
  1969	
  1970		if (bp->ts0) {
  1971			ts_reg = bp->ts0->mem;
  1972			on = ioread32(&ts_reg->enable);
  1973			src = "GNSS";
  1974			seq_printf(s, "%7s: %s, src: %s\n", "TS0",
  1975				   on ? " ON" : "OFF", src);
  1976		}
  1977	
  1978		if (bp->ts1) {
  1979			ts_reg = bp->ts1->mem;
  1980			on = ioread32(&ts_reg->enable);
  1981			src = gpio_map(sma_in, 2, "sma1", "sma2", "----");
  1982			seq_printf(s, "%7s: %s, src: %s\n", "TS1",
  1983				   on ? " ON" : "OFF", src);
  1984		}
  1985	
  1986		if (bp->ts2) {
  1987			ts_reg = bp->ts2->mem;
  1988			on = ioread32(&ts_reg->enable);
  1989			src = gpio_map(sma_in, 3, "sma1", "sma2", "----");
  1990			seq_printf(s, "%7s: %s, src: %s\n", "TS2",
  1991				   on ? " ON" : "OFF", src);
  1992		}
  1993	
  1994		if (bp->pps) {
  1995			ts_reg = bp->pps->mem;
  1996			src = "PHC";
  1997			on = ioread32(&ts_reg->enable);
  1998			map = !!(bp->pps_req_map & OCP_REQ_TIMESTAMP);
  1999			seq_printf(s, "%7s: %s, src: %s\n", "TS3",
> 2000				   on & map ? " ON" : "OFF", src);
  2001	
  2002			map = !!(bp->pps_req_map & OCP_REQ_PPS);
  2003			seq_printf(s, "%7s: %s, src: %s\n", "PPS",
  2004				   on & map ? " ON" : "OFF", src);
  2005		}
  2006	
  2007		if (bp->irig_out) {
  2008			ctrl = ioread32(&bp->irig_out->ctrl);
  2009			on = ctrl & IRIG_M_CTRL_ENABLE;
  2010			val = ioread32(&bp->irig_out->status);
  2011			gpio_multi_map(buf, sma_out, 4, "sma3", "sma4", "----");
  2012			seq_printf(s, "%7s: %s, error: %d, mode %d, out: %s\n", "IRIG",
  2013				   on ? " ON" : "OFF", val, (ctrl >> 16), buf);
  2014		}
  2015	
  2016		if (bp->irig_in) {
  2017			on = ioread32(&bp->irig_in->ctrl) & IRIG_S_CTRL_ENABLE;
  2018			val = ioread32(&bp->irig_in->status);
  2019			src = gpio_map(sma_in, 4, "sma1", "sma2", "----");
  2020			seq_printf(s, "%7s: %s, error: %d, src: %s\n", "IRIG in",
  2021				   on ? " ON" : "OFF", val, src);
  2022		}
  2023	
  2024		if (bp->dcf_out) {
  2025			on = ioread32(&bp->dcf_out->ctrl) & DCF_M_CTRL_ENABLE;
  2026			val = ioread32(&bp->dcf_out->status);
  2027			gpio_multi_map(buf, sma_out, 5, "sma3", "sma4", "----");
  2028			seq_printf(s, "%7s: %s, error: %d, out: %s\n", "DCF",
  2029				   on ? " ON" : "OFF", val, buf);
  2030		}
  2031	
  2032		if (bp->dcf_in) {
  2033			on = ioread32(&bp->dcf_in->ctrl) & DCF_S_CTRL_ENABLE;
  2034			val = ioread32(&bp->dcf_in->status);
  2035			src = gpio_map(sma_in, 5, "sma1", "sma2", "----");
  2036			seq_printf(s, "%7s: %s, error: %d, src: %s\n", "DCF in",
  2037				   on ? " ON" : "OFF", val, src);
  2038		}
  2039	
  2040		if (bp->nmea_out) {
  2041			on = ioread32(&bp->nmea_out->ctrl) & 1;
  2042			val = ioread32(&bp->nmea_out->status);
  2043			seq_printf(s, "%7s: %s, error: %d\n", "NMEA",
  2044				   on ? " ON" : "OFF", val);
  2045		}
  2046	
  2047		/* compute src for PPS1, used below. */
  2048		if (bp->pps_select) {
  2049			val = ioread32(&bp->pps_select->gpio1);
  2050			if (val & 0x01)
  2051				src = gpio_map(sma_in, 0, "sma1", "sma2", "----");
  2052			else if (val & 0x02)
  2053				src = "MAC";
  2054			else if (val & 0x04)
  2055				src = "GNSS";
  2056			else
  2057				src = "----";
  2058		} else {
  2059			src = "?";
  2060		}
  2061	
  2062		/* assumes automatic switchover/selection */
  2063		val = ioread32(&bp->reg->select);
  2064		switch (val >> 16) {
  2065		case 0:
  2066			sprintf(buf, "----");
  2067			break;
  2068		case 2:
  2069			sprintf(buf, "IRIG");
  2070			break;
  2071		case 3:
  2072			sprintf(buf, "%s via PPS1", src);
  2073			break;
  2074		case 6:
  2075			sprintf(buf, "DCF");
  2076			break;
  2077		default:
  2078			strcpy(buf, "unknown");
  2079			break;
  2080		}
  2081		val = ioread32(&bp->reg->status);
  2082		seq_printf(s, "%7s: %s, state: %s\n", "PHC src", buf,
  2083			   val & OCP_STATUS_IN_SYNC ? "sync" : "unsynced");
  2084	
  2085		/* reuses PPS1 src from earlier */
  2086		seq_printf(s, "MAC PPS1 src: %s\n", src);
  2087	
  2088		src = gpio_map(sma_in, 1, "sma1", "sma2", "GNSS2");
  2089		seq_printf(s, "MAC PPS2 src: %s\n", src);
  2090	
  2091		if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, &sts)) {
  2092			struct timespec64 sys_ts;
  2093			s64 pre_ns, post_ns, ns;
  2094	
  2095			pre_ns = timespec64_to_ns(&sts.pre_ts);
  2096			post_ns = timespec64_to_ns(&sts.post_ts);
  2097			ns = (pre_ns + post_ns) / 2;
  2098			ns += (s64)bp->utc_tai_offset * NSEC_PER_SEC;
  2099			sys_ts = ns_to_timespec64(ns);
  2100	
  2101			seq_printf(s, "%7s: %lld.%ld == %ptT TAI\n", "PHC",
  2102				   ts.tv_sec, ts.tv_nsec, &ts);
  2103			seq_printf(s, "%7s: %lld.%ld == %ptT UTC offset %d\n", "SYS",
  2104				   sys_ts.tv_sec, sys_ts.tv_nsec, &sys_ts,
  2105				   bp->utc_tai_offset);
  2106			seq_printf(s, "%7s: PHC:SYS offset: %lld  window: %lld\n", "",
  2107				   timespec64_to_ns(&ts) - ns,
  2108				   post_ns - pre_ns);
  2109		}
  2110	
  2111		free_page((unsigned long)buf);
  2112		return 0;
  2113	}
  2114	DEFINE_SHOW_ATTRIBUTE(ptp_ocp_summary);
  2115	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 32485 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH net-next 15/18] ptp: ocp: Enable 4th timestamper / PPS generator
@ 2021-11-06 22:25     ` kernel test robot
  0 siblings, 0 replies; 22+ messages in thread
From: kernel test robot @ 2021-11-06 22:25 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 9592 bytes --]

Hi Jonathan,

I love your patch! Perhaps something to improve:

[auto build test WARNING on net/master]
[also build test WARNING on horms-ipvs/master v5.15]
[cannot apply to net-next/master linus/master next-20211106]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jonathan-Lemon/timecard-updates-for-v13-firmware/20210929-111346
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git 4ccb9f03fee7b20484187ba7e25a7b9b79fe63d5
config: i386-randconfig-a001-20210928 (attached as .config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project dc6e8dfdfe7efecfda318d43a06fae18b40eb498)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/e0ae415a29dcf1eaa46cf3ffde625d87339216b7
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jonathan-Lemon/timecard-updates-for-v13-firmware/20210929-111346
        git checkout e0ae415a29dcf1eaa46cf3ffde625d87339216b7
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/ptp/ptp_ocp.c:2000:16: warning: operator '?:' has lower precedence than '&'; '&' will be evaluated first [-Wbitwise-conditional-parentheses]
                              on & map ? " ON" : "OFF", src);
                              ~~~~~~~~ ^
   drivers/ptp/ptp_ocp.c:2000:16: note: place parentheses around the '&' expression to silence this warning
                              on & map ? " ON" : "OFF", src);
                                       ^
                              (       )
   drivers/ptp/ptp_ocp.c:2000:16: note: place parentheses around the '?:' expression to evaluate it first
                              on & map ? " ON" : "OFF", src);
                                       ^
                                   (                  )
   drivers/ptp/ptp_ocp.c:2004:16: warning: operator '?:' has lower precedence than '&'; '&' will be evaluated first [-Wbitwise-conditional-parentheses]
                              on & map ? " ON" : "OFF", src);
                              ~~~~~~~~ ^
   drivers/ptp/ptp_ocp.c:2004:16: note: place parentheses around the '&' expression to silence this warning
                              on & map ? " ON" : "OFF", src);
                                       ^
                              (       )
   drivers/ptp/ptp_ocp.c:2004:16: note: place parentheses around the '?:' expression to evaluate it first
                              on & map ? " ON" : "OFF", src);
                                       ^
                                   (                  )
   2 warnings generated.


vim +2000 drivers/ptp/ptp_ocp.c

  1934	
  1935	static int
  1936	ptp_ocp_summary_show(struct seq_file *s, void *data)
  1937	{
  1938		struct device *dev = s->private;
  1939		struct ptp_system_timestamp sts;
  1940		u32 sma_in, sma_out, ctrl, val;
  1941		struct ts_reg __iomem *ts_reg;
  1942		struct timespec64 ts;
  1943		struct ptp_ocp *bp;
  1944		const char *src;
  1945		bool on, map;
  1946		char *buf;
  1947	
  1948		buf = (char *)__get_free_page(GFP_KERNEL);
  1949		if (!buf)
  1950			return -ENOMEM;
  1951	
  1952		bp = dev_get_drvdata(dev);
  1953		sma_in = ioread32(&bp->sma->gpio1);
  1954		sma_out = ioread32(&bp->sma->gpio2);
  1955	
  1956		seq_printf(s, "%7s: /dev/ptp%d\n", "PTP", ptp_clock_index(bp->ptp));
  1957	
  1958		sma1_show(dev, NULL, buf);
  1959		seq_printf(s, "   sma1: %s", buf);
  1960	
  1961		sma2_show(dev, NULL, buf);
  1962		seq_printf(s, "   sma2: %s", buf);
  1963	
  1964		sma3_show(dev, NULL, buf);
  1965		seq_printf(s, "   sma3: %s", buf);
  1966	
  1967		sma4_show(dev, NULL, buf);
  1968		seq_printf(s, "   sma4: %s", buf);
  1969	
  1970		if (bp->ts0) {
  1971			ts_reg = bp->ts0->mem;
  1972			on = ioread32(&ts_reg->enable);
  1973			src = "GNSS";
  1974			seq_printf(s, "%7s: %s, src: %s\n", "TS0",
  1975				   on ? " ON" : "OFF", src);
  1976		}
  1977	
  1978		if (bp->ts1) {
  1979			ts_reg = bp->ts1->mem;
  1980			on = ioread32(&ts_reg->enable);
  1981			src = gpio_map(sma_in, 2, "sma1", "sma2", "----");
  1982			seq_printf(s, "%7s: %s, src: %s\n", "TS1",
  1983				   on ? " ON" : "OFF", src);
  1984		}
  1985	
  1986		if (bp->ts2) {
  1987			ts_reg = bp->ts2->mem;
  1988			on = ioread32(&ts_reg->enable);
  1989			src = gpio_map(sma_in, 3, "sma1", "sma2", "----");
  1990			seq_printf(s, "%7s: %s, src: %s\n", "TS2",
  1991				   on ? " ON" : "OFF", src);
  1992		}
  1993	
  1994		if (bp->pps) {
  1995			ts_reg = bp->pps->mem;
  1996			src = "PHC";
  1997			on = ioread32(&ts_reg->enable);
  1998			map = !!(bp->pps_req_map & OCP_REQ_TIMESTAMP);
  1999			seq_printf(s, "%7s: %s, src: %s\n", "TS3",
> 2000				   on & map ? " ON" : "OFF", src);
  2001	
  2002			map = !!(bp->pps_req_map & OCP_REQ_PPS);
  2003			seq_printf(s, "%7s: %s, src: %s\n", "PPS",
  2004				   on & map ? " ON" : "OFF", src);
  2005		}
  2006	
  2007		if (bp->irig_out) {
  2008			ctrl = ioread32(&bp->irig_out->ctrl);
  2009			on = ctrl & IRIG_M_CTRL_ENABLE;
  2010			val = ioread32(&bp->irig_out->status);
  2011			gpio_multi_map(buf, sma_out, 4, "sma3", "sma4", "----");
  2012			seq_printf(s, "%7s: %s, error: %d, mode %d, out: %s\n", "IRIG",
  2013				   on ? " ON" : "OFF", val, (ctrl >> 16), buf);
  2014		}
  2015	
  2016		if (bp->irig_in) {
  2017			on = ioread32(&bp->irig_in->ctrl) & IRIG_S_CTRL_ENABLE;
  2018			val = ioread32(&bp->irig_in->status);
  2019			src = gpio_map(sma_in, 4, "sma1", "sma2", "----");
  2020			seq_printf(s, "%7s: %s, error: %d, src: %s\n", "IRIG in",
  2021				   on ? " ON" : "OFF", val, src);
  2022		}
  2023	
  2024		if (bp->dcf_out) {
  2025			on = ioread32(&bp->dcf_out->ctrl) & DCF_M_CTRL_ENABLE;
  2026			val = ioread32(&bp->dcf_out->status);
  2027			gpio_multi_map(buf, sma_out, 5, "sma3", "sma4", "----");
  2028			seq_printf(s, "%7s: %s, error: %d, out: %s\n", "DCF",
  2029				   on ? " ON" : "OFF", val, buf);
  2030		}
  2031	
  2032		if (bp->dcf_in) {
  2033			on = ioread32(&bp->dcf_in->ctrl) & DCF_S_CTRL_ENABLE;
  2034			val = ioread32(&bp->dcf_in->status);
  2035			src = gpio_map(sma_in, 5, "sma1", "sma2", "----");
  2036			seq_printf(s, "%7s: %s, error: %d, src: %s\n", "DCF in",
  2037				   on ? " ON" : "OFF", val, src);
  2038		}
  2039	
  2040		if (bp->nmea_out) {
  2041			on = ioread32(&bp->nmea_out->ctrl) & 1;
  2042			val = ioread32(&bp->nmea_out->status);
  2043			seq_printf(s, "%7s: %s, error: %d\n", "NMEA",
  2044				   on ? " ON" : "OFF", val);
  2045		}
  2046	
  2047		/* compute src for PPS1, used below. */
  2048		if (bp->pps_select) {
  2049			val = ioread32(&bp->pps_select->gpio1);
  2050			if (val & 0x01)
  2051				src = gpio_map(sma_in, 0, "sma1", "sma2", "----");
  2052			else if (val & 0x02)
  2053				src = "MAC";
  2054			else if (val & 0x04)
  2055				src = "GNSS";
  2056			else
  2057				src = "----";
  2058		} else {
  2059			src = "?";
  2060		}
  2061	
  2062		/* assumes automatic switchover/selection */
  2063		val = ioread32(&bp->reg->select);
  2064		switch (val >> 16) {
  2065		case 0:
  2066			sprintf(buf, "----");
  2067			break;
  2068		case 2:
  2069			sprintf(buf, "IRIG");
  2070			break;
  2071		case 3:
  2072			sprintf(buf, "%s via PPS1", src);
  2073			break;
  2074		case 6:
  2075			sprintf(buf, "DCF");
  2076			break;
  2077		default:
  2078			strcpy(buf, "unknown");
  2079			break;
  2080		}
  2081		val = ioread32(&bp->reg->status);
  2082		seq_printf(s, "%7s: %s, state: %s\n", "PHC src", buf,
  2083			   val & OCP_STATUS_IN_SYNC ? "sync" : "unsynced");
  2084	
  2085		/* reuses PPS1 src from earlier */
  2086		seq_printf(s, "MAC PPS1 src: %s\n", src);
  2087	
  2088		src = gpio_map(sma_in, 1, "sma1", "sma2", "GNSS2");
  2089		seq_printf(s, "MAC PPS2 src: %s\n", src);
  2090	
  2091		if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, &sts)) {
  2092			struct timespec64 sys_ts;
  2093			s64 pre_ns, post_ns, ns;
  2094	
  2095			pre_ns = timespec64_to_ns(&sts.pre_ts);
  2096			post_ns = timespec64_to_ns(&sts.post_ts);
  2097			ns = (pre_ns + post_ns) / 2;
  2098			ns += (s64)bp->utc_tai_offset * NSEC_PER_SEC;
  2099			sys_ts = ns_to_timespec64(ns);
  2100	
  2101			seq_printf(s, "%7s: %lld.%ld == %ptT TAI\n", "PHC",
  2102				   ts.tv_sec, ts.tv_nsec, &ts);
  2103			seq_printf(s, "%7s: %lld.%ld == %ptT UTC offset %d\n", "SYS",
  2104				   sys_ts.tv_sec, sys_ts.tv_nsec, &sys_ts,
  2105				   bp->utc_tai_offset);
  2106			seq_printf(s, "%7s: PHC:SYS offset: %lld  window: %lld\n", "",
  2107				   timespec64_to_ns(&ts) - ns,
  2108				   post_ns - pre_ns);
  2109		}
  2110	
  2111		free_page((unsigned long)buf);
  2112		return 0;
  2113	}
  2114	DEFINE_SHOW_ATTRIBUTE(ptp_ocp_summary);
  2115	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 32485 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2021-11-06 22:26 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-15  2:16 [PATCH net-next 00/18] timecard updates for v13 firmware Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 01/18] ptp: ocp: parameterize the i2c driver used Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 02/18] ptp: ocp: Parameterize the TOD information display Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 03/18] ptp: ocp: Skip I2C flash read when there is no controller Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 04/18] ptp: ocp: Skip resources with out of range irqs Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 05/18] ptp: ocp: Report error if resource registration fails Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 06/18] ptp: ocp: Add third timestamper Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 07/18] ptp: ocp: Add SMA selector and controls Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 08/18] ptp: ocp: Add IRIG-B and DCF blocks Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 09/18] ptp: ocp: Add IRIG-B output mode control Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 10/18] ptp: ocp: Add sysfs attribute utc_tai_offset Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 11/18] ptp: ocp: Separate the init and info logic Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 12/18] ptp: ocp: Add debugfs entry for timecard Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 13/18] ptp: ocp: Add NMEA output Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 14/18] ptp: ocp: Add second GNSS device Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 15/18] ptp: ocp: Enable 4th timestamper / PPS generator Jonathan Lemon
2021-11-06 22:25   ` kernel test robot
2021-11-06 22:25     ` kernel test robot
2021-09-15  2:16 ` [PATCH net-next 16/18] ptp: ocp: Have FPGA fold in ns adjustment for adjtime Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 17/18] ptp: ocp: Add timestamp window adjustment Jonathan Lemon
2021-09-15  2:16 ` [PATCH net-next 18/18] docs: ABI: Add sysfs documentation for timecard Jonathan Lemon
2021-09-15 10:30 ` [PATCH net-next 00/18] timecard updates for v13 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.