From nobody Mon Feb 9 07:20:39 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 15166326D62 for ; Thu, 13 Nov 2025 07:41:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763019697; cv=none; b=GUrnVOBFYvbXcaKN+wYE5s40NTTOktLQKTBcwNJfd/UX155elDJLrp8HrHaCfciS05bageOXdhpFst79+z4jBJYu6/PhexV6c5ai8R4/CwvpXboTG3BCZKpJJWRjLvktesoIluOCysJ+ZDEMaNof3+KCI2CRQXD8y3JianRxDTw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763019697; c=relaxed/simple; bh=Q10Pim46siCmc3d06xxxZn+mmA1nimoVkEdje/y4ks0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nvBZIHOrlYnLuYrhfxbnIpgaI+nud52MdyyevOncib71fXfR6QEXmDeH3bud3+P/tSIjaW3SsbPVwyIWY4ue1/J1u2AkDp9cgx8H/V/7wyvIGMBcF2i9IYrqoYZ5tiM0SngFDgyqpTEKtMqOSHZw2AzaK/hE+eNbXdsNRxHkVww= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Y821xhfp; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Y821xhfp" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1763019690; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xSOS8l6TmapXuH9VxJnuiJz5r7n/Mpv1w30w5lvKRSE=; b=Y821xhfpCHyjwfiVKXIhPUuCbPHh0kLgOoftjFmap9b8Q5pWQjWzi+3PnHfc4/Za59lrSl vNtcqygSNvZXoP+x+Qlhv4ZXcZFHEMF9LIQrZM8waRy62XNt6BTiJ99QvKlTFiezgVsPVJ K8LiSd1M5lTfZnCntgC90A+2PxAJ4VE= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-411-UKDes3evMgyKKK81H16vcg-1; Thu, 13 Nov 2025 02:41:29 -0500 X-MC-Unique: UKDes3evMgyKKK81H16vcg-1 X-Mimecast-MFC-AGG-ID: UKDes3evMgyKKK81H16vcg_1763019687 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C08AE19373D8; Thu, 13 Nov 2025 07:41:27 +0000 (UTC) Received: from p16v.luc.cera.cz (unknown [10.45.224.239]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 033F7300018D; Thu, 13 Nov 2025 07:41:24 +0000 (UTC) From: Ivan Vecera To: netdev@vger.kernel.org Cc: Petr Oros , Prathosh Satish , Vadim Fedorenko , Arkadiusz Kubalewski , Jiri Pirko , Michal Schmidt , linux-kernel@vger.kernel.org Subject: [PATCH net-next v3 5/6] dpll: zl3073x: Cache all output properties in zl3073x_out Date: Thu, 13 Nov 2025 08:41:04 +0100 Message-ID: <20251113074105.141379-6-ivecera@redhat.com> In-Reply-To: <20251113074105.141379-1-ivecera@redhat.com> References: <20251113074105.141379-1-ivecera@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 Content-Type: text/plain; charset="utf-8" Expand the zl3073x_out structure to cache all output-related hardware registers, including divisors, widths, embedded-sync parameters and phase compensation. Modify zl3073x_out_state_fetch() to read and populate all these new fields at once, including zero-divisor checks. Refactor all dpll "getter" functions in dpll.c to read from this new cached state instead of performing direct register access. Introduce a new function, zl3073x_out_state_set(), to handle writing changes back to the hardware. This function compares the provided state with the current cached state and writes *only* the modified register values via a single mailbox sequence before updating the local cache. Refactor all dpll "setter" functions to modify a local copy of the output state and then call zl3073x_out_state_set() to commit the changes. This change centralizes all output-related register I/O into out.c, significantly reduces bus traffic, and simplifies the logic in dpll.c. Reviewed-by: Petr Oros Tested-by: Prathosh Satish Signed-off-by: Ivan Vecera --- Changes: v2: - added new fields' description in zl3073x_out - fixed uninitialized variable warning - dropped usage of ZL3073X_OUT_SYNC_ONE --- drivers/dpll/zl3073x/dpll.c | 380 +++++++++--------------------------- drivers/dpll/zl3073x/out.c | 90 +++++++++ drivers/dpll/zl3073x/out.h | 13 ++ 3 files changed, 193 insertions(+), 290 deletions(-) diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c index e0d696bc1909e..9879d85d29af0 100644 --- a/drivers/dpll/zl3073x/dpll.c +++ b/drivers/dpll/zl3073x/dpll.c @@ -770,21 +770,19 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_p= in *dpll_pin, struct zl3073x_dpll *zldpll =3D dpll_priv; struct zl3073x_dev *zldev =3D zldpll->dev; struct zl3073x_dpll_pin *pin =3D pin_priv; - struct device *dev =3D zldev->dev; - u32 esync_period, esync_width; - u8 clock_type, synth; - u8 out, output_mode; - u32 output_div; + const struct zl3073x_synth *synth; + const struct zl3073x_out *out; + u8 clock_type, out_id; u32 synth_freq; - int rc; =20 - out =3D zl3073x_output_pin_out_get(pin->id); + out_id =3D zl3073x_output_pin_out_get(pin->id); + out =3D zl3073x_out_state_get(zldev, out_id); =20 /* If N-division is enabled, esync is not supported. The register used * for N-division is also used for the esync divider so both cannot * be used. */ - switch (zl3073x_dev_out_signal_format_get(zldev, out)) { + switch (zl3073x_out_signal_format_get(out)) { case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: return -EOPNOTSUPP; @@ -792,38 +790,11 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_p= in *dpll_pin, break; } =20 - guard(mutex)(&zldev->multiop_lock); - - /* Read output configuration into mailbox */ - rc =3D zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, - ZL_REG_OUTPUT_MB_MASK, BIT(out)); - if (rc) - return rc; - - /* Read output mode */ - rc =3D zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode); - if (rc) - return rc; - - /* Read output divisor */ - rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div); - if (rc) - return rc; - - /* Check output divisor for zero */ - if (!output_div) { - dev_err(dev, "Zero divisor for OUTPUT%u got from device\n", - out); - return -EINVAL; - } - - /* Get synth attached to output pin */ - synth =3D zl3073x_dev_out_synth_get(zldev, out); - - /* Get synth frequency */ - synth_freq =3D zl3073x_dev_synth_freq_get(zldev, synth); + /* Get attached synth frequency */ + synth =3D zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); + synth_freq =3D zl3073x_synth_freq_get(synth); =20 - clock_type =3D FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, output_mode); + clock_type =3D FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode); if (clock_type !=3D ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) { /* No need to read esync data if it is not enabled */ esync->freq =3D 0; @@ -832,38 +803,21 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_p= in *dpll_pin, goto finish; } =20 - /* Read esync period */ - rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, &esync_period); - if (rc) - return rc; - - /* Check esync divisor for zero */ - if (!esync_period) { - dev_err(dev, "Zero esync divisor for OUTPUT%u got from device\n", - out); - return -EINVAL; - } - - /* Get esync pulse width in units of half synth cycles */ - rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, &esync_width); - if (rc) - return rc; - /* Compute esync frequency */ - esync->freq =3D synth_freq / output_div / esync_period; + esync->freq =3D synth_freq / out->div / out->esync_n_period; =20 /* By comparing the esync_pulse_width to the half of the pulse width * the esync pulse percentage can be determined. * Note that half pulse width is in units of half synth cycles, which * is why it reduces down to be output_div. */ - esync->pulse =3D (50 * esync_width) / output_div; + esync->pulse =3D (50 * out->esync_n_width) / out->div; =20 finish: /* Set supported esync ranges if the pin supports esync control and * if the output frequency is > 1 Hz. */ - if (pin->esync_control && (synth_freq / output_div) > 1) { + if (pin->esync_control && (synth_freq / out->div) > 1) { esync->range =3D esync_freq_ranges; esync->range_num =3D ARRAY_SIZE(esync_freq_ranges); } else { @@ -881,21 +835,22 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_p= in *dpll_pin, void *dpll_priv, u64 freq, struct netlink_ext_ack *extack) { - u32 esync_period, esync_width, output_div; struct zl3073x_dpll *zldpll =3D dpll_priv; struct zl3073x_dev *zldev =3D zldpll->dev; struct zl3073x_dpll_pin *pin =3D pin_priv; - u8 clock_type, out, output_mode, synth; + const struct zl3073x_synth *synth; + struct zl3073x_out out; + u8 clock_type, out_id; u32 synth_freq; - int rc; =20 - out =3D zl3073x_output_pin_out_get(pin->id); + out_id =3D zl3073x_output_pin_out_get(pin->id); + out =3D *zl3073x_out_state_get(zldev, out_id); =20 /* If N-division is enabled, esync is not supported. The register used * for N-division is also used for the esync divider so both cannot * be used. */ - switch (zl3073x_dev_out_signal_format_get(zldev, out)) { + switch (zl3073x_out_signal_format_get(&out)) { case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: return -EOPNOTSUPP; @@ -903,19 +858,6 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pi= n *dpll_pin, break; } =20 - guard(mutex)(&zldev->multiop_lock); - - /* Read output configuration into mailbox */ - rc =3D zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, - ZL_REG_OUTPUT_MB_MASK, BIT(out)); - if (rc) - return rc; - - /* Read output mode */ - rc =3D zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode); - if (rc) - return rc; - /* Select clock type */ if (freq) clock_type =3D ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC; @@ -923,38 +865,19 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_p= in *dpll_pin, clock_type =3D ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL; =20 /* Update clock type in output mode */ - output_mode &=3D ~ZL_OUTPUT_MODE_CLOCK_TYPE; - output_mode |=3D FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type); - rc =3D zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, output_mode); - if (rc) - return rc; + out.mode &=3D ~ZL_OUTPUT_MODE_CLOCK_TYPE; + out.mode |=3D FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type); =20 /* If esync is being disabled just write mailbox and finish */ if (!freq) goto write_mailbox; =20 - /* Get synth attached to output pin */ - synth =3D zl3073x_dev_out_synth_get(zldev, out); - - /* Get synth frequency */ - synth_freq =3D zl3073x_dev_synth_freq_get(zldev, synth); - - rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div); - if (rc) - return rc; - - /* Check output divisor for zero */ - if (!output_div) { - dev_err(zldev->dev, - "Zero divisor for OUTPUT%u got from device\n", out); - return -EINVAL; - } + /* Get attached synth frequency */ + synth =3D zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(&out)); + synth_freq =3D zl3073x_synth_freq_get(synth); =20 /* Compute and update esync period */ - esync_period =3D synth_freq / (u32)freq / output_div; - rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, esync_period); - if (rc) - return rc; + out.esync_n_period =3D synth_freq / (u32)freq / out.div; =20 /* Half of the period in units of 1/2 synth cycle can be represented by * the output_div. To get the supported esync pulse width of 25% of the @@ -962,15 +885,11 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_p= in *dpll_pin, * assumes that output_div is even, otherwise some resolution will be * lost. */ - esync_width =3D output_div / 2; - rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, esync_width); - if (rc) - return rc; + out.esync_n_width =3D out.div / 2; =20 write_mailbox: /* Commit output configuration */ - return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, - ZL_REG_OUTPUT_MB_MASK, BIT(out)); + return zl3073x_out_state_set(zldev, out_id, &out); } =20 static int @@ -983,83 +902,46 @@ zl3073x_dpll_output_pin_frequency_get(const struct dp= ll_pin *dpll_pin, struct zl3073x_dpll *zldpll =3D dpll_priv; struct zl3073x_dev *zldev =3D zldpll->dev; struct zl3073x_dpll_pin *pin =3D pin_priv; - struct device *dev =3D zldev->dev; - u8 out, signal_format, synth; - u32 output_div, synth_freq; - int rc; - - out =3D zl3073x_output_pin_out_get(pin->id); - synth =3D zl3073x_dev_out_synth_get(zldev, out); - synth_freq =3D zl3073x_dev_synth_freq_get(zldev, synth); - - guard(mutex)(&zldev->multiop_lock); - - /* Read output configuration into mailbox */ - rc =3D zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, - ZL_REG_OUTPUT_MB_MASK, BIT(out)); - if (rc) - return rc; - - rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div); - if (rc) - return rc; + const struct zl3073x_synth *synth; + const struct zl3073x_out *out; + u32 synth_freq; + u8 out_id; =20 - /* Check output divisor for zero */ - if (!output_div) { - dev_err(dev, "Zero divisor for output %u got from device\n", - out); - return -EINVAL; - } + out_id =3D zl3073x_output_pin_out_get(pin->id); + out =3D zl3073x_out_state_get(zldev, out_id); =20 - /* Read used signal format for the given output */ - signal_format =3D zl3073x_dev_out_signal_format_get(zldev, out); + /* Get attached synth frequency */ + synth =3D zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); + synth_freq =3D zl3073x_synth_freq_get(synth); =20 - switch (signal_format) { + switch (zl3073x_out_signal_format_get(out)) { case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: /* In case of divided format we have to distiguish between * given output pin type. + * + * For P-pin the resulting frequency is computed as simple + * division of synth frequency and output divisor. + * + * For N-pin we have to divide additionally by divisor stored + * in esync_n_period output mailbox register that is used as + * N-pin divisor for these modes. */ - if (zl3073x_dpll_is_p_pin(pin)) { - /* For P-pin the resulting frequency is computed as - * simple division of synth frequency and output - * divisor. - */ - *frequency =3D synth_freq / output_div; - } else { - /* For N-pin we have to divide additionally by - * divisor stored in esync_period output mailbox - * register that is used as N-pin divisor for these - * modes. - */ - u32 ndiv; - - rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, - &ndiv); - if (rc) - return rc; + *frequency =3D synth_freq / out->div; =20 - /* Check N-pin divisor for zero */ - if (!ndiv) { - dev_err(dev, - "Zero N-pin divisor for output %u got from device\n", - out); - return -EINVAL; - } + if (!zl3073x_dpll_is_p_pin(pin)) + *frequency =3D (u32)*frequency / out->esync_n_period; =20 - /* Compute final divisor for N-pin */ - *frequency =3D synth_freq / output_div / ndiv; - } break; default: /* In other modes the resulting frequency is computed as * division of synth frequency and output divisor. */ - *frequency =3D synth_freq / output_div; + *frequency =3D synth_freq / out->div; break; } =20 - return rc; + return 0; } =20 static int @@ -1072,28 +954,21 @@ zl3073x_dpll_output_pin_frequency_set(const struct d= pll_pin *dpll_pin, struct zl3073x_dpll *zldpll =3D dpll_priv; struct zl3073x_dev *zldev =3D zldpll->dev; struct zl3073x_dpll_pin *pin =3D pin_priv; - struct device *dev =3D zldev->dev; - u32 output_n_freq, output_p_freq; - u8 out, signal_format, synth; - u32 cur_div, new_div, ndiv; - u32 synth_freq; - int rc; + const struct zl3073x_synth *synth; + u8 out_id, signal_format; + u32 new_div, synth_freq; + struct zl3073x_out out; =20 - out =3D zl3073x_output_pin_out_get(pin->id); - synth =3D zl3073x_dev_out_synth_get(zldev, out); - synth_freq =3D zl3073x_dev_synth_freq_get(zldev, synth); + out_id =3D zl3073x_output_pin_out_get(pin->id); + out =3D *zl3073x_out_state_get(zldev, out_id); + + /* Get attached synth frequency and compute new divisor */ + synth =3D zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(&out)); + synth_freq =3D zl3073x_synth_freq_get(synth); new_div =3D synth_freq / (u32)frequency; =20 /* Get used signal format for the given output */ - signal_format =3D zl3073x_dev_out_signal_format_get(zldev, out); - - guard(mutex)(&zldev->multiop_lock); - - /* Load output configuration */ - rc =3D zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, - ZL_REG_OUTPUT_MB_MASK, BIT(out)); - if (rc) - return rc; + signal_format =3D zl3073x_out_signal_format_get(&out); =20 /* Check signal format */ if (signal_format !=3D ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV && @@ -1101,99 +976,50 @@ zl3073x_dpll_output_pin_frequency_set(const struct d= pll_pin *dpll_pin, /* For non N-divided signal formats the frequency is computed * as division of synth frequency and output divisor. */ - rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, new_div); - if (rc) - return rc; + out.div =3D new_div; =20 /* For 50/50 duty cycle the divisor is equal to width */ - rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, new_div); - if (rc) - return rc; + out.width =3D new_div; =20 /* Commit output configuration */ - return zl3073x_mb_op(zldev, - ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, - ZL_REG_OUTPUT_MB_MASK, BIT(out)); + return zl3073x_out_state_set(zldev, out_id, &out); } =20 - /* For N-divided signal format get current divisor */ - rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &cur_div); - if (rc) - return rc; - - /* Check output divisor for zero */ - if (!cur_div) { - dev_err(dev, "Zero divisor for output %u got from device\n", - out); - return -EINVAL; - } - - /* Get N-pin divisor (shares the same register with esync */ - rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, &ndiv); - if (rc) - return rc; - - /* Check N-pin divisor for zero */ - if (!ndiv) { - dev_err(dev, - "Zero N-pin divisor for output %u got from device\n", - out); - return -EINVAL; - } - - /* Compute current output frequency for P-pin */ - output_p_freq =3D synth_freq / cur_div; - - /* Compute current N-pin frequency */ - output_n_freq =3D output_p_freq / ndiv; - if (zl3073x_dpll_is_p_pin(pin)) { /* We are going to change output frequency for P-pin but * if the requested frequency is less than current N-pin * frequency then indicate a failure as we are not able * to compute N-pin divisor to keep its frequency unchanged. + * + * Update divisor for N-pin to keep N-pin frequency. */ - if (frequency <=3D output_n_freq) + out.esync_n_period =3D (out.esync_n_period * out.div) / new_div; + if (!out.esync_n_period) return -EINVAL; =20 /* Update the output divisor */ - rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, new_div); - if (rc) - return rc; + out.div =3D new_div; =20 /* For 50/50 duty cycle the divisor is equal to width */ - rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, new_div); - if (rc) - return rc; - - /* Compute new divisor for N-pin */ - ndiv =3D (u32)frequency / output_n_freq; + out.width =3D out.div; } else { /* We are going to change frequency of N-pin but if * the requested freq is greater or equal than freq of P-pin * in the output pair we cannot compute divisor for the N-pin. * In this case indicate a failure. + * + * Update divisor for N-pin */ - if (output_p_freq <=3D frequency) + out.esync_n_period =3D div64_u64(synth_freq, frequency * out.div); + if (!out.esync_n_period) return -EINVAL; - - /* Compute new divisor for N-pin */ - ndiv =3D output_p_freq / (u32)frequency; } =20 - /* Update divisor for the N-pin */ - rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, ndiv); - if (rc) - return rc; - /* For 50/50 duty cycle the divisor is equal to width */ - rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, ndiv); - if (rc) - return rc; + out.esync_n_width =3D out.esync_n_period; =20 /* Commit output configuration */ - return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, - ZL_REG_OUTPUT_MB_MASK, BIT(out)); + return zl3073x_out_state_set(zldev, out_id, &out); } =20 static int @@ -1207,30 +1033,18 @@ zl3073x_dpll_output_pin_phase_adjust_get(const stru= ct dpll_pin *dpll_pin, struct zl3073x_dpll *zldpll =3D dpll_priv; struct zl3073x_dev *zldev =3D zldpll->dev; struct zl3073x_dpll_pin *pin =3D pin_priv; - s32 phase_comp; - u8 out; - int rc; - - guard(mutex)(&zldev->multiop_lock); + const struct zl3073x_out *out; + u8 out_id; =20 - /* Read output configuration */ - out =3D zl3073x_output_pin_out_get(pin->id); - rc =3D zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, - ZL_REG_OUTPUT_MB_MASK, BIT(out)); - if (rc) - return rc; - - /* Read current output phase compensation */ - rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, &phase_comp); - if (rc) - return rc; + out_id =3D zl3073x_output_pin_out_get(pin->id); + out =3D zl3073x_out_state_get(zldev, out_id); =20 /* Convert value to ps and reverse two's complement negation applied * during 'set' */ - *phase_adjust =3D -phase_comp * pin->phase_gran; + *phase_adjust =3D -out->phase_comp * pin->phase_gran; =20 - return rc; + return 0; } =20 static int @@ -1244,31 +1058,19 @@ zl3073x_dpll_output_pin_phase_adjust_set(const stru= ct dpll_pin *dpll_pin, struct zl3073x_dpll *zldpll =3D dpll_priv; struct zl3073x_dev *zldev =3D zldpll->dev; struct zl3073x_dpll_pin *pin =3D pin_priv; - u8 out; - int rc; + struct zl3073x_out out; + u8 out_id; + + out_id =3D zl3073x_output_pin_out_get(pin->id); + out =3D *zl3073x_out_state_get(zldev, out_id); =20 /* The value in the register is stored as two's complement negation * of requested value and expressed in half synth clock cycles. */ - phase_adjust =3D -phase_adjust / pin->phase_gran; - - guard(mutex)(&zldev->multiop_lock); - - /* Read output configuration */ - out =3D zl3073x_output_pin_out_get(pin->id); - rc =3D zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, - ZL_REG_OUTPUT_MB_MASK, BIT(out)); - if (rc) - return rc; - - /* Write the requested value into the compensation register */ - rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, phase_adjust); - if (rc) - return rc; + out.phase_comp =3D -phase_adjust / pin->phase_gran; =20 /* Update output configuration from mailbox */ - return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, - ZL_REG_OUTPUT_MB_MASK, BIT(out)); + return zl3073x_out_state_set(zldev, out_id, &out); } =20 static int @@ -1680,17 +1482,15 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll= *zldpll, /* Output P&N pair shares single HW output */ u8 out =3D zl3073x_output_pin_out_get(index); =20 - name =3D "OUT"; - /* Skip the pin if it is connected to different DPLL channel */ if (zl3073x_dev_out_dpll_get(zldev, out) !=3D zldpll->id) { dev_dbg(zldev->dev, - "%s%u is driven by different DPLL\n", name, - out); + "OUT%u is driven by different DPLL\n", out); =20 return false; } =20 + name =3D "OUT"; is_diff =3D zl3073x_dev_out_is_diff(zldev, out); is_enabled =3D zl3073x_dev_output_pin_is_enabled(zldev, index); } diff --git a/drivers/dpll/zl3073x/out.c b/drivers/dpll/zl3073x/out.c index a48f6917b39fb..86829a0c1c022 100644 --- a/drivers/dpll/zl3073x/out.c +++ b/drivers/dpll/zl3073x/out.c @@ -50,6 +50,46 @@ int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u= 8 index) dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index, zl3073x_out_signal_format_get(out)); =20 + /* Read output divisor */ + rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &out->div); + if (rc) + return rc; + + if (!out->div) { + dev_err(zldev->dev, "Zero divisor for OUT%u got from device\n", + index); + return -EINVAL; + } + + dev_dbg(zldev->dev, "OUT%u divisor: %u\n", index, out->div); + + /* Read output width */ + rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_WIDTH, &out->width); + if (rc) + return rc; + + rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, + &out->esync_n_period); + if (rc) + return rc; + + if (!out->esync_n_period) { + dev_err(zldev->dev, + "Zero esync divisor for OUT%u got from device\n", + index); + return -EINVAL; + } + + rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, + &out->esync_n_width); + if (rc) + return rc; + + rc =3D zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, + &out->phase_comp); + if (rc) + return rc; + return rc; } =20 @@ -65,3 +105,53 @@ const struct zl3073x_out *zl3073x_out_state_get(struct = zl3073x_dev *zldev, { return &zldev->out[index]; } + +int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, + const struct zl3073x_out *out) +{ + struct zl3073x_out *dout =3D &zldev->out[index]; + int rc; + + guard(mutex)(&zldev->multiop_lock); + + /* Read output configuration into mailbox */ + rc =3D zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, + ZL_REG_OUTPUT_MB_MASK, BIT(index)); + if (rc) + return rc; + + /* Update mailbox with changed values */ + if (dout->div !=3D out->div) + rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, out->div); + if (!rc && dout->width !=3D out->width) + rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, out->width); + if (!rc && dout->esync_n_period !=3D out->esync_n_period) + rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, + out->esync_n_period); + if (!rc && dout->esync_n_width !=3D out->esync_n_width) + rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, + out->esync_n_width); + if (!rc && dout->mode !=3D out->mode) + rc =3D zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, out->mode); + if (!rc && dout->phase_comp !=3D out->phase_comp) + rc =3D zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, + out->phase_comp); + if (rc) + return rc; + + /* Commit output configuration */ + rc =3D zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, + ZL_REG_OUTPUT_MB_MASK, BIT(index)); + if (rc) + return rc; + + /* After successful commit store new state */ + dout->div =3D out->div; + dout->width =3D out->width; + dout->esync_n_period =3D out->esync_n_period; + dout->esync_n_width =3D out->esync_n_width; + dout->mode =3D out->mode; + dout->phase_comp =3D out->phase_comp; + + return 0; +} diff --git a/drivers/dpll/zl3073x/out.h b/drivers/dpll/zl3073x/out.h index 986aa046221da..e8ea7a0e0f071 100644 --- a/drivers/dpll/zl3073x/out.h +++ b/drivers/dpll/zl3073x/out.h @@ -12,10 +12,20 @@ struct zl3073x_dev; =20 /** * struct zl3073x_out - output state + * @div: output divisor + * @width: output pulse width + * @esync_n_period: embedded sync or n-pin period (for n-div formats) + * @esync_n_width: embedded sync or n-pin pulse width + * @phase_comp: phase compensation * @ctrl: output control * @mode: output mode */ struct zl3073x_out { + u32 div; + u32 width; + u32 esync_n_period; + u32 esync_n_width; + s32 phase_comp; u8 ctrl; u8 mode; }; @@ -24,6 +34,9 @@ int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8= index); const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev, u8 index); =20 +int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, + const struct zl3073x_out *out); + /** * zl3073x_out_signal_format_get - get output signal format * @out: pointer to out state --=20 2.51.0