mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Ali Rouhi <arouhi@sitime.com>
To: "jiri@resnulli.us" <jiri@resnulli.us>
Cc: "vadim.fedorenko@linux.dev" <vadim.fedorenko@linux.dev>,
	"arkadiusz.kubalewski@intel.com" <arkadiusz.kubalewski@intel.com>,
	"ivecera@redhat.com" <ivecera@redhat.com>,
	"kuba@kernel.org" <kuba@kernel.org>,
	"pabeni@redhat.com" <pabeni@redhat.com>,
	"robh@kernel.org" <robh@kernel.org>,
	"krzk+dt@kernel.org" <krzk+dt@kernel.org>,
	"conor+dt@kernel.org" <conor+dt@kernel.org>,
	"cjubran@nvidia.com" <cjubran@nvidia.com>,
	"Oleg.Zadorozhnyi@devoxsoftware.com"
	<Oleg.Zadorozhnyi@devoxsoftware.com>,
	"prabhakar.mahadev-lad.rj@bp.renesas.com"
	<prabhakar.mahadev-lad.rj@bp.renesas.com>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"netdev@vger.kernel.org" <netdev@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: [PATCH net-next v15 08/13] dpll: sit9531x: add support to get and set priority on input pins
Date: Tue, 10 Nov 2026 20:26:14 +0000	[thread overview]
Message-ID: <20261110202607.55744-9-arouhi@sitime.com> (raw)
In-Reply-To: <20261110202607.55744-1-arouhi@sitime.com>

From: Oleg Zadorozhnyi <Oleg.Zadorozhnyi@devoxsoftware.com>

Keep a priority per input and PLL, seeded from the table the part
loaded, and rebuild the table from it on a set. Priority and state are
separate: a priority set on a disconnected input applies when it is
connected. The range is 0 to 255 over eleven slots; inputs of equal
priority keep their table order.

A table rewritten outside the driver, by a profile reload or an I2C
tool, becomes the new configuration, and the poll notifies the pins
whose priority moved.

Signed-off-by: Oleg Zadorozhnyi <Oleg.Zadorozhnyi@devoxsoftware.com>
Signed-off-by: Ali Rouhi <arouhi@sitime.com>
---
 drivers/dpll/sit9531x/core.c |  52 ++++++++++-
 drivers/dpll/sit9531x/core.h |   2 +
 drivers/dpll/sit9531x/dpll.c | 163 +++++++++++++++++++++++++++++++----
 drivers/dpll/sit9531x/dpll.h |   4 +-
 drivers/dpll/sit9531x/prop.c |   2 +
 5 files changed, 201 insertions(+), 22 deletions(-)

diff --git a/drivers/dpll/sit9531x/core.c b/drivers/dpll/sit9531x/core.c
index af6d7918958d..b4e44f0d9820 100644
--- a/drivers/dpll/sit9531x/core.c
+++ b/drivers/dpll/sit9531x/core.c
@@ -605,6 +605,33 @@ bool sit9531x_input_prio_present(struct sit9531x_dev *sitdev, u8 pll_idx,
 	return !!(sitdev->chan[pll_idx].prio_mask & BIT(input_idx));
 }
 
