Commit 718878c7 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'dpll-add-support-for-phase-adjustment-granularity'

Ivan Vecera says:

====================
dpll: Add support for phase adjustment granularity

Phase-adjust values are currently limited only by a min-max range. Some
hardware requires, for certain pin types, that values be multiples of
a specific granularity, as in the zl3073x driver.

Patch 1: Adds 'phase-adjust-gran' pin attribute and an appropriate
         handling
Patch 2: Adds a support for this attribute into zl3073x driver
====================

Link: https://patch.msgid.link/20251029153207.178448-1-ivecera@redhat.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 29f7ae9e 055a01b2
Loading
Loading
Loading
Loading
+20 −16
Original line number Diff line number Diff line
@@ -198,15 +198,17 @@ be requested with the same attribute with ``DPLL_CMD_DEVICE_SET`` command.
  ================================== ======================================

Device may also provide ability to adjust a signal phase on a pin.
If pin phase adjustment is supported, minimal and maximal values that pin
handle shall be provide to the user on ``DPLL_CMD_PIN_GET`` respond
with ``DPLL_A_PIN_PHASE_ADJUST_MIN`` and ``DPLL_A_PIN_PHASE_ADJUST_MAX``
If pin phase adjustment is supported, minimal and maximal values and
granularity that pin handle shall be provided to the user on
``DPLL_CMD_PIN_GET`` respond with ``DPLL_A_PIN_PHASE_ADJUST_MIN``,
``DPLL_A_PIN_PHASE_ADJUST_MAX`` and ``DPLL_A_PIN_PHASE_ADJUST_GRAN``
attributes. Configured phase adjust value is provided with
``DPLL_A_PIN_PHASE_ADJUST`` attribute of a pin, and value change can be
requested with the same attribute with ``DPLL_CMD_PIN_SET`` command.

  =============================== ======================================
  ================================ ==========================================
  ``DPLL_A_PIN_ID``                configured pin id
  ``DPLL_A_PIN_PHASE_ADJUST_GRAN`` attr granularity of phase adjustment value
  ``DPLL_A_PIN_PHASE_ADJUST_MIN``  attr minimum value of phase adjustment
  ``DPLL_A_PIN_PHASE_ADJUST_MAX``  attr maximum value of phase adjustment
  ``DPLL_A_PIN_PHASE_ADJUST``      attr configured value of phase
@@ -217,7 +219,7 @@ requested with the same attribute with ``DPLL_CMD_PIN_SET`` command.
    ``DPLL_A_PIN_PARENT_ID``       parent dpll device id
    ``DPLL_A_PIN_PHASE_OFFSET``    attr measured phase difference
                                   between a pin and parent dpll device
  =============================== ======================================
  ================================ ==========================================

All phase related values are provided in pico seconds, which represents
time difference between signals phase. The negative value means that
@@ -384,6 +386,8 @@ according to attribute purpose.
                                       frequencies
      ``DPLL_A_PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency
      ``DPLL_A_PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency
    ``DPLL_A_PIN_PHASE_ADJUST_GRAN``   attr granularity of phase
                                       adjustment value
    ``DPLL_A_PIN_PHASE_ADJUST_MIN``    attr minimum value of phase
                                       adjustment
    ``DPLL_A_PIN_PHASE_ADJUST_MAX``    attr maximum value of phase
+7 −0
Original line number Diff line number Diff line
@@ -440,6 +440,12 @@ attribute-sets:
        doc: |
          Capable pin provides list of pins that can be bound to create a
          reference-sync pin pair.
      -
        name: phase-adjust-gran
        type: u32
        doc: |
          Granularity of phase adjustment, in picoseconds. The value of
          phase adjustment must be a multiple of this granularity.

  -
    name: pin-parent-device
@@ -616,6 +622,7 @@ operations:
            - capabilities
            - parent-device
            - parent-pin
            - phase-adjust-gran
            - phase-adjust-min
            - phase-adjust-max
            - phase-adjust
+11 −1
Original line number Diff line number Diff line
@@ -637,6 +637,10 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
	ret = dpll_msg_add_pin_freq(msg, pin, ref, extack);
	if (ret)
		return ret;
	if (prop->phase_gran &&
	    nla_put_u32(msg, DPLL_A_PIN_PHASE_ADJUST_GRAN,
			prop->phase_gran))
		return -EMSGSIZE;
	if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MIN,
			prop->phase_range.min))
		return -EMSGSIZE;
@@ -1261,7 +1265,13 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
	if (phase_adj > pin->prop.phase_range.max ||
	    phase_adj < pin->prop.phase_range.min) {
		NL_SET_ERR_MSG_ATTR(extack, phase_adj_attr,
				    "phase adjust value not supported");
				    "phase adjust value of out range");
		return -EINVAL;
	}
	if (pin->prop.phase_gran && phase_adj % (s32)pin->prop.phase_gran) {
		NL_SET_ERR_MSG_ATTR_FMT(extack, phase_adj_attr,
					"phase adjust value not multiple of %u",
					pin->prop.phase_gran);
		return -EINVAL;
	}

