Skip to content

Commit f03b646

Browse files
committed
dpll: zl3073x: Add support to adjust phase
JIRA: https://issues.redhat.com/browse/RHEL-105063 commit 6287262 Author: Ivan Vecera <ivecera@redhat.com> Date: Tue Jul 15 16:46:32 2025 +0200 dpll: zl3073x: Add support to adjust phase Add support to get/set phase adjustment for both input and output pins. The phase adjustment is implemented using reference and output phase offset compensation registers. For input pins the adjustment value can be arbitrary number but for outputs the value has to be a multiple of half synthesizer clock cycles. Reviewed-by: Jiri Pirko <jiri@nvidia.com> Tested-by: Prathosh Satish <prathosh.satish@microchip.com> Co-developed-by: Prathosh Satish <Prathosh.Satish@microchip.com> Signed-off-by: Prathosh Satish <Prathosh.Satish@microchip.com> Signed-off-by: Ivan Vecera <ivecera@redhat.com> Link: https://patch.msgid.link/20250715144633.149156-5-ivecera@redhat.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
1 parent f6d576f commit f03b646

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed

drivers/dpll/zl3073x/dpll.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,85 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin,
574574
return rc;
575575
}
576576

577+
static int
578+
zl3073x_dpll_input_pin_phase_adjust_get(const struct dpll_pin *dpll_pin,
579+
void *pin_priv,
580+
const struct dpll_device *dpll,
581+
void *dpll_priv,
582+
s32 *phase_adjust,
583+
struct netlink_ext_ack *extack)
584+
{
585+
struct zl3073x_dpll *zldpll = dpll_priv;
586+
struct zl3073x_dev *zldev = zldpll->dev;
587+
struct zl3073x_dpll_pin *pin = pin_priv;
588+
s64 phase_comp;
589+
u8 ref;
590+
int rc;
591+
592+
guard(mutex)(&zldev->multiop_lock);
593+
594+
/* Read reference configuration */
595+
ref = zl3073x_input_pin_ref_get(pin->id);
596+
rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
597+
ZL_REG_REF_MB_MASK, BIT(ref));
598+
if (rc)
599+
return rc;
600+
601+
/* Read current phase offset compensation */
602+
rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, &phase_comp);
603+
if (rc)
604+
return rc;
605+
606+
/* Perform sign extension for 48bit signed value */
607+
phase_comp = sign_extend64(phase_comp, 47);
608+
609+
/* Reverse two's complement negation applied during set and convert
610+
* to 32bit signed int
611+
*/
612+
*phase_adjust = (s32)-phase_comp;
613+
614+
return rc;
615+
}
616+
617+
static int
618+
zl3073x_dpll_input_pin_phase_adjust_set(const struct dpll_pin *dpll_pin,
619+
void *pin_priv,
620+
const struct dpll_device *dpll,
621+
void *dpll_priv,
622+
s32 phase_adjust,
623+
struct netlink_ext_ack *extack)
624+
{
625+
struct zl3073x_dpll *zldpll = dpll_priv;
626+
struct zl3073x_dev *zldev = zldpll->dev;
627+
struct zl3073x_dpll_pin *pin = pin_priv;
628+
s64 phase_comp;
629+
u8 ref;
630+
int rc;
631+
632+
/* The value in the register is stored as two's complement negation
633+
* of requested value.
634+
*/
635+
phase_comp = -phase_adjust;
636+
637+
guard(mutex)(&zldev->multiop_lock);
638+
639+
/* Read reference configuration */
640+
ref = zl3073x_input_pin_ref_get(pin->id);
641+
rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
642+
ZL_REG_REF_MB_MASK, BIT(ref));
643+
if (rc)
644+
return rc;
645+
646+
/* Write the requested value into the compensation register */
647+
rc = zl3073x_write_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, phase_comp);
648+
if (rc)
649+
return rc;
650+
651+
/* Commit reference configuration */
652+
return zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR,
653+
ZL_REG_REF_MB_MASK, BIT(ref));
654+
}
655+
577656
/**
578657
* zl3073x_dpll_ref_prio_get - get priority for given input pin
579658
* @pin: pointer to pin
@@ -1284,6 +1363,114 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin,
12841363
ZL_REG_OUTPUT_MB_MASK, BIT(out));
12851364
}
12861365

1366+
static int
1367+
zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin,
1368+
void *pin_priv,
1369+
const struct dpll_device *dpll,
1370+
void *dpll_priv,
1371+
s32 *phase_adjust,
1372+
struct netlink_ext_ack *extack)
1373+
{
1374+
struct zl3073x_dpll *zldpll = dpll_priv;
1375+
struct zl3073x_dev *zldev = zldpll->dev;
1376+
struct zl3073x_dpll_pin *pin = pin_priv;
1377+
u32 synth_freq;
1378+
s32 phase_comp;
1379+
u8 out, synth;
1380+
int rc;
1381+
1382+
out = zl3073x_output_pin_out_get(pin->id);
1383+
synth = zl3073x_out_synth_get(zldev, out);
1384+
synth_freq = zl3073x_synth_freq_get(zldev, synth);
1385+
1386+
/* Check synth freq for zero */
1387+
if (!synth_freq) {
1388+
dev_err(zldev->dev, "Got zero synth frequency for output %u\n",
1389+
out);
1390+
return -EINVAL;
1391+
}
1392+
1393+
guard(mutex)(&zldev->multiop_lock);
1394+
1395+
/* Read output configuration */
1396+
rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
1397+
ZL_REG_OUTPUT_MB_MASK, BIT(out));
1398+
if (rc)
1399+
return rc;
1400+
1401+
/* Read current output phase compensation */
1402+
rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, &phase_comp);
1403+
if (rc)
1404+
return rc;
1405+
1406+
/* Value in register is expressed in half synth clock cycles */
1407+
phase_comp *= (int)div_u64(PSEC_PER_SEC, 2 * synth_freq);
1408+
1409+
/* Reverse two's complement negation applied during 'set' */
1410+
*phase_adjust = -phase_comp;
1411+
1412+
return rc;
1413+
}
1414+
1415+
static int
1416+
zl3073x_dpll_output_pin_phase_adjust_set(const struct dpll_pin *dpll_pin,
1417+
void *pin_priv,
1418+
const struct dpll_device *dpll,
1419+
void *dpll_priv,
1420+
s32 phase_adjust,
1421+
struct netlink_ext_ack *extack)
1422+
{
1423+
struct zl3073x_dpll *zldpll = dpll_priv;
1424+
struct zl3073x_dev *zldev = zldpll->dev;
1425+
struct zl3073x_dpll_pin *pin = pin_priv;
1426+
int half_synth_cycle;
1427+
u32 synth_freq;
1428+
u8 out, synth;
1429+
int rc;
1430+
1431+
/* Get attached synth */
1432+
out = zl3073x_output_pin_out_get(pin->id);
1433+
synth = zl3073x_out_synth_get(zldev, out);
1434+
1435+
/* Get synth's frequency */
1436+
synth_freq = zl3073x_synth_freq_get(zldev, synth);
1437+
1438+
/* Value in register is expressed in half synth clock cycles so
1439+
* the given phase adjustment a multiple of half synth clock.
1440+
*/
1441+
half_synth_cycle = (int)div_u64(PSEC_PER_SEC, 2 * synth_freq);
1442+
1443+
if ((phase_adjust % half_synth_cycle) != 0) {
1444+
NL_SET_ERR_MSG_FMT(extack,
1445+
"Phase adjustment value has to be multiple of %d",
1446+
half_synth_cycle);
1447+
return -EINVAL;
1448+
}
1449+
phase_adjust /= half_synth_cycle;
1450+
1451+
/* The value in the register is stored as two's complement negation
1452+
* of requested value.
1453+
*/
1454+
phase_adjust = -phase_adjust;
1455+
1456+
guard(mutex)(&zldev->multiop_lock);
1457+
1458+
/* Read output configuration */
1459+
rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
1460+
ZL_REG_OUTPUT_MB_MASK, BIT(out));
1461+
if (rc)
1462+
return rc;
1463+
1464+
/* Write the requested value into the compensation register */
1465+
rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, phase_adjust);
1466+
if (rc)
1467+
return rc;
1468+
1469+
/* Update output configuration from mailbox */
1470+
return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR,
1471+
ZL_REG_OUTPUT_MB_MASK, BIT(out));
1472+
}
1473+
12871474
static int
12881475
zl3073x_dpll_output_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin,
12891476
void *pin_priv,
@@ -1411,6 +1598,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
14111598
.frequency_get = zl3073x_dpll_input_pin_frequency_get,
14121599
.frequency_set = zl3073x_dpll_input_pin_frequency_set,
14131600
.phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get,
1601+
.phase_adjust_get = zl3073x_dpll_input_pin_phase_adjust_get,
1602+
.phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set,
14141603
.prio_get = zl3073x_dpll_input_pin_prio_get,
14151604
.prio_set = zl3073x_dpll_input_pin_prio_set,
14161605
.state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get,
@@ -1423,6 +1612,8 @@ static const struct dpll_pin_ops zl3073x_dpll_output_pin_ops = {
14231612
.esync_set = zl3073x_dpll_output_pin_esync_set,
14241613
.frequency_get = zl3073x_dpll_output_pin_frequency_get,
14251614
.frequency_set = zl3073x_dpll_output_pin_frequency_set,
1615+
.phase_adjust_get = zl3073x_dpll_output_pin_phase_adjust_get,
1616+
.phase_adjust_set = zl3073x_dpll_output_pin_phase_adjust_set,
14261617
.state_on_dpll_get = zl3073x_dpll_output_pin_state_on_dpll_get,
14271618
};
14281619

drivers/dpll/zl3073x/regs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@
168168
#define ZL_REF_CONFIG_ENABLE BIT(0)
169169
#define ZL_REF_CONFIG_DIFF_EN BIT(2)
170170

171+
#define ZL_REG_REF_PHASE_OFFSET_COMP ZL_REG(10, 0x28, 6)
172+
171173
#define ZL_REG_REF_SYNC_CTRL ZL_REG(10, 0x2e, 1)
172174
#define ZL_REF_SYNC_CTRL_MODE GENMASK(2, 0)
173175
#define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF 0
@@ -237,5 +239,6 @@
237239
#define ZL_REG_OUTPUT_WIDTH ZL_REG(14, 0x10, 4)
238240
#define ZL_REG_OUTPUT_ESYNC_PERIOD ZL_REG(14, 0x14, 4)
239241
#define ZL_REG_OUTPUT_ESYNC_WIDTH ZL_REG(14, 0x18, 4)
242+
#define ZL_REG_OUTPUT_PHASE_COMP ZL_REG(14, 0x20, 4)
240243

241244
#endif /* _ZL3073X_REGS_H */

0 commit comments

Comments
 (0)