]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
dpll: zl3073x: fix REF_PHASE_OFFSET_COMP register width for some chip IDs
authorIvan Vecera <ivecera@redhat.com>
Fri, 20 Feb 2026 15:57:54 +0000 (16:57 +0100)
committerJakub Kicinski <kuba@kernel.org>
Tue, 24 Feb 2026 01:35:39 +0000 (17:35 -0800)
The REF_PHASE_OFFSET_COMP register is 48-bit wide on most zl3073x chip
variants, but only 32-bit wide on chip IDs 0x0E30, 0x0E93..0x0E97 and
0x1F60. The driver unconditionally uses 48-bit read/write operations,
which on 32-bit variants causes reading 2 bytes past the register
boundary (corrupting the value) and writing 2 bytes into the adjacent
register.

Fix this by storing the chip ID in the device structure during probe
and adding a helper to detect the affected variants. Use the correct
register width for read/write operations and the matching sign extension
bit (31 vs 47) when interpreting the phase compensation value.

Fixes: 6287262f761e ("dpll: zl3073x: Add support to adjust phase")
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260220155755.448185-1-ivecera@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/dpll/zl3073x/core.c
drivers/dpll/zl3073x/core.h
drivers/dpll/zl3073x/dpll.c
drivers/dpll/zl3073x/ref.c
drivers/dpll/zl3073x/regs.h

index 63bd97181b9ee9be1b87166610b8e9b074a2daac..8c5ee28e02f41cb3b2827dc9ec5308f757a94180 100644 (file)
@@ -1026,6 +1026,7 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
                                     "Unknown or non-match chip ID: 0x%0x\n",
                                     id);
        }
+       zldev->chip_id = id;
 
        /* Read revision, firmware version and custom config version */
        rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision);
index dddfcacea5c0a5484739192c963f063f2b008e6f..fd2af3c62a7d5cfce1f25b244a922ceb2d098a38 100644 (file)
@@ -35,6 +35,7 @@ struct zl3073x_dpll;
  * @dev: pointer to device
  * @regmap: regmap to access device registers
  * @multiop_lock: to serialize multiple register operations
+ * @chip_id: chip ID read from hardware
  * @ref: array of input references' invariants
  * @out: array of outs' invariants
  * @synth: array of synths' invariants
@@ -48,6 +49,7 @@ struct zl3073x_dev {
        struct device           *dev;
        struct regmap           *regmap;
        struct mutex            multiop_lock;
+       u16                     chip_id;
 
        /* Invariants */
        struct zl3073x_ref      ref[ZL3073X_NUM_REFS];
@@ -144,6 +146,32 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
 
 int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);
 
+/**
+ * zl3073x_dev_is_ref_phase_comp_32bit - check ref phase comp register size
+ * @zldev: pointer to zl3073x device
+ *
+ * Some chip IDs have a 32-bit wide ref_phase_offset_comp register instead
+ * of the default 48-bit.
+ *
+ * Return: true if the register is 32-bit, false if 48-bit
+ */
+static inline bool
+zl3073x_dev_is_ref_phase_comp_32bit(struct zl3073x_dev *zldev)
+{
+       switch (zldev->chip_id) {
+       case 0x0E30:
+       case 0x0E93:
+       case 0x0E94:
+       case 0x0E95:
+       case 0x0E96:
+       case 0x0E97:
+       case 0x1F60:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static inline bool
 zl3073x_is_n_pin(u8 id)
 {
index 78edc36b17fbb83afa9d4856dfff8a01359a7d3c..8ffbede117c6fec1a9351d91cbad299808980f4d 100644 (file)
@@ -475,8 +475,11 @@ zl3073x_dpll_input_pin_phase_adjust_get(const struct dpll_pin *dpll_pin,
        ref_id = zl3073x_input_pin_ref_get(pin->id);
        ref = zl3073x_ref_state_get(zldev, ref_id);
 
-       /* Perform sign extension for 48bit signed value */
-       phase_comp = sign_extend64(ref->phase_comp, 47);
+       /* Perform sign extension based on register width */
+       if (zl3073x_dev_is_ref_phase_comp_32bit(zldev))
+               phase_comp = sign_extend64(ref->phase_comp, 31);
+       else
+               phase_comp = sign_extend64(ref->phase_comp, 47);
 
        /* Reverse two's complement negation applied during set and convert
         * to 32bit signed int
index aa2de13effa878c8291bf581d01ce326b0dc2849..6b65e61039999b52cf2e8690614f950ab30e9684 100644 (file)
@@ -121,8 +121,16 @@ int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
                return rc;
 
        /* Read phase compensation register */
-       rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
-                             &ref->phase_comp);
+       if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) {
+               u32 val;
+
+               rc = zl3073x_read_u32(zldev, ZL_REG_REF_PHASE_OFFSET_COMP_32,
+                                     &val);
+               ref->phase_comp = val;
+       } else {
+               rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
+                                     &ref->phase_comp);
+       }
        if (rc)
                return rc;
 
@@ -179,9 +187,16 @@ int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index,
        if (!rc && dref->sync_ctrl != ref->sync_ctrl)
                rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL,
                                      ref->sync_ctrl);
-       if (!rc && dref->phase_comp != ref->phase_comp)
-               rc = zl3073x_write_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
-                                      ref->phase_comp);
+       if (!rc && dref->phase_comp != ref->phase_comp) {
+               if (zl3073x_dev_is_ref_phase_comp_32bit(zldev))
+                       rc = zl3073x_write_u32(zldev,
+                                              ZL_REG_REF_PHASE_OFFSET_COMP_32,
+                                              ref->phase_comp);
+               else
+                       rc = zl3073x_write_u48(zldev,
+                                              ZL_REG_REF_PHASE_OFFSET_COMP,
+                                              ref->phase_comp);
+       }
        if (rc)
                return rc;
 
index d837bee72b17806ddbdbcb85c4edcfb70d2fcb6f..5573d7188406bb7cf8f041aabb4f309bd96111c4 100644 (file)
 #define ZL_REF_CONFIG_DIFF_EN                  BIT(2)
 
 #define ZL_REG_REF_PHASE_OFFSET_COMP           ZL_REG(10, 0x28, 6)
+#define ZL_REG_REF_PHASE_OFFSET_COMP_32        ZL_REG(10, 0x28, 4)
 
 #define ZL_REG_REF_SYNC_CTRL                   ZL_REG(10, 0x2e, 1)
 #define ZL_REF_SYNC_CTRL_MODE                  GENMASK(2, 0)