Skip to content

Commit

Permalink
Fix several user clock configuration bugs:
Browse files Browse the repository at this point in the history
- Agilex slow clock was limited to 600MHz instead of 800MHz because the
  wrong parameters were tested.
- Write a new setting even if the clock is not locked. This makes it possible
  to recover from a previous failure.
- Extreme frequency changes sometimes result in configuration failures.
  Program an intermediate frequency before setting the actual target.
  • Loading branch information
michael-adler committed Aug 25, 2023
1 parent 02584b6 commit f96c46f
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 7 deletions.
3 changes: 2 additions & 1 deletion binaries/userclk/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,14 @@ int main(int argc, char *argv[])
ON_ERR_GOTO(result, out_destroy_prop, "opening accelerator");

res = fpgaGetUserClock(accelerator_handle, &userclk_high, &userclk_low, 0);
ON_ERR_GOTO(res, out_close, "Failed to get user clock");
ON_ERR_GOTO(res, cur_clock_invalid, "Failed to get user clock");

printf("\nApproximate frequency:\n"
"High clock = %5.1f MHz\n"
"Low clock = %5.1f MHz\n \n",
userclk_high / 1.0e6, userclk_low / 1.0e6);

cur_clock_invalid:
if (userclkCmdLine.freq_high <= -1 && userclkCmdLine.freq_low <= -1) {
goto out_close;
}
Expand Down
28 changes: 22 additions & 6 deletions libraries/plugins/xfpga/usrclk/fpga_user_clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,10 @@ fpga_result set_userclock(const char *sysfs_path,
ssize_t bytes_written = 0;
struct opae_uio uio;

unsigned int iopll_max_freq = IOPLL_MAX_FREQ;
unsigned int iopll_min_freq = IOPLL_MIN_FREQ;
unsigned int slow_freq = MIN_FPGA_FREQ;

memset(&uio, 0, sizeof(uio));

if (sysfs_path == NULL) {
Expand All @@ -676,9 +680,12 @@ fpga_result set_userclock(const char *sysfs_path,
// S10 & A10 user clock DFH revision 0
result = get_userclk_revision(sysfs_path, &revision);
if (result == FPGA_OK && revision == AGILEX_USRCLK_REV) {
iopll_max_freq = IOPLL_AGILEX_MAX_FREQ;
iopll_min_freq = IOPLL_AGILEX_MIN_FREQ;

// Enforce 1x clock within valid range
if ((userclk_low > IOPLL_AGILEX_MAX_FREQ) ||
(userclk_low < IOPLL_AGILEX_MIN_FREQ)) {
if ((userclk_low > iopll_max_freq) ||
(userclk_low < iopll_min_freq)) {
OPAE_ERR("Invalid Input frequency");
return FPGA_INVALID_PARAM;
}
Expand All @@ -687,14 +694,23 @@ fpga_result set_userclock(const char *sysfs_path,
} else {
// S10 & A10 user clock
// Enforce 1x clock within valid range
if ((userclk_low > IOPLL_MAX_FREQ) ||
(userclk_low < IOPLL_MIN_FREQ)) {
if ((userclk_low > iopll_max_freq) ||
(userclk_low < iopll_min_freq)) {
OPAE_ERR("Invalid Input frequency");
return FPGA_INVALID_PARAM;
}
bufp = (char *)&iopll_freq_config[userclk_low];
}

// Transitions from a currently configured very high frequency
// or very low frequency to another extreme frequency sometimes
// fails to stabilize. Start by forcing the fast clock to half
// speed.
slow_freq = iopll_max_freq / 4;
if (userclk_low != slow_freq) {
result = set_userclock(sysfs_path, slow_freq * 2, slow_freq);
}

ret = using_iopll(sysfs_usrpath, sysfs_path);
if (ret == FPGA_OK) {

Expand All @@ -720,8 +736,8 @@ fpga_result set_userclock(const char *sysfs_path,
}

struct pll_config *iopll_config = (struct pll_config *)bufp;
if ((iopll_config->pll_freq_khz > IOPLL_MAX_FREQ * 1000) ||
(iopll_config->pll_freq_khz < IOPLL_MIN_FREQ * 1000))
if ((iopll_config->pll_freq_khz > iopll_max_freq * 1000) ||
(iopll_config->pll_freq_khz < iopll_min_freq * 1000))
return FPGA_EXCEPTION;

result = get_usrclk_uio(sysfs_path,
Expand Down

0 comments on commit f96c46f

Please sign in to comment.