sdk/userspace/fpga_libs/fpga_clkgen/fpga_clkgen_utils.c (334 lines of code) (raw):

/* * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may * not use this file except in compliance with the License. A copy of the * License is located at * * http://aws.amazon.com/apache2.0/ * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ #include "fpga_clkgen_mmcm.h" #include <utils/lcd.h> #include <utils/log.h> #include <fpga_clkgen.h> // // Frequency Table with multiplier and divider values for MMCM, sorted as per increasing frequency order. // #define AWS_CLKGEN_TABLE_ROWS 42 #define AWS_CLKGEN_TABLE_COLS 6 static const uint32_t FREQ_TABLE [AWS_CLKGEN_TABLE_ROWS][AWS_CLKGEN_TABLE_COLS] = { /*idx=0 */ {/*freq*/ 87, /*sharedMult*/ 8, /*sharedDiv*/ 1, /*sharedMultFrac*/ 750, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=1 */ {/*freq*/ 97, /*sharedMult*/ 9, /*sharedDiv*/ 1, /*sharedMultFrac*/ 750, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=2 */ {/*freq*/ 100, /*sharedMult*/ 12, /*sharedDiv*/ 1, /*sharedMultFrac*/ 0, /*div0*/ 12, /*div0Frac*/ 0}, /*idx=3 */ {/*freq*/ 109, /*sharedMult*/ 10, /*sharedDiv*/ 1, /*sharedMultFrac*/ 875, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=4 */ {/*freq*/ 125, /*sharedMult*/ 11, /*sharedDiv*/ 1, /*sharedMultFrac*/ 875, /*div0*/ 9, /*div0Frac*/ 500}, /*idx=5 */ {/*freq*/ 136, /*sharedMult*/ 13, /*sharedDiv*/ 1, /*sharedMultFrac*/ 625, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=6 */ {/*freq*/ 150, /*sharedMult*/ 12, /*sharedDiv*/ 1, /*sharedMultFrac*/ 0, /*div0*/ 8, /*div0Frac*/ 0}, /*idx=7 */ {/*freq*/ 156, /*sharedMult*/ 15, /*sharedDiv*/ 1, /*sharedMultFrac*/ 625, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=8 */ {/*freq*/ 166, /*sharedMult*/ 16, /*sharedDiv*/ 1, /*sharedMultFrac*/ 625, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=9 */ {/*freq*/ 171, /*sharedMult*/ 17, /*sharedDiv*/ 1, /*sharedMultFrac*/ 125, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=10*/ {/*freq*/ 177, /*sharedMult*/ 17, /*sharedDiv*/ 1, /*sharedMultFrac*/ 750, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=11*/ {/*freq*/ 182, /*sharedMult*/ 18, /*sharedDiv*/ 1, /*sharedMultFrac*/ 250, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=12*/ {/*freq*/ 187, /*sharedMult*/ 18, /*sharedDiv*/ 1, /*sharedMultFrac*/ 750, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=13*/ {/*freq*/ 196, /*sharedMult*/ 19, /*sharedDiv*/ 1, /*sharedMultFrac*/ 625, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=14*/ {/*freq*/ 200, /*sharedMult*/ 12, /*sharedDiv*/ 1, /*sharedMultFrac*/ 0, /*div0*/ 6, /*div0Frac*/ 0}, /*idx=15*/ {/*freq*/ 218, /*sharedMult*/ 21, /*sharedDiv*/ 1, /*sharedMultFrac*/ 750, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=16*/ {/*freq*/ 227, /*sharedMult*/ 22, /*sharedDiv*/ 1, /*sharedMultFrac*/ 750, /*div0*/ 10, /*div0Frac*/ 0}, /*idx=17*/ {/*freq*/ 250, /*sharedMult*/ 11, /*sharedDiv*/ 1, /*sharedMultFrac*/ 875, /*div0*/ 4, /*div0Frac*/ 750}, /*idx=18*/ {/*freq*/ 265, /*sharedMult*/ 26, /*sharedDiv*/ 2, /*sharedMultFrac*/ 500, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=19*/ {/*freq*/ 266, /*sharedMult*/ 8, /*sharedDiv*/ 1, /*sharedMultFrac*/ 0, /*div0*/ 3, /*div0Frac*/ 0}, /*idx=20*/ {/*freq*/ 273, /*sharedMult*/ 27, /*sharedDiv*/ 2, /*sharedMultFrac*/ 250, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=21*/ {/*freq*/ 291, /*sharedMult*/ 29, /*sharedDiv*/ 2, /*sharedMultFrac*/ 0, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=22*/ {/*freq*/ 300, /*sharedMult*/ 12, /*sharedDiv*/ 1, /*sharedMultFrac*/ 0, /*div0*/ 4, /*div0Frac*/ 0}, /*idx=23*/ {/*freq*/ 318, /*sharedMult*/ 31, /*sharedDiv*/ 2, /*sharedMultFrac*/ 750, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=24*/ {/*freq*/ 333, /*sharedMult*/ 10, /*sharedDiv*/ 1, /*sharedMultFrac*/ 0, /*div0*/ 3, /*div0Frac*/ 0}, /*idx=25*/ {/*freq*/ 343, /*sharedMult*/ 34, /*sharedDiv*/ 4, /*sharedMultFrac*/ 250, /*div0*/ 2, /*div0Frac*/ 500}, /*idx=26*/ {/*freq*/ 364, /*sharedMult*/ 36, /*sharedDiv*/ 4, /*sharedMultFrac*/ 750, /*div0*/ 2, /*div0Frac*/ 500}, /*idx=27*/ {/*freq*/ 375, /*sharedMult*/ 37, /*sharedDiv*/ 4, /*sharedMultFrac*/ 500, /*div0*/ 2, /*div0Frac*/ 500}, /*idx=28*/ {/*freq*/ 400, /*sharedMult*/ 12, /*sharedDiv*/ 1, /*sharedMultFrac*/ 0, /*div0*/ 3, /*div0Frac*/ 0}, /*idx=29*/ {/*freq*/ 405, /*sharedMult*/ 20, /*sharedDiv*/ 1, /*sharedMultFrac*/ 250, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=30*/ {/*freq*/ 410, /*sharedMult*/ 20, /*sharedDiv*/ 1, /*sharedMultFrac*/ 500, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=31*/ {/*freq*/ 415, /*sharedMult*/ 20, /*sharedDiv*/ 1, /*sharedMultFrac*/ 750, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=32*/ {/*freq*/ 420, /*sharedMult*/ 21, /*sharedDiv*/ 1, /*sharedMultFrac*/ 0, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=33*/ {/*freq*/ 425, /*sharedMult*/ 21, /*sharedDiv*/ 1, /*sharedMultFrac*/ 250, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=34*/ {/*freq*/ 430, /*sharedMult*/ 21, /*sharedDiv*/ 1, /*sharedMultFrac*/ 500, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=35*/ {/*freq*/ 435, /*sharedMult*/ 21, /*sharedDiv*/ 1, /*sharedMultFrac*/ 750, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=36*/ {/*freq*/ 437, /*sharedMult*/ 43, /*sharedDiv*/ 4, /*sharedMultFrac*/ 625, /*div0*/ 2, /*div0Frac*/ 500}, /*idx=37*/ {/*freq*/ 440, /*sharedMult*/ 22, /*sharedDiv*/ 1, /*sharedMultFrac*/ 0, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=38*/ {/*freq*/ 445, /*sharedMult*/ 22, /*sharedDiv*/ 1, /*sharedMultFrac*/ 250, /*div0*/ 5, /*div0Frac*/ 0}, /*idx=39*/ {/*freq*/ 450, /*sharedMult*/ 11, /*sharedDiv*/ 1, /*sharedMultFrac*/ 250, /*div0*/ 2, /*div0Frac*/ 500}, /*idx=40*/ {/*freq*/ 458, /*sharedMult*/ 45, /*sharedDiv*/ 4, /*sharedMultFrac*/ 750, /*div0*/ 2, /*div0Frac*/ 500}, /*idx=41*/ {/*freq*/ 500, /*sharedMult*/ 15, /*sharedDiv*/ 1, /*sharedMultFrac*/ 0, /*div0*/ 3, /*div0Frac*/ 0}, }; #define CLKGEN_A_RECIPE_TABLE_ROWS 3 static const struct clkgen_recipe clkgen_a_recipes[CLKGEN_A_RECIPE_TABLE_ROWS] = { {/*index 0*/ /*mult*/ 15, /*mult_frac*/ 0, /*div*/ 1, /*div0*/ 24, /*div0_frac*/ 0, /*div1*/ 8, /*div2*/ 6}, {/*index 1*/ /*mult*/ 15, /*mult_frac*/ 0, /*div*/ 1, /*div0*/ 12, /*div0_frac*/ 0, /*div1*/ 4, /*div2*/ 3}, {/*index 2*/ /*mult*/ 12, /*mult_frac*/ 500, /*div*/ 1, /*div0*/ 80, /*div0_frac*/ 0, /*div1*/ 10, /*div2*/ 20} }; #define CLKGEN_B_RECIPE_TABLE_ROWS 6 static const struct clkgen_recipe clkgen_b_recipes[CLKGEN_B_RECIPE_TABLE_ROWS] = { {/*index 0*/ /*mult*/ 12, /*mult_frac*/ 500, /*div*/ 1, /*div0*/ 5, /*div0_frac*/ 0, /*div1*/ 10, /*div2*/ 1}, {/*index 1*/ /*mult*/ 11, /*mult_frac*/ 875, /*div*/ 1, /*div0*/ 9, /*div0_frac*/ 500, /*div1*/ 19, /*div2*/ 1}, {/*index 2*/ /*mult*/ 11, /*mult_frac*/ 250, /*div*/ 1, /*div0*/ 2, /*div0_frac*/ 500, /*div1*/ 5, /*div2*/ 1}, {/*index 3*/ /*mult*/ 11, /*mult_frac*/ 875, /*div*/ 1, /*div0*/ 4, /*div0_frac*/ 750, /*div1*/ 19, /*div2*/ 1}, {/*index 4*/ /*mult*/ 12, /*mult_frac*/ 0, /*div*/ 1, /*div0*/ 4, /*div0_frac*/ 0, /*div1*/ 16, /*div2*/ 1}, {/*index 5*/ /*mult*/ 12, /*mult_frac*/ 0, /*div*/ 1, /*div0*/ 3, /*div0_frac*/ 0, /*div1*/ 12, /*div2*/ 1} }; #define CLKGEN_C_RECIPE_TABLE_ROWS 4 static const struct clkgen_recipe clkgen_c_recipes[CLKGEN_C_RECIPE_TABLE_ROWS] = { {/*index 0*/ /*mult*/ 12, /*mult_frac*/ 0, /*div*/ 1, /*div0*/ 4, /*div0_frac*/ 0, /*div1*/ 3, /*div2*/ 1}, {/*index 1*/ /*mult*/ 12, /*mult_frac*/ 0, /*div*/ 1, /*div0*/ 8, /*div0_frac*/ 0, /*div1*/ 6, /*div2*/ 1}, {/*index 2*/ /*mult*/ 12, /*mult_frac*/ 0, /*div*/ 1, /*div0*/ 16, /*div0_frac*/ 0, /*div1*/ 12, /*div2*/ 1}, {/*index 3*/ /*mult*/ 8, /*mult_frac*/ 0, /*div*/ 1, /*div0*/ 4, /*div0_frac*/ 0, /*div1*/ 3, /*div2*/ 1} }; #define CLKGEN_HBM_RECIPE_TABLE_ROWS 5 static const struct clkgen_recipe clkgen_hbm_recipes[CLKGEN_HBM_RECIPE_TABLE_ROWS] = { {/*index 0*/ /*mult*/ 12, /*mult_frac*/ 500, /*div*/ 1, /*div0*/ 5, /*div0_frac*/ 0, /*div1*/ 1, /*div2*/ 1}, {/*index 1*/ /*mult*/ 11, /*mult_frac*/ 875, /*div*/ 1, /*div0*/ 9, /*div0_frac*/ 500, /*div1*/ 1, /*div2*/ 1}, {/*index 2*/ /*mult*/ 11, /*mult_frac*/ 250, /*div*/ 1, /*div0*/ 2, /*div0_frac*/ 500, /*div1*/ 1, /*div2*/ 1}, {/*index 3*/ /*mult*/ 12, /*mult_frac*/ 0, /*div*/ 1, /*div0*/ 4, /*div0_frac*/ 0, /*div1*/ 1, /*div2*/ 1}, {/*index 4*/ /*mult*/ 12, /*mult_frac*/ 0, /*div*/ 1, /*div0*/ 3, /*div0_frac*/ 0, /*div1*/ 1, /*div2*/ 1} }; static int aws_clkgen_mmcm_init(pci_bar_handle_t pci_bar_handle) { int rc = 0; rc = mmcm_init(clkgen_group_a, pci_bar_handle); fail_on(rc, out, "ERROR: Failed to mmcm_init\n"); rc = mmcm_init(clkgen_group_b, pci_bar_handle); fail_on(rc, out, "ERROR: Failed to mmcm_init\n"); rc = mmcm_init(clkgen_group_c, pci_bar_handle); fail_on(rc, out, "ERROR: Failed to mmcm_init\n"); rc = mmcm_init(clkgen_group_hbm, pci_bar_handle); fail_on(rc, out, "ERROR: Failed to mmcm_init\n"); out: return rc; } static int aws_clkgen_get_freq(enum fpga_clkgen_mmcm_group group, double* cfg_freq, uint32_t num_clocks) { int rc = 0; fail_on_with_code(cfg_freq == NULL, out, rc, FPGA_ERR_SOFTWARE_PROBLEM, "cfg_freq invalid pointer"); fail_on_with_code(num_clocks < 1, out, rc, FPGA_ERR_SOFTWARE_PROBLEM, "num_clocks less than 1"); fail_on_with_code(num_clocks > FPGA_CLKGEN_GROUP_CLKS_MAX, out, rc, FPGA_ERR_SOFTWARE_PROBLEM, "num_clocks greater than FPGA_CLKGEN_GROUP_CLKS_MAX"); uint32_t mult = 0; uint32_t mult_frac = 0; uint32_t div = 0; bool any_clocks_available; rc = mmcm_clk_avail_any(group, &any_clocks_available); fail_on(rc, out, "ERROR: Failed to mmcm_clk_avail_any"); if (!any_clocks_available) { log_debug("No clocks available"); goto out; } rc = mmcm_get_shared_clock(group, &mult, &mult_frac, &div); fail_on(rc, out, "ERROR: Failed to mmcm_get_shared_clock"); double shared_group_freq = 100.0; // start with the 100 MHz reference clock double global_multiplier = mult + (double)mult_frac / 1000; shared_group_freq *= global_multiplier; shared_group_freq /= div; for (uint32_t i = 0; i < num_clocks; ++i) { uint32_t clk_cfg_div = 0; uint32_t clk_cfg_div_frac = 0; rc = mmcm_get_clk_div(group, i, &clk_cfg_div, &clk_cfg_div_frac); fail_on(rc, out, "ERROR: Failed to mmcm_get_shared_clock"); double clock_divider = clk_cfg_div; clock_divider += (double)clk_cfg_div_frac / 1000; double clock = shared_group_freq / clock_divider; *(cfg_freq + i) = clock; } out: return rc; } static int aws_clkgen_set_mmcm(enum fpga_clkgen_mmcm_group group, const struct clkgen_recipe* recipe, uint32_t reset) { int rc = 0; fail_on_with_code(recipe == NULL, out, rc, FPGA_ERR_SOFTWARE_PROBLEM, "recipe invalid pointer"); bool any_clocks_available; rc = mmcm_clk_avail_any(group, &any_clocks_available); fail_on(rc, out, "ERROR: Failed to mmcm_clk_avail_any"); if (!any_clocks_available) { log_debug("No clocks available"); goto out; } uint32_t divs[] = {recipe->div0, recipe->div1, recipe->div2}; uint32_t div_fracs[] = {recipe->div0_frac, 0, 0}; const int div_size = sizeof(divs)/sizeof(uint32_t); if (!reset) { rc = mmcm_set_shared_clock(group, recipe->mult, recipe->mult_frac, recipe->div); fail_on(rc, out, "ERROR: Failed to mmcm_set_shared_clock"); bool clock_available = false; for (int i = 0; i < div_size; ++i) { rc = mmcm_clk_avail(group, i, &clock_available); fail_on(rc, out, "ERROR: Failed to mmcm_clk_avail"); if (clock_available) { rc = mmcm_set_clk_div(group, i, divs[i], div_fracs[i]); fail_on(rc, out, "ERROR: Failed to mmcm_set_clk_div"); } } } rc = mmcm_wait_for_locked(group); fail_on(rc, out, "ERROR: Failed to mmcm_wait_for_locked"); rc = mmcm_load_cfg(group, reset); fail_on(rc, out, "ERROR: Failed to mmcm_load_cfg"); rc = mmcm_wait_for_locked(group); fail_on(rc, out, "ERROR: Failed to mmcm_wait_for_locked"); out: return rc; } static int aws_clkgen_set_freq(enum fpga_clkgen_mmcm_group group, uint32_t req_freq, uint32_t reset) { int rc = 0; fail_on_with_code(!reset && req_freq < FREQ_TABLE[0][0], out, rc, FPGA_ERR_INVALID_CLKGEN_INPUTS, "freq for clock group invalid"); int idx_choice = 0; struct clkgen_recipe recipe; // get index of closest match to the target freq from the FREQ_TABLE if (!reset) { for (int i = AWS_CLKGEN_TABLE_ROWS - 1; i >= 0; --i) { if (FREQ_TABLE[i][0] <= req_freq) { idx_choice = i; break; } } recipe.mult = FREQ_TABLE[idx_choice][1]; recipe.div = FREQ_TABLE[idx_choice][2]; recipe.mult_frac = FREQ_TABLE[idx_choice][3]; recipe.div0 = FREQ_TABLE[idx_choice][4]; recipe.div0_frac = FREQ_TABLE[idx_choice][5]; recipe.div1 = 0xF; recipe.div2 = 0xF; } rc = aws_clkgen_set_mmcm (group, &recipe, reset); fail_on(rc, out, "ERROR: Failed to aws_clkgen_set_mmcm"); out: return rc; } static int aws_clkgen_reset(pci_bar_handle_t pci_bar_handle, uint32_t reset) { int rc = 0; uint64_t grst_reg_offset = AWS_CLKGEN_GRST_REG; uint32_t grst_reg_value = 0; rc = fpga_pci_poke(pci_bar_handle, grst_reg_offset, grst_reg_value); fail_on(rc, out, "Failed to write to register @ 0x%08lx, value = 0x%08x", grst_reg_offset, grst_reg_value); // Wait for MMCM lock if de-asserting resets if (!reset) { int loop_count = 0; uint64_t lock_reg_offset = AWS_CLKGEN_LOCK_REG; uint32_t lock_reg_value = 0; uint32_t lock_mask = 0; rc = mmcm_get_expected_lock_mask(&lock_mask); while (loop_count < MAX_CLKGEN_LOOP_RETRIES) { rc = fpga_pci_peek(pci_bar_handle, lock_reg_offset, &lock_reg_value); fail_on(rc, out, "Failed to read from register @0x%08lx", lock_reg_offset); if ((lock_reg_value & lock_mask) == lock_mask) { break; } msleep(AWS_CLKGEN_LOOP_DELAY_MS); ++loop_count; } fail_on((loop_count >= MAX_CLKGEN_LOOP_RETRIES), out, "Timeout: Failed to achieve MMCM lock after %d iterations.", loop_count); } uint64_t sysrst_reg_offset = AWS_CLKGEN_SYSRST_REG; uint32_t sysrst_reg_value = reset ? 0xFFFFFFFF : 0; rc = fpga_pci_poke(pci_bar_handle, sysrst_reg_offset, sysrst_reg_value); fail_on(rc, out, "Failed to write to register @ 0x%08lx, value = 0x%08x", sysrst_reg_offset, sysrst_reg_value); out: return rc; } static int aws_clkgen_check_id(pci_bar_handle_t pci_bar_handle) { int rc = 0; uint64_t id_reg_offset = AWS_CLKGEN_ID_REG; uint32_t id_reg_value = 0; rc = fpga_pci_peek(pci_bar_handle, id_reg_offset, &id_reg_value); fail_on(rc, out, "Failed to read from register @0x%08lx", id_reg_offset); fail_on(rc = (id_reg_value != AWS_CLKGEN_ID), out, "ERROR: ID_REG mismatch."); uint64_t ver_reg_offset = AWS_CLKGEN_VER_REG; uint32_t ver_reg_value = 0; rc = fpga_pci_peek(pci_bar_handle, ver_reg_offset, &ver_reg_value); fail_on(rc, out, "Failed to read from register @0x%08lx", ver_reg_offset); fail_on(rc = (ver_reg_value != AWS_CLKGEN_VER), out, "ERROR: VER_REG mismatch."); uint64_t bld_reg_offset = AWS_CLKGEN_BLD_REG; uint32_t bld_reg_value = 0; rc = fpga_pci_peek(pci_bar_handle, bld_reg_offset, &bld_reg_value); fail_on(rc, out, "Failed to read from register @0x%08lx", bld_reg_offset); fail_on(rc = (bld_reg_value != AWS_CLKGEN_BLD), out, "ERROR: BUILD_REG mismatch."); out: return rc; } int aws_clkgen_get_dynamic(int slot_id, struct fpga_clkgen_info* info) { int rc = 0; fail_on_with_code(info == NULL, out, rc, FPGA_ERR_SOFTWARE_PROBLEM, "info invalid pointer"); pci_bar_handle_t pci_bar_handle = PCI_BAR_HANDLE_INIT; int fpga_attach_flags = 0; // Attach to PCIe PF/BAR rc = fpga_pci_attach(slot_id, AWS_CLKGEN_PF, AWS_CLKGEN_BAR, fpga_attach_flags, &pci_bar_handle); fail_on(rc, out, "Unable to attach to the AFI on slot id %d", fpga_attach_flags); rc = aws_clkgen_mmcm_init(pci_bar_handle); fail_on(rc, out, "ERROR: Failed to aws_clkgen_mmcm_init\n"); rc = aws_clkgen_check_id(pci_bar_handle); fail_on_with_code(rc, out, rc, FPGA_ERR_CLKGEN_NOT_FOUND, "aws_clkgen_check_id() check failed."); // Configure MMCMs in AWS_CLK_GEN rc = aws_clkgen_get_freq(clkgen_group_a, info->clock_group_a.clocks, FPGA_CLKGEN_GROUP_A_CLKS); fail_on(rc, out, "aws_clkgen_get_freq(pci_bar_handle, AWS_CLKGEN_BASE_A, freq_clk_a) failed."); rc = aws_clkgen_get_freq(clkgen_group_b, info->clock_group_b.clocks, FPGA_CLKGEN_GROUP_B_CLKS); fail_on(rc, out, "aws_clkgen_get_freq(pci_bar_handle, AWS_CLKGEN_BASE_B, freq_clk_b) failed."); rc = aws_clkgen_get_freq(clkgen_group_c, info->clock_group_c.clocks, FPGA_CLKGEN_GROUP_C_CLKS); fail_on(rc, out, "aws_clkgen_get_freq(pci_bar_handle, AWS_CLKGEN_BASE_C, freq_clk_c) failed."); rc = aws_clkgen_get_freq(clkgen_group_hbm, info->clock_group_hbm.clocks, FPGA_CLKGEN_GROUP_HBM_CLKS); fail_on(rc, out, "aws_clkgen_get_freq(pci_bar_handle, AWS_CLKGEN_BASE_HBM, freq_clk_hbm) failed."); out: if (pci_bar_handle != PCI_BAR_HANDLE_INIT) { fpga_pci_detach(pci_bar_handle); } return rc; } int aws_clkgen_set_recipe(int slot_id, uint32_t recipe_a, uint32_t recipe_b, uint32_t recipe_c, uint32_t recipe_hbm, uint32_t reset) { int rc = 0; if (!reset) { fail_on_with_code(recipe_a >= CLKGEN_A_RECIPE_TABLE_ROWS, out, rc, FPGA_ERR_INVALID_CLKGEN_INPUTS, "recipe for clock group a invalid"); fail_on_with_code(recipe_b >= CLKGEN_B_RECIPE_TABLE_ROWS, out, rc, FPGA_ERR_INVALID_CLKGEN_INPUTS, "recipe for clock group b invalid"); fail_on_with_code(recipe_c >= CLKGEN_C_RECIPE_TABLE_ROWS, out, rc, FPGA_ERR_INVALID_CLKGEN_INPUTS, "recipe for clock group c invalid"); fail_on_with_code(recipe_hbm >= CLKGEN_HBM_RECIPE_TABLE_ROWS, out, rc, FPGA_ERR_INVALID_CLKGEN_INPUTS, "recipe for clock group hbm invalid"); } else { recipe_a = recipe_b = recipe_c = recipe_hbm = 0; } pci_bar_handle_t pci_bar_handle = PCI_BAR_HANDLE_INIT; int fpga_attach_flags = 0; rc = fpga_pci_attach(slot_id, AWS_CLKGEN_PF, AWS_CLKGEN_BAR, fpga_attach_flags, &pci_bar_handle); fail_on(rc, out, "Unable to attach to the AFI on slot id %d", fpga_attach_flags); rc = aws_clkgen_mmcm_init(pci_bar_handle); fail_on(rc, out, "ERROR: Failed to aws_clkgen_mmcm_init\n"); rc = aws_clkgen_check_id(pci_bar_handle); fail_on_with_code(rc, out, rc, FPGA_ERR_CLKGEN_NOT_FOUND, "aws_clkgen_check_id() check failed."); rc = aws_clkgen_reset(pci_bar_handle, 1); fail_on(rc, out, "aws_clkgen_reset(1) failed."); rc = aws_clkgen_set_mmcm(clkgen_group_a, &clkgen_a_recipes[recipe_a], reset); fail_on(rc, out, "aws_clkgen_set_mmcm(clkgen_group_a, ...) failed."); rc = aws_clkgen_set_mmcm(clkgen_group_b, &clkgen_b_recipes[recipe_b], reset); fail_on(rc, out, "aws_clkgen_set_mmcm(clkgen_group_b, ...) failed."); rc = aws_clkgen_set_mmcm(clkgen_group_c, &clkgen_c_recipes[recipe_c], reset); fail_on(rc, out, "aws_clkgen_set_mmcm(clkgen_group_c, ...) failed."); rc = aws_clkgen_set_mmcm(clkgen_group_hbm, &clkgen_hbm_recipes[recipe_hbm], reset); fail_on(rc, out, "aws_clkgen_set_mmcm(clkgen_group_hbm, ...) failed."); // De-assert all resets rc = aws_clkgen_reset(pci_bar_handle, 0); fail_on(rc, out, "aws_clkgen_reset(0) failed."); out: if (pci_bar_handle != PCI_BAR_HANDLE_INIT) { fpga_pci_detach(pci_bar_handle); } return rc; } int aws_clkgen_set_dynamic(int slot_id, uint32_t clk_a_freq, uint32_t clk_b_freq, uint32_t clk_c_freq, uint32_t clk_hbm_freq, uint32_t reset) { int rc = 0; if (!reset) { fail_on_with_code(clk_a_freq > CLKGEN_A_1_MAX, out, rc, FPGA_ERR_INVALID_CLKGEN_INPUTS, "frequency for clock group a invalid"); fail_on_with_code(clk_b_freq > CLKGEN_B_0_MAX, out, rc, FPGA_ERR_INVALID_CLKGEN_INPUTS, "frequency for clock group b invalid"); fail_on_with_code(clk_c_freq > CLKGEN_C_0_MAX, out, rc, FPGA_ERR_INVALID_CLKGEN_INPUTS, "frequency for clock group c invalid"); fail_on_with_code(clk_hbm_freq > CLKGEN_HBM_MAX, out, rc, FPGA_ERR_INVALID_CLKGEN_INPUTS, "frequency for clock group hbm invalid"); } else { clk_a_freq = clk_b_freq = clk_c_freq = clk_hbm_freq = 0; } pci_bar_handle_t pci_bar_handle = PCI_BAR_HANDLE_INIT; int fpga_attach_flags = 0; // Attach to PCIe PF/BAR rc = fpga_pci_attach(slot_id, AWS_CLKGEN_PF, AWS_CLKGEN_BAR, fpga_attach_flags, &pci_bar_handle); fail_on(rc, out, "Unable to attach to the AFI on slot id %d", fpga_attach_flags); rc = aws_clkgen_mmcm_init(pci_bar_handle); fail_on(rc, out, "ERROR: Failed to aws_clkgen_mmcm_init\n"); rc = aws_clkgen_check_id(pci_bar_handle); fail_on_with_code(rc, out, rc, FPGA_ERR_CLKGEN_NOT_FOUND, "aws_clkgen_check_id() check failed."); rc = aws_clkgen_reset(pci_bar_handle, 1); fail_on(rc, out, "aws_clkgen_reset(1) failed."); rc = aws_clkgen_set_freq(clkgen_group_a, clk_a_freq, reset); fail_on(rc, out, "aws_clkgen_set_freq(clkgen_group_a, ...) failed."); rc = aws_clkgen_set_freq(clkgen_group_b, clk_b_freq, reset); fail_on(rc, out, "aws_clkgen_set_freq(clkgen_group_b, ...) failed."); rc = aws_clkgen_set_freq(clkgen_group_c, clk_c_freq, reset); fail_on(rc, out, "aws_clkgen_set_freq(clkgen_group_c, ...) failed."); rc = aws_clkgen_set_freq(clkgen_group_hbm, clk_hbm_freq, reset); fail_on(rc, out, "aws_clkgen_set_freq(clkgen_group_hbm, ...) failed."); // De-assert all resets rc = aws_clkgen_reset(pci_bar_handle, 0); fail_on(rc, out, "aws_clkgen_reset(0) failed."); out: if (pci_bar_handle != PCI_BAR_HANDLE_INIT) { fpga_pci_detach(pci_bar_handle); } return rc; }