lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <d5285a54-2ffc-413f-8371-431a6d8d8b32@microchip.com>
Date: Mon, 14 Jul 2025 14:13:58 +0000
From: <Prathosh.Satish@...rochip.com>
To: <ivecera@...hat.com>, <netdev@...r.kernel.org>
CC: <arkadiusz.kubalewski@...el.com>, <jiri@...nulli.us>,
	<davem@...emloft.net>, <kuba@...nel.org>, <pabeni@...hat.com>,
	<linux-kernel@...r.kernel.org>, <mschmidt@...hat.com>, <poros@...hat.com>
Subject: Re: [PATCH net-next 1/5] dpll: zl3073x: Add support to get/set esync
 on pins

On 10/07/2025 16:38, Ivan Vecera wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> Add support to get/set embedded sync for both input and output pins.
> The DPLL is able to lock on input reference when the embedded sync
> frequency is 1 PPS and pulse width 25%. The esync on outputs are more
> versatille and theoretically supports any esync frequency that divides
> current output frequency but for now support the same that supported on
> input pins (1 PPS & 25% pulse).
>
> Note that for the output pins the esync divisor shares the same register
> used for N-divided signal formats. Due to this the esync cannot be
> enabled on outputs configured with one of the N-divided signal formats.
>
> Co-developed-by: Prathosh Satish <Prathosh.Satish@...rochip.com>
> Signed-off-by: Prathosh Satish <Prathosh.Satish@...rochip.com>
> Signed-off-by: Ivan Vecera <ivecera@...hat.com>
> ---
>   drivers/dpll/zl3073x/dpll.c | 343 +++++++++++++++++++++++++++++++++++-
>   drivers/dpll/zl3073x/regs.h |  11 ++
>   2 files changed, 353 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
> index cb0f1a43c5fbd..2af20532b1ca0 100644
> --- a/drivers/dpll/zl3073x/dpll.c
> +++ b/drivers/dpll/zl3073x/dpll.c
> @@ -34,6 +34,7 @@
>    * @id: pin id
>    * @prio: pin priority <0, 14>
>    * @selectable: pin is selectable in automatic mode
> + * @esync_control: embedded sync is controllable
>    * @pin_state: last saved pin state
>    */
>   struct zl3073x_dpll_pin {
> @@ -45,9 +46,17 @@ struct zl3073x_dpll_pin {
>          u8                      id;
>          u8                      prio;
>          bool                    selectable;
> +       bool                    esync_control;
>          enum dpll_pin_state     pin_state;
>   };
>
> +/*
> + * Supported esync ranges for input and for output per output pair type
> + */
> +static const struct dpll_pin_frequency esync_freq_ranges[] = {
> +       DPLL_PIN_FREQUENCY_RANGE(0, 1),
> +};
> +
>   /**
>    * zl3073x_dpll_is_input_pin - check if the pin is input one
>    * @pin: pin to check
> @@ -139,6 +148,126 @@ zl3073x_dpll_input_ref_frequency_get(struct zl3073x_dpll *zldpll, u8 ref_id,
>          return rc;
>   }
>
> +static int
> +zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
> +                                void *pin_priv,
> +                                const struct dpll_device *dpll,
> +                                void *dpll_priv,
> +                                struct dpll_pin_esync *esync,
> +                                struct netlink_ext_ack *extack)
> +{
> +       struct zl3073x_dpll *zldpll = dpll_priv;
> +       struct zl3073x_dev *zldev = zldpll->dev;
> +       struct zl3073x_dpll_pin *pin = pin_priv;
> +       u8 ref, ref_sync_ctrl, sync_mode;
> +       u32 esync_div, ref_freq;
> +       int rc;
> +
> +       /* Get reference frequency */
> +       ref = zl3073x_input_pin_ref_get(pin->id);
> +       rc = zl3073x_dpll_input_ref_frequency_get(zldpll, pin->id, &ref_freq);
> +       if (rc)
> +               return rc;
> +
> +       guard(mutex)(&zldev->multiop_lock);
> +
> +       /* Read reference configuration into mailbox */
> +       rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
> +                          ZL_REG_REF_MB_MASK, BIT(ref));
> +       if (rc)
> +               return rc;
> +
> +       /* Get ref sync mode */
> +       rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref_sync_ctrl);
> +       if (rc)
> +               return rc;
> +
> +       /* Get esync divisor */
> +       rc = zl3073x_read_u32(zldev, ZL_REG_REF_ESYNC_DIV, &esync_div);
> +       if (rc)
> +               return rc;
> +
> +       sync_mode = FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref_sync_ctrl);
> +
> +       switch (sync_mode) {
> +       case ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75:
> +               esync->freq = (esync_div == ZL_REF_ESYNC_DIV_1HZ) ? 1 : 0;
> +               esync->pulse = 25;
> +               break;
> +       default:
> +               esync->freq = 0;
> +               esync->pulse = 0;
> +               break;
> +       }
> +
> +       /* If the pin supports esync control expose its range but only
> +        * if the current reference frequency is > 1 Hz.
> +        */
> +       if (pin->esync_control && ref_freq > 1) {
> +               esync->range = esync_freq_ranges;
> +               esync->range_num = ARRAY_SIZE(esync_freq_ranges);
> +       } else {
> +               esync->range = NULL;
> +               esync->range_num = 0;
> +       }
> +
> +       return rc;
> +}
> +
> +static int
> +zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
> +                                void *pin_priv,
> +                                const struct dpll_device *dpll,
> +                                void *dpll_priv, u64 freq,
> +                                struct netlink_ext_ack *extack)
> +{
> +       struct zl3073x_dpll *zldpll = dpll_priv;
> +       struct zl3073x_dev *zldev = zldpll->dev;
> +       struct zl3073x_dpll_pin *pin = pin_priv;
> +       u8 ref, ref_sync_ctrl, sync_mode;
> +       int rc;
> +
> +       guard(mutex)(&zldev->multiop_lock);
> +
> +       /* Read reference configuration into mailbox */
> +       ref = zl3073x_input_pin_ref_get(pin->id);
> +       rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
> +                          ZL_REG_REF_MB_MASK, BIT(ref));
> +       if (rc)
> +               return rc;
> +
> +       /* Get ref sync mode */
> +       rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref_sync_ctrl);
> +       if (rc)
> +               return rc;
> +
> +       /* Use freq == 0 to disable esync */
> +       if (!freq)
> +               sync_mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF;
> +       else
> +               sync_mode = ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75;
> +
> +       ref_sync_ctrl &= ~ZL_REF_SYNC_CTRL_MODE;
> +       ref_sync_ctrl |= FIELD_PREP(ZL_REF_SYNC_CTRL_MODE, sync_mode);
> +
> +       /* Update ref sync control register */
> +       rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL, ref_sync_ctrl);
> +       if (rc)
> +               return rc;
> +
> +       if (freq) {
> +               /* 1 Hz is only supported frequnecy currently */
> +               rc = zl3073x_write_u32(zldev, ZL_REG_REF_ESYNC_DIV,
> +                                      ZL_REF_ESYNC_DIV_1HZ);
> +               if (rc)
> +                       return rc;
> +       }
> +
> +       /* Commit reference configuration */
> +       return zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR,
> +                            ZL_REG_REF_MB_MASK, BIT(ref));
> +}
> +
>   static int
>   zl3073x_dpll_input_pin_frequency_get(const struct dpll_pin *dpll_pin,
>                                       void *pin_priv,
> @@ -640,6 +769,213 @@ zl3073x_dpll_input_pin_prio_set(const struct dpll_pin *dpll_pin, void *pin_priv,
>          return 0;
>   }
>
> +static int
> +zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
> +                                 void *pin_priv,
> +                                 const struct dpll_device *dpll,
> +                                 void *dpll_priv,
> +                                 struct dpll_pin_esync *esync,
> +                                 struct netlink_ext_ack *extack)
> +{
> +       struct zl3073x_dpll *zldpll = dpll_priv;
> +       struct zl3073x_dev *zldev = zldpll->dev;
> +       struct zl3073x_dpll_pin *pin = pin_priv;
> +       struct device *dev = zldev->dev;
> +       u32 esync_period, esync_width;
> +       u8 clock_type, synth;
> +       u8 out, output_mode;
> +       u32 output_div;
> +       u32 synth_freq;
> +       int rc;
> +
> +       out = zl3073x_output_pin_out_get(pin->id);
> +
> +       /* 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_out_signal_format_get(zldev, out)) {
> +       case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
> +       case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
> +               return -EOPNOTSUPP;
> +       default:
> +               break;
> +       }
> +
> +       guard(mutex)(&zldev->multiop_lock);
> +
> +       /* Read output configuration into mailbox */
> +       rc = 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 = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode);
> +       if (rc)
> +               return rc;
> +
> +       /* Read output divisor */
> +       rc = 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 = zl3073x_out_synth_get(zldev, out);
> +
> +       /* Get synth frequency */
> +       synth_freq = zl3073x_synth_freq_get(zldev, synth);
> +
> +       clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, output_mode);
> +       if (clock_type != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) {
> +               /* No need to read esync data if it is not enabled */
> +               esync->freq = 0;
> +               esync->pulse = 0;
> +
> +               goto finish;
> +       }
> +
> +       /* Read esync period */
> +       rc = 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 = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, &esync_width);
> +       if (rc)
> +               return rc;
> +
> +       /* Compute esync frequency */
> +       esync->freq = synth_freq / output_div / esync_period;
> +
> +       /* 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 = (50 * esync_width) / output_div;
> +
> +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) {
> +               esync->range = esync_freq_ranges;
> +               esync->range_num = ARRAY_SIZE(esync_freq_ranges);
> +       } else {
> +               esync->range = NULL;
> +               esync->range_num = 0;
> +       }
> +
> +       return 0;
> +}
> +
> +static int
> +zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
> +                                 void *pin_priv,
> +                                 const struct dpll_device *dpll,
> +                                 void *dpll_priv, u64 freq,
> +                                 struct netlink_ext_ack *extack)
> +{
> +       struct zl3073x_dpll *zldpll = dpll_priv;
> +       struct zl3073x_dev *zldev = zldpll->dev;
> +       struct zl3073x_dpll_pin *pin = pin_priv;
> +       u32 esync_period, esync_width, output_div;
> +       u8 clock_type, out, output_mode, synth;
> +       u32 synth_freq;
> +       int rc;
> +
> +       out = zl3073x_output_pin_out_get(pin->id);
> +
> +       /* 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_out_signal_format_get(zldev, out)) {
> +       case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
> +       case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
> +               return -EOPNOTSUPP;
> +       default:
> +               break;
> +       }
> +
> +       guard(mutex)(&zldev->multiop_lock);
> +
> +       /* Read output configuration into mailbox */
> +       rc = 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 = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode);
> +       if (rc)
> +               return rc;
> +
> +       /* Select clock type */
> +       if (freq)
> +               clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC;
> +       else
> +               clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL;
> +
> +       /* Update clock type in output mode */
> +       output_mode &= ~ZL_OUTPUT_MODE_CLOCK_TYPE;
> +       output_mode |= FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type);
> +       rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, output_mode);
> +       if (rc)
> +               return rc;
> +
> +       /* If esync is being disabled just write mailbox and finish */
> +       if (!freq)
> +               goto write_mailbox;
> +
> +       /* Get synth attached to output pin */
> +       synth = zl3073x_out_synth_get(zldev, out);
> +
> +       /* Get synth frequency */
> +       synth_freq = zl3073x_synth_freq_get(zldev, synth);
> +
> +       rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div);
> +       if (rc)
> +               return rc;
> +
> +       /* Compute and update esync period */
> +       esync_period = synth_freq / (u32)freq / output_div;
> +       rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, esync_period);
> +       if (rc)
> +               return rc;
> +
> +       /* 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
> +        * period the output_div can just be divided by 2. Note that this
> +        * assumes that output_div is even, otherwise some resolution will be
> +        * lost.
> +        */
> +       esync_width = output_div / 2;
> +       rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, esync_width);
> +       if (rc)
> +               return rc;
> +
> +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));
> +}
> +
>   static int
>   zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin,
>                                        void *pin_priv,
> @@ -956,6 +1292,8 @@ zl3073x_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv,
>
>   static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
>          .direction_get = zl3073x_dpll_pin_direction_get,
> +       .esync_get = zl3073x_dpll_input_pin_esync_get,
> +       .esync_set = zl3073x_dpll_input_pin_esync_set,
>          .frequency_get = zl3073x_dpll_input_pin_frequency_get,
>          .frequency_set = zl3073x_dpll_input_pin_frequency_set,
>          .prio_get = zl3073x_dpll_input_pin_prio_get,
> @@ -966,6 +1304,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
>
>   static const struct dpll_pin_ops zl3073x_dpll_output_pin_ops = {
>          .direction_get = zl3073x_dpll_pin_direction_get,
> +       .esync_get = zl3073x_dpll_output_pin_esync_get,
> +       .esync_set = zl3073x_dpll_output_pin_esync_set,
>          .frequency_get = zl3073x_dpll_output_pin_frequency_get,
>          .frequency_set = zl3073x_dpll_output_pin_frequency_set,
>          .state_on_dpll_get = zl3073x_dpll_output_pin_state_on_dpll_get,
> @@ -1040,8 +1380,9 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
>          if (IS_ERR(props))
>                  return PTR_ERR(props);
>
> -       /* Save package label */
> +       /* Save package label & esync capability */
>          strscpy(pin->label, props->package_label);
> +       pin->esync_control = props->esync_control;
>
>          if (zl3073x_dpll_is_input_pin(pin)) {
>                  rc = zl3073x_dpll_ref_prio_get(pin, &pin->prio);
> diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h
> index 493c63e729208..64bb43bbc3168 100644
> --- a/drivers/dpll/zl3073x/regs.h
> +++ b/drivers/dpll/zl3073x/regs.h
> @@ -146,6 +146,14 @@
>   #define ZL_REF_CONFIG_ENABLE                   BIT(0)
>   #define ZL_REF_CONFIG_DIFF_EN                  BIT(2)
>
> +#define ZL_REG_REF_SYNC_CTRL                   ZL_REG(10, 0x2e, 1)
> +#define ZL_REF_SYNC_CTRL_MODE                  GENMASK(2, 0)
> +#define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF 0
> +#define ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75        2
> +
> +#define ZL_REG_REF_ESYNC_DIV                   ZL_REG(10, 0x30, 4)
> +#define ZL_REF_ESYNC_DIV_1HZ                   0
> +
>   /********************************
>    * Register Page 12, DPLL Mailbox
>    ********************************/
> @@ -188,6 +196,9 @@
>   #define ZL_OUTPUT_MB_SEM_RD                    BIT(1)
>
>   #define ZL_REG_OUTPUT_MODE                     ZL_REG(14, 0x05, 1)
> +#define ZL_OUTPUT_MODE_CLOCK_TYPE              GENMASK(2, 0)
> +#define ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL       0
> +#define ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC                1
>   #define ZL_OUTPUT_MODE_SIGNAL_FORMAT           GENMASK(7, 4)
>   #define ZL_OUTPUT_MODE_SIGNAL_FORMAT_DISABLED  0
>   #define ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS      1
> --
> 2.49.0
>
Tested-by: Prathosh Satish <prathosh.satish@...rochip.com>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