+14 −44
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
 * @prio: pin priority <0, 14>
 * @selectable: pin is selectable in automatic mode
 * @esync_control: embedded sync is controllable
 * @phase_gran: phase adjustment granularity
 * @pin_state: last saved pin state
 * @phase_offset: last saved pin phase offset
 * @freq_offset: last saved fractional frequency offset
@@ -49,6 +50,7 @@ struct zl3073x_dpll_pin {
	u8			prio;
	bool			selectable;
	bool			esync_control;
	s32			phase_gran;
	enum dpll_pin_state	pin_state;
	s64			phase_offset;
	s64			freq_offset;
@@ -1388,25 +1390,14 @@ zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin,
	struct zl3073x_dpll *zldpll = dpll_priv;
	struct zl3073x_dev *zldev = zldpll->dev;
	struct zl3073x_dpll_pin *pin = pin_priv;
	u32 synth_freq;
	s32 phase_comp;
	u8 out, synth;
	u8 out;
	int rc;

	out = zl3073x_output_pin_out_get(pin->id);
	synth = zl3073x_out_synth_get(zldev, out);
	synth_freq = zl3073x_synth_freq_get(zldev, synth);

	/* Check synth freq for zero */
	if (!synth_freq) {
		dev_err(zldev->dev, "Got zero synth frequency for output %u\n",
			out);
		return -EINVAL;
	}

	guard(mutex)(&zldev->multiop_lock);

	/* Read output configuration */
	out = zl3073x_output_pin_out_get(pin->id);
	rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
			   ZL_REG_OUTPUT_MB_MASK, BIT(out));
	if (rc)
@@ -1417,11 +1408,10 @@ zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin,
	if (rc)
		return rc;

	/* Value in register is expressed in half synth clock cycles */
	phase_comp *= (int)div_u64(PSEC_PER_SEC, 2 * synth_freq);

	/* Reverse two's complement negation applied during 'set' */
	*phase_adjust = -phase_comp;
	/* Convert value to ps and reverse two's complement negation applied
	 * during 'set'
	 */
	*phase_adjust = -phase_comp * pin->phase_gran;

	return rc;
}
@@ -1437,39 +1427,18 @@ zl3073x_dpll_output_pin_phase_adjust_set(const struct dpll_pin *dpll_pin,
	struct zl3073x_dpll *zldpll = dpll_priv;
	struct zl3073x_dev *zldev = zldpll->dev;
	struct zl3073x_dpll_pin *pin = pin_priv;
	int half_synth_cycle;
	u32 synth_freq;
	u8 out, synth;
	u8 out;
	int rc;

	/* Get attached synth */
	out = zl3073x_output_pin_out_get(pin->id);
	synth = zl3073x_out_synth_get(zldev, out);

	/* Get synth's frequency */
	synth_freq = zl3073x_synth_freq_get(zldev, synth);

	/* Value in register is expressed in half synth clock cycles so
	 * the given phase adjustment a multiple of half synth clock.
	 */
	half_synth_cycle = (int)div_u64(PSEC_PER_SEC, 2 * synth_freq);

	if ((phase_adjust % half_synth_cycle) != 0) {
		NL_SET_ERR_MSG_FMT(extack,
				   "Phase adjustment value has to be multiple of %d",
				   half_synth_cycle);
		return -EINVAL;
	}
	phase_adjust /= half_synth_cycle;

	/* The value in the register is stored as two's complement negation
	 * of requested value.
	 * of requested value and expressed in half synth clock cycles.
	 */
	phase_adjust = -phase_adjust;
	phase_adjust = -phase_adjust / pin->phase_gran;

	guard(mutex)(&zldev->multiop_lock);

	/* Read output configuration */
	out = zl3073x_output_pin_out_get(pin->id);
	rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
			   ZL_REG_OUTPUT_MB_MASK, BIT(out));
	if (rc)
@@ -1758,9 +1727,10 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
	if (IS_ERR(props))
		return PTR_ERR(props);

	/* Save package label & esync capability */
	/* Save package label, esync capability and phase adjust granularity */
	strscpy(pin->label, props->package_label);
	pin->esync_control = props->esync_control;
	pin->phase_gran = props->dpll_props.phase_gran;

	if (zl3073x_dpll_is_input_pin(pin)) {
		rc = zl3073x_dpll_ref_prio_get(pin, &pin->prio);
+11 −0
Original line number Diff line number Diff line
@@ -208,7 +208,18 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
			DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE |
			DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
	} else {
		u8 out, synth;
		u32 f;

		props->dpll_props.type = DPLL_PIN_TYPE_GNSS;

		/* The output pin phase adjustment granularity equals half of
		 * the synth frequency count.
		 */
		out = zl3073x_output_pin_out_get(index);
		synth = zl3073x_out_synth_get(zldev, out);
		f = 2 * zl3073x_synth_freq_get(zldev, synth);
		props->dpll_props.phase_gran = f ? div_u64(PSEC_PER_SEC, f) : 1;
	}

	props->dpll_props.phase_range.min = S32_MIN;
Loading