Commit 5534a820 authored by Ivan Vecera's avatar Ivan Vecera Committed by Jakub Kicinski
Browse files

dpll: zl3073x: Cache reference monitor status



Instead of reading the ZL_REG_REF_MON_STATUS register every time
the reference status is needed, cache this value in the zl3073x_ref
struct.

This is achieved by:
* Adding a mon_status field to struct zl3073x_ref
* Introducing zl3073x_dev_ref_status_update() to read the status for
  all references into this new cache field
* Calling this update function from the periodic work handler
* Adding zl3073x_ref_is_status_ok() and zl3073x_dev_ref_is_status_ok()
  helpers to check the cached value
* Refactoring all callers in dpll.c to use the new
  zl3073x_dev_ref_is_status_ok() helper, removing direct register reads

This change consolidates all status register reads into a single periodic
function and reduces I/O bus traffic in dpll callbacks.

Reviewed-by: default avatarPetr Oros <poros@redhat.com>
Tested-by: default avatarPrathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: default avatarIvan Vecera <ivecera@redhat.com>
Link: https://patch.msgid.link/20251113074105.141379-4-ivecera@redhat.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 607f2c00
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -591,6 +591,21 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
	return rc;
}

static void
zl3073x_dev_ref_status_update(struct zl3073x_dev *zldev)
{
	int i, rc;

	for (i = 0; i < ZL3073X_NUM_REFS; i++) {
		rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(i),
				     &zldev->ref[i].mon_status);
		if (rc)
			dev_warn(zldev->dev,
				 "Failed to get REF%u status: %pe\n", i,
				 ERR_PTR(rc));
	}
}

/**
 * zl3073x_ref_phase_offsets_update - update reference phase offsets
 * @zldev: pointer to zl3073x_dev structure
@@ -710,6 +725,9 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
	struct zl3073x_dpll *zldpll;
	int rc;

	/* Update input references status */
	zl3073x_dev_ref_status_update(zldev);

	/* Update DPLL-to-connected-ref phase offsets registers */
	rc = zl3073x_ref_phase_offsets_update(zldev, -1);
	if (rc)
+15 −0
Original line number Diff line number Diff line
@@ -227,6 +227,21 @@ zl3073x_dev_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)
	return zl3073x_ref_is_enabled(ref);
}

/*
 * zl3073x_dev_ref_is_status_ok - check the given input reference status
 * @zldev: pointer to zl3073x device
 * @index: input reference index
 *
 * Return: true if the status is ok, false otherwise
 */
static inline bool
zl3073x_dev_ref_is_status_ok(struct zl3073x_dev *zldev, u8 index)
{
	const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);

	return zl3073x_ref_is_status_ok(ref);
}

/**
 * zl3073x_dev_synth_dpll_get - get DPLL ID the synth is driven by
 * @zldev: pointer to zl3073x device
+21 −75
Original line number Diff line number Diff line
@@ -497,19 +497,10 @@ zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref)
	if (rc)
		return rc;

	if (ZL3073X_DPLL_REF_IS_VALID(*ref)) {
		u8 ref_status;

		/* Read the reference monitor status */
		rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(*ref),
				     &ref_status);
		if (rc)
			return rc;

	/* If the monitor indicates an error nothing is connected */
		if (ref_status != ZL_REF_MON_STATUS_OK)
	if (ZL3073X_DPLL_REF_IS_VALID(*ref) &&
	    !zl3073x_dev_ref_is_status_ok(zldev, *ref))
		*ref = ZL3073X_DPLL_REF_NONE;
	}

	return 0;
}
@@ -524,7 +515,7 @@ zl3073x_dpll_input_pin_phase_offset_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;
	u8 conn_ref, ref, ref_status;
	u8 conn_ref, ref;
	s64 ref_phase;
	int rc;

