All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/5] net: lan966x: Add support for PTP programmable pins
@ 2022-04-24 14:58 Horatiu Vultur
  2022-04-24 14:58 ` [PATCH net-next 1/5] dt-bindings: net: lan966x: Extend with the ptp external interrupt Horatiu Vultur
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Horatiu Vultur @ 2022-04-24 14:58 UTC (permalink / raw)
  To: netdev, devicetree, linux-kernel
  Cc: davem, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	UNGLinuxDriver, richardcochran, Horatiu Vultur

Lan966x has 8 PTP programmable pins. The last pin is hardcoded to be used
by PHC0 and all the rest are shareable between the PHCs. The PTP pins can
implement both extts and perout functions.

Horatiu Vultur (5):
  dt-bindings: net: lan966x: Extend with the ptp external interrupt.
  net: lan966x: Change the PTP pin used to read/write the PHC.
  net: lan966x: Add registers used to configure the PTP pin
  net: lan966x: Add support for PTP_PF_PEROUT
  net: lan966x: Add support for PTP_PF_EXTTS

 .../net/microchip,lan966x-switch.yaml         |   2 +
 .../ethernet/microchip/lan966x/lan966x_main.c |  17 ++
 .../ethernet/microchip/lan966x/lan966x_main.h |   4 +
 .../ethernet/microchip/lan966x/lan966x_ptp.c  | 276 +++++++++++++++++-
 .../ethernet/microchip/lan966x/lan966x_regs.h |  40 +++
 5 files changed, 338 insertions(+), 1 deletion(-)

-- 
2.33.0


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

* [PATCH net-next 1/5] dt-bindings: net: lan966x: Extend with the ptp external interrupt.
  2022-04-24 14:58 [PATCH net-next 0/5] net: lan966x: Add support for PTP programmable pins Horatiu Vultur
@ 2022-04-24 14:58 ` Horatiu Vultur
  2022-04-24 14:58 ` [PATCH net-next 2/5] net: lan966x: Change the PTP pin used to read/write the PHC Horatiu Vultur
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Horatiu Vultur @ 2022-04-24 14:58 UTC (permalink / raw)
  To: netdev, devicetree, linux-kernel
  Cc: davem, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	UNGLinuxDriver, richardcochran, Horatiu Vultur

Extend dt-bindings for lan966x with ptp external interrupt. This is
generated when an external 1pps signal is received on the ptp pin.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../devicetree/bindings/net/microchip,lan966x-switch.yaml       | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml b/Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml
index 13812768b923..131dc5a652de 100644
--- a/Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml
+++ b/Documentation/devicetree/bindings/net/microchip,lan966x-switch.yaml
@@ -39,6 +39,7 @@ properties:
       - description: frame dma based extraction
       - description: analyzer interrupt
       - description: ptp interrupt
+      - description: ptp external interrupt
 
   interrupt-names:
     minItems: 1
@@ -47,6 +48,7 @@ properties:
       - const: fdma
       - const: ana
       - const: ptp
+      - const: ptp-ext
 
   resets:
     items:
-- 
2.33.0


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

* [PATCH net-next 2/5] net: lan966x: Change the PTP pin used to read/write the PHC.
  2022-04-24 14:58 [PATCH net-next 0/5] net: lan966x: Add support for PTP programmable pins Horatiu Vultur
  2022-04-24 14:58 ` [PATCH net-next 1/5] dt-bindings: net: lan966x: Extend with the ptp external interrupt Horatiu Vultur
@ 2022-04-24 14:58 ` Horatiu Vultur
  2022-04-24 14:58 ` [PATCH net-next 3/5] net: lan966x: Add registers used to configure the PTP pin Horatiu Vultur
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Horatiu Vultur @ 2022-04-24 14:58 UTC (permalink / raw)
  To: netdev, devicetree, linux-kernel
  Cc: davem, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	UNGLinuxDriver, richardcochran, Horatiu Vultur

To read/write a value to a PHC, it is required to use a PTP pin.
Currently it is used pin 5, but change to pin 7 as is the last pin.
All the other pins will have different functions.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
index 0a1041da4384..3e455a3fad08 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
@@ -16,7 +16,7 @@
  */
 #define LAN966X_1PPB_FORMAT		3480517749LL
 