+/*
+ * @input_idx is in hardware encoding (see sit9531x_input_hw_src()). A source
+ * the PLL has never listed reports the last slot index, 10. Caller must hold
+ * sitdev->multiop_lock.
+ */
+int sit9531x_input_prio_get(struct sit9531x_dev *sitdev, u8 pll_idx,
+			    u8 input_idx, u8 *prio)
+{
+	const struct sit9531x_chan *chan;
+
+	lockdep_assert_held(&sitdev->multiop_lock);
+
+	if (pll_idx >= SIT9531X_NUM_PLLS)
+		return -EINVAL;
+	input_idx = sit9531x_prio_src_canon(sitdev, input_idx);
+	if (input_idx >= SIT9531X_PRIO_NUM_SRC)
+		return -EINVAL;
+
+	chan = &sitdev->chan[pll_idx];
+	if (chan->cfg_known & BIT(input_idx))
+		*prio = chan->cfg_prio[input_idx];
+	else
+		*prio = SIT9531X_PRIO_MAX_SLOTS - 1;
+
+	return 0;
+}
+
 /*
  * Take the configured priorities from the hardware table: a listed source gets
  * the first slot it occupies.
@@ -735,7 +762,8 @@ static u8 sit9531x_prio_top_live(const struct sit9531x_dev *sitdev,
  * until it loses signal.
  */
 static u8 sit9531x_prio_activesel_pick(struct sit9531x_dev *sitdev,
-				       const u8 *old, const u8 *srcs, u8 cur)
+				       const u8 *old, const u8 *srcs, u8 cur,
+				       u8 routed)
 {
 	u8 top, i;
 
@@ -744,6 +772,12 @@ static u8 sit9531x_prio_activesel_pick(struct sit9531x_dev *sitdev,
 	    top != sit9531x_prio_top_live(sitdev, old))
 		return top;
 
+	if (sit9531x_prio_src_usable(routed) &&
+	    sit9531x_prio_src_live(sitdev, routed))
+		for (i = 0; i < SIT9531X_PRIO_MAX_SLOTS; i++)
+			if (srcs[i] == routed)
+				return routed;
+
 	cur = sit9531x_prio_src_canon(sitdev, cur & SIT9531X_PRIO_NIBBLE_MASK);
 
 	if (sit9531x_prio_src_usable(cur) &&
@@ -826,12 +860,18 @@ static int sit9531x_prio_table_commit(struct sit9531x_dev *sitdev, u8 pll_idx,
 
 	if (!empty) {
 		u8 sel = sit9531x_prio_slot_get(val, slot + 1);
+		u8 routed = SIT9531X_PRIO_SRC_NONE;
 
+		/*
+		 * The pick needs the signal state now, not as of the last poll.
+		 */
 		rc = sit9531x_input_mon_fetch(sitdev);
 		if (rc)
 			goto rollback;
+		if (!chan->stale && chan->routed_ref != SIT9531X_REF_INVALID)
+			routed = sit9531x_input_hw_src(chan->routed_ref);
 		sel = sit9531x_prio_activesel_pick(sitdev, chan->prio_srcs,
-						   srcs, sel);
+						   srcs, sel, routed);
 		val = sit9531x_prio_slot_set(val, slot + 1, sel);
 	}
 
@@ -2277,6 +2317,14 @@ static int sit9531x_dpll_pins_register(struct sit9531x_dpll *sitdpll)
 			goto error;
 		}
 
+		/*
+		 * Taken before the pin is published; see
+		 * sit9531x_dpll_pin_baseline().
+		 */
+		mutex_lock(&sitdpll->dev->multiop_lock);
+		sit9531x_dpll_pin_baseline(pin);
+		mutex_unlock(&sitdpll->dev->multiop_lock);
+
 		rc = sit9531x_dpll_pin_register(pin, index);
 		if (rc) {
 			kfree(pin);
diff --git a/drivers/dpll/sit9531x/core.h b/drivers/dpll/sit9531x/core.h
index c2fa6a17be43..fa779acf7de5 100644
--- a/drivers/dpll/sit9531x/core.h
+++ b/drivers/dpll/sit9531x/core.h
@@ -265,6 +265,8 @@ bool sit9531x_input_prio_present(struct sit9531x_dev *sitdev,
 				 u8 pll_idx, u8 input_idx);
 int sit9531x_input_prio_set(struct sit9531x_dev *sitdev, u8 pll_idx,
 			    u8 input_idx, u8 prio);
+int sit9531x_input_prio_get(struct sit9531x_dev *sitdev, u8 pll_idx,
+			    u8 input_idx, u8 *prio);
 int sit9531x_input_prio_remove(struct sit9531x_dev *sitdev, u8 pll_idx,
 			       u8 input_idx);
 int sit9531x_input_prio_add(struct sit9531x_dev *sitdev, u8 pll_idx,
diff --git a/drivers/dpll/sit9531x/dpll.c b/drivers/dpll/sit9531x/dpll.c
index 56bdec4bcf67..f03145f4d1ee 100644
--- a/drivers/dpll/sit9531x/dpll.c
+++ b/drivers/dpll/sit9531x/dpll.c
@@ -34,6 +34,14 @@ sit9531x_dpll_is_xo_pin(const struct sit9531x_dpll_pin *pin)
 	       pin->id == SIT9531X_MAX_INPUTS;
 }
 
+/* Check if the pin's state and priority can change without a request */
+static bool
+sit9531x_dpll_is_selection_pin(const struct sit9531x_dpll_pin *pin)
+{
+	return sit9531x_dpll_is_input_pin(pin) &&
+	       !sit9531x_dpll_is_xo_pin(pin);
+}
+
 /*
  * A frozen PLL with an empty table is in forced holdover; report holdover only
  * while its holdover memory is valid.
@@ -396,11 +404,78 @@ sit9531x_dpll_input_pin_state_on_dpll_set(const struct dpll_pin *pin,
 	return rc;
 }
 
+/* Report the configured priority of the source on this PLL, listed or not */
+static int
+sit9531x_dpll_input_pin_prio_get(const struct dpll_pin *pin, void *pin_priv,
+				 const struct dpll_device *dpll,
+				 void *dpll_priv, u32 *prio,
+				 struct netlink_ext_ack *extack)
+{
+	struct sit9531x_dpll_pin *dpin = pin_priv;
+	struct sit9531x_dpll *sitdpll = dpll_priv;
+	struct sit9531x_dev *sitdev = sitdpll->dev;
+	u8 slot;
+	int rc;
+
+	mutex_lock(&sitdev->multiop_lock);
+	rc = sit9531x_input_prio_get(sitdev, sitdpll->id,
+				     sit9531x_input_hw_src(dpin->id), &slot);
+	mutex_unlock(&sitdev->multiop_lock);
+	if (rc)
+		return rc;
+
+	*prio = slot;
+	return 0;
+}
+
+/*
+ * Rewrite the Page 1 priority table for a listed pin; an unlisted pin keeps the
+ * priority until it is connected.
+ */
+static int
+sit9531x_dpll_input_pin_prio_set(const struct dpll_pin *pin, void *pin_priv,
+				 const struct dpll_device *dpll,
+				 void *dpll_priv, u32 prio,
+				 struct netlink_ext_ack *extack)
+{
+	struct sit9531x_dpll_pin *dpin = pin_priv;
+	struct sit9531x_dpll *sitdpll = dpll_priv;
+	struct sit9531x_dev *sitdev = sitdpll->dev;
+	int rc;
+
+	if (dpin->dir != DPLL_PIN_DIRECTION_INPUT) {
+		NL_SET_ERR_MSG(extack, "Priority applies only to input pins");
+		return -EINVAL;
+	}
+
+	if (prio > U8_MAX) {
+		NL_SET_ERR_MSG(extack, "Priority out of range (0-255)");
+		return -EINVAL;
+	}
+
+	mutex_lock(&sitdev->multiop_lock);
+	rc = sit9531x_input_prio_set(sitdev, sitdpll->id,
+				     sit9531x_input_hw_src(dpin->id),
+				     (u8)prio);
+	if (!rc)
+		dpin->prio = prio;
+	mutex_unlock(&sitdev->multiop_lock);
+
+	if (rc) {
+		NL_SET_ERR_MSG(extack, "Failed to set input priority");
+		return rc;
+	}
+
+	return 0;
+}
+
 static const struct dpll_pin_ops sit9531x_dpll_input_pin_ops = {
 	.direction_get		= sit9531x_dpll_input_pin_direction_get,
 	.state_on_dpll_get	= sit9531x_dpll_input_pin_state_on_dpll_get,
 	.state_on_dpll_set	= sit9531x_dpll_input_pin_state_on_dpll_set,
 	.operstate_on_dpll_get	= sit9531x_dpll_input_pin_operstate_on_dpll_get,
+	.prio_get		= sit9531x_dpll_input_pin_prio_get,
+	.prio_set		= sit9531x_dpll_input_pin_prio_set,
 };
 
 /*
@@ -477,6 +552,43 @@ sit9531x_dpll_pin_ops_get(const struct sit9531x_dpll_pin *pin)
 	return &sit9531x_dpll_input_pin_ops;
 }
 
+/* Caller must hold sitdev->multiop_lock. */
+static void sit9531x_dpll_pin_snapshot(struct sit9531x_dpll *sitdpll,
+				       const struct sit9531x_dpll_pin *pin,
+				       enum dpll_pin_state *state,
+				       enum dpll_pin_operstate *operstate,
+				       u8 *prio)
+{
+	struct sit9531x_dev *sitdev = sitdpll->dev;
+	u8 id = pin->id;
+
+	if (id == SIT9531X_INTSYNC_PIN_ID && sitdev->intsync_src == sitdpll->id)
+		*state = DPLL_PIN_STATE_DISCONNECTED;
+	else
+		sit9531x_dpll_selection_state_get(sitdev, sitdpll, id, state);
+	sit9531x_dpll_selection_operstate_get(sitdev, sitdpll, id, operstate);
+	if (sit9531x_input_prio_get(sitdev, sitdpll->id,
+				    sit9531x_input_hw_src(id), prio))
+		*prio = pin->prio;
+}
+
+/*
+ * Take the baseline before the pin is registered, so the first poll notifies a
+ * change a request made. Caller must hold sitdev->multiop_lock.
+ */
+void sit9531x_dpll_pin_baseline(struct sit9531x_dpll_pin *pin)
+{
+	struct sit9531x_dpll *sitdpll = pin->dpll;
+
+	lockdep_assert_held(&sitdpll->dev->multiop_lock);
+
+	if (!sit9531x_dpll_is_selection_pin(pin))
+		return;
+
+	sit9531x_dpll_pin_snapshot(sitdpll, pin, &pin->pin_state,
+				   &pin->operstate, &pin->prio);
+}
+
 /*
  * Send notifications for changed lock status and pin state; called from
  * sit9531x_dev_periodic_work().
@@ -511,32 +623,45 @@ void sit9531x_dpll_changes_check(struct sit9531x_dpll *sitdpll)
 	if (sitdpll->ntf_pending && !dpll_device_change_ntf(sitdpll->dpll_dev))
 		sitdpll->ntf_pending = false;
 
+	mutex_lock(&sitdev->multiop_lock);
 	list_for_each_entry(pin, &sitdpll->pins, list) {
-		const struct dpll_pin_ops *ops;
+		enum dpll_pin_operstate operstate;
 		enum dpll_pin_state state;
 		bool changed;
+		u8 prio;
 
-		/*
-		 * Only references and the INTSYNC destination change state
-		 * without a request.
-		 */
-		if (!sit9531x_dpll_is_input_pin(pin) ||
-		    sit9531x_dpll_is_xo_pin(pin))
+		if (!sit9531x_dpll_is_selection_pin(pin))
 			continue;
 
-		ops = sit9531x_dpll_pin_ops_get(pin);
-		rc = ops->state_on_dpll_get(pin->dpll_pin, pin,
-					    sitdpll->dpll_dev, sitdpll,
-					    &state, NULL);
-		if (rc)
-			continue;
+		sit9531x_dpll_pin_snapshot(sitdpll, pin, &state, &operstate,
+					   &prio);
+
+		changed = state != pin->pin_state ||
+			  operstate != pin->operstate || prio != pin->prio;
+		if (changed)
+			dev_dbg(sitdev->dev,
+				"%s: state %u->%u operstate %u->%u prio %u->%u\n",
+				pin->label, pin->pin_state, state,
+				pin->operstate, operstate, pin->prio, prio);
 
-		changed = pin->seen && state != pin->pin_state;
 		pin->pin_state = state;
-		pin->seen = true;
-		if (changed) {
-			dev_dbg(sitdev->dev, "%s state changed\n", pin->label);
-			dpll_pin_change_ntf(pin->dpll_pin);
-		}
+		pin->operstate = operstate;
+		pin->prio = prio;
+
+		/*
+		 * The notification takes DPLL-subsystem locks the callbacks run
+		 * under; send it after dropping multiop_lock.
+		 */
+		if (changed)
+			pin->ntf_pending = true;
+	}
+	mutex_unlock(&sitdev->multiop_lock);
+
+	list_for_each_entry(pin, &sitdpll->pins, list) {
+		if (!pin->ntf_pending)
+			continue;
+		if (dpll_pin_change_ntf(pin->dpll_pin))
+			continue;
+		pin->ntf_pending = false;
 	}
 }
