All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 00/11] ocp timecard updates
@ 2021-08-30 23:52 Jonathan Lemon
  2021-08-30 23:52 ` [PATCH net-next 01/11] ptp: ocp: parameterize the i2c driver used Jonathan Lemon
                   ` (10 more replies)
  0 siblings, 11 replies; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

This update mainly deals with features for the TimeCard v10 firmware.
The signals provided from the external SMA connectors can be steered
to different locations, and the generated SMA signals can be chosen.

The update also adds support for IRIG-B and DCF formats.

Jonathan Lemon (11):
  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: Add third timestamper
  ptp: ocp: Add SMA selector and controls
  ptp: ocp: Add IRIG-B and DCF blocks
  ptp: ocp: Add sysfs attribute utc_tai_offset
  ptp: ocp: Add debugfs entry for timecard
  ptp: ocp: Add IRIG-B output mode control
  docs: ABI: Add sysfs documentation for timecard

 Documentation/ABI/testing/sysfs-timecard | 141 ++++
 drivers/ptp/ptp_ocp.c                    | 855 +++++++++++++++++++++--
 2 files changed, 929 insertions(+), 67 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-timecard

-- 
2.31.1


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

* [PATCH net-next 01/11] ptp: ocp: parameterize the i2c driver used
  2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
@ 2021-08-30 23:52 ` Jonathan Lemon
  2021-08-30 23:52 ` [PATCH net-next 02/11] ptp: ocp: Parameterize the TOD information display Jonathan Lemon
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

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

* [PATCH net-next 02/11] ptp: ocp: Parameterize the TOD information display.
  2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
  2021-08-30 23:52 ` [PATCH net-next 01/11] ptp: ocp: parameterize the i2c driver used Jonathan Lemon
@ 2021-08-30 23:52 ` Jonathan Lemon
  2021-08-30 23:52 ` [PATCH net-next 03/11] ptp: ocp: Skip I2C flash read when there is no controller Jonathan Lemon
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

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

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

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

* [PATCH net-next 04/11] ptp: ocp: Skip resources with out of range irqs
  2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
                   ` (2 preceding siblings ...)
  2021-08-30 23:52 ` [PATCH net-next 03/11] ptp: ocp: Skip I2C flash read when there is no controller Jonathan Lemon
@ 2021-08-30 23:52 ` Jonathan Lemon
  2021-08-30 23:52 ` [PATCH net-next 05/11] ptp: ocp: Add third timestamper Jonathan Lemon
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

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

* [PATCH net-next 05/11] ptp: ocp: Add third timestamper
  2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
                   ` (3 preceding siblings ...)
  2021-08-30 23:52 ` [PATCH net-next 04/11] ptp: ocp: Skip resources with out of range irqs Jonathan Lemon
@ 2021-08-30 23:52 ` Jonathan Lemon
  2021-08-30 23:52 ` [PATCH net-next 06/11] ptp: ocp: Add SMA selector and controls Jonathan Lemon
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

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 ad8b794fa7e6..c5fbccab57a8 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
@@ -1403,6 +1416,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] 21+ messages in thread

* [PATCH net-next 06/11] ptp: ocp: Add SMA selector and controls
  2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
                   ` (4 preceding siblings ...)
  2021-08-30 23:52 ` [PATCH net-next 05/11] ptp: ocp: Add third timestamper Jonathan Lemon
@ 2021-08-30 23:52 ` Jonathan Lemon
  2021-09-01 23:56   ` Jakub Kicinski
  2021-08-30 23:52 ` [PATCH net-next 07/11] ptp: ocp: Add IRIG-B and DCF blocks Jonathan Lemon
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

The v10 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 | 315 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 287 insertions(+), 28 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index c5fbccab57a8..3920bdb1977a 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,71 @@ 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 },
+	{ .name = "IRIG",	.value = 0x10 },
+	{ .name = "DCF",	.value = 0x20 },
+	{ }
+};
+
+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 },
+	{ .name = "IRIG",	.value = 0x10 },
+	{ .name = "DCF",	.value = 0x20 },
+	{ }
 };
 
 static const char *
-ptp_ocp_clock_name_from_val(int val)
+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)
+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
+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 +808,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),
+		 select_name_from_val(ptp_ocp_clock, select >> 16),
 		 ptp_clock_index(bp->ptp));
 
 	if (bp->tod)
@@ -1204,6 +1256,219 @@ gnss_sync_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR_RO(gnss_sync);
 