@@ -537,21 +528,9 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin,
	 * monitor feature is disabled.
	 */
	ref = zl3073x_input_pin_ref_get(pin->id);
	if (!zldpll->phase_monitor && ref != conn_ref) {
		*phase_offset = 0;

		return 0;
	}

	/* Get this pin monitor status */
	rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref), &ref_status);
	if (rc)
		return rc;

	/* Report phase offset only if the input pin signal is present */
	if (ref_status != ZL_REF_MON_STATUS_OK) {
	if ((!zldpll->phase_monitor && ref != conn_ref) ||
	    !zl3073x_dev_ref_is_status_ok(zldev, ref)) {
		*phase_offset = 0;

		return 0;
	}

@@ -777,7 +756,7 @@ zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin,
{
	struct zl3073x_dpll *zldpll = pin->dpll;
	struct zl3073x_dev *zldev = zldpll->dev;
	u8 ref, ref_conn, status;
	u8 ref, ref_conn;
	int rc;

	ref = zl3073x_input_pin_ref_get(pin->id);
@@ -797,21 +776,10 @@ zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin,
	 * pin as selectable.
	 */
	if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_AUTO &&
	    pin->selectable) {
		/* Read reference monitor status */
		rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref),
				     &status);
		if (rc)
			return rc;

		/* If the monitor indicates errors report the reference
		 * as disconnected
		 */
		if (status == ZL_REF_MON_STATUS_OK) {
	    zl3073x_dev_ref_is_status_ok(zldev, ref) && pin->selectable) {
		*state = DPLL_PIN_STATE_SELECTABLE;
		return 0;
	}
	}

	/* Otherwise report the pin as disconnected */
	*state = DPLL_PIN_STATE_DISCONNECTED;
@@ -2036,37 +2004,23 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin)

	ref = zl3073x_input_pin_ref_get(pin->id);

	/* No phase offset if the ref monitor reports signal errors */
	if (!zl3073x_dev_ref_is_status_ok(zldev, ref))
		return false;

	/* Select register to read phase offset value depending on pin and
	 * phase monitor state:
	 * 1) For connected pin use dpll_phase_err_data register
	 * 2) For other pins use appropriate ref_phase register if the phase
	 *    monitor feature is enabled and reference monitor does not
	 *    report signal errors for given input pin
	 *    monitor feature is enabled.
	 */
	if (pin->pin_state == DPLL_PIN_STATE_CONNECTED) {
	if (pin->pin_state == DPLL_PIN_STATE_CONNECTED)
		reg = ZL_REG_DPLL_PHASE_ERR_DATA(zldpll->id);
	} else if (zldpll->phase_monitor) {
		u8 status;

		/* Get reference monitor status */
		rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref),
				     &status);
		if (rc) {
			dev_err(zldev->dev,
				"Failed to read %s refmon status: %pe\n",
				pin->label, ERR_PTR(rc));

			return false;
		}

		if (status != ZL_REF_MON_STATUS_OK)
			return false;

	else if (zldpll->phase_monitor)
		reg = ZL_REG_REF_PHASE(ref);
	} else {
	else
		/* The pin is not connected or phase monitor disabled */
		return false;
	}

	/* Read measured phase offset value */
	rc = zl3073x_read_u48(zldev, reg, &phase_offset);
@@ -2105,22 +2059,14 @@ zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin)
{
	struct zl3073x_dpll *zldpll = pin->dpll;
	struct zl3073x_dev *zldev = zldpll->dev;
	u8 ref, status;
	s64 ffo;
	int rc;
	u8 ref;

	/* Get reference monitor status */
	ref = zl3073x_input_pin_ref_get(pin->id);
	rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref), &status);
	if (rc) {
		dev_err(zldev->dev, "Failed to read %s refmon status: %pe\n",
			pin->label, ERR_PTR(rc));

		return false;
	}

	/* Do not report ffo changes if the reference monitor report errors */
	if (status != ZL_REF_MON_STATUS_OK)
	if (!zl3073x_dev_ref_is_status_ok(zldev, ref))
		return false;

	/* Get the latest measured ref's ffo */
+14 −0
Original line number Diff line number Diff line
@@ -14,10 +14,12 @@ struct zl3073x_dev;
 * struct zl3073x_ref - input reference state
 * @ffo: current fractional frequency offset
 * @config: reference config
 * @mon_status: reference monitor status
 */
struct zl3073x_ref {
	s64	ffo;
	u8	config;
	u8	mon_status;
};

int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index);
@@ -63,4 +65,16 @@ zl3073x_ref_is_enabled(const struct zl3073x_ref *ref)
	return !!FIELD_GET(ZL_REF_CONFIG_ENABLE, ref->config);
}

/**
 * zl3073x_ref_is_status_ok - check the given input reference status
 * @ref: pointer to ref state
 *
 * Return: true if the status is ok, false otherwise
 */
static inline bool
zl3073x_ref_is_status_ok(const struct zl3073x_ref *ref)
{
	return ref->mon_status == ZL_REF_MON_STATUS_OK;
}

#endif /* _ZL3073X_REF_H */