diff --git a/drivers/dpll/sit9531x/dpll.h b/drivers/dpll/sit9531x/dpll.h
index 6c02aa131328..3ded177b871b 100644
--- a/drivers/dpll/sit9531x/dpll.h
+++ b/drivers/dpll/sit9531x/dpll.h
@@ -30,7 +30,8 @@ struct sit9531x_dpll_pin {
 	u8				id;		/* hardware index */
 	u8				prio;
 	enum dpll_pin_state		pin_state;
-	bool				seen;	/* baseline taken by the poll */
+	enum dpll_pin_operstate		operstate;
+	bool				ntf_pending;
 };
 
 struct sit9531x_dpll {
@@ -56,6 +57,7 @@ int  sit9531x_dpll_register(struct sit9531x_dpll *sitdpll);
 void sit9531x_dpll_unregister(struct sit9531x_dpll *sitdpll);
 
 void sit9531x_dpll_lock_status_baseline(struct sit9531x_dpll *sitdpll);
+void sit9531x_dpll_pin_baseline(struct sit9531x_dpll_pin *pin);
 void sit9531x_dpll_changes_check(struct sit9531x_dpll *sitdpll);
 
 #endif /* _SIT9531X_DPLL_H */
diff --git a/drivers/dpll/sit9531x/prop.c b/drivers/dpll/sit9531x/prop.c
index b9405eba49a3..69877fc94028 100644
--- a/drivers/dpll/sit9531x/prop.c
+++ b/drivers/dpll/sit9531x/prop.c
@@ -146,6 +146,7 @@ sit9531x_pin_props_get(struct sit9531x_dev *sitdev,
 		/* INTSYNC destination: a reference the PLL can lock to. */
 		props->dpll_props.type = DPLL_PIN_TYPE_INT_OSCILLATOR;
 		props->dpll_props.capabilities =
+			DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE |
 			DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
 		curr_freq = 0;
 	} else if (sync_out) {
@@ -161,6 +162,7 @@ sit9531x_pin_props_get(struct sit9531x_dev *sitdev,
 	} else if (dir == DPLL_PIN_DIRECTION_INPUT) {
 		props->dpll_props.type = DPLL_PIN_TYPE_EXT;
 		props->dpll_props.capabilities =
+			DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE |
 			DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
 		curr_freq = sitdev->ref[index].freq;
 	} else {
-- 
2.39.2 (Apple Git-143)


  parent reply	other threads:[~2026-11-10 20:26 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 20:26 [PATCH net-next v15 00/13] dpll: add SiTime SiT9531x DPLL clock driver Ali Rouhi
2026-11-10 20:26 ` [PATCH net-next v15 01/13] dpll: omit pin phase attributes the driver has no value for Ali Rouhi
2026-11-11 15:35   ` Ivan Vecera
2026-11-10 20:26 ` [PATCH net-next v15 02/13] dt-bindings: vendor-prefixes: add SiTime Corporation Ali Rouhi
2026-11-10 20:26 ` [PATCH net-next v15 04/13] dpll: add basic SiTime SiT9531x support Ali Rouhi
2026-11-10 20:26 ` [PATCH net-next v15 03/13] dt-bindings: dpll: add SiTime SiT95316 clock generator Ali Rouhi
2026-11-10 20:26 ` [PATCH net-next v15 06/13] dpll: sit9531x: register DPLL devices and pins Ali Rouhi
2026-11-10 20:26 ` [PATCH net-next v15 05/13] dpll: sit9531x: read DPLL types and pin properties from system firmware Ali Rouhi
2026-11-10 20:26 ` [PATCH net-next v15 07/13] dpll: sit9531x: implement input pin state on a DPLL Ali Rouhi
2026-11-10 20:26 ` Ali Rouhi [this message]
2026-11-10 20:26 ` [PATCH net-next v15 09/13] dpll: sit9531x: add support to get and set frequency on pins Ali Rouhi
2026-11-10 20:26 ` [PATCH net-next v15 10/13] dpll: sit9531x: implement output pin state on a DPLL Ali Rouhi
2026-11-10 20:26 ` [PATCH net-next v15 12/13] dpll: sit9531x: add support to get phase offset on the connected input pin Ali Rouhi
2026-11-10 20:26 ` [PATCH net-next v15 11/13] dpll: sit9531x: add support to adjust output phase Ali Rouhi
2026-11-10 20:26 ` [PATCH net-next v15 13/13] dpll: sit9531x: model the inter-PLL sync line as a pair of pins Ali Rouhi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261110202607.55744-9-arouhi@sitime.com \
    --to=arouhi@sitime.com \
    --cc=Oleg.Zadorozhnyi@devoxsoftware.com \
    --cc=arkadiusz.kubalewski@intel.com \
    --cc=cjubran@nvidia.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=ivecera@redhat.com \
    --cc=jiri@resnulli.us \
    --cc=krzk+dt@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=prabhakar.mahadev-lad.rj@bp.renesas.com \
    --cc=robh@kernel.org \
    --cc=vadim.fedorenko@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®