+/*
+ * In the schematic, pins are ANTx, these map to the external connectors:
+ * ANT1 == sma2
+ * ANT2 == sma1
+ * ANT3 == sma4
+ * ANT4 == sma3
+ */
+
+static ssize_t
+sma_show_output(u32 val, char *buf, int default_idx)
+{
+	const char *name;
+
+	name = select_name_from_val(ptp_ocp_sma_out, val);
+	if (!name)
+		name = ptp_ocp_sma_out[default_idx].name;
+	return sysfs_emit(buf, "%s\n", name);
+}
+
+static ssize_t
+sma_show_inputs(u32 val, char *buf)
+{
+	const char *name;
+	ssize_t count;
+	int i;
+
+	count = 0;
+	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 (count)
+		count--;
+	count += sysfs_emit_at(buf, count, "\n");
+	return count;
+}
+
+static int
+sma_parse_inputs(const char *buf)
+{
+	int i, count;
+	char **argv;
+	int ret;
+
+	argv = argv_split(GFP_KERNEL, buf, &count);
+	if (!argv)
+		return -ENOMEM;
+
+	ret = -EINVAL;
+	if (!count)
+		goto out;
+
+	ret = 0;
+	for (i = 0; i < count; i++)
+		ret |= select_val_from_name(ptp_ocp_sma_in, argv[i]);
+
+out:
+	argv_free(argv);
+	return ret;
+}
+
+static ssize_t
+sma2_out_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 sma_show_output(val, buf, 0);
+}
+
+static ssize_t
+sma1_out_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 sma_show_output(val, buf, 1);
+}
+
+static ssize_t
+sma2_out_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;
+	u32 gpio;
+	int val;
+
+	val = select_val_from_name(ptp_ocp_sma_out, buf);
+	if (val < 0)
+		return val;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	gpio = ioread32(&bp->sma->gpio2);
+	gpio = (gpio & 0xffff0000) | val;
+	iowrite32(gpio, &bp->sma->gpio2);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	return count;
+}
+static DEVICE_ATTR_RW(sma2_out);
+
+static ssize_t
+sma1_out_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;
+	u32 gpio;
+	int val;
+
+	val = select_val_from_name(ptp_ocp_sma_out, buf);
+	if (val < 0)
+		return val;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	gpio = ioread32(&bp->sma->gpio2);
+	gpio = (gpio & 0xffff) | (val << 16);
+	iowrite32(gpio, &bp->sma->gpio2);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	return count;
+}
+static DEVICE_ATTR_RW(sma1_out);
+
+static ssize_t
+sma4_in_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;
+	if (val == 0)
+		return sysfs_emit(buf, "%s\n", ptp_ocp_sma_in[0].name);
+	return sma_show_inputs(val, buf);
+}
+
+static ssize_t
+sma3_in_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 sma_show_inputs(val, buf);
+}
+
+static ssize_t
+sma4_in_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;
+	u32 gpio;
+	int val;
+
+	val = sma_parse_inputs(buf);
+	if (val < 0)
+		return val;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	gpio = ioread32(&bp->sma->gpio1);
+	gpio = (gpio & 0xffff0000) | val;
+	iowrite32(gpio, &bp->sma->gpio1);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	return count;
+}
+static DEVICE_ATTR_RW(sma4_in);
+
+static ssize_t
+sma3_in_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;
+	u32 gpio;
+	int val;
+
+	val = sma_parse_inputs(buf);
+	if (val < 0)
+		return val;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	gpio = ioread32(&bp->sma->gpio1);
+	gpio = (gpio & 0xffff) | (val << 16);
+	iowrite32(gpio, &bp->sma->gpio1);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	return count;
+}
+static DEVICE_ATTR_RW(sma3_in);
+
+static ssize_t
+available_sma_inputs_show(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	return 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 select_table_show(ptp_ocp_sma_out, buf);
+}
+static DEVICE_ATTR_RO(available_sma_outputs);
+
 static ssize_t
 clock_source_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -1212,7 +1477,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 = select_name_from_val(ptp_ocp_clock, select >> 16);
 
 	return sysfs_emit(buf, "%s\n", p);
 }
@@ -1225,7 +1490,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 = select_val_from_name(ptp_ocp_clock, buf);
 	if (val < 0)
 		return val;
 
@@ -1241,19 +1506,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 select_table_show(ptp_ocp_clock, buf);
 }
 static DEVICE_ATTR_RO(available_clock_sources);
 
@@ -1262,6 +1515,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_out.attr,
+	&dev_attr_sma2_out.attr,
+	&dev_attr_sma3_in.attr,
+	&dev_attr_sma4_in.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] 21+ messages in thread

* [PATCH net-next 07/11] ptp: ocp: Add IRIG-B and DCF blocks
  2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
                   ` (5 preceding siblings ...)
  2021-08-30 23:52 ` [PATCH net-next 06/11] ptp: ocp: Add SMA selector and controls Jonathan Lemon
@ 2021-08-30 23:52 ` Jonathan Lemon
  2021-08-30 23:52 ` [PATCH net-next 08/11] ptp: ocp: Add sysfs attribute utc_tai_offset Jonathan Lemon
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

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 | 123 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 123 insertions(+)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 3920bdb1977a..fceeee380d9f 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,
@@ -1295,6 +1357,49 @@ sma_show_inputs(u32 val, char *buf)
 	return count;
 }
 
+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 int
 sma_parse_inputs(const char *buf)
 {
@@ -1319,6 +1424,20 @@ sma_parse_inputs(const char *buf)
 	return ret;
 }
 
+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);
+}
+
 static ssize_t
 sma2_out_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -1355,6 +1474,7 @@ sma2_out_store(struct device *dev, struct device_attribute *attr,
 	spin_lock_irqsave(&bp->lock, flags);
 	gpio = ioread32(&bp->sma->gpio2);
 	gpio = (gpio & 0xffff0000) | val;
+	__handle_signal_outputs(bp, gpio);
 	iowrite32(gpio, &bp->sma->gpio2);
 	spin_unlock_irqrestore(&bp->lock, flags);
 
@@ -1378,6 +1498,7 @@ sma1_out_store(struct device *dev, struct device_attribute *attr,
 	spin_lock_irqsave(&bp->lock, flags);
 	gpio = ioread32(&bp->sma->gpio2);
 	gpio = (gpio & 0xffff) | (val << 16);
+	__handle_signal_outputs(bp, gpio);
 	iowrite32(gpio, &bp->sma->gpio2);
 	spin_unlock_irqrestore(&bp->lock, flags);
 
@@ -1423,6 +1544,7 @@ sma4_in_store(struct device *dev, struct device_attribute *attr,
 	spin_lock_irqsave(&bp->lock, flags);
 	gpio = ioread32(&bp->sma->gpio1);
 	gpio = (gpio & 0xffff0000) | val;
+	__handle_signal_inputs(bp, gpio);
 	iowrite32(gpio, &bp->sma->gpio1);
 	spin_unlock_irqrestore(&bp->lock, flags);
 
@@ -1446,6 +1568,7 @@ sma3_in_store(struct device *dev, struct device_attribute *attr,
 	spin_lock_irqsave(&bp->lock, flags);
 	gpio = ioread32(&bp->sma->gpio1);
 	gpio = (gpio & 0xffff) | (val << 16);
+	__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] 21+ messages in thread

* [PATCH net-next 08/11] ptp: ocp: Add sysfs attribute utc_tai_offset
  2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
                   ` (6 preceding siblings ...)
  2021-08-30 23:52 ` [PATCH net-next 07/11] ptp: ocp: Add IRIG-B and DCF blocks Jonathan Lemon
@ 2021-08-30 23:52 ` Jonathan Lemon
  2021-09-01 23:56   ` Jakub Kicinski
  2021-08-30 23:52 ` [PATCH net-next 09/11] ptp: ocp: Add debugfs entry for timecard Jonathan Lemon
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

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 | 38 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index fceeee380d9f..093385c6fed0 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;
+	s32			utc_tai_offset;
 };
 
 struct ocp_resource {
@@ -1592,6 +1593,40 @@ available_sma_outputs_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(available_sma_outputs);
 
+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);
+	unsigned long flags;
+	int err;
+	s32 val;
+
+	err = kstrtos32(buf, 0, &val);
+	if (err)
+		return err;
+
+	bp->utc_tai_offset = val;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	iowrite32(val, &bp->irig_out->adj_sec);
+	iowrite32(val, &bp->dcf_out->adj_sec);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	return count;
+}
+static DEVICE_ATTR_RW(utc_tai_offset);
+
 static ssize_t
 clock_source_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -1644,6 +1679,7 @@ static struct attribute *timecard_attrs[] = {
 	&dev_attr_sma4_in.attr,
 	&dev_attr_available_sma_inputs.attr,
 	&dev_attr_available_sma_outputs.attr,
+	&dev_attr_utc_tai_offset.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(timecard);
-- 
2.31.1


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

* [PATCH net-next 09/11] ptp: ocp: Add debugfs entry for timecard
  2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
                   ` (7 preceding siblings ...)
  2021-08-30 23:52 ` [PATCH net-next 08/11] ptp: ocp: Add sysfs attribute utc_tai_offset Jonathan Lemon
@ 2021-08-30 23:52 ` Jonathan Lemon
  2021-09-02  0:06   ` Jakub Kicinski
  2021-08-30 23:52 ` [PATCH net-next 10/11] ptp: ocp: Add IRIG-B output mode control Jonathan Lemon
  2021-08-30 23:52 ` [PATCH net-next 11/11] docs: ABI: Add sysfs documentation for timecard Jonathan Lemon
  10 siblings, 1 reply; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

Provide a view into the timecard internals for debugging.

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

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 093385c6fed0..daa95f48c39f 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,
@@ -1684,6 +1691,223 @@ static struct attribute *timecard_attrs[] = {
 };
 ATTRIBUTE_GROUPS(timecard);
 
+#ifdef CONFIG_DEBUG_FS
+#define gpio_map(gpio, bit, pri, sec, def) ({			\
+	char *_ans;						\
+	if (gpio & (1 << bit))					\
+		_ans = pri;					\
+	else if (gpio & (1 << (bit + 16)))			\
+		_ans = sec;					\
+	else							\
+		_ans = def;					\
+	_ans;							\
+})
+
+#define gpio_multi_map(buf, gpio, bit, pri, sec, def) ({	\
+		char *_ans;					\
+		_ans = buf;					\
+		strcpy(buf, def);				\
+		if (gpio & (1 << (bit + 16)))			\
+			_ans += sprintf(_ans, "%s ", pri);	\
+		if (gpio & (1 << bit))				\
+			_ans += sprintf(_ans, "%s ", sec);	\
+})
+
+static int
+ptp_ocp_summary_show(struct seq_file *s, void *data)
+{
+	struct device *dev = s->private;
+	struct ts_reg __iomem *ts_reg;
+	u32 sma_in, sma_out, val;
+	struct timespec64 ts;
+	struct ptp_ocp *bp;
+	char *buf, *src;
+	bool on;
+
+	buf = (char *)__get_free_page(GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	sma1_out_show(dev, NULL, buf);
+	seq_printf(s, "   sma1: out from %s", buf);
+
+	sma2_out_show(dev, NULL, buf);
+	seq_printf(s, "   sma2: out from %s", buf);
+
+	sma3_in_show(dev, NULL, buf);
+	seq_printf(s, "   sma3: input to %s", buf);
+
+	sma4_in_show(dev, NULL, buf);
+	seq_printf(s, "   sma4: input to %s", buf);
+
+	bp = dev_get_drvdata(dev);
+	sma_in = ioread32(&bp->sma->gpio1);
+	sma_out = ioread32(&bp->sma->gpio2);
+
+	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, "sma4", "sma3", "----");
+		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, "sma4", "sma3", "----");
+		seq_printf(s, "%7s: %s, src: %s\n", "TS2",
+			   on ? " ON" : "OFF", src);
+	}
+
+	if (bp->irig_out) {
+		on = ioread32(&bp->irig_out->ctrl) & IRIG_M_CTRL_ENABLE;
+		val = ioread32(&bp->irig_out->status);
+		gpio_multi_map(buf, sma_out, 4, "sma1", "sma2", "----");
+		seq_printf(s, "%7s: %s, error: %d, out: %s\n", "IRIG",
+			   on ? " ON" : "OFF", val, 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, "sma4", "sma3", "----");
+		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, "sma1", "sma2", "----");
+		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, "sma4", "sma3", "----");
+		seq_printf(s, "%7s: %s, error: %d, src: %s\n", "DCF in",
+			   on ? " ON" : "OFF", val, src);
+	}
+
+	src = gpio_map(sma_in, 2, "sma4", "sma3", "GNSS");
+	sprintf(buf, "%s via PPS2", src);
+	seq_printf(s, " MAC PPS src: %s\n", buf);
+
+	/* 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:
+		if (bp->pps_select) {
+			val = ioread32(&bp->pps_select->gpio1);
+			if (val & 0x01) {
+				src = gpio_map(sma_in, 1,
+					       "sma4", "sma3", "----");
+			} else if (val & 0x02)
+				src = "MAC";
+			else if (val & 0x04)
+				src = "GNSS";
+			else
+				src = "----";
+			sprintf(buf, "%s via PPS1", src);
+		} else {
+			strcpy(buf, "PPS1");
+		}
+		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");
+
+	if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL))
+		seq_printf(s, "%7s: %lld.%ld == %ptT\n", "PHC",
+			   ts.tv_sec, ts.tv_nsec, &ts);
+
+	free_page((unsigned long)buf);
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ptp_ocp_summary);
+
+static struct dentry *ptp_ocp_debugfs_root;
+
+static int
+ptp_ocp_debugfs_add_device(struct ptp_ocp *bp)
+{
+	struct dentry *d;
+
+	d = debugfs_create_dir(dev_name(&bp->dev), ptp_ocp_debugfs_root);
+	if (IS_ERR(d))
+		return PTR_ERR(d);
+	bp->debug_root = d;
+
+	d = debugfs_create_file("summary", 0444, bp->debug_root,
+				&bp->dev, &ptp_ocp_summary_fops);
+	if (IS_ERR(d))
+		goto fail;
+
+	return 0;
+
+fail:
+	debugfs_remove_recursive(bp->debug_root);
+	bp->debug_root = NULL;
+
+	return PTR_ERR(d);
+}
+
+static void
+ptp_ocp_debugfs_remove_device(struct ptp_ocp *bp)
+{
+	debugfs_remove_recursive(bp->debug_root);
+}
+
+static int
+ptp_ocp_debugfs_init(void)
+{
+	struct dentry *d;
+
+	d = debugfs_create_dir("timecard", NULL);
+	if (IS_ERR(d))
+		return PTR_ERR(d);
+
+	ptp_ocp_debugfs_root = d;
+
+	return 0;
+}
+
+static void
+ptp_ocp_debugfs_fini(void)
+{
+	debugfs_remove_recursive(ptp_ocp_debugfs_root);
+}
+#else
+#define ptp_ocp_debugfs_init()			0
+#define ptp_ocp_debugfs_fini()
+#define ptp_ocp_debugfs_add_device(bp)		0
+#define ptp_ocp_debugfs_remove_device(bp)
+#endif
+
 static void
 ptp_ocp_dev_release(struct device *dev)
 {
@@ -1787,6 +2011,9 @@ ptp_ocp_complete(struct ptp_ocp *bp)
 	if (device_add_groups(&bp->dev, timecard_groups))
 		pr_err("device add groups failed\n");
 
+	if (ptp_ocp_debugfs_add_device(bp))
+		pr_err("debugfs add device failed\n");
+
 	return 0;
 }
 
@@ -1827,6 +2054,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);
@@ -1997,10 +2225,15 @@ ptp_ocp_init(void)
 	const char *what;
 	int err;
 
+	what = "debugfs entry";
+	err = ptp_ocp_debugfs_init();
+	if (err)
+		goto out;
+
 	what = "timecard class";
 	err = class_register(&timecard_class);
 	if (err)
-		goto out;
+		goto out_debug;
 
 	what = "i2c notifier";
 	err = bus_register_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier);
@@ -2018,6 +2251,8 @@ ptp_ocp_init(void)
 	bus_unregister_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier);
 out_notifier:
 	class_unregister(&timecard_class);
+out_debug:
+	ptp_ocp_debugfs_fini();
 out:
 	pr_err(KBUILD_MODNAME ": failed to register %s: %d\n", what, err);
 	return err;
@@ -2029,6 +2264,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] 21+ messages in thread

* [PATCH net-next 10/11] ptp: ocp: Add IRIG-B output mode control
  2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
                   ` (8 preceding siblings ...)
  2021-08-30 23:52 ` [PATCH net-next 09/11] ptp: ocp: Add debugfs entry for timecard Jonathan Lemon
@ 2021-08-30 23:52 ` Jonathan Lemon
  2021-09-02  0:07   ` Jakub Kicinski
  2021-08-30 23:52 ` [PATCH net-next 11/11] docs: ABI: Add sysfs documentation for timecard Jonathan Lemon
  10 siblings, 1 reply; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

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 | 50 +++++++++++++++++++++++++++++++++++++++----
 1 file changed, 46 insertions(+), 4 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index daa95f48c39f..3cc1b5e661af 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -1634,6 +1634,46 @@ utc_tai_offset_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(utc_tai_offset);
 
+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)
 {
@@ -1687,6 +1727,7 @@ static struct attribute *timecard_attrs[] = {
 	&dev_attr_available_sma_inputs.attr,
 	&dev_attr_available_sma_outputs.attr,
 	&dev_attr_utc_tai_offset.attr,
+	&dev_attr_irig_b_mode.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(timecard);
@@ -1718,7 +1759,7 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
 {
 	struct device *dev = s->private;
 	struct ts_reg __iomem *ts_reg;
-	u32 sma_in, sma_out, val;
+	u32 sma_in, sma_out, ctrl, val;
 	struct timespec64 ts;
 	struct ptp_ocp *bp;
 	char *buf, *src;
@@ -1769,11 +1810,12 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
 	}
 
 	if (bp->irig_out) {
-		on = ioread32(&bp->irig_out->ctrl) & IRIG_M_CTRL_ENABLE;
+		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, "sma1", "sma2", "----");
-		seq_printf(s, "%7s: %s, error: %d, out: %s\n", "IRIG",
-			   on ? " ON" : "OFF", val, buf);
+		seq_printf(s, "%7s: %s, error: %d, mode %d, out: %s\n", "IRIG",
+			   on ? " ON" : "OFF", val, (ctrl >> 16), buf);
 	}
 
 	if (bp->irig_in) {
-- 
2.31.1


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

* [PATCH net-next 11/11] docs: ABI: Add sysfs documentation for timecard
  2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
                   ` (9 preceding siblings ...)
  2021-08-30 23:52 ` [PATCH net-next 10/11] ptp: ocp: Add IRIG-B output mode control Jonathan Lemon
@ 2021-08-30 23:52 ` Jonathan Lemon
  10 siblings, 0 replies; 21+ messages in thread
From: Jonathan Lemon @ 2021-08-30 23:52 UTC (permalink / raw)
  To: davem, kuba, richardcochran; +Cc: netdev, kernel-team, abyagowi

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 | 141 +++++++++++++++++++++++
 1 file changed, 141 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..a473b953b4d3
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-timecard
@@ -0,0 +1,141 @@
+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_out
+What:		/sys/class/timecard/ocpN/sma2_out
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RW) These attributes specify the signal present on the
+		associated SMA connectors.  May be changed by writing one of
+		the listed values from the available_sma_outputs attribute set.
+
+What:		/sys/class/timecard/ocpN/sma3_in
+What:		/sys/class/timecard/ocpN/sma4_in
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	(RW) These attributes specify where the input signal on the
+		associated connector should be sent.  May be changed by writing
+		multiple values from the available_sma_outputs attribute set,
+		separated by spaces.  If there are duplicated destinations
+		between the two connectors, SMA4 is given priority.
+
+		Note that not all combinations may make sense.
+
+		The 10Mhz reference clock is only valid on SMA4 and may not
+		be combined with other destination sinks.
+
+What:		/sys/class/timecard/ocpN/ttyGNSS
+Date:		September 2021
+Contact:	Jonathan Lemon <jonathan.lemon@gmail.com>
+Description:	This optional attribute links to the TTY serial port
+		associated with the GNSS device.
+
+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/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 a signed integer.
-- 
2.31.1


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

* Re: [PATCH net-next 06/11] ptp: ocp: Add SMA selector and controls
  2021-08-30 23:52 ` [PATCH net-next 06/11] ptp: ocp: Add SMA selector and controls Jonathan Lemon
@ 2021-09-01 23:56   ` Jakub Kicinski
  2021-09-02 16:55     ` Jonathan Lemon
  0 siblings, 1 reply; 21+ messages in thread
From: Jakub Kicinski @ 2021-09-01 23:56 UTC (permalink / raw)
  To: Jonathan Lemon; +Cc: davem, richardcochran, netdev, kernel-team, abyagowi

On Mon, 30 Aug 2021 16:52:31 -0700 Jonathan Lemon wrote:
>  static int
> -ptp_ocp_clock_val_from_name(const char *name)
> +select_val_from_name(struct ocp_selector *tbl, const char *name)

Why not prefix the helpers with ptp_ocp_ ? Makes code easier to follow
IMHO.

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

* Re: [PATCH net-next 08/11] ptp: ocp: Add sysfs attribute utc_tai_offset
  2021-08-30 23:52 ` [PATCH net-next 08/11] ptp: ocp: Add sysfs attribute utc_tai_offset Jonathan Lemon
@ 2021-09-01 23:56   ` Jakub Kicinski
  2021-09-02 16:57     ` Jonathan Lemon
  0 siblings, 1 reply; 21+ messages in thread
From: Jakub Kicinski @ 2021-09-01 23:56 UTC (permalink / raw)
  To: Jonathan Lemon; +Cc: davem, richardcochran, netdev, kernel-team, abyagowi

On Mon, 30 Aug 2021 16:52:33 -0700 Jonathan Lemon wrote:
> +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);
> +	unsigned long flags;
> +	int err;
> +	s32 val;
> +
> +	err = kstrtos32(buf, 0, &val);
> +	if (err)
> +		return err;
> +
> +	bp->utc_tai_offset = val;

This line should probably be under the lock.

> +	spin_lock_irqsave(&bp->lock, flags);
> +	iowrite32(val, &bp->irig_out->adj_sec);
> +	iowrite32(val, &bp->dcf_out->adj_sec);
> +	spin_unlock_irqrestore(&bp->lock, flags);
> +
> +	return count;
> +}
> +static DEVICE_ATTR_RW(utc_tai_offset);

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

* Re: [PATCH net-next 09/11] ptp: ocp: Add debugfs entry for timecard
  2021-08-30 23:52 ` [PATCH net-next 09/11] ptp: ocp: Add debugfs entry for timecard Jonathan Lemon
@ 2021-09-02  0:06   ` Jakub Kicinski
  2021-09-02 17:00     ` Jonathan Lemon
  0 siblings, 1 reply; 21+ messages in thread
From: Jakub Kicinski @ 2021-09-02  0:06 UTC (permalink / raw)
  To: Jonathan Lemon; +Cc: davem, richardcochran, netdev, kernel-team, abyagowi

On Mon, 30 Aug 2021 16:52:34 -0700 Jonathan Lemon wrote:
> Provide a view into the timecard internals for debugging.
> 
> Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>

> +#ifdef CONFIG_DEBUG_FS
> +#define gpio_map(gpio, bit, pri, sec, def) ({			\
> +	char *_ans;						\
> +	if (gpio & (1 << bit))					\
> +		_ans = pri;					\
> +	else if (gpio & (1 << (bit + 16)))			\
> +		_ans = sec;					\
> +	else							\
> +		_ans = def;					\
> +	_ans;							\
> +})
> +
> +#define gpio_multi_map(buf, gpio, bit, pri, sec, def) ({	\
> +		char *_ans;					\
> +		_ans = buf;					\
> +		strcpy(buf, def);				\
> +		if (gpio & (1 << (bit + 16)))			\
> +			_ans += sprintf(_ans, "%s ", pri);	\
> +		if (gpio & (1 << bit))				\
> +			_ans += sprintf(_ans, "%s ", sec);	\
> +})

These can't be static inlines?

> +static int
> +ptp_ocp_summary_show(struct seq_file *s, void *data)
> +{
> +	struct device *dev = s->private;
> +	struct ts_reg __iomem *ts_reg;
> +	u32 sma_in, sma_out, val;
> +	struct timespec64 ts;
> +	struct ptp_ocp *bp;
> +	char *buf, *src;
> +	bool on;
> +
> +	buf = (char *)__get_free_page(GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	sma1_out_show(dev, NULL, buf);
> +	seq_printf(s, "   sma1: out from %s", buf);
> +
> +	sma2_out_show(dev, NULL, buf);
> +	seq_printf(s, "   sma2: out from %s", buf);
> +
> +	sma3_in_show(dev, NULL, buf);
> +	seq_printf(s, "   sma3: input to %s", buf);
> +
> +	sma4_in_show(dev, NULL, buf);
> +	seq_printf(s, "   sma4: input to %s", buf);

Why duplicate the data already available via sysfs?

> +static int
> +ptp_ocp_debugfs_add_device(struct ptp_ocp *bp)
> +{
> +	struct dentry *d;
> +
> +	d = debugfs_create_dir(dev_name(&bp->dev), ptp_ocp_debugfs_root);
> +	if (IS_ERR(d))
> +		return PTR_ERR(d);

Driver's are not supposed to depend on debugfs, you should be able to
carry on and all debugfs functions you pass an error pointer as a
parent will just return the same error right back.

> +	bp->debug_root = d;
> +
> +	d = debugfs_create_file("summary", 0444, bp->debug_root,
> +				&bp->dev, &ptp_ocp_summary_fops);
> +	if (IS_ERR(d))
> +		goto fail;
> +
> +	return 0;
> +
> +fail:
> +	debugfs_remove_recursive(bp->debug_root);
> +	bp->debug_root = NULL;
> +
> +	return PTR_ERR(d);
> +}
> +
> +static void
> +ptp_ocp_debugfs_remove_device(struct ptp_ocp *bp)
> +{
> +	debugfs_remove_recursive(bp->debug_root);
> +}
> +
> +static int
> +ptp_ocp_debugfs_init(void)
> +{
> +	struct dentry *d;
> +
> +	d = debugfs_create_dir("timecard", NULL);
> +	if (IS_ERR(d))
> +		return PTR_ERR(d);
> +
> +	ptp_ocp_debugfs_root = d;
> +
> +	return 0;
> +}
> +
> +static void
> +ptp_ocp_debugfs_fini(void)
> +{
> +	debugfs_remove_recursive(ptp_ocp_debugfs_root);
> +}
> +#else
> +#define ptp_ocp_debugfs_init()			0
> +#define ptp_ocp_debugfs_fini()
> +#define ptp_ocp_debugfs_add_device(bp)		0
> +#define ptp_ocp_debugfs_remove_device(bp)
> +#endif

This should not be necessary. Compiler should remove all those
functions as dead code when debugfs is not compiled in.

>  static void
>  ptp_ocp_dev_release(struct device *dev)
>  {

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

* Re: [PATCH net-next 10/11] ptp: ocp: Add IRIG-B output mode control
  2021-08-30 23:52 ` [PATCH net-next 10/11] ptp: ocp: Add IRIG-B output mode control Jonathan Lemon
@ 2021-09-02  0:07   ` Jakub Kicinski
  2021-09-02 17:02     ` Jonathan Lemon
  0 siblings, 1 reply; 21+ messages in thread
From: Jakub Kicinski @ 2021-09-02  0:07 UTC (permalink / raw)
  To: Jonathan Lemon; +Cc: davem, richardcochran, netdev, kernel-team, abyagowi

On Mon, 30 Aug 2021 16:52:35 -0700 Jonathan Lemon wrote:
> +	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);

locking

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

* Re: [PATCH net-next 06/11] ptp: ocp: Add SMA selector and controls
  2021-09-01 23:56   ` Jakub Kicinski
@ 2021-09-02 16:55     ` Jonathan Lemon
  0 siblings, 0 replies; 21+ messages in thread
From: Jonathan Lemon @ 2021-09-02 16:55 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, richardcochran, netdev, kernel-team, abyagowi

On Wed, Sep 01, 2021 at 04:56:12PM -0700, Jakub Kicinski wrote:
> On Mon, 30 Aug 2021 16:52:31 -0700 Jonathan Lemon wrote:
> >  static int
> > -ptp_ocp_clock_val_from_name(const char *name)
> > +select_val_from_name(struct ocp_selector *tbl, const char *name)
> 
> Why not prefix the helpers with ptp_ocp_ ? Makes code easier to follow
> IMHO.

Will fix.  Was adding these for use by the DEVICE_ATTR functions, and
those don't have prefixes, so I neglected to namespace them.
-- 
Jonathan

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

* Re: [PATCH net-next 08/11] ptp: ocp: Add sysfs attribute utc_tai_offset
  2021-09-01 23:56   ` Jakub Kicinski
@ 2021-09-02 16:57     ` Jonathan Lemon
  0 siblings, 0 replies; 21+ messages in thread
From: Jonathan Lemon @ 2021-09-02 16:57 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, richardcochran, netdev, kernel-team, abyagowi

On Wed, Sep 01, 2021 at 04:56:42PM -0700, Jakub Kicinski wrote:
> On Mon, 30 Aug 2021 16:52:33 -0700 Jonathan Lemon wrote:
> > +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);
> > +	unsigned long flags;
> > +	int err;
> > +	s32 val;
> > +
> > +	err = kstrtos32(buf, 0, &val);
> > +	if (err)
> > +		return err;
> > +
> > +	bp->utc_tai_offset = val;
> 
> This line should probably be under the lock.

Ack.

BTW, I hate this entire function - but don't really 
see a better way to handle it.  One suggestion was 
to automatically get the offset from the NMEA parser,
but I can't depend on GNSS being available.
-- 
Jonathan

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

* Re: [PATCH net-next 09/11] ptp: ocp: Add debugfs entry for timecard
  2021-09-02  0:06   ` Jakub Kicinski
@ 2021-09-02 17:00     ` Jonathan Lemon
  0 siblings, 0 replies; 21+ messages in thread
From: Jonathan Lemon @ 2021-09-02 17:00 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, richardcochran, netdev, kernel-team, abyagowi

On Wed, Sep 01, 2021 at 05:06:41PM -0700, Jakub Kicinski wrote:
> On Mon, 30 Aug 2021 16:52:34 -0700 Jonathan Lemon wrote:
> > Provide a view into the timecard internals for debugging.
> > 
> > Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
> 
> > +#ifdef CONFIG_DEBUG_FS
> > +#define gpio_map(gpio, bit, pri, sec, def) ({			\
> > +	char *_ans;						\
> > +	if (gpio & (1 << bit))					\
> > +		_ans = pri;					\
> > +	else if (gpio & (1 << (bit + 16)))			\
> > +		_ans = sec;					\
> > +	else							\
> > +		_ans = def;					\
> > +	_ans;							\
> > +})
> > +
> > +#define gpio_multi_map(buf, gpio, bit, pri, sec, def) ({	\
> > +		char *_ans;					\
> > +		_ans = buf;					\
> > +		strcpy(buf, def);				\
> > +		if (gpio & (1 << (bit + 16)))			\
> > +			_ans += sprintf(_ans, "%s ", pri);	\
> > +		if (gpio & (1 << bit))				\
> > +			_ans += sprintf(_ans, "%s ", sec);	\
> > +})
> 
> These can't be static inlines?

Fixed - old habit of writing macros.


> > +static int
> > +ptp_ocp_summary_show(struct seq_file *s, void *data)
> > +{
> > +	struct device *dev = s->private;
> > +	struct ts_reg __iomem *ts_reg;
> > +	u32 sma_in, sma_out, val;
> > +	struct timespec64 ts;
> > +	struct ptp_ocp *bp;
> > +	char *buf, *src;
> > +	bool on;
> > +
> > +	buf = (char *)__get_free_page(GFP_KERNEL);
> > +	if (!buf)
> > +		return -ENOMEM;
> > +
> > +	sma1_out_show(dev, NULL, buf);
> > +	seq_printf(s, "   sma1: out from %s", buf);
> > +
> > +	sma2_out_show(dev, NULL, buf);
> > +	seq_printf(s, "   sma2: out from %s", buf);
> > +
> > +	sma3_in_show(dev, NULL, buf);
> > +	seq_printf(s, "   sma3: input to %s", buf);
> > +
> > +	sma4_in_show(dev, NULL, buf);
> > +	seq_printf(s, "   sma4: input to %s", buf);
> 
> Why duplicate the data already available via sysfs?

It is convenient to have all the information on 
one page when trying to understand where the signals
are being steered.


[ snip ]

> Driver's are not supposed to depend on debugfs, you should be able to
> carry on and all debugfs functions you pass an error pointer as a
> parent will just return the same error right back.

Ack.

> This should not be necessary. Compiler should remove all those
> functions as dead code when debugfs is not compiled in.

Removed #ifdef - now the _summary function is left in 
and the compiler removes it in the dead code pass.
-- 
Jonathan

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

* Re: [PATCH net-next 10/11] ptp: ocp: Add IRIG-B output mode control
  2021-09-02  0:07   ` Jakub Kicinski
@ 2021-09-02 17:02     ` Jonathan Lemon
  2021-09-02 22:41       ` Jakub Kicinski
  0 siblings, 1 reply; 21+ messages in thread
From: Jonathan Lemon @ 2021-09-02 17:02 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, richardcochran, netdev, kernel-team, abyagowi

On Wed, Sep 01, 2021 at 05:07:00PM -0700, Jakub Kicinski wrote:
> On Mon, 30 Aug 2021 16:52:35 -0700 Jonathan Lemon wrote:
> > +	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);
> 
> locking

Not sure what you mean - all register manipulations are 
already done under the lock here.
-- 
Jonathan

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

* Re: [PATCH net-next 10/11] ptp: ocp: Add IRIG-B output mode control
  2021-09-02 17:02     ` Jonathan Lemon
@ 2021-09-02 22:41       ` Jakub Kicinski
  0 siblings, 0 replies; 21+ messages in thread
From: Jakub Kicinski @ 2021-09-02 22:41 UTC (permalink / raw)
  To: Jonathan Lemon; +Cc: davem, richardcochran, netdev, kernel-team, abyagowi

On Thu, 2 Sep 2021 10:02:16 -0700 Jonathan Lemon wrote:
> On Wed, Sep 01, 2021 at 05:07:00PM -0700, Jakub Kicinski wrote:
> > On Mon, 30 Aug 2021 16:52:35 -0700 Jonathan Lemon wrote:  
> > > +	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);  
> > 
> > locking  
> 
> Not sure what you mean - all register manipulations are 
> already done under the lock here.

I must have misread and thought it has the same problem as patch 8, 
ignore, sorry.

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

end of thread, other threads:[~2021-09-02 22:41 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-30 23:52 [PATCH net-next 00/11] ocp timecard updates Jonathan Lemon
2021-08-30 23:52 ` [PATCH net-next 01/11] ptp: ocp: parameterize the i2c driver used Jonathan Lemon
2021-08-30 23:52 ` [PATCH net-next 02/11] ptp: ocp: Parameterize the TOD information display Jonathan Lemon
2021-08-30 23:52 ` [PATCH net-next 03/11] ptp: ocp: Skip I2C flash read when there is no controller Jonathan Lemon
2021-08-30 23:52 ` [PATCH net-next 04/11] ptp: ocp: Skip resources with out of range irqs Jonathan Lemon
2021-08-30 23:52 ` [PATCH net-next 05/11] ptp: ocp: Add third timestamper Jonathan Lemon
2021-08-30 23:52 ` [PATCH net-next 06/11] ptp: ocp: Add SMA selector and controls Jonathan Lemon
2021-09-01 23:56   ` Jakub Kicinski
2021-09-02 16:55     ` Jonathan Lemon
2021-08-30 23:52 ` [PATCH net-next 07/11] ptp: ocp: Add IRIG-B and DCF blocks Jonathan Lemon
2021-08-30 23:52 ` [PATCH net-next 08/11] ptp: ocp: Add sysfs attribute utc_tai_offset Jonathan Lemon
2021-09-01 23:56   ` Jakub Kicinski
2021-09-02 16:57     ` Jonathan Lemon
2021-08-30 23:52 ` [PATCH net-next 09/11] ptp: ocp: Add debugfs entry for timecard Jonathan Lemon
2021-09-02  0:06   ` Jakub Kicinski
2021-09-02 17:00     ` Jonathan Lemon
2021-08-30 23:52 ` [PATCH net-next 10/11] ptp: ocp: Add IRIG-B output mode control Jonathan Lemon
2021-09-02  0:07   ` Jakub Kicinski
2021-09-02 17:02     ` Jonathan Lemon
2021-09-02 22:41       ` Jakub Kicinski
2021-08-30 23:52 ` [PATCH net-next 11/11] docs: ABI: Add sysfs documentation for timecard Jonathan Lemon

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.