mpm: x440: add fabric resampling to clock policy

Adjusting the MPM code to enable the correct generation of data_clk and
data_clk_2x based on the fabric resampler rate. Further increasing the
rfdc_clocks to match the desired higher sampling rates of the RFDC.
This commit is contained in:
Max Köhler 2026-06-02 00:56:38 +02:00 committed by Martin Braun
parent 94dd1084f8
commit 4bf834a9a8

View File

@ -464,7 +464,7 @@ class X440ClockPolicy(X4xxClockPolicy):
def _read_converter_rates(self):
"""Gets the converter rate.
Gets the converter rate from the argument string, if it is given there,
Gets the converter rate from the argument string, if it is given there,
None otherwise.
"""
self.conv_rates = self.args.get("converter_rate")
@ -545,14 +545,14 @@ class X440ClockPolicy(X4xxClockPolicy):
# Calculate desired converter rate: If a converter rate was passed, check if
# we can decimate from converter rate to master clock rate and if this converter rate
# is within the valid range. If this is impossible, pick the converter rate automatically.
div = desired_conv_rate / desired_mcr
coerced_mcr = desired_mcr
coerced_mcr = desired_mcr * self._extra_resampling
div = desired_conv_rate / coerced_mcr
if (
div not in X4xxRfdcCtrl.RFDC_RESAMPLER
or not X4xxRfdcCtrl.CONV_RATE_MIN <= desired_conv_rate <= X4xxRfdcCtrl.CONV_RATE_MAX
or desired_mcr not in MCR_LMK_VCO
or coerced_mcr not in MCR_LMK_VCO
):
coerced_mcr = min(sorted(MCR_LMK_VCO), key=lambda x: abs(x - desired_mcr))
coerced_mcr = min(sorted(MCR_LMK_VCO), key=lambda x: abs(x - coerced_mcr))
for div in sorted(X4xxRfdcCtrl.RFDC_RESAMPLER, reverse=True):
if coerced_mcr * div <= X4xxRfdcCtrl.CONV_RATE_MAX:
break
@ -682,6 +682,14 @@ class X440ClockPolicy(X4xxClockPolicy):
if len(master_clock_rates) < self.get_num_rates():
master_clock_rates = [master_clock_rates[0]] * self.get_num_rates()
# In case resamplers are present there is only 1 MCR allowed
if len(master_clock_rates) > 1 and self._extra_resampling > 1:
if master_clock_rates[0] != master_clock_rates[1]:
raise ValueError(
"X440 with resamplers only supports identical "
"master clock rates on both DBs."
)
# Check if MCR meets BW
for mcr in master_clock_rates:
if not self._get_min_mcr() <= mcr <= self._get_max_mcr():
@ -695,6 +703,8 @@ class X440ClockPolicy(X4xxClockPolicy):
conv_rates = []
for idx, mcr in enumerate(master_clock_rates):
conv_rate = 0 if self.conv_rates is None else self.conv_rates[idx]
# If extra_resampling is >1, then from this place on, mcr will be
# the MCR multiplied by the extra resampling factor in the PL.
mcr, cvr = self._match_mcrs(mcr, conv_rate)
mcrs.append(mcr)
conv_rates.append(cvr)
@ -707,7 +717,7 @@ class X440ClockPolicy(X4xxClockPolicy):
conv_rates[1] = conv_rates[0]
# With these values check if we can do this in MMCM
rfdc_rate = list(map(lambda x: int(x / (self._spc * self._extra_resampling)), mcrs))
rfdc_rate = [int(x / self._spc) for x in mcrs]
min_mmcm_vco_rate = lcm(rfdc_rate[0], rfdc_rate[1])
# Inform user if we don't have an exact match
if min_mmcm_vco_rate > X4xxRfdcCtrl.MMCM_VCO_MAX:
@ -715,10 +725,11 @@ class X440ClockPolicy(X4xxClockPolicy):
# Ensure we're falling back to converter rate 0, too
conv_rates[1] = conv_rates[0]
if mcrs != master_clock_rates:
if mcrs != [mcr * self._extra_resampling for mcr in master_clock_rates]:
self.log.warning(
f"Unable to use desired master clock rate(s), using "
f"{mcrs[0]/1e6} MHz for DB0 and {mcrs[1]/1e6} MHz for DB1."
f"{mcrs[0]/self._extra_resampling/1e6} MHz for DB0 and "
f"{mcrs[1]/self._extra_resampling/1e6} MHz for DB1."
)
if self.conv_rates is not None and self.conv_rates != conv_rates:
self.log.warning(
@ -726,16 +737,18 @@ class X440ClockPolicy(X4xxClockPolicy):
f"{conv_rates[0]/1e6} MSps for DB0 "
f"and {conv_rates[1]/1e6} MSps for DB1. Converter rate needs "
f"to be a {X4xxRfdcCtrl.RFDC_RESAMPLER} multiple of the master "
f"clock rates {mcrs[0]/1e6} MHz and {mcrs[1]/1e6} MHz "
f"clock rates {mcrs[0]/self._extra_resampling/1e6} MHz and "
f"{mcrs[1]/self._extra_resampling/1e6} MHz multiplied by the "
f"extra resampling factor {self._extra_resampling}, "
f"but additional clock constraints may limit this."
)
self.conv_rates = conv_rates
return mcrs
return [mcr / self._extra_resampling for mcr in mcrs]
def get_config(self, ref_clock_freq, master_clock_rates):
"""Returns a valid configuration based on the master clock rate.
It uses the configuration where the RFDC_CLOCK/SPC is the closest to the MCR
It uses the configuration where the RFDC_CLOCK/SPC is the closest to the MCR.
This method is called after coerce_mcr() has run and - if necessary -
rounded the MCR values, so will skip the checks here to save some time.
"""
@ -747,6 +760,8 @@ class X440ClockPolicy(X4xxClockPolicy):
conv_rates = []
for idx, mcr in enumerate(master_clock_rates):
conv_rate = 0 if self.conv_rates is None else self.conv_rates[idx]
# If extra_resampling is >1, then from this place on, mcr will be
# the MCR multiplied by the extra resampling factor in the PL.
mcr, cvr = self._match_mcrs(mcr, conv_rate)
mcrs.append(mcr)
conv_rates.append(cvr)
@ -790,7 +805,7 @@ class X440ClockPolicy(X4xxClockPolicy):
conv_rate % sysref_config["SYSREF_FREQ"] == 0.0 for conv_rate in conv_rates
), "Converter Rate is not a multiple of the SysRef freq"
rfdc_rate = list(map(lambda x: int(x / (self._spc * self._extra_resampling)), mcrs))
rfdc_rate = list(map(lambda x: int(x / self._spc), mcrs))
mmcm_input, mmcm_vco_rate = self._get_mmcm_rates(
rfdc_rate, lmk_vco, sysref_config["SYSREF_FREQ"]
)
@ -799,7 +814,8 @@ class X440ClockPolicy(X4xxClockPolicy):
if not mmcm_input or mmcm_input > lmk_vco:
error_msg = (
f"Unable to find a valid MMCM configuration for Master Clock Rate(s) "
f"{mcrs[0]/1e6} MHz and {mcrs[1]/1e6} MHz. Please choose different "
f"{mcrs[0]/self._extra_resampling/1e6} MHz and "
f"{mcrs[1]/self._extra_resampling/1e6} MHz. Please choose different "
f"Master Clock Rate(s)."
)
self.log.error(error_msg)
@ -857,6 +873,8 @@ class X440ClockPolicy(X4xxClockPolicy):
"r0_clk_2x": r0_clk2x,
"r1_clk_2x": r1_clk2x,
"prc": prc_out_div,
"data_clk": r0_clk * self._extra_resampling,
"data_clk_2x": r0_clk2x * self._extra_resampling,
},
"rfdc_configs": [RfdcConfig(**rfdc_cfg0), RfdcConfig(**rfdc_cfg1)],
"spll_config": SpllConfig(**spll_cfg),