-#define TOD_ACC_PIN		0x5
+#define TOD_ACC_PIN		0x7
 
 enum {
 	PTP_PIN_ACTION_IDLE = 0,
-- 
2.33.0


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

* [PATCH net-next 3/5] net: lan966x: Add registers used to configure the PTP pin
  2022-04-24 14:58 [PATCH net-next 0/5] net: lan966x: Add support for PTP programmable pins Horatiu Vultur
  2022-04-24 14:58 ` [PATCH net-next 1/5] dt-bindings: net: lan966x: Extend with the ptp external interrupt Horatiu Vultur
  2022-04-24 14:58 ` [PATCH net-next 2/5] net: lan966x: Change the PTP pin used to read/write the PHC Horatiu Vultur
@ 2022-04-24 14:58 ` Horatiu Vultur
  2022-04-24 14:58 ` [PATCH net-next 4/5] net: lan966x: Add support for PTP_PF_PEROUT Horatiu Vultur
  2022-04-24 14:58 ` [PATCH net-next 5/5] net: lan966x: Add support for PTP_PF_EXTTS Horatiu Vultur
  4 siblings, 0 replies; 8+ messages in thread
From: Horatiu Vultur @ 2022-04-24 14:58 UTC (permalink / raw)
  To: netdev, devicetree, linux-kernel
  Cc: davem, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	UNGLinuxDriver, richardcochran, Horatiu Vultur

Add registers that are used to configure the PTP pins. These registers
are used to enable the interrupts per PTP pin and to set the waveform
generated by the pin.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../ethernet/microchip/lan966x/lan966x_regs.h | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
index 2f59285bef29..8265ad89f0bc 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
@@ -684,6 +684,24 @@ enum lan966x_target {
 /*      FDMA:FDMA:FDMA_ERRORS */
 #define FDMA_ERRORS               __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 412, 0, 1, 4)
 
+/*      PTP:PTP_CFG:PTP_PIN_INTR */
+#define PTP_PIN_INTR              __REG(TARGET_PTP, 0, 1, 512, 0, 1, 16, 0, 0, 1, 4)
+
+#define PTP_PIN_INTR_INTR_PTP                    GENMASK(7, 0)
+#define PTP_PIN_INTR_INTR_PTP_SET(x)\
+	FIELD_PREP(PTP_PIN_INTR_INTR_PTP, x)
+#define PTP_PIN_INTR_INTR_PTP_GET(x)\
+	FIELD_GET(PTP_PIN_INTR_INTR_PTP, x)
+
+/*      PTP:PTP_CFG:PTP_PIN_INTR_ENA */
+#define PTP_PIN_INTR_ENA          __REG(TARGET_PTP, 0, 1, 512, 0, 1, 16, 4, 0, 1, 4)
+
+#define PTP_PIN_INTR_ENA_INTR_ENA                GENMASK(7, 0)
+#define PTP_PIN_INTR_ENA_INTR_ENA_SET(x)\
+	FIELD_PREP(PTP_PIN_INTR_ENA_INTR_ENA, x)
+#define PTP_PIN_INTR_ENA_INTR_ENA_GET(x)\
+	FIELD_GET(PTP_PIN_INTR_ENA_INTR_ENA, x)
+
 /*      PTP:PTP_CFG:PTP_DOM_CFG */
 #define PTP_DOM_CFG               __REG(TARGET_PTP, 0, 1, 512, 0, 1, 16, 12, 0, 1, 4)
 
@@ -717,6 +735,12 @@ enum lan966x_target {
 #define PTP_PIN_CFG_PIN_SYNC_GET(x)\
 	FIELD_GET(PTP_PIN_CFG_PIN_SYNC, x)
 
+#define PTP_PIN_CFG_PIN_SELECT                   GENMASK(23, 21)
+#define PTP_PIN_CFG_PIN_SELECT_SET(x)\
+	FIELD_PREP(PTP_PIN_CFG_PIN_SELECT, x)
+#define PTP_PIN_CFG_PIN_SELECT_GET(x)\
+	FIELD_GET(PTP_PIN_CFG_PIN_SELECT, x)
+
 #define PTP_PIN_CFG_PIN_DOM                      GENMASK(17, 16)
 #define PTP_PIN_CFG_PIN_DOM_SET(x)\
 	FIELD_PREP(PTP_PIN_CFG_PIN_DOM, x)
@@ -744,6 +768,22 @@ enum lan966x_target {
 #define PTP_TOD_NSEC_TOD_NSEC_GET(x)\
 	FIELD_GET(PTP_TOD_NSEC_TOD_NSEC, x)
 
+/*      PTP:PTP_PINS:WF_HIGH_PERIOD */
+#define PTP_WF_HIGH_PERIOD(g)     __REG(TARGET_PTP,\
+					0, 1, 0, g, 8, 64, 24, 0, 1, 4)
+
+#define PTP_WF_HIGH_PERIOD_PIN_WFH(x)            ((x) & GENMASK(29, 0))
+#define PTP_WF_HIGH_PERIOD_PIN_WFH_M             GENMASK(29, 0)
+#define PTP_WF_HIGH_PERIOD_PIN_WFH_X(x)          ((x) & GENMASK(29, 0))
+
+/*      PTP:PTP_PINS:WF_LOW_PERIOD */
+#define PTP_WF_LOW_PERIOD(g)      __REG(TARGET_PTP,\
+					0, 1, 0, g, 8, 64, 28, 0, 1, 4)
+
+#define PTP_WF_LOW_PERIOD_PIN_WFL(x)             ((x) & GENMASK(29, 0))
+#define PTP_WF_LOW_PERIOD_PIN_WFL_M              GENMASK(29, 0)
+#define PTP_WF_LOW_PERIOD_PIN_WFL_X(x)           ((x) & GENMASK(29, 0))
+
 /*      PTP:PTP_TS_FIFO:PTP_TWOSTEP_CTRL */
 #define PTP_TWOSTEP_CTRL          __REG(TARGET_PTP, 0, 1, 612, 0, 1, 12, 0, 0, 1, 4)
 
-- 
2.33.0


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

* [PATCH net-next 4/5] net: lan966x: Add support for PTP_PF_PEROUT
  2022-04-24 14:58 [PATCH net-next 0/5] net: lan966x: Add support for PTP programmable pins Horatiu Vultur
                   ` (2 preceding siblings ...)
  2022-04-24 14:58 ` [PATCH net-next 3/5] net: lan966x: Add registers used to configure the PTP pin Horatiu Vultur
@ 2022-04-24 14:58 ` Horatiu Vultur
  2022-04-24 14:58 ` [PATCH net-next 5/5] net: lan966x: Add support for PTP_PF_EXTTS Horatiu Vultur
  4 siblings, 0 replies; 8+ messages in thread
From: Horatiu Vultur @ 2022-04-24 14:58 UTC (permalink / raw)
  To: netdev, devicetree, linux-kernel
  Cc: davem, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	UNGLinuxDriver, richardcochran, Horatiu Vultur

Lan966x has 8 PTP programmable pins, where the last pins is hardcoded to
be used by PHC0, which does the frame timestamping. All the rest of the
PTP pins can be shared between the PHCs and can have different functions
like perout or extts. For now add support for PTP_FS_PEROUT.
The HW is not able to support absolute start time but can use the nsec
for phase adjustment when generating PPS.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../ethernet/microchip/lan966x/lan966x_main.h |   2 +
 .../ethernet/microchip/lan966x/lan966x_ptp.c  | 167 ++++++++++++++++++
 2 files changed, 169 insertions(+)

diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
index 5213263c4e87..76255e2a86f3 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
@@ -56,6 +56,7 @@
 
 #define LAN966X_PHC_COUNT		3
 #define LAN966X_PHC_PORT		0
+#define LAN966X_PHC_PINS_NUM		7
 
 #define IFH_REW_OP_NOOP			0x0
 #define IFH_REW_OP_ONE_STEP_PTP		0x3
@@ -177,6 +178,7 @@ struct lan966x_stat_layout {
 struct lan966x_phc {
 	struct ptp_clock *clock;
 	struct ptp_clock_info info;
+	struct ptp_pin_desc pins[LAN966X_PHC_PINS_NUM];
 	struct hwtstamp_config hwtstamp_config;
 	struct lan966x *lan966x;
 	u8 index;
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
index 3e455a3fad08..3199a266ed3d 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
@@ -493,6 +493,158 @@ static int lan966x_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 	return 0;
 }
 
+static int lan966x_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
+			      enum ptp_pin_function func, unsigned int chan)
+{
+	struct lan966x_phc *phc = container_of(ptp, struct lan966x_phc, info);
+	struct lan966x *lan966x = phc->lan966x;
+	struct ptp_clock_info *info;
+	int i;
+
+	/* Currently support only 1 channel */
+	if (chan != 0)
+		return -1;
+
+	switch (func) {
+	case PTP_PF_NONE:
+	case PTP_PF_PEROUT:
+		break;
+	default:
+		return -1;
+	}
+
+	/* The PTP pins are shared by all the PHC. So it is required to see if
+	 * the pin is connected to another PHC. The pin is connected to another
+	 * PHC if that pin already has a function on that PHC.
+	 */
+	for (i = 0; i < LAN966X_PHC_COUNT; ++i) {
+		info = &lan966x->phc[i].info;
+
+		/* Ignore the check with ourself */
+		if (ptp == info)
+			continue;
+
+		if (info->pin_config[pin].func == PTP_PF_PEROUT)
+			return -1;
+	}
+
+	return 0;
+}
+
+static int lan966x_ptp_perout(struct ptp_clock_info *ptp,
+			      struct ptp_clock_request *rq, int on)
+{
+	struct lan966x_phc *phc = container_of(ptp, struct lan966x_phc, info);
+	struct lan966x *lan966x = phc->lan966x;
+	struct timespec64 ts_phase, ts_period;
+	unsigned long flags;
+	s64 wf_high, wf_low;
+	bool pps = false;
+	int pin;
+
+	if (rq->perout.flags & ~(PTP_PEROUT_DUTY_CYCLE |
+				 PTP_PEROUT_PHASE))
+		return -EOPNOTSUPP;
+
+	pin = ptp_find_pin(phc->clock, PTP_PF_PEROUT, rq->perout.index);
+	if (pin == -1 || pin >= LAN966X_PHC_PINS_NUM)
+		return -EINVAL;
+
+	if (!on) {
+		spin_lock_irqsave(&lan966x->ptp_clock_lock, flags);
+		lan_rmw(PTP_PIN_CFG_PIN_ACTION_SET(PTP_PIN_ACTION_IDLE) |
+			PTP_PIN_CFG_PIN_DOM_SET(phc->index) |
+			PTP_PIN_CFG_PIN_SYNC_SET(0),
+			PTP_PIN_CFG_PIN_ACTION |
+			PTP_PIN_CFG_PIN_DOM |
+			PTP_PIN_CFG_PIN_SYNC,
+			lan966x, PTP_PIN_CFG(pin));
+		spin_unlock_irqrestore(&lan966x->ptp_clock_lock, flags);
+		return 0;
+	}
+
+	if (rq->perout.period.sec == 1 &&
+	    rq->perout.period.nsec == 0)
+		pps = true;
+
+	if (rq->perout.flags & PTP_PEROUT_PHASE) {
+		ts_phase.tv_sec = rq->perout.phase.sec;
+		ts_phase.tv_nsec = rq->perout.phase.nsec;
+	} else {
+		ts_phase.tv_sec = rq->perout.start.sec;
+		ts_phase.tv_nsec = rq->perout.start.nsec;
+	}
+
+	if (ts_phase.tv_sec || (ts_phase.tv_nsec && !pps)) {
+		dev_warn(lan966x->dev,
+			 "Absolute time not supported!\n");
+		return -EINVAL;
+	}
+
+	if (rq->perout.flags & PTP_PEROUT_DUTY_CYCLE) {
+		struct timespec64 ts_on;
+
+		ts_on.tv_sec = rq->perout.on.sec;
+		ts_on.tv_nsec = rq->perout.on.nsec;
+
+		wf_high = timespec64_to_ns(&ts_on);
+	} else {
+		wf_high = 5000;
+	}
+
+	if (pps) {
+		spin_lock_irqsave(&lan966x->ptp_clock_lock, flags);
+		lan_wr(PTP_WF_LOW_PERIOD_PIN_WFL(ts_phase.tv_nsec),
+		       lan966x, PTP_WF_LOW_PERIOD(pin));
+		lan_wr(PTP_WF_HIGH_PERIOD_PIN_WFH(wf_high),
+		       lan966x, PTP_WF_HIGH_PERIOD(pin));
+		lan_rmw(PTP_PIN_CFG_PIN_ACTION_SET(PTP_PIN_ACTION_CLOCK) |
+			PTP_PIN_CFG_PIN_DOM_SET(phc->index) |
+			PTP_PIN_CFG_PIN_SYNC_SET(3),
+			PTP_PIN_CFG_PIN_ACTION |
+			PTP_PIN_CFG_PIN_DOM |
+			PTP_PIN_CFG_PIN_SYNC,
+			lan966x, PTP_PIN_CFG(pin));
+		spin_unlock_irqrestore(&lan966x->ptp_clock_lock, flags);
+		return 0;
+	}
+
+	ts_period.tv_sec = rq->perout.period.sec;
+	ts_period.tv_nsec = rq->perout.period.nsec;
+
+	wf_low = timespec64_to_ns(&ts_period);
+	wf_low -= wf_high;
+
+	spin_lock_irqsave(&lan966x->ptp_clock_lock, flags);
+	lan_wr(PTP_WF_LOW_PERIOD_PIN_WFL(wf_low),
+	       lan966x, PTP_WF_LOW_PERIOD(pin));
+	lan_wr(PTP_WF_HIGH_PERIOD_PIN_WFH(wf_high),
+	       lan966x, PTP_WF_HIGH_PERIOD(pin));
+	lan_rmw(PTP_PIN_CFG_PIN_ACTION_SET(PTP_PIN_ACTION_CLOCK) |
+		PTP_PIN_CFG_PIN_DOM_SET(phc->index) |
+		PTP_PIN_CFG_PIN_SYNC_SET(0),
+		PTP_PIN_CFG_PIN_ACTION |
+		PTP_PIN_CFG_PIN_DOM |
+		PTP_PIN_CFG_PIN_SYNC,
+		lan966x, PTP_PIN_CFG(pin));
+	spin_unlock_irqrestore(&lan966x->ptp_clock_lock, flags);
+
+	return 0;
+}
+
+static int lan966x_ptp_enable(struct ptp_clock_info *ptp,
+			      struct ptp_clock_request *rq, int on)
+{
+	switch (rq->type) {
+	case PTP_CLK_REQ_PEROUT:
+		return lan966x_ptp_perout(ptp, rq, on);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
 static struct ptp_clock_info lan966x_ptp_clock_info = {
 	.owner		= THIS_MODULE,
 	.name		= "lan966x ptp",
@@ -501,6 +653,10 @@ static struct ptp_clock_info lan966x_ptp_clock_info = {
 	.settime64	= lan966x_ptp_settime64,
 	.adjtime	= lan966x_ptp_adjtime,
 	.adjfine	= lan966x_ptp_adjfine,
+	.verify		= lan966x_ptp_verify,
+	.enable		= lan966x_ptp_enable,
+	.n_per_out	= LAN966X_PHC_PINS_NUM,
+	.n_pins		= LAN966X_PHC_PINS_NUM,
 };
 
 static int lan966x_ptp_phc_init(struct lan966x *lan966x,
@@ -508,8 +664,19 @@ static int lan966x_ptp_phc_init(struct lan966x *lan966x,
 				struct ptp_clock_info *clock_info)
 {
 	struct lan966x_phc *phc = &lan966x->phc[index];
+	struct ptp_pin_desc *p;
+	int i;
+
+	for (i = 0; i < LAN966X_PHC_PINS_NUM; i++) {
+		p = &phc->pins[i];
+
+		snprintf(p->name, sizeof(p->name), "pin%d", i);
+		p->index = i;
+		p->func = PTP_PF_NONE;
+	}
 
 	phc->info = *clock_info;
+	phc->info.pin_config = &phc->pins[0];
 	phc->clock = ptp_clock_register(&phc->info, lan966x->dev);
 	if (IS_ERR(phc->clock))
 		return PTR_ERR(phc->clock);
-- 
2.33.0


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

* [PATCH net-next 5/5] net: lan966x: Add support for PTP_PF_EXTTS
  2022-04-24 14:58 [PATCH net-next 0/5] net: lan966x: Add support for PTP programmable pins Horatiu Vultur
                   ` (3 preceding siblings ...)
  2022-04-24 14:58 ` [PATCH net-next 4/5] net: lan966x: Add support for PTP_PF_PEROUT Horatiu Vultur
@ 2022-04-24 14:58 ` Horatiu Vultur
  2022-04-24 15:09   ` Richard Cochran
  4 siblings, 1 reply; 8+ messages in thread
From: Horatiu Vultur @ 2022-04-24 14:58 UTC (permalink / raw)
  To: netdev, devicetree, linux-kernel
  Cc: davem, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	UNGLinuxDriver, richardcochran, Horatiu Vultur

Extend the PTP programmable pins to implement also PTP_PF_EXTTS
function. The PTP pin can be configured to capture only on the rising
edge of the PPS signal. And once an event is seen then an interrupt is
generated and the local time counter is saved.
The interrupt is shared between all the pins.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 .../ethernet/microchip/lan966x/lan966x_main.c |  17 +++
 .../ethernet/microchip/lan966x/lan966x_main.h |   2 +
 .../ethernet/microchip/lan966x/lan966x_ptp.c  | 109 +++++++++++++++++-
 3 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
index afec115e46eb..6579c7062aa5 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
@@ -692,6 +692,9 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x)
 
 	if (lan966x->ptp_irq)
 		devm_free_irq(lan966x->dev, lan966x->ptp_irq, lan966x);
+
+	if (lan966x->ptp_ext_irq)
+		devm_free_irq(lan966x->dev, lan966x->ptp_ext_irq, lan966x);
 }
 
 static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
@@ -1058,6 +1061,20 @@ static int lan966x_probe(struct platform_device *pdev)
 		lan966x->fdma = true;
 	}
 
+	if (lan966x->ptp) {
+		lan966x->ptp_ext_irq = platform_get_irq_byname(pdev, "ptp-ext");
+		if (lan966x->ptp_ext_irq > 0) {
+			err = devm_request_threaded_irq(&pdev->dev,
+							lan966x->ptp_ext_irq, NULL,
+							lan966x_ptp_ext_irq_handler,
+							IRQF_ONESHOT,
+							"ptp-ext irq", lan966x);
+			if (err)
+				return dev_err_probe(&pdev->dev, err,
+						     "Unable to use ptp-ext irq");
+		}
+	}
+
 	/* init switch */
 	lan966x_init(lan966x);
 	lan966x_stats_init(lan966x);
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
index 76255e2a86f3..3b86ddddc756 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
@@ -233,6 +233,7 @@ struct lan966x {
 	int ana_irq;
 	int ptp_irq;
 	int fdma_irq;
+	int ptp_ext_irq;
 
 	/* worqueue for fdb */
 	struct workqueue_struct *fdb_work;
@@ -394,6 +395,7 @@ int lan966x_ptp_txtstamp_request(struct lan966x_port *port,
 void lan966x_ptp_txtstamp_release(struct lan966x_port *port,
 				  struct sk_buff *skb);
 irqreturn_t lan966x_ptp_irq_handler(int irq, void *args);
+irqreturn_t lan966x_ptp_ext_irq_handler(int irq, void *args);
 
 int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev);
 int lan966x_fdma_change_mtu(struct lan966x *lan966x);
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
index 3199a266ed3d..9c39a3c7e9fa 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
@@ -321,6 +321,63 @@ irqreturn_t lan966x_ptp_irq_handler(int irq, void *args)
 	return IRQ_HANDLED;
 }
 
+irqreturn_t lan966x_ptp_ext_irq_handler(int irq, void *args)
+{
+	struct lan966x *lan966x = args;
+	struct lan966x_phc *phc;
+	unsigned long flags;
+	u64 time = 0;
+	time64_t s;
+	int pin, i;
+	s64 ns;
+
+	if (!(lan_rd(lan966x, PTP_PIN_INTR)))
+		return IRQ_NONE;
+
+	/* Go through all domains and see which pin generated the interrupt */
+	for (i = 0; i < LAN966X_PHC_COUNT; ++i) {
+		struct ptp_clock_event ptp_event = {0};
+
+		phc = &lan966x->phc[i];
+		pin = ptp_find_pin(phc->clock, PTP_PF_EXTTS, 0);
+		if (pin == -1)
+			continue;
+
+		if (!(lan_rd(lan966x, PTP_PIN_INTR) & BIT(pin)))
+			continue;
+
+		spin_lock_irqsave(&lan966x->ptp_clock_lock, flags);
+
+		/* Enable to get the new interrupt.
+		 * By writing 1 it clears the bit
+		 */
+		lan_wr(BIT(pin), lan966x, PTP_PIN_INTR);
+
+		/* Get current time */
+		s = lan_rd(lan966x, PTP_TOD_SEC_MSB(pin));
+		s <<= 32;
+		s |= lan_rd(lan966x, PTP_TOD_SEC_LSB(pin));
+		ns = lan_rd(lan966x, PTP_TOD_NSEC(pin));
+		ns &= PTP_TOD_NSEC_TOD_NSEC;
+
+		spin_unlock_irqrestore(&lan966x->ptp_clock_lock, flags);
+
+		if ((ns & 0xFFFFFFF0) == 0x3FFFFFF0) {
+			s--;
+			ns &= 0xf;
+			ns += 999999984;
+		}
+		time = ktime_set(s, ns);
+
+		ptp_event.index = pin;
+		ptp_event.timestamp = time;
+		ptp_event.type = PTP_CLOCK_EXTTS;
+		ptp_clock_event(phc->clock, &ptp_event);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static int lan966x_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
 {
 	struct lan966x_phc *phc = container_of(ptp, struct lan966x_phc, info);
@@ -508,6 +565,7 @@ static int lan966x_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
 	switch (func) {
 	case PTP_PF_NONE:
 	case PTP_PF_PEROUT:
+	case PTP_PF_EXTTS:
 		break;
 	default:
 		return -1;
@@ -524,7 +582,8 @@ static int lan966x_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
 		if (ptp == info)
 			continue;
 
-		if (info->pin_config[pin].func == PTP_PF_PEROUT)
+		if (info->pin_config[pin].func == PTP_PF_PEROUT ||
+		    info->pin_config[pin].func == PTP_PF_EXTTS)
 			return -1;
 	}
 
@@ -632,12 +691,59 @@ static int lan966x_ptp_perout(struct ptp_clock_info *ptp,
 	return 0;
 }
 
+static int lan966x_ptp_extts(struct ptp_clock_info *ptp,
+			     struct ptp_clock_request *rq, int on)
+{
+	struct lan966x_phc *phc = container_of(ptp, struct lan966x_phc, info);
+	struct lan966x *lan966x = phc->lan966x;
+	unsigned long flags;
+	int pin;
+	u32 val;
+
+	if (lan966x->ptp_ext_irq <= 0)
+		return -EOPNOTSUPP;
+
+	/* Reject requests with unsupported flags */
+	if (rq->extts.flags & ~(PTP_ENABLE_FEATURE |
+				PTP_RISING_EDGE |
+				PTP_STRICT_FLAGS))
+		return -EOPNOTSUPP;
+
+	pin = ptp_find_pin(phc->clock, PTP_PF_EXTTS, rq->extts.index);
+	if (pin == -1 || pin >= LAN966X_PHC_PINS_NUM)
+		return -EINVAL;
+
+	spin_lock_irqsave(&lan966x->ptp_clock_lock, flags);
+	lan_rmw(PTP_PIN_CFG_PIN_ACTION_SET(PTP_PIN_ACTION_SAVE) |
+		PTP_PIN_CFG_PIN_SYNC_SET(on ? 3 : 0) |
+		PTP_PIN_CFG_PIN_DOM_SET(phc->index) |
+		PTP_PIN_CFG_PIN_SELECT_SET(pin),
+		PTP_PIN_CFG_PIN_ACTION |
+		PTP_PIN_CFG_PIN_SYNC |
+		PTP_PIN_CFG_PIN_DOM |
+		PTP_PIN_CFG_PIN_SELECT,
+		lan966x, PTP_PIN_CFG(pin));
+
+	val = lan_rd(lan966x, PTP_PIN_INTR_ENA);
+	if (on)
+		val |= BIT(pin);
+	else
+		val &= ~BIT(pin);
+	lan_wr(val, lan966x, PTP_PIN_INTR_ENA);
+
+	spin_unlock_irqrestore(&lan966x->ptp_clock_lock, flags);
+
+	return 0;
+}
+
 static int lan966x_ptp_enable(struct ptp_clock_info *ptp,
 			      struct ptp_clock_request *rq, int on)
 {
 	switch (rq->type) {
 	case PTP_CLK_REQ_PEROUT:
 		return lan966x_ptp_perout(ptp, rq, on);
+	case PTP_CLK_REQ_EXTTS:
+		return lan966x_ptp_extts(ptp, rq, on);
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -656,6 +762,7 @@ static struct ptp_clock_info lan966x_ptp_clock_info = {
 	.verify		= lan966x_ptp_verify,
 	.enable		= lan966x_ptp_enable,
 	.n_per_out	= LAN966X_PHC_PINS_NUM,
+	.n_ext_ts	= LAN966X_PHC_PINS_NUM,
 	.n_pins		= LAN966X_PHC_PINS_NUM,
 };
 
-- 
2.33.0


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

* Re: [PATCH net-next 5/5] net: lan966x: Add support for PTP_PF_EXTTS
  2022-04-24 14:58 ` [PATCH net-next 5/5] net: lan966x: Add support for PTP_PF_EXTTS Horatiu Vultur
@ 2022-04-24 15:09   ` Richard Cochran
  2022-04-25 20:31     ` Horatiu Vultur
  0 siblings, 1 reply; 8+ messages in thread
From: Richard Cochran @ 2022-04-24 15:09 UTC (permalink / raw)
  To: Horatiu Vultur
  Cc: netdev, devicetree, linux-kernel, davem, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, UNGLinuxDriver

On Sun, Apr 24, 2022 at 04:58:24PM +0200, Horatiu Vultur wrote:

> @@ -321,6 +321,63 @@ irqreturn_t lan966x_ptp_irq_handler(int irq, void *args)
>  	return IRQ_HANDLED;
>  }
>  
> +irqreturn_t lan966x_ptp_ext_irq_handler(int irq, void *args)
> +{
> +	struct lan966x *lan966x = args;
> +	struct lan966x_phc *phc;
> +	unsigned long flags;
> +	u64 time = 0;
> +	time64_t s;
> +	int pin, i;
> +	s64 ns;
> +
> +	if (!(lan_rd(lan966x, PTP_PIN_INTR)))
> +		return IRQ_NONE;
> +
> +	/* Go through all domains and see which pin generated the interrupt */
> +	for (i = 0; i < LAN966X_PHC_COUNT; ++i) {
> +		struct ptp_clock_event ptp_event = {0};
> +
> +		phc = &lan966x->phc[i];
> +		pin = ptp_find_pin(phc->clock, PTP_PF_EXTTS, 0);

Not safe to call ptp_find_pin() from ISR.  See comment in include/linux/ptp_clock_kernel.h

Thanks,
Richard

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

* Re: [PATCH net-next 5/5] net: lan966x: Add support for PTP_PF_EXTTS
  2022-04-24 15:09   ` Richard Cochran
@ 2022-04-25 20:31     ` Horatiu Vultur
  0 siblings, 0 replies; 8+ messages in thread
From: Horatiu Vultur @ 2022-04-25 20:31 UTC (permalink / raw)
  To: Richard Cochran
  Cc: netdev, devicetree, linux-kernel, davem, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, UNGLinuxDriver

The 04/24/2022 08:09, Richard Cochran wrote:

Hi Richard,

> 
> On Sun, Apr 24, 2022 at 04:58:24PM +0200, Horatiu Vultur wrote:
> 
> > @@ -321,6 +321,63 @@ irqreturn_t lan966x_ptp_irq_handler(int irq, void *args)
> >       return IRQ_HANDLED;
> >  }
> >
> > +irqreturn_t lan966x_ptp_ext_irq_handler(int irq, void *args)
> > +{
> > +     struct lan966x *lan966x = args;
> > +     struct lan966x_phc *phc;
> > +     unsigned long flags;
> > +     u64 time = 0;
> > +     time64_t s;
> > +     int pin, i;
> > +     s64 ns;
> > +
> > +     if (!(lan_rd(lan966x, PTP_PIN_INTR)))
> > +             return IRQ_NONE;
> > +
> > +     /* Go through all domains and see which pin generated the interrupt */
> > +     for (i = 0; i < LAN966X_PHC_COUNT; ++i) {
> > +             struct ptp_clock_event ptp_event = {0};
> > +
> > +             phc = &lan966x->phc[i];
> > +             pin = ptp_find_pin(phc->clock, PTP_PF_EXTTS, 0);
> 
> Not safe to call ptp_find_pin() from ISR.  See comment in include/linux/ptp_clock_kernel.h

Good catch.
From what I can see, I should be able to use ptp_find_pin_unlocked.

> 
> Thanks,
> Richard

-- 
/Horatiu

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

end of thread, other threads:[~2022-04-25 20:28 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-24 14:58 [PATCH net-next 0/5] net: lan966x: Add support for PTP programmable pins Horatiu Vultur
2022-04-24 14:58 ` [PATCH net-next 1/5] dt-bindings: net: lan966x: Extend with the ptp external interrupt Horatiu Vultur
2022-04-24 14:58 ` [PATCH net-next 2/5] net: lan966x: Change the PTP pin used to read/write the PHC Horatiu Vultur
2022-04-24 14:58 ` [PATCH net-next 3/5] net: lan966x: Add registers used to configure the PTP pin Horatiu Vultur
2022-04-24 14:58 ` [PATCH net-next 4/5] net: lan966x: Add support for PTP_PF_PEROUT Horatiu Vultur
2022-04-24 14:58 ` [PATCH net-next 5/5] net: lan966x: Add support for PTP_PF_EXTTS Horatiu Vultur
2022-04-24 15:09   ` Richard Cochran
2022-04-25 20:31     ` Horatiu Vultur

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.