Hi,
I am trying to run the NO-OS reference design in ADRV9009 where I am getting an error stating "error: rx_adxcvr: adxcvr_clk_enable() failed". My sampling rate and clock rates are 245.76MHz, Rx Lane Rate is 9.8304GHz, ORx lane rate is 4.9152GHz, Tx lane rate is 4.9152GHz. What is the root cause of this problem ?
I have updated the SDK code to print extra logs for debugging purposes and have provided the SDK code with UART terminal logs for reference.
/***************************************************************************//**
* @file app_clocking.c
* @brief Clock setup and initialization routines.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
// stdlibs
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "app_config.h"
// clock chips
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
#include "hmc7044.h"
#else
#include "ad9528.h"
#endif
// platform drivers
#include "no_os_spi.h"
#include "no_os_gpio.h"
#include "no_os_error.h"
#include "no_os_delay.h"
#include "no_os_util.h"
// platform specific
#ifdef ALTERA_PLATFORM
#include "clk_altera_a10_fpll.h"
#include "altera_spi.h"
#include "altera_gpio.h"
#else
#include "xil_cache.h"
#include "xilinx_spi.h"
#if !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
#include "clk_axi_clkgen.h"
#include "xilinx_gpio.h"
#endif
#endif
// hal
#include "parameters.h"
#include "adi_hal.h"
// devices
#include "app_talise.h"
// header
#include "app_clocking.h"
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
struct hmc7044_dev* clkchip_device;
struct hmc7044_dev * car_clkchip_device;
#else
struct ad9528_dev* clkchip_device;
#endif
#ifdef ALTERA_PLATFORM
struct altera_a10_fpll *rx_device_clk_pll;
struct altera_a10_fpll *tx_device_clk_pll;
struct altera_a10_fpll *rx_os_device_clk_pll;
#elif !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
struct axi_clkgen *rx_clkgen;
struct axi_clkgen *tx_clkgen;
struct axi_clkgen *rx_os_clkgen;
#endif
adiHalErr_t clocking_init(uint32_t rx_div40_rate_hz,
uint32_t tx_div40_rate_hz,
uint32_t rx_os_div40_rate_hz,
uint32_t device_clock_khz,
uint32_t lmfc_rate_hz)
{
int32_t status;
uint64_t dev_clk, fmc_clk;
uint64_t rate_dev = device_clock_khz * 1000;
uint64_t rate_fmc = device_clock_khz * 1000;
uint32_t n;
int ret;
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
struct hmc7044_init_param hmc7044_param = {
.spi_init = NULL,
.clkin_freq = {122880000, 122880000, 0, 0},
.vcxo_freq = 122880000,
.pll2_freq = 2949120000,
.pll1_loop_bw = 200,
.sysref_timer_div = 3840,
.in_buf_mode = {0x09, 0x09, 0x00, 0x00, 0x15},
.gpi_ctrl = {0x00, 0x00, 0x00, 0x11},
.gpo_ctrl = {0x1f, 0x2b, 0x00, 0x00},
.num_channels = 10,
.pll1_ref_prio_ctrl = 0xE5,
.sync_pin_mode = 0x1,
.high_performance_mode_clock_dist_en = true,
.pulse_gen_mode = 0x0,
};
struct hmc7044_chan_spec chan_spec[10] = {
/* DEV_REFCLK_A */
{
.disable = 0, .num = 0, .divider = 12, .driver_mode = 2
// .coarse_delay = 15
},
/* DEV_SYSREF_A */
{
.disable = 0, .num = 1, .divider = 3840, .driver_mode = 1,
// .start_up_mode_dynamic_enable = true,
// .high_performance_mode_dis = true,
// .output_control0_rb4_enable = true,
// .force_mute_enable = true,
// .driver_impedance = 1
},
/* DEV_REFCLK_B */
{
.disable = 0, .num = 2, .divider = 12, .driver_mode = 2
// .coarse_delay = 15
},
/* DEV_SYSREF_B */
{
.disable = 0, .num = 3, .divider = 3840, .driver_mode = 1
// .start_up_mode_dynamic_enable = true,
// .high_performance_mode_dis = true,
// .output_control0_rb4_enable = true,
// .force_mute_enable = true,
// .driver_impedance = 1
},
/* JESD_REFCLK_TX_OBS_AB */
{
.disable = 0, .num = 4, .divider = 12, .driver_mode = 2
// .coarse_delay = 15
},
/* JESD_REFCLK_RX_AB */
{
.disable = 0, .num = 6, .divider = 12, .driver_mode = 2
},
//nm-start
//refclk MGT B
{
.disable = 0, .num = 8, .divider = 6, .driver_mode = 2
},
//sysref MGT B
{
.disable = 0, .num = 9, .divider = 3840, .driver_mode = 1
},
//refclk MGT A
{
.disable = 0, .num = 12, .divider = 6, .driver_mode = 2
},
//sysref MGT A
{
.disable = 0, .num = 13, .divider = 3840, .driver_mode = 1
},
//nm-end
#if defined(ZU11EG)
/* CORE_CLK_TX_OBS_AB */
{
.disable = 0, .num = 6,
.divider = hmc7044_param.pll2_freq / tx_div40_rate_hz,
.driver_mode = 0,
.driver_impedance = 1
},
/* CORE_CLK_RX_AB */
{
.disable = 0, .num = 7,
.divider = hmc7044_param.pll2_freq / rx_div40_rate_hz,
.driver_mode = 0,
.driver_impedance = 1
},
/* FPGA_SYSREF_TX_OBS_AB */
{
.disable = 0, .num = 8, .divider = 3840, .driver_mode = 1,
.start_up_mode_dynamic_enable = true,
.high_performance_mode_dis = true,
.output_control0_rb4_enable = true,
.force_mute_enable = true
},
/* FPGA_SYSREF_RX_AB */
{
.disable = 0, .num = 9, .divider = 3840, .driver_mode = 1,
.start_up_mode_dynamic_enable = true,
.high_performance_mode_dis = true,
.output_control0_rb4_enable = true,
.force_mute_enable = true
}
#elif defined(FMCOMMS8_ZCU102)
/* FPGA_SYSREF_TX_OBS_AB */
{
.disable = 1, .num = 5, .divider = 3840, .driver_mode = 1
// .start_up_mode_dynamic_enable = true,
// .high_performance_mode_dis = true,
// .output_control0_rb4_enable = true,
// .force_mute_enable = true
},
/* FPGA_SYSREF_RX_AB */
{
.disable = 1, .num = 7, .divider = 3840, .driver_mode = 1
// .start_up_mode_dynamic_enable = true,
// .high_performance_mode_dis = true,
// .output_control0_rb4_enable = true,
// .force_mute_enable = true
},
/* CORE_CLK_TX_OBS_AB */
/*{
.disable = 0, .num = 8, .divider = 24, .driver_mode = 0,
.driver_impedance = 1
},*/
/* CORE_CLK_RX_AB */
/*{
.disable = 0, .num = 9, .divider = 12, .driver_mode = 0,
.driver_impedance = 1
}*/
#endif
};
hmc7044_param.channels = chan_spec;
struct hmc7044_chan_spec car_chan_spec[2] = {
/* REFCLK_OUT2 */
{
.disable = 0, .num = 2, .divider = 24, .driver_mode = 1,
},
/* SYNC_OUT1 */
{
.disable = 0, .num = 5, .divider = 3840, .driver_mode = 3,
.start_up_mode_dynamic_enable = true,
.high_performance_mode_dis = true,
.driver_impedance = 3
}
};
struct hmc7044_init_param hmc7044_car_param = {
.spi_init = NULL,
.clkin_freq = {122880000, 122880000, 0, 19200000},
.vcxo_freq = 122880000,
.pll2_freq = 2949120000,
.pll1_loop_bw = 200,
.sysref_timer_div = 3840,
.in_buf_mode = {0x07, 0x07, 0x00, 0x11, 0x15},
.gpi_ctrl = {0x00, 0x00, 0x00, 0x11},
.gpo_ctrl = {0x1f, 0x2b, 0x00, 0x00},
.num_channels = 2,
.pll1_ref_prio_ctrl = 0xB1,
.sync_pin_mode = 0x1,
.pulse_gen_mode = 0x1,
.channels = car_chan_spec
};
#else
struct ad9528_channel_spec ad9528_channels[14];
struct ad9528_init_param ad9528_param;
struct ad9528_platform_data ad9528_pdata;
// ad9528 defaults
ad9528_param.pdata = &ad9528_pdata;
ad9528_param.pdata->num_channels = 14;
ad9528_param.pdata->channels = &ad9528_channels[0];
status = ad9528_init(&ad9528_param);
if(status) {
printf("error: ad9528_init() failed with %d\n", status);
goto error_0;
}
// ad9528 channel defaults
for(unsigned int ch = 0; ch < ad9528_param.pdata->num_channels; ch++) {
ad9528_channels[ch].channel_num = ch;
ad9528_channels[ch].output_dis = 1;
}
// ad9528 channel specifics
// adrv9009 device clock
ad9528_channels[13].output_dis = 0;
ad9528_channels[13].driver_mode = DRIVER_MODE_LVDS;
ad9528_channels[13].divider_phase = 0;
ad9528_channels[13].signal_source = SOURCE_VCO;
// fpga device clock
ad9528_channels[1].output_dis = 0;
ad9528_channels[1].driver_mode = DRIVER_MODE_LVDS;
ad9528_channels[1].divider_phase = 0;
ad9528_channels[1].signal_source = SOURCE_VCO;
// adrv9009 sysref
ad9528_channels[12].output_dis = 0;
ad9528_channels[12].driver_mode = DRIVER_MODE_LVDS;
ad9528_channels[12].divider_phase = 0;
ad9528_channels[12].signal_source = SOURCE_SYSREF_VCO;
// fpga sysref
ad9528_channels[3].output_dis = 0;
ad9528_channels[3].driver_mode = DRIVER_MODE_LVDS;
ad9528_channels[3].divider_phase = 0;
ad9528_channels[3].signal_source = SOURCE_SYSREF_VCO;
// ad9528 settings
ad9528_param.pdata->spi3wire = 0;
ad9528_param.pdata->vcxo_freq = 122880000;
ad9528_param.pdata->refa_en = 1;
ad9528_param.pdata->refa_diff_rcv_en = 1;
ad9528_param.pdata->refa_r_div = 1;
ad9528_param.pdata->osc_in_cmos_neg_inp_en = 1;
ad9528_param.pdata->pll1_feedback_div = 4;
ad9528_param.pdata->pll1_feedback_src_vcxo = 0; /* VCO */
ad9528_param.pdata->pll1_charge_pump_current_nA = 5000;
ad9528_param.pdata->pll1_bypass_en = 0;
ad9528_param.pdata->pll2_vco_div_m1 = 3;
ad9528_param.pdata->pll2_n2_div = 10;
ad9528_param.pdata->pll2_r1_div = 1;
ad9528_param.pdata->pll2_charge_pump_current_nA = 805000;
ad9528_param.pdata->pll2_bypass_en = false;
ad9528_param.pdata->sysref_src = SYSREF_SRC_INTERNAL;
ad9528_param.pdata->sysref_pattern_mode = SYSREF_PATTERN_CONTINUOUS;
ad9528_param.pdata->sysref_req_en = true;
ad9528_param.pdata->sysref_nshot_mode = SYSREF_NSHOT_4_PULSES;
ad9528_param.pdata->sysref_req_trigger_mode = SYSREF_LEVEL_HIGH;
ad9528_param.pdata->rpole2 = RPOLE2_900_OHM;
ad9528_param.pdata->rzero = RZERO_1850_OHM;
ad9528_param.pdata->cpole1 = CPOLE1_16_PF;
ad9528_param.pdata->stat0_pin_func_sel = 0x1; /* PLL1 & PLL2 Locked */
ad9528_param.pdata->stat1_pin_func_sel = 0x7; /* REFA Correct */
#endif
#ifdef ALTERA_PLATFORM
struct altera_spi_init_param ad9528_spi_param = {
.type = NIOS_II_SPI,
.device_id = 0,
.base_address = SPI_BASEADDR
};
struct altera_gpio_init_param ad9528_gpio_param = {
.type = NIOS_II_GPIO,
.device_id = 0,
.base_address = GPIO_BASEADDR
};
struct altera_a10_fpll_init rx_device_clk_pll_init = {
"rx_device_clk_pll",
RX_A10_FPLL_BASEADDR,
device_clock_khz * 1000
};
struct altera_a10_fpll_init tx_device_clk_pll_init = {
"tx_device_clk_pll",
TX_A10_FPLL_BASEADDR,
device_clock_khz * 1000
};
struct altera_a10_fpll_init rx_os_device_clk_pll_init = {
"rx_os_device_clk_pll",
RX_OS_A10_FPLL_BASEADDR,
device_clock_khz * 1000
};
struct altera_a10_fpll *rx_device_clk_pll;
struct altera_a10_fpll *tx_device_clk_pll;
struct altera_a10_fpll *rx_os_device_clk_pll;
#else
struct xil_spi_init_param xil_spi_param = {
#ifdef PLATFORM_MB
.type = SPI_PL,
#else
.type = SPI_PS,
#endif
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
.flags = SPI_CS_DECODE
#endif
};
#if !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
struct xil_gpio_init_param xil_gpio_param = {
#ifdef PLATFORM_MB
.type = GPIO_PL,
#else
.type = GPIO_PS,
#endif
.device_id = GPIO_DEVICE_ID,
};
struct axi_clkgen_init rx_clkgen_init = {
"rx_clkgen",
RX_CLKGEN_BASEADDR,
device_clock_khz * 1000
};
struct axi_clkgen_init tx_clkgen_init = {
"tx_clkgen",
TX_CLKGEN_BASEADDR,
device_clock_khz * 1000
};
struct axi_clkgen_init rx_os_clkgen_init = {
"rx_os_clkgen",
RX_OS_CLKGEN_BASEADDR,
device_clock_khz * 1000
};
#endif
#endif
// clock chip spi settings
struct no_os_spi_init_param clkchip_spi_init_param = { //1st clock chip (HMC7044)
.device_id = 1,
.max_speed_hz = 10000000,
.mode = NO_OS_SPI_MODE_0,
.chip_select = CLK_CS,
#ifndef ALTERA_PLATFORM
.platform_ops = &xil_spi_ops,
#else
.platform_ops = &altera_spi_ops,
#endif
.extra = &xil_spi_param
};
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
// clock chip spi settings
struct no_os_spi_init_param car_clkchip_spi_init_param = { //2nd clock chip (HMC7044)
.device_id = 1,
.max_speed_hz = 10000000,
.mode = NO_OS_SPI_MODE_0,
.chip_select = CAR_CLK_CS,
.platform_ops = &xil_spi_ops,
.extra = &xil_spi_param
};
hmc7044_car_param.spi_init = &car_clkchip_spi_init_param;
hmc7044_param.spi_init = &clkchip_spi_init_param;
#else
ad9528_param.spi_init = clkchip_spi_init_param;
#endif
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
// reset pin not needed, hmc7044_init performs a soft reset over SPI.
#else
struct no_os_gpio_init_param clkchip_gpio_init_param = {
.number = CLK_RESETB_GPIO,
.platform_ops = &xil_gpio_ops,
.extra = &xil_gpio_param
};
ad9528_param.gpio_resetb = &clkchip_gpio_init_param;
#endif
/** < Insert User System Clock(s) Initialization Code Here >
* System Clock should provide a device clock and SYSREF signal
* to the Talise device.
**/
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
status = hmc7044_init(&car_clkchip_device, &hmc7044_car_param);
if (status != 0) {
printf("hmc7044_init() error: %d\n", status);
goto error_1;
}
status = hmc7044_init(&clkchip_device, &hmc7044_param);
if (status != 0) {
printf("hmc7044_init() error: %d\n", status);
goto error_1;
}
status = hmc7044_clk_round_rate(clkchip_device, device_clock_khz * 1000,
&dev_clk);
if (status != 0) {
printf("hmc7044_clk_round_rate() error: %d\n", status);
goto error_1;
}
status = hmc7044_clk_round_rate(clkchip_device, device_clock_khz * 1000,
&fmc_clk);
if (status != 0) {
printf("hmc7044_clk_round_rate() error: %d\n", status);
goto error_1;
}
#else
status = ad9528_setup(&clkchip_device, ad9528_param);
if(status < 0) {
printf("error: ad9528_setup() failed with %d\n", status);
goto error_1;
}
dev_clk = ad9528_clk_round_rate(clkchip_device, DEV_CLK,
device_clock_khz * 1000);
fmc_clk = ad9528_clk_round_rate(clkchip_device, FMC_CLK,
device_clock_khz * 1000);
#endif
if (dev_clk > 0 && fmc_clk > 0 && fmc_clk == dev_clk &&
(dev_clk / 1000) == device_clock_khz) {
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
ret = hmc7044_clk_set_rate(clkchip_device, DEV_REFCLK_A, dev_clk);
if (ret != 0) {
printf("hmc7044_clk_set_rate() error: %d\n", status);
goto error_1;
}
ret = hmc7044_clk_set_rate(clkchip_device, DEV_REFCLK_B, dev_clk);
if (ret != 0) {
printf("hmc7044_clk_set_rate() error: %d\n", status);
goto error_1;
}
ret = hmc7044_clk_set_rate(clkchip_device, JESD_REFCLK_TX_OBS_AB, fmc_clk);
if (ret != 0) {
printf("hmc7044_clk_set_rate() error: %d\n", status);
goto error_1;
}
ret = hmc7044_clk_set_rate(clkchip_device, JESD_REFCLK_RX_AB, fmc_clk);
if (ret != 0) {
printf("hmc7044_clk_set_rate() error: %d\n", status);
goto error_1;
}
#else
ad9528_clk_set_rate(clkchip_device, DEV_CLK, dev_clk);
ad9528_clk_set_rate(clkchip_device, FMC_CLK, fmc_clk);
#endif
} else {
printf("Requesting device clock %u failed got %u\n",
device_clock_khz * 1000, dev_clk);
goto error_1;
}
/* If the current rate is not OK, change it */
if (!(adrv9009_check_sysref_rate(lmfc_rate_hz, rate_dev) &&
(rate_fmc == rate_dev))) {
/*
* Try to find a rate that integer divides the LMFC. Starting with a low
* rate is a good idea and then slowly go up in case the clock generator
* can't generate such slow rates.
*/
for (n = 64; n > 0; n--) {
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
hmc7044_clk_round_rate(clkchip_device, lmfc_rate_hz / n,
&rate_dev);
#else
rate_dev = ad9528_clk_round_rate(clkchip_device, DEV_SYSREF, lmfc_rate_hz / n);
#endif
if (adrv9009_check_sysref_rate(lmfc_rate_hz, rate_dev))
break;
}
if (n == 0) {
printf("Could not find suitable SYSREF rate for LMFC of %u\n", lmfc_rate_hz);
goto error_1;
}
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
ret = hmc7044_clk_set_rate(clkchip_device, JESD_REFCLK_TX_OBS_AB, rate_fmc);
if (ret)
printf("Failed to set JESD_REFCLK_TX_OBS_AB rate to %u Hz: %d\n",
rate_fmc, ret);
ret = hmc7044_clk_set_rate(clkchip_device, JESD_REFCLK_RX_AB, rate_fmc);
if (ret)
printf("Failed to set JESD_REFCLK_RX_AB rate to %u Hz: %d\n",
rate_fmc, ret);
#else
ret = ad9528_clk_set_rate(clkchip_device, FMC_SYSREF, rate_fmc);
if (ret)
printf("Failed to set FMC SYSREF rate to %u Hz: %d\n",
rate_fmc, ret);
#endif
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
ret = hmc7044_clk_set_rate(clkchip_device, DEV_SYSREF_A, rate_dev);
if (ret)
printf("Failed to set DEV SYSREF A rate to %u Hz: %d\n",
rate_dev, ret);
ret = hmc7044_clk_set_rate(clkchip_device, DEV_SYSREF_B, rate_dev);
if (ret)
printf("Failed to set DEV SYSREF B rate to %u Hz: %d\n",
rate_dev, ret);
#else
ret = ad9528_clk_set_rate(clkchip_device, DEV_SYSREF, rate_dev);
if (ret)
printf("Failed to set DEV SYSREF rate to %u Hz: %d\n",
rate_fmc, ret);
#endif
}
#ifdef ALTERA_PLATFORM
#ifndef ADRV9008_2
/* Initialize A10 FPLLs */
status = altera_a10_fpll_init(&rx_device_clk_pll,
&rx_device_clk_pll_init);
if (status != 0) {
printf("error: %s: altera_a10_fpll_init() failed\n",
rx_device_clk_pll_init.name);
goto error_1;
}
#endif
#ifndef ADRV9008_1
status = altera_a10_fpll_init(&tx_device_clk_pll,
&tx_device_clk_pll_init);
if (status != 0) {
printf("error: %s: altera_a10_fpll_init() failed\n",
tx_device_clk_pll_init.name);
goto error_2;
}
status = altera_a10_fpll_init(&rx_os_device_clk_pll,
&rx_os_device_clk_pll_init);
if (status != 0) {
printf("error: %s: altera_a10_fpll_init() failed\n",
rx_os_device_clk_pll_init.name);
goto error_3;
}
#endif
#ifndef ADRV9008_2
altera_a10_fpll_disable(rx_device_clk_pll);
status = altera_a10_fpll_set_rate(rx_device_clk_pll,
rx_div40_rate_hz);
if (status != 0) {
printf("error: %s: altera_a10_fpll_set_rate() failed\n",
rx_device_clk_pll->name);
goto error_4;
}
altera_a10_fpll_enable(rx_device_clk_pll);
#endif
#ifndef ADRV9008_1
altera_a10_fpll_disable(tx_device_clk_pll);
status = altera_a10_fpll_set_rate(tx_device_clk_pll,
tx_div40_rate_hz);
if (status != 0) {
printf("error: %s: altera_a10_fpll_set_rate() failed\n",
tx_device_clk_pll->name);
goto error_4;
}
altera_a10_fpll_enable(tx_device_clk_pll);
altera_a10_fpll_disable(rx_os_device_clk_pll);
status = altera_a10_fpll_set_rate(rx_os_device_clk_pll,
rx_os_div40_rate_hz);
if (status != 0) {
printf("error: %s: altera_a10_fpll_set_rate() failed\n",
rx_os_device_clk_pll->name);
goto error_4;
}
altera_a10_fpll_enable(rx_os_device_clk_pll);
#endif
#else
#if !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
/* Initialize CLKGEN */
#ifndef ADRV9008_2
status = axi_clkgen_init(&rx_clkgen, &rx_clkgen_init);
if (status != 0) {
printf("error: %s: axi_clkgen_init() failed\n", rx_clkgen_init.name);
goto error_1;
}
#endif
#ifndef ADRV9008_1
status = axi_clkgen_init(&tx_clkgen, &tx_clkgen_init);
if (status != 0) {
printf("error: %s: axi_clkgen_init() failed\n", tx_clkgen_init.name);
goto error_2;
}
status = axi_clkgen_init(&rx_os_clkgen, &rx_os_clkgen_init);
if (status != 0) {
printf("error: %s: axi_clkgen_set_rate() failed\n", rx_os_clkgen_init.name);
goto error_3;
}
#endif
#ifndef ADRV9008_2
status = axi_clkgen_set_rate(rx_clkgen, rx_div40_rate_hz);
if (status != 0) {
printf("error: %s: axi_clkgen_set_rate() failed\n", rx_clkgen->name);
goto error_4;
}
#endif
#ifndef ADRV9008_1
status = axi_clkgen_set_rate(tx_clkgen, tx_div40_rate_hz);
if (status != 0) {
printf("error: %s: axi_clkgen_set_rate() failed\n", tx_clkgen->name);
goto error_4;
}
status = axi_clkgen_set_rate(rx_os_clkgen, rx_os_div40_rate_hz);
if (status != 0) {
printf("error: %s: axi_clkgen_set_rate() failed\n", rx_os_clkgen->name);
goto error_4;
}
#endif
#endif
#endif
return ADIHAL_OK;
#if !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
error_4:
#endif
#ifdef ALTERA_PLATFORM
#ifndef ADRV9008_1
altera_a10_fpll_remove(rx_os_device_clk_pll);
#endif
#elif !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
#ifndef ADRV9008_1
axi_clkgen_remove(rx_os_clkgen);
#endif
#endif
#if !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
error_3:
#endif
#ifdef ALTERA_PLATFORM
#ifndef ADRV9008_1
altera_a10_fpll_remove(tx_device_clk_pll);
#endif
#elif !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
#ifndef ADRV9008_1
axi_clkgen_remove(tx_clkgen);
#endif
#endif
#if !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
error_2:
#endif
#ifdef ALTERA_PLATFORM
#ifndef ADRV9008_2
altera_a10_fpll_remove(rx_device_clk_pll);
#endif
#elif !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
#ifndef ADRV9008_2
axi_clkgen_remove(rx_clkgen);
#endif
#endif
error_1:
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
hmc7044_remove(clkchip_device);
#else
ad9528_remove(clkchip_device);
error_0:
#endif
return ADIHAL_ERR;
}
void clocking_deinit(void)
{
#ifdef ALTERA_PLATFORM
#ifndef ADRV9008_2
altera_a10_fpll_remove(rx_device_clk_pll);
#endif
#ifndef ADRV9008_1
altera_a10_fpll_remove(tx_device_clk_pll);
altera_a10_fpll_remove(rx_os_device_clk_pll);
#endif
#elif !defined(ZU11EG) && !defined(FMCOMMS8_ZCU102)
#ifndef ADRV9008_1
axi_clkgen_remove(rx_os_clkgen);
axi_clkgen_remove(tx_clkgen);
#endif
#ifndef ADRV9008_2
axi_clkgen_remove(rx_clkgen);
#endif
#endif
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
hmc7044_remove(clkchip_device);
#else
ad9528_remove(clkchip_device);
#endif
}
/***************************************************************************//**
* @file app_transceiver.c
* @brief FPGA XCVR setup and initialization routines.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
// stdlibs
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// platform drivers
#include "no_os_error.h"
#include "no_os_util.h"
// xcvr
#ifdef ALTERA_PLATFORM
#include "altera_adxcvr.h"
#else
#include "axi_adxcvr.h"
#endif
// hal
#include "parameters.h"
#include "adi_hal.h"
// header
#include "app_jesd.h"
static struct adxcvr *rx_adxcvr;
static struct adxcvr *tx_adxcvr;
static struct adxcvr *rx_os_adxcvr;
adiHalErr_t fpga_xcvr_init(uint32_t rx_lane_rate_khz,
uint32_t tx_lane_rate_khz,
uint32_t rx_os_lane_rate_khz,
uint32_t device_clock)
{
int32_t status;
#ifdef ALTERA_PLATFORM
struct adxcvr_init rx_adxcvr_init = {
"rx_adxcvr",
RX_XCVR_BASEADDR,
{RX_ADXCFG_0_BASEADDR, RX_ADXCFG_1_BASEADDR, 0, 0},
0,
rx_lane_rate_khz,
device_clock,
};
struct adxcvr_init tx_adxcvr_init = {
"tx_adxcvr",
TX_XCVR_BASEADDR,
{TX_ADXCFG_0_BASEADDR, TX_ADXCFG_1_BASEADDR, TX_ADXCFG_2_BASEADDR, TX_ADXCFG_3_BASEADDR},
TX_PLL_BASEADDR,
tx_lane_rate_khz,
device_clock,
};
struct adxcvr_init rx_os_adxcvr_init = {
"rx_os_adxcvr",
RX_OS_XCVR_BASEADDR,
{RX_OS_ADXCFG_0_BASEADDR, RX_OS_ADXCFG_1_BASEADDR, 0, 0},
0,
rx_os_lane_rate_khz,
device_clock,
};
#else
struct adxcvr_init rx_adxcvr_init = {
.name = "rx_adxcvr",
.base = RX_XCVR_BASEADDR,
.sys_clk_sel = ADXCVR_SYS_CLK_QPLL0,//ADXCVR_SYS_CLK_CPLL
.out_clk_sel = ADXCVR_REFCLK,
.lpm_enable = 1,
.lane_rate_khz = rx_lane_rate_khz,
.ref_rate_khz = device_clock,
};
struct adxcvr_init tx_adxcvr_init = {
.name = "tx_adxcvr",
.base = TX_XCVR_BASEADDR,
.sys_clk_sel = ADXCVR_SYS_CLK_QPLL0,
.out_clk_sel = ADXCVR_REFCLK,
.lpm_enable = 0,
.lane_rate_khz = tx_lane_rate_khz,
.ref_rate_khz = device_clock,
};
struct adxcvr_init rx_os_adxcvr_init = {
.name = "rx_os_adxcvr",
.base = RX_OS_XCVR_BASEADDR,
.sys_clk_sel = ADXCVR_SYS_CLK_CPLL,
.out_clk_sel = ADXCVR_REFCLK,
.lpm_enable = 1,
.lane_rate_khz = rx_os_lane_rate_khz,
.ref_rate_khz = device_clock,
};
#endif
/* Initialize ADXCR */
#ifndef ADRV9008_2
status = adxcvr_init(&rx_adxcvr, &rx_adxcvr_init);
if (status != 0) {
printf("error: %s: adxcvr_init() failed\n", rx_adxcvr_init.name);
goto error_0;
}
else {
printf ("adxcvr init successful : rx_adxcvr\n");
}
#endif
#ifndef ADRV9008_1
status = adxcvr_init(&tx_adxcvr, &tx_adxcvr_init);
if (status != 0) {
printf("error: %s: adxcvr_init() failed\n", tx_adxcvr_init.name);
goto error_8;
}
else {
printf ("adxcvr init successful : tx_adxcvr\n");
}
status = adxcvr_init(&rx_os_adxcvr, &rx_os_adxcvr_init);
if (status != 0) {
printf("error: %s: adxcvr_init() failed\n", rx_os_adxcvr_init.name);
goto error_9;
}
else {
printf ("adxcvr init successful : rx_os_adxcvr\n");
}
#endif
#ifndef ALTERA_PLATFORM
#ifndef ADRV9008_2
status = adxcvr_clk_enable(rx_adxcvr);
if (status != 0) {
printf("error: %s: adxcvr_clk_enable() failed\n", rx_adxcvr->name);
printf("error status : %d\n", status);
goto error_10;
}
#endif
#ifndef ADRV9008_1
status = adxcvr_clk_enable(tx_adxcvr);
if (status != 0) {
printf("error: %s: adxcvr_clk_enable() failed\n", tx_adxcvr->name);
goto error_10;
}
status = adxcvr_clk_enable(rx_os_adxcvr);
if (status != 0) {
printf("error: %s: adxcvr_clk_enable() failed\n", rx_os_adxcvr->name);
goto error_10;
}
#endif
#endif
return ADIHAL_OK;
#ifndef ALTERA_PLATFORM
error_10:
#ifndef ADRV9008_1
adxcvr_remove(rx_os_adxcvr);
#endif
#endif
error_9:
#ifndef ADRV9008_1
adxcvr_remove(tx_adxcvr);
#endif
error_8:
#ifndef ADRV9008_2
adxcvr_remove(rx_adxcvr);
#endif
error_0:
return ADIHAL_ERR;
}
void fpga_xcvr_deinit(void)
{
#ifndef ADRV9008_1
adxcvr_remove(rx_os_adxcvr);
adxcvr_remove(tx_adxcvr);
#endif
#ifndef ADRV9008_1
adxcvr_remove(rx_adxcvr);
#endif
}
/***************************************************************************//**
* @file axi_adxcvr.c
* @brief Driver for the ADI AXI-ADXCVR Module.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2018(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include "no_os_axi_io.h"
#include "no_os_util.h"
#include "no_os_error.h"
#include "no_os_delay.h"
#include "xilinx_transceiver.h"
#include "axi_adxcvr.h"
#include "no_os_print_log.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define ADXCVR_REG_RESETN 0x0010
#define ADXCVR_RESETN (1 << 0)
#define ADXCVR_BUFSTATUS_RST NO_OS_BIT(1)
#define ADXCVR_REG_STATUS 0x0014
#define ADXCVR_STATUS (1 << 0)
#define ADXCVR_BUFSTATUS_UNDERFLOW NO_OS_BIT(5)
#define ADXCVR_BUFSTATUS_OVERFLOW NO_OS_BIT(6)
#define ADXCVR_REG_CONTROL 0x0020
#define ADXCVR_LPM_DFE_N (1 << 12)
#define ADXCVR_RATE(x) (((x) & 0x7) << 8)
#define ADXCVR_SYSCLK_SEL(x) (((x) & 0x3) << 4)
#define ADXCVR_OUTCLK_SEL(x) (((x) & 0x7) << 0)
#define ADXCVR_REG_SYNTH 0x24
#define ADXCVR_REG_DRP_SEL(x) (0x0040 + (x))
#define ADXCVR_REG_DRP_CTRL(x) (0x0044 + (x))
#define ADXCVR_DRP_CTRL_WR (1 << 28)
#define ADXCVR_DRP_CTRL_ADDR(x) (((x) & 0xFFF) << 16)
#define ADXCVR_DRP_CTRL_WDATA(x) (((x) & 0xFFFF) << 0)
#define ADXCVR_REG_DRP_STATUS(x) (0x0048 + (x))
#define ADXCVR_DRP_STATUS_BUSY (1 << 16)
#define ADXCVR_DRP_STATUS_RDATA(x) (((x) & 0xFFFF) << 0)
#define ADXCVR_DRP_PORT_ADDR_COMMON 0x00
#define ADXCVR_DRP_PORT_ADDR_CHANNEL 0x20
#define ADXCVR_DRP_PORT_COMMON(x) (x)
#define ADXCVR_DRP_PORT_CHANNEL(x) (0x100 + (x))
#define ADXCVR_BROADCAST 0xff
#define ADI_AXI_PCORE_VER(major, minor, patch) \
(((major) << 16) | ((minor) << 8) | (patch))
static const char *const adxcvr_sys_clock_sel_names[] = {
"CPLL", "UNDEF", "QPLL1", "QPLL"
};
/**
* @brief AXI ADXCVR Write
* @param xcvr - Device Structure.
* @param reg_addr - The register address.
* @param reg_val - Data value to write.
* @return Returns 0 in case of success or negative error code otherwise.
*/
int32_t adxcvr_write(struct adxcvr *xcvr,
uint32_t reg_addr,
uint32_t reg_val)
{
no_os_axi_io_write(xcvr->base, reg_addr, reg_val);
return 0;
}
/**
* @brief AXI ADXCVR Read
* @param xcvr - Device Structure.
* @param reg_addr - The register address.
* @param reg_val - Data read from the device.
* @return Returns 0 in case of success or negative error code otherwise.
*/
int32_t adxcvr_read(struct adxcvr *xcvr,
uint32_t reg_addr,
uint32_t *reg_val)
{
no_os_axi_io_read(xcvr->base, reg_addr, reg_val);
return 0;
}
/**
* @brief Read AXI ADXCVR DRP status
* @param xcvr - Device Structure.
* @param drp_addr - DRP Port address.
* @return Returns status in case of success or negative error code otherwise.
*/
int32_t adxcvr_drp_wait_idle(struct adxcvr *xcvr,
uint32_t drp_addr)
{
uint32_t val;
int32_t timeout = 20;
do {
adxcvr_read(xcvr, ADXCVR_REG_DRP_STATUS(drp_addr), &val);
if (!(val & ADXCVR_DRP_STATUS_BUSY))
return ADXCVR_DRP_STATUS_RDATA(val);
no_os_mdelay(1);
} while (timeout--);
printf("%s: %s: Timeout!", xcvr->name, __func__);
return -1;
}
/**
* @brief AXI ADXCVR DPR Port Read
* @param xcvr - The device structure.
* @param drp_port - The DRP Port.
* @param reg - DRP Register address.
* @param val - Data read.
* @return Returns 0 in case of success or negative error code otherwise.
*/
int adxcvr_drp_read(struct adxcvr *xcvr,
unsigned int drp_port,
unsigned int reg,
unsigned int *val)
{
uint32_t drp_sel, drp_addr;
int32_t ret;
if (drp_port < ADXCVR_DRP_PORT_CHANNEL(0))
drp_addr = ADXCVR_DRP_PORT_ADDR_COMMON;
else
drp_addr = ADXCVR_DRP_PORT_ADDR_CHANNEL;
drp_sel = drp_port & 0xFF;
adxcvr_write(xcvr, ADXCVR_REG_DRP_SEL(drp_addr), drp_sel);
adxcvr_write(xcvr, ADXCVR_REG_DRP_CTRL(drp_addr), ADXCVR_DRP_CTRL_ADDR(reg));
ret = adxcvr_drp_wait_idle(xcvr, drp_addr);
if (ret < 0)
return ret;
*val = ret & 0xffff;
return 0;
}
/**
* @brief AXI ADXCVR DPR Port Write
* @param xcvr - The device structure.
* @param drp_port - The DRP Port.
* @param reg - DRP Register address.
* @param val - Data to be written.
* @return Returns 0 in case of success or negative error code otherwise.
*/
int adxcvr_drp_write(struct adxcvr *xcvr,
unsigned int drp_port,
unsigned int reg,
unsigned int val)
{
uint32_t drp_sel, drp_addr;
int32_t ret;
if (drp_port < ADXCVR_DRP_PORT_CHANNEL(0))
drp_addr = ADXCVR_DRP_PORT_ADDR_COMMON;
else
drp_addr = ADXCVR_DRP_PORT_ADDR_CHANNEL;
drp_sel = drp_port & 0xFF;
adxcvr_write(xcvr, ADXCVR_REG_DRP_SEL(drp_addr), drp_sel);
adxcvr_write(xcvr, ADXCVR_REG_DRP_CTRL(drp_addr), (ADXCVR_DRP_CTRL_WR |
ADXCVR_DRP_CTRL_ADDR(reg) | ADXCVR_DRP_CTRL_WDATA(val)));
ret = adxcvr_drp_wait_idle(xcvr, drp_addr);
if (ret < 0)
return ret;
return 0;
}
static const struct xilinx_xcvr_drp_ops adxcvr_drp_ops = {
.read = adxcvr_drp_read,
.write = adxcvr_drp_write,
};
static unsigned long adxcvr_clk_recalc_rate(struct adxcvr *xcvr,
unsigned long parent_rate)
{
unsigned int *rx_out_div;
unsigned int *tx_out_div;
unsigned int out_div;
pr_debug("%s: Parent Rate %lu Hz", __func__, parent_rate);
if (xcvr->tx_enable) {
rx_out_div = NULL;
tx_out_div = &out_div;
} else {
rx_out_div = &out_div;
tx_out_div = NULL;
}
xilinx_xcvr_read_out_div(&xcvr->xlx_xcvr, ADXCVR_DRP_PORT_CHANNEL(0),
rx_out_div, tx_out_div);
if (xcvr->cpll_enable) {
struct xilinx_xcvr_cpll_config cpll_conf;
xilinx_xcvr_cpll_read_config(&xcvr->xlx_xcvr, ADXCVR_DRP_PORT_CHANNEL(0),
&cpll_conf);
return xilinx_xcvr_cpll_calc_lane_rate(&xcvr->xlx_xcvr, parent_rate,
&cpll_conf, out_div);
} else {
struct xilinx_xcvr_qpll_config qpll_conf;
if (!xcvr->qpll_enable)
return xcvr->lane_rate_khz;
xilinx_xcvr_qpll_read_config(&xcvr->xlx_xcvr, xcvr->sys_clk_sel,
ADXCVR_DRP_PORT_COMMON(0), &qpll_conf);
return xilinx_xcvr_qpll_calc_lane_rate(&xcvr->xlx_xcvr,
xcvr->sys_clk_sel, &qpll_conf, out_div);
}
}
static long adxcvr_clk_round_rate(struct adxcvr *xcvr,
unsigned long rate,
unsigned long *prate)
{
int ret;
if (xcvr->ref_rate_khz % 40 == 0)
*prate = rate * (1000 / 40);
pr_debug("%s: Rate %lu kHz Parent Rate %lu Hz",
__func__, rate, *prate);
/* Just check if we can support the requested rate */
if (xcvr->cpll_enable)
ret = xilinx_xcvr_calc_cpll_config(&xcvr->xlx_xcvr, *prate, rate,
NULL, NULL);
else
ret = xilinx_xcvr_calc_qpll_config(&xcvr->xlx_xcvr,
xcvr->sys_clk_sel, *prate, rate, NULL, NULL);
return ret < 0 ? ret : rate;
}
static const struct clk_ops clkout_ops = {
.recalc_rate = adxcvr_clk_recalc_rate,
.enable = adxcvr_clk_enable,
.disable = adxcvr_clk_disable,
.round_rate = adxcvr_clk_round_rate,
.set_rate = adxcvr_clk_set_rate,
};
static unsigned long adxcvr_qpll_recalc_rate(struct adxcvr *xcvr,
unsigned long parent_rate)
{
struct xilinx_xcvr_qpll_config qpll_conf;
pr_debug("%s: Parent Rate %lu Hz", __func__, parent_rate);
xilinx_xcvr_qpll_read_config(&xcvr->xlx_xcvr,
ADXCVR_DRP_PORT_COMMON(0), xcvr->sys_clk_sel, &qpll_conf);
return xilinx_xcvr_qpll_calc_lane_rate(&xcvr->xlx_xcvr,
parent_rate, &qpll_conf, 1);
}
static const struct clk_ops qpll_ops = {
.recalc_rate = adxcvr_qpll_recalc_rate,
};
/**
* @brief AXI ADXCVR Clock Set Rate
* @param xcvr - The device structure.
* @param rate - The output rate (kHz).
* @param parent_rate - The parent rate (kHz).
* @return Returns 0 in case of success or negative error code otherwise.
*/
int adxcvr_clk_set_rate(struct adxcvr *xcvr,
unsigned long rate,
unsigned long parent_rate)
{
struct xilinx_xcvr_cpll_config cpll_conf;
struct xilinx_xcvr_qpll_config qpll_conf;
uint32_t out_div, clk25_div, prog_div;
uint32_t i;
int ret;
pr_debug("%s: Rate %lu Hz Parent Rate %lu Hz\n",
__func__, rate, parent_rate);
clk25_div = NO_OS_DIV_ROUND_CLOSEST(parent_rate, 25000);
if (xcvr->cpll_enable)
ret = xilinx_xcvr_calc_cpll_config(&xcvr->xlx_xcvr, parent_rate, rate,
&cpll_conf, &out_div);
else
ret = xilinx_xcvr_calc_qpll_config(&xcvr->xlx_xcvr, xcvr->sys_clk_sel,
parent_rate, rate, &qpll_conf, &out_div);
if (ret < 0)
return ret;
for (i = 0; i < xcvr->num_lanes; i++) {
if (xcvr->cpll_enable)
ret = xilinx_xcvr_cpll_write_config(&xcvr->xlx_xcvr,
ADXCVR_DRP_PORT_CHANNEL(i), &cpll_conf);
else if ((i % 4 == 0) && xcvr->qpll_enable)
ret = xilinx_xcvr_qpll_write_config(&xcvr->xlx_xcvr,
xcvr->sys_clk_sel,
ADXCVR_DRP_PORT_COMMON(i), &qpll_conf);
if (ret < 0)
return ret;
ret = xilinx_xcvr_write_out_div(&xcvr->xlx_xcvr,
ADXCVR_DRP_PORT_CHANNEL(i),
xcvr->tx_enable ? -1 : (int32_t)out_div,
xcvr->tx_enable ? (int32_t)out_div : -1);
if (ret < 0)
return ret;
if (xcvr->out_clk_sel == ADXCVR_PROGDIV_CLK) {
unsigned int max_progdiv, div = 1, ratio;
if (xcvr->xlx_xcvr.encoding == ENC_66B64B)
ratio = 66;
else
ratio = 40;
/* Set RX|TX_PROGDIV_RATE = 2 on GTY4 */
ret = xilinx_xcvr_write_prog_div_rate(&xcvr->xlx_xcvr,
ADXCVR_DRP_PORT_CHANNEL(i),
xcvr->tx_enable ? -1 : 2,
xcvr->tx_enable ? 2 : -1);
if (!ret)
div = 2;
switch (xcvr->xlx_xcvr.type) {
case XILINX_XCVR_TYPE_US_GTH3:
max_progdiv = 100;
/* This is done in the FPGA fabric */
if (xcvr->xlx_xcvr.encoding == ENC_66B64B)
div = 2;
break;
case XILINX_XCVR_TYPE_US_GTH4:
max_progdiv = 132;
/* This is done in the FPGA fabric */
if (xcvr->xlx_xcvr.encoding == ENC_66B64B)
div = 2;
break;
case XILINX_XCVR_TYPE_US_GTY4:
max_progdiv = 100;
break;
default:
return -EINVAL;
}
prog_div = NO_OS_DIV_ROUND_CLOSEST(ratio * out_div, 2 * div);
if (prog_div > max_progdiv) {
prog_div = 0; /* disabled */
pr_info("%s: No PROGDIV divider found for OUTDIV=%lu, disabling output!\n",
__func__, out_div);
}
ret = xilinx_xcvr_write_prog_div(&xcvr->xlx_xcvr,
ADXCVR_DRP_PORT_CHANNEL(i),
xcvr->tx_enable ? -1 : (int32_t)prog_div,
xcvr->tx_enable ? (int32_t)prog_div : -1);
if (ret < 0)
return ret;
}
if (!xcvr->tx_enable) {
ret = xilinx_xcvr_configure_cdr(&xcvr->xlx_xcvr,
ADXCVR_DRP_PORT_CHANNEL(i), rate, out_div,
xcvr->lpm_enable);
if (ret < 0)
return ret;
ret = xilinx_xcvr_write_rx_clk25_div(&xcvr->xlx_xcvr,
ADXCVR_DRP_PORT_CHANNEL(i), clk25_div);
} else {
ret = xilinx_xcvr_write_tx_clk25_div(&xcvr->xlx_xcvr,
ADXCVR_DRP_PORT_CHANNEL(i), clk25_div);
}
if (ret < 0)
return ret;
}
xcvr->lane_rate_khz = rate;
return 0;
}
/**
* @brief AXI ADXCVR Status Read
* @param xcvr - The device structure.
* @return Returns 0 in case of success or negative error code otherwise.
*/
int32_t adxcvr_status_error(struct adxcvr *xcvr)
{
int32_t timeout = 100;
uint32_t status;
do {
no_os_mdelay(1);
//printf("Starting ADXCVR Status Error function\n");
adxcvr_read(xcvr, ADXCVR_REG_STATUS, &status); //<-----nm
} while ((timeout--) && !(status & ADXCVR_STATUS));
if (!status)
printf("adxcvr status error = 0\n");
return -1;
printf("%s: OK (%"PRId32" kHz)\n", xcvr->name, xcvr->lane_rate_khz);
return 0;
}
/**
* @brief AXI ADXCVR Reset
* @param xcvr - The device structure.
* @return Returns 0 in case of success or negative error code otherwise.
*/
static int adxcvr_reset(struct adxcvr *xcvr)
{
int ret = -1, retry = 1;
do {
adxcvr_write(xcvr, ADXCVR_REG_RESETN, 0);
no_os_udelay(2);
adxcvr_write(xcvr, ADXCVR_REG_RESETN, ADXCVR_RESETN);
pr_debug("%s: %s %s Reset\n",
__func__,
adxcvr_sys_clock_sel_names[xcvr->sys_clk_sel],
xcvr->tx_enable ? "TX" : "RX");
ret = adxcvr_status_error(xcvr);
} while (ret < 0 && retry--);
return ret;
}
/**
* @brief AXI ADXCVR Clock Enable
* @param xcvr - The device structure.
* @return Returns 0 in case of success or negative error code otherwise.
*/
int adxcvr_clk_enable(struct adxcvr *xcvr)
{
int ret, retry = 10;
unsigned int status;
int bufstatus_err;
pr_debug("%s: %s\n", __func__, xcvr->tx_enable ? "TX" : "RX");
printf("starting adxcvr reset\n");
ret = adxcvr_reset(xcvr);
if (ret < 0){
printf("adxcvr reset error\n");
return ret;
}
printf("adxcvr reset completed\n");
if (xcvr->xlx_xcvr.version >= ADI_AXI_PCORE_VER(17, 5, 'a')) {
do {
adxcvr_write(xcvr, ADXCVR_REG_RESETN, ADXCVR_BUFSTATUS_RST | ADXCVR_RESETN);
adxcvr_write(xcvr, ADXCVR_REG_RESETN, ADXCVR_RESETN);
no_os_mdelay(1);
adxcvr_read(xcvr, ADXCVR_REG_STATUS, &status);
bufstatus_err = ((status & ADXCVR_BUFSTATUS_UNDERFLOW)
|| (status & ADXCVR_BUFSTATUS_OVERFLOW));
if (bufstatus_err) {
ret = adxcvr_reset(xcvr);
if (ret < 0){
printf("buffer status error\n");
return ret;
}
}
} while (bufstatus_err && retry--);
if (status & ADXCVR_BUFSTATUS_UNDERFLOW)
pr_err("%s: %s %s %s error, status: 0x%x\n",
__func__,
adxcvr_sys_clock_sel_names[xcvr->sys_clk_sel],
xcvr->tx_enable ? "TX" : "RX",
"buffer underflow", status);
if (status & ADXCVR_BUFSTATUS_OVERFLOW)
pr_err("%s: %s %s %s error, status: 0x%x\n",
__func__,
adxcvr_sys_clock_sel_names[xcvr->sys_clk_sel],
xcvr->tx_enable ? "TX" : "RX",
"buffer overflow", status);
}
return ret;
}
/**
* @brief AXI ADXCVR Clock Disable
* @param xcvr - The device structure.
* @return Returns 0 in case of success or negative error code otherwise.
*/
int adxcvr_clk_disable(struct adxcvr *xcvr)
{
pr_debug("%s: %s", __func__, xcvr->tx_enable ? "TX" : "RX");
adxcvr_write(xcvr, ADXCVR_REG_RESETN, 0);
return 0;
}
/**
* @brief AXI ADXCVR Get Information
* @param xcvr - The device structure.
*/
static void adxcvr_get_info(struct adxcvr *xcvr)
{
uint32_t reg_value;
adxcvr_read(xcvr, AXI_REG_FPGA_INFO, ®_value);
xcvr->xlx_xcvr.tech = AXI_INFO_FPGA_TECH(reg_value);
xcvr->xlx_xcvr.family = AXI_INFO_FPGA_FAMILY(reg_value);
xcvr->xlx_xcvr.speed_grade = AXI_INFO_FPGA_SPEED_GRADE(reg_value);
xcvr->xlx_xcvr.dev_package = AXI_INFO_FPGA_DEV_PACKAGE(reg_value);
adxcvr_read(xcvr, AXI_REG_FPGA_VOLTAGE, ®_value);
xcvr->xlx_xcvr.voltage = AXI_INFO_FPGA_VOLTAGE(reg_value);
}
/**
* @brief AXI ADXCVR Device Initialization
* @param ad_xcvr - The device structure.
* @param init - The structure containing the device initial parameters.
* @return Returns 0 in case of success or negative error code otherwise.
*/
int32_t adxcvr_init(struct adxcvr **ad_xcvr,
const struct adxcvr_init *init)
{
struct adxcvr *xcvr;
uint32_t synth_conf, xcvr_type;
uint32_t i;
int32_t ret;
xcvr = (struct adxcvr *)calloc(1, sizeof(*xcvr));
if (!xcvr)
return -1;
printf("XCVR identified.\n");
xcvr->base = init->base;
xcvr->name = init->name;
xcvr->sys_clk_sel = init->sys_clk_sel;
xcvr->out_clk_sel = init->out_clk_sel;
if (init->sys_clk_sel == ADXCVR_SYS_CLK_CPLL)
xcvr->cpll_enable = 1;
else
xcvr->cpll_enable = 0;
xcvr->lpm_enable = init->lpm_enable;
xcvr->lane_rate_khz = init->lane_rate_khz;
xcvr->ref_rate_khz = init->ref_rate_khz;
adxcvr_read(xcvr, ADXCVR_REG_SYNTH, &synth_conf);
xcvr->tx_enable = (synth_conf >> 8) & 1;
xcvr->num_lanes = synth_conf & 0xff;
xcvr->qpll_enable = (synth_conf >> 20) & 1;
if ((!xcvr->qpll_enable) && (init->sys_clk_sel != ADXCVR_SYS_CLK_CPLL))
pr_info("%s: Using QPLL with previously defined settings.\n", xcvr->name);
xcvr_type = (synth_conf >> 16) & 0xf;
adxcvr_read(xcvr, AXI_REG_VERSION, &xcvr->xlx_xcvr.version);
if (AXI_PCORE_VER_MAJOR(xcvr->xlx_xcvr.version) > 0x10)
adxcvr_get_info(xcvr);
/* Ensure compliance with legacy xcvr type */
if (AXI_PCORE_VER_MAJOR(xcvr->xlx_xcvr.version) <= 0x10) {
switch (xcvr_type) {
case XILINX_XCVR_LEGACY_TYPE_S7_GTX2:
xcvr->xlx_xcvr.type = XILINX_XCVR_TYPE_S7_GTX2;
break;
case XILINX_XCVR_LEGACY_TYPE_US_GTH3:
xcvr->xlx_xcvr.type = XILINX_XCVR_TYPE_US_GTH3;
break;
case XILINX_XCVR_LEGACY_TYPE_US_GTH4:
xcvr->xlx_xcvr.type = XILINX_XCVR_TYPE_US_GTH4;
break;
case XILINX_XCVR_LEGACY_TYPE_US_GTY4:
xcvr->xlx_xcvr.type = XILINX_XCVR_TYPE_US_GTY4;
break;
default:
goto err;
}
} else
xcvr->xlx_xcvr.type = xcvr_type;
switch (xcvr->xlx_xcvr.type) {
case XILINX_XCVR_TYPE_S7_GTX2:
case XILINX_XCVR_TYPE_US_GTH3:
case XILINX_XCVR_TYPE_US_GTH4:
case XILINX_XCVR_TYPE_US_GTY4:
break;
default:
printf("Unknown transceiver type: %d\n", xcvr->xlx_xcvr.type);
goto err;
}
xcvr->xlx_xcvr.encoding = ENC_8B10B;
xcvr->xlx_xcvr.refclk_ppm = PM_200; /* TODO use clock accuracy */
adxcvr_write(xcvr, ADXCVR_REG_RESETN, 0);
adxcvr_write(xcvr, ADXCVR_REG_CONTROL,
((xcvr->lpm_enable ? ADXCVR_LPM_DFE_N : 0) |
ADXCVR_SYSCLK_SEL(xcvr->sys_clk_sel) |
ADXCVR_OUTCLK_SEL(xcvr->out_clk_sel)));
xcvr->xlx_xcvr.ad_xcvr = xcvr;
if (!xcvr->tx_enable) {
for (i = 0; i < xcvr->num_lanes; i++) {
xilinx_xcvr_configure_lpm_dfe_mode(&xcvr->xlx_xcvr,
ADXCVR_DRP_PORT_CHANNEL(i),
xcvr->lpm_enable);
}
}
if (xcvr->lane_rate_khz && xcvr->ref_rate_khz) {
ret = adxcvr_clk_set_rate(xcvr, xcvr->lane_rate_khz, xcvr->ref_rate_khz);
if (ret)
goto err;
}
*ad_xcvr = xcvr;
return 0;
err:
free(xcvr);
return -1;
}
/**
* @brief Free resoulces allocated for AXI_ADXCVR
* @param xcvr - The device structure.
* @return Returns 0 in case of success or negative error code.
*/
int32_t adxcvr_remove(struct adxcvr *xcvr)
{
free(xcvr);
return 0;
}
/***************************************************************************//**
* @file hmc7044.c
* @brief Implementation of HMC7044, HMC7043 Driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2018-2020(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include "no_os_error.h"
#include "no_os_util.h"
#include "hmc7044.h"
/******************************************************************************/
/********************** Macros and Constants Definitions **********************/
/******************************************************************************/
#define HMC7044_WRITE (0 << 15)
#define HMC7044_READ (1 << 15)
#define HMC7044_CNT(x) (((x) - 1) << 13)
#define HMC7044_ADDR(x) ((x) & 0xFFF)
/* Global Control */
#define HMC7044_REG_SOFT_RESET 0x0000
#define HMC7044_SOFT_RESET NO_OS_BIT(0)
#define HMC7044_REG_REQ_MODE_0 0x0001
#define HMC7044_RESEED_REQ NO_OS_BIT(7)
#define HMC7044_HIGH_PERF_DISTRIB_PATH NO_OS_BIT(6)
#define HMC7044_HIGH_PERF_PLL_VCO NO_OS_BIT(5)
#define HMC7044_FORCE_HOLDOVER NO_OS_BIT(4)
#define HMC7044_MUTE_OUT_DIV NO_OS_BIT(3)
#define HMC7044_PULSE_GEN_REQ NO_OS_BIT(2)
#define HMC7044_RESTART_DIV_FSM NO_OS_BIT(1)
#define HMC7044_SLEEP_MODE NO_OS_BIT(0)
#define HMC7044_REG_REQ_MODE_1 0x0002
#define HMC7044_PLL2_AUTOTUNE_TRIG NO_OS_BIT(2)
#define HMC7044_SLIP_REQ NO_OS_BIT(1)
#define HMC7044_REG_EN_CTRL_0 0x0003
#define HMC7044_RF_RESEEDER_EN NO_OS_BIT(5)
#define HMC7044_VCO_SEL(x) (((x) & 0x3) << 3)
#define HMC7044_VCO_EXT 0
#define HMC7044_VCO_HIGH 1
#define HMC7044_VCO_LOW 2
#define HMC7044_SYSREF_TIMER_EN NO_OS_BIT(2)
#define HMC7044_PLL2_EN NO_OS_BIT(1)
#define HMC7044_PLL1_EN NO_OS_BIT(0)
#define HMC7044_REG_EN_CTRL_1 0x0004
#define HMC7044_SEVEN_PAIRS(x) ((x) & 0x7f)
#define HMC7044_REG_GLOB_MODE 0x0005
#define HMC7044_REF_PATH_EN(x) ((x) & 0xf)
#define HMC7044_RFSYNC_EN NO_OS_BIT(4)
#define HMC7044_VCOIN_MODE_EN NO_OS_BIT(5)
#define HMC7044_SYNC_PIN_MODE(x) (((x) & 0x3) << 6)
/* PLL1 */
#define HMC7044_REG_CLKIN0_BUF_CTRL 0x000A
#define HMC7044_REG_CLKIN1_BUF_CTRL 0x000B
#define HMC7044_REG_CLKIN2_BUF_CTRL 0x000C
#define HMC7044_REG_CLKIN3_BUF_CTRL 0x000D
#define HMC7044_REG_OSCIN_BUF_CTRL 0x000E
#define HMC7044_REG_PLL1_REF_PRIO_CTRL 0x0014
#define HMC7044_HIGH_Z_EN NO_OS_BIT(4)
#define HMC7044_LVPECL_EN NO_OS_BIT(3)
#define HMC7044_AC_COUPLING_EN NO_OS_BIT(2)
#define HMC7044_100_OHM_EN NO_OS_BIT(1)
#define HMC7044_BUF_EN NO_OS_BIT(0)
#define HMC7044_REG_CLKIN_PRESCALER(x) (0x001C + (x))
#define HMC7044_REG_OSCIN_PRESCALER 0x0020
#define HMC7044_REG_PLL1_R_LSB 0x0021
#define HMC7044_R1_LSB(x) ((x) & 0xff)
#define HMC7044_REG_PLL1_R_MSB 0x0022
#define HMC7044_R1_MSB(x) (((x) & 0xff00) >> 8)
#define HMC7044_REG_PLL1_N_LSB 0x0026
#define HMC7044_N1_LSB(x) ((x) & 0xff)
#define HMC7044_REG_PLL1_N_MSB 0x0027
#define HMC7044_N1_MSB(x) (((x) & 0xff00) >> 8)
#define HMC7044_REG_PLL1_LOCK_DETECT 0x0028
#define HMC7044_LOCK_DETECT_SLIP NO_OS_BIT(5)
#define HMC7044_LOCK_DETECT_TIMER(x) ((x) & 0x1f)
/* PLL2 */
#define HMC7044_REG_PLL2_FREQ_DOUBLER 0x0032
#define HMC7044_PLL2_FREQ_DOUBLER_DIS NO_OS_BIT(0)
#define HMC7044_REG_PLL2_R_LSB 0x0033
#define HMC7044_R2_LSB(x) ((x) & 0xff)
#define HMC7044_REG_PLL2_R_MSB 0x0034
#define HMC7044_R2_MSB(x) (((x) & 0xf00) >> 8)
#define HMC7044_REG_PLL2_N_LSB 0x0035
#define HMC7044_N2_LSB(x) ((x) & 0xff)
#define HMC7044_REG_PLL2_N_MSB 0x0036
#define HMC7044_N2_MSB(x) (((x) & 0xff00) >> 8)
#define HMC7044_REG_OSCOUT_PATH 0x0039
#define HMC7044_REG_OSCOUT_DRIVER_0 0x003A
#define HMC7044_REG_OSCOUT_DRIVER_1 0x003B
/* GPIO/SDATA Control */
#define HMC7044_REG_GPI_CTRL(x) (0x0046 + (x))
#define HMC7044_REG_GPI_SEL(x) ((x) & 0xf)
#define HMC7044_REG_GPO_CTRL(x) (0x0050 + (x))
#define HMC7044_GPO_SEL(x) (((x) & 0x3f) << 2)
#define HMC7044_GPO_MODE NO_OS_BIT(1)
#define HMC7044_GPO_EN NO_OS_BIT(0)
/* SYSREF/SYNC Control */
#define HMC7044_REG_PULSE_GEN 0x005A
#define HMC7044_PULSE_GEN_MODE(x) ((x) & 0x7)
#define HMC7044_REG_SYNC 0x005B
#define HMC7044_SYNC_RETIME NO_OS_BIT(2)
#define HMC7044_SYNC_THROUGH_PLL2 NO_OS_BIT(1)
#define HMC7044_SYNC_POLARITY NO_OS_BIT(0)
#define HMC7044_REG_SYSREF_TIMER_LSB 0x005C
#define HMC7044_SYSREF_TIMER_LSB(x) ((x) & 0xff)
#define HMC7044_REG_SYSREF_TIMER_MSB 0x005D
#define HMC7044_SYSREF_TIMER_MSB(x) (((x) & 0xf00) >> 8)
#define HMC7044_CLK_INPUT_CTRL 0x0064
#define HMC7044_LOW_FREQ_INPUT_MODE NO_OS_BIT(0)
#define HMC7044_DIV_2_INPUT_MODE NO_OS_BIT(1)
/* Status and Alarm readback */
#define HMC7044_REG_ALARM_READBACK 0x007D
#define HMC7044_REG_PLL1_STATUS 0x0082
#define HMC7044_PLL1_FSM_STATE(x) ((x) & 0x7)
#define HMC7044_PLL1_ACTIVE_CLKIN(x) (((x) >> 3) & 0x3)
#define HMC7044_PLL2_LOCK_DETECT(x) ((x) & 0x1)
#define HMC7044_SYSREF_SYNC_STAT(x) ((x) & 0x2)
#define HMC7044_CLK_OUT_PH_STATUS(x) ((x) & 0x4)
#define HMC7044_PLL1_PLL2_LOCK_STAT(x) ((x) & 0x8)
#define HMC7044_SYNC_REQ_STATUS(x) ((x) & 0x10)
/* Other Controls */
#define HMC7044_REG_CLK_OUT_DRV_LOW_PW 0x009F
#define HMC7044_REG_CLK_OUT_DRV_HIGH_PW 0x00A0
#define HMC7044_REG_PLL1_DELAY 0x00A5
#define HMC7044_REG_PLL1_HOLDOVER 0x00A8
#define HMC7044_REG_VTUNE_PRESET 0x00B0
/* Clock Distribution */
#define HMC7044_REG_CH_OUT_CRTL_0(ch) (0x00C8 + 0xA * (ch))
#define HMC7044_HI_PERF_MODE NO_OS_BIT(7)
#define HMC7044_SYNC_EN NO_OS_BIT(6)
#define HMC7044_CH_EN NO_OS_BIT(0)
#define HMC7044_START_UP_MODE_DYN_EN (NO_OS_BIT(3) | NO_OS_BIT(2))
#define HMC7044_REG_CH_OUT_CRTL_1(ch) (0x00C9 + 0xA * (ch))
#define HMC7044_DIV_LSB(x) ((x) & 0xFF)
#define HMC7044_REG_CH_OUT_CRTL_2(ch) (0x00CA + 0xA * (ch))
#define HMC7044_DIV_MSB(x) (((x) >> 8) & 0xFF)
#define HMC7044_REG_CH_OUT_CRTL_3(ch) (0x00CB + 0xA * (ch))
#define HMC7044_REG_CH_OUT_CRTL_4(ch) (0x00CC + 0xA * (ch))
#define HMC7044_REG_CH_OUT_CRTL_5(ch) (0x00CD + 0xA * (ch))
#define HMC7044_REG_CH_OUT_CRTL_6(ch) (0x00CE + 0xA * (ch))
#define HMC7044_REG_CH_OUT_CRTL_7(ch) (0x00CF + 0xA * (ch))
#define HMC7044_REG_CH_OUT_CRTL_8(ch) (0x00D0 + 0xA * (ch))
#define HMC7044_DRIVER_MODE(x) (((x) & 0x3) << 3)
#define HMC7044_DRIVER_Z_MODE(x) (((x) & 0x3) << 0)
#define HMC7044_DYN_DRIVER_EN NO_OS_BIT(5)
#define HMC7044_FORCE_MUTE_EN NO_OS_BIT(7)
#define HMC7044_NUM_CHAN 14
#define HMC7044_LOW_VCO_MIN 2150000
#define HMC7044_LOW_VCO_MAX 2880000
#define HMC7044_HIGH_VCO_MIN 2650000
#define HMC7044_HIGH_VCO_MAX 3200000
#define HMC7044_RECOMM_LCM_MIN 30000
#define HMC7044_RECOMM_LCM_MAX 70000
#define HMC7044_RECOMM_FPD1 10000
#define HMC7044_R1_MAX 65535
#define HMC7044_N1_MAX 65535
#define HMC7044_R2_MIN 1
#define HMC7044_R2_MAX 4095
#define HMC7044_N2_MIN 8
#define HMC7044_N2_MAX 65535
#define HMC7044_OUT_DIV_MIN 1
#define HMC7044_OUT_DIV_MAX 4094
/******************************************************************************/
/************************** Functions Implementation **************************/
/******************************************************************************/
/**
* SPI register write to device.
* @param dev - The device structure.
* @param reg - The register address.
* @param val - The register data.
* @return 0 in case of success, negative error code otherwise.
*/
static int hmc7044_write(struct hmc7044_dev *dev,
uint16_t reg,
uint8_t val)
{
uint8_t buf[3];
uint16_t cmd;
cmd = HMC7044_WRITE | HMC7044_CNT(1) | HMC7044_ADDR(reg);
buf[0] = cmd >> 8;
buf[1] = cmd & 0xFF;
buf[2] = val;
return no_os_spi_write_and_read(dev->spi_desc, buf, NO_OS_ARRAY_SIZE(buf));
}
/**
* SPI register read from device.
* @param dev - The device structure.
* @param reg - The register address.
* @param val - The register data.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t hmc7044_read(struct hmc7044_dev *dev, uint16_t reg, uint8_t *val)
{
uint8_t buf[3];
uint16_t cmd;
int ret;
cmd = HMC7044_READ | HMC7044_CNT(1) | HMC7044_ADDR(reg);
buf[0] = cmd >> 8;
buf[1] = cmd & 0xFF;
buf[2] = 0;
ret = no_os_spi_write_and_read(dev->spi_desc, buf, NO_OS_ARRAY_SIZE(buf));
if (ret < 0)
return ret;
*val = buf[2];
return 0;
}
/**
* Calculate the output channel divider.
* @param rate - The desired rate.
* @param parent_rate - The parent rate.
* @return The output divider.
*/
uint32_t hmc7044_calc_out_div(uint32_t rate,
uint32_t parent_rate)
{
uint32_t div;
div = NO_OS_DIV_ROUND_CLOSEST(parent_rate, rate);
/* Supported odd divide ratios are 1, 3, and 5 */
if ((div != 1) && (div != 3) && (div != 5) && (div % 2))
div = NO_OS_DIV_ROUND_CLOSEST(parent_rate, rate * 2) * 2;
div = no_os_clamp_t(unsigned int,
div,
HMC7044_OUT_DIV_MIN,
HMC7044_OUT_DIV_MAX);
return div;
}
/**
* Recalculate rate corresponding to a channel.
* @param dev - The device structure.
* @param chan_num - Channel number.
* @param rate - Channel rate.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t hmc7044_clk_recalc_rate(struct hmc7044_dev *dev, uint32_t chan_num,
uint64_t *rate)
{
int i;
struct hmc7044_chan_spec *chan = NULL;
/* Find the reqested channel number */
for (i = 0; i < dev->num_channels; i++) {
if (dev->channels[i].num == chan_num) {
chan = &dev->channels[i];
break;
}
}
if (chan == NULL )
return -1;
*rate = dev->pll2_freq / chan->divider;
return 0;
}
/**
* Calculate closest possible rate
* @param dev - The device structure
* @param rate - The desired rate.
* @param rounded_rate - The closest possible rate of desired rate.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t hmc7044_clk_round_rate(struct hmc7044_dev *dev, uint32_t rate,
uint64_t *rounded_rate)
{
uint32_t div = hmc7044_calc_out_div(rate, dev->pll2_freq);
*rounded_rate = NO_OS_DIV_ROUND_CLOSEST(dev->pll2_freq, div);
return 0;
}
/**
* Set channel rate.
* @param dev - The device structure.
* @param chan_num - Channel number.
* @param rate - Channel rate.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t hmc7044_clk_set_rate(struct hmc7044_dev *dev, uint32_t chan_num,
uint64_t rate)
{
uint32_t div;
int32_t ret;
int i;
struct hmc7044_chan_spec *chan = NULL;
/* Find the reqested channel number */
for (i = 0; i < dev->num_channels; i++) {
if (dev->channels[i].num == chan_num) {
chan = &dev->channels[i];
break;
}
}
if (chan == NULL )
return -1;
div = hmc7044_calc_out_div(rate, dev->pll2_freq);
chan->divider = div;
ret = hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
HMC7044_DIV_LSB(div));
if(ret < 0)
return ret;
return hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
HMC7044_DIV_MSB(div));
}
/**
* Setup the device.
* @param dev - The device structure.
* @return 0 in case of success, negative error code otherwise.
*/
static int32_t hmc7044_setup(struct hmc7044_dev *dev)
{
struct hmc7044_chan_spec *chan;
bool high_vco_en;
bool pll2_freq_doubler_en;
uint32_t vcxo_freq, pll2_freq;
uint32_t clkin_freq[4];
uint32_t lcm_freq;
uint32_t in_prescaler[5];
uint32_t pll1_lock_detect;
uint32_t n1, r1;
uint32_t pfd1_freq;
uint32_t vco_limit;
uint32_t n2[2], r2[2];
uint32_t i, ref_en = 0;
vcxo_freq = dev->vcxo_freq / 1000;
pll2_freq = dev->pll2_freq / 1000;
lcm_freq = vcxo_freq;
for (i = 0; i < NO_OS_ARRAY_SIZE(clkin_freq); i++) {
if (dev->clkin_freq_ccf[i])
clkin_freq[i] = dev->clkin_freq_ccf[i] / 1000;
else
clkin_freq[i] = dev->clkin_freq[i] / 1000;
if (clkin_freq[i]) {
lcm_freq = no_os_greatest_common_divisor(clkin_freq[i], lcm_freq);
ref_en |= NO_OS_BIT(i);
}
}
while (lcm_freq > HMC7044_RECOMM_LCM_MAX)
lcm_freq /= 2;
for (i = 0; i < NO_OS_ARRAY_SIZE(clkin_freq); i++) {
if (clkin_freq[i])
in_prescaler[i] = clkin_freq[i] / lcm_freq;
else
in_prescaler[i] = 1;
}
in_prescaler[4] = vcxo_freq / lcm_freq;
pll1_lock_detect = no_os_log_base_2((lcm_freq * 4000) / dev->pll1_loop_bw);
/* fVCXO / N1 = fLCM / R1 */
no_os_rational_best_approximation(vcxo_freq, lcm_freq,
HMC7044_N1_MAX, HMC7044_R1_MAX,
&n1, &r1);
pfd1_freq = vcxo_freq / n1;
while ((pfd1_freq > HMC7044_RECOMM_FPD1) &&
(n1 <= HMC7044_N1_MAX / 2) &&
(r1 <= HMC7044_R1_MAX / 2)) {
pfd1_freq /= 2;
n1 *= 2;
r1 *= 2;
}
dev->pll1_pfd = pfd1_freq;
if (pll2_freq < HMC7044_LOW_VCO_MIN ||
pll2_freq > HMC7044_HIGH_VCO_MAX)
return -1;
vco_limit = (HMC7044_LOW_VCO_MAX + HMC7044_HIGH_VCO_MIN) / 2;
if (pll2_freq >= vco_limit)
high_vco_en = true;
else
high_vco_en = false;
/* fVCO / N2 = fVCXO * doubler / R2 */
pll2_freq_doubler_en = true;
no_os_rational_best_approximation(pll2_freq, vcxo_freq * 2,
HMC7044_N2_MAX, HMC7044_R2_MAX,
&n2[0], &r2[0]);
if (pll2_freq != vcxo_freq * n2[0] / r2[0]) {
no_os_rational_best_approximation(pll2_freq, vcxo_freq,
HMC7044_N2_MAX, HMC7044_R2_MAX,
&n2[1], &r2[1]);
if (abs((int)pll2_freq - (int)(vcxo_freq * 2 * n2[0] / r2[0])) >
abs((int)pll2_freq - (int)(vcxo_freq * n2[1] / r2[1]))) {
n2[0] = n2[1];
r2[0] = r2[1];
pll2_freq_doubler_en = false;
}
}
while ((n2[0] < HMC7044_N2_MIN) && (r2[0] <= HMC7044_R2_MAX / 2)) {
n2[0] *= 2;
r2[0] *= 2;
}
if (n2[0] < HMC7044_N2_MIN)
return -1;
/* Resets all registers to default values */
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, HMC7044_SOFT_RESET);
no_os_mdelay(10);
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, 0);
no_os_mdelay(10);
/* Disable all channels */
for (i = 0; i < HMC7044_NUM_CHAN; i++)
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(i), 0);
/* Load the configuration updates (provided by Analog Devices) */
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_LOW_PW, 0x4d);
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_HIGH_PW, 0xdf);
hmc7044_write(dev, HMC7044_REG_PLL1_DELAY, 0x06);
hmc7044_write(dev, HMC7044_REG_PLL1_HOLDOVER, 0x06);
hmc7044_write(dev, HMC7044_REG_VTUNE_PRESET, 0x04);
hmc7044_write(dev, HMC7044_REG_GLOB_MODE,
HMC7044_SYNC_PIN_MODE(dev->sync_pin_mode) |
(dev->clkin0_rfsync_en ? HMC7044_RFSYNC_EN : 0) |
(dev->clkin1_vcoin_en ? HMC7044_VCOIN_MODE_EN : 0) |
HMC7044_REF_PATH_EN(ref_en));
/* Program PLL2 */
/* Select the VCO range */
hmc7044_write(dev, HMC7044_REG_EN_CTRL_0,
(dev->rf_reseeder_en ? HMC7044_RF_RESEEDER_EN : 0) |
HMC7044_VCO_SEL(high_vco_en ?
HMC7044_VCO_HIGH :
HMC7044_VCO_LOW) |
HMC7044_SYSREF_TIMER_EN | HMC7044_PLL2_EN |
HMC7044_PLL1_EN);
/* Program the dividers */
hmc7044_write(dev, HMC7044_REG_PLL2_R_LSB,
HMC7044_R2_LSB(r2[0]));
hmc7044_write(dev, HMC7044_REG_PLL2_R_MSB,
HMC7044_R2_MSB(r2[0]));
hmc7044_write(dev, HMC7044_REG_PLL2_N_LSB,
HMC7044_N2_LSB(n2[0]));
hmc7044_write(dev, HMC7044_REG_PLL2_N_MSB,
HMC7044_N2_MSB(n2[0]));
/* Program the reference doubler */
hmc7044_write(dev, HMC7044_REG_PLL2_FREQ_DOUBLER,
pll2_freq_doubler_en ? 0 : HMC7044_PLL2_FREQ_DOUBLER_DIS);
/* Program PLL1 */
/* Set the lock detect timer threshold */
hmc7044_write(dev, HMC7044_REG_PLL1_LOCK_DETECT,
HMC7044_LOCK_DETECT_TIMER(pll1_lock_detect));
/* Set the LCM */
for (i = 0; i < NO_OS_ARRAY_SIZE(clkin_freq); i++) {
hmc7044_write(dev, HMC7044_REG_CLKIN_PRESCALER(i),
in_prescaler[i]);
}
hmc7044_write(dev, HMC7044_REG_OSCIN_PRESCALER,
in_prescaler[4]);
/* Program the dividers */
hmc7044_write(dev, HMC7044_REG_PLL1_R_LSB,
HMC7044_R2_LSB(r1));
hmc7044_write(dev, HMC7044_REG_PLL1_R_MSB,
HMC7044_R2_MSB(r1));
hmc7044_write(dev, HMC7044_REG_PLL1_N_LSB,
HMC7044_N2_LSB(n1));
hmc7044_write(dev, HMC7044_REG_PLL1_N_MSB,
HMC7044_N2_MSB(n1));
hmc7044_write(dev, HMC7044_REG_PLL1_REF_PRIO_CTRL,
dev->pll1_ref_prio_ctrl);
/* Program the SYSREF timer */
/* Set the divide ratio */
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_LSB,
HMC7044_SYSREF_TIMER_LSB(dev->sysref_timer_div));
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_MSB,
HMC7044_SYSREF_TIMER_MSB(dev->sysref_timer_div));
/* Set the pulse generator mode configuration */
hmc7044_write(dev, HMC7044_REG_PULSE_GEN,
HMC7044_PULSE_GEN_MODE(dev->pulse_gen_mode));
/* Enable the input buffers */
hmc7044_write(dev, HMC7044_REG_CLKIN0_BUF_CTRL,
dev->in_buf_mode[0]);
hmc7044_write(dev, HMC7044_REG_CLKIN1_BUF_CTRL,
dev->in_buf_mode[1]);
hmc7044_write(dev, HMC7044_REG_CLKIN2_BUF_CTRL,
dev->in_buf_mode[2]);
hmc7044_write(dev, HMC7044_REG_CLKIN3_BUF_CTRL,
dev->in_buf_mode[3]);
hmc7044_write(dev, HMC7044_REG_OSCIN_BUF_CTRL,
dev->in_buf_mode[4]);
/* Set GPIOs */
for (i = 0; i < NO_OS_ARRAY_SIZE(dev->gpi_ctrl); i++) {
hmc7044_write(dev, HMC7044_REG_GPI_CTRL(i),
dev->gpi_ctrl[i]);
}
for (i = 0; i < NO_OS_ARRAY_SIZE(dev->gpo_ctrl); i++) {
hmc7044_write(dev, HMC7044_REG_GPO_CTRL(i),
dev->gpo_ctrl[i]);
}
no_os_mdelay(10);
/* Program the output channels */
for (i = 0; i < dev->num_channels; i++) {
chan = &dev->channels[i];
if (chan->num >= HMC7044_NUM_CHAN || chan->disable)
continue;
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
HMC7044_DIV_LSB(chan->divider));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
HMC7044_DIV_MSB(chan->divider));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_8(chan->num),
HMC7044_DRIVER_MODE(chan->driver_mode) |
HMC7044_DRIVER_Z_MODE(chan->driver_impedance) |
(chan->dynamic_driver_enable ?
HMC7044_DYN_DRIVER_EN : 0) |
(chan->force_mute_enable ?
HMC7044_FORCE_MUTE_EN : 0));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_3(chan->num),
chan->fine_delay & 0x1F);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_4(chan->num),
chan->coarse_delay & 0x1F);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_7(chan->num),
chan->out_mux_mode & 0x3);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num),
(chan->start_up_mode_dynamic_enable ?
HMC7044_START_UP_MODE_DYN_EN : 0) |
(chan->output_control0_rb4_enable ? NO_OS_BIT(4) : 0) |
(chan->high_performance_mode_dis ?
0 : HMC7044_HI_PERF_MODE) | HMC7044_SYNC_EN |
HMC7044_CH_EN);
}
no_os_mdelay(10);
/* Do a restart to reset the system and initiate calibration */
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
HMC7044_RESTART_DIV_FSM);
no_os_mdelay(1);
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
(dev->high_performance_mode_clock_dist_en ?
HMC7044_HIGH_PERF_DISTRIB_PATH : 0));
no_os_mdelay(1);
uint8_t val;
hmc7044_read(dev, 0x0082, &val);
xil_printf("hmc7044 pll1 status%x\n\r",val);
return 0;
}
/**
* Setup the device.
* @param dev - The device structure.
* @return 0 in case of success, negative error code otherwise.
*/
static int32_t hmc7043_setup(struct hmc7044_dev *dev)
{
struct hmc7044_chan_spec *chan;
uint32_t i;
if (dev->clkin_freq_ccf[0])
dev->pll2_freq = dev->clkin_freq_ccf[0];
else
dev->pll2_freq = dev->clkin_freq[0];
if (!dev->pll2_freq) {
printf("%s: Failed to get valid parent rate\n", __func__);
return -1;
}
/* Resets all registers to default values */
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, HMC7044_SOFT_RESET);
no_os_mdelay(10);
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, 0);
no_os_mdelay(10);
/* Load the configuration updates (provided by Analog Devices) */
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_LOW_PW, 0x4d);
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_HIGH_PW, 0xdf);
/* Disable all channels */
for (i = 0; i < HMC7044_NUM_CHAN; i++)
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(i), 0);
if (dev->pll2_freq < 1000000000U)
hmc7044_write(dev, HMC7044_CLK_INPUT_CTRL,
HMC7044_LOW_FREQ_INPUT_MODE);
hmc7044_write(dev, HMC7044_REG_EN_CTRL_0,
(dev->rf_reseeder_en ? HMC7044_RF_RESEEDER_EN : 0) |
HMC7044_SYSREF_TIMER_EN);
/* Program the SYSREF timer */
/* Set the divide ratio */
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_LSB,
HMC7044_SYSREF_TIMER_LSB(dev->sysref_timer_div));
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_MSB,
HMC7044_SYSREF_TIMER_MSB(dev->sysref_timer_div));
/* Set the pulse generator mode configuration */
hmc7044_write(dev, HMC7044_REG_PULSE_GEN,
HMC7044_PULSE_GEN_MODE(dev->pulse_gen_mode));
/* Enable the input buffers */
hmc7044_write(dev, HMC7044_REG_CLKIN0_BUF_CTRL,
dev->in_buf_mode[0]);
hmc7044_write(dev, HMC7044_REG_CLKIN1_BUF_CTRL,
dev->in_buf_mode[1]);
/* Set GPIOs */
hmc7044_write(dev, HMC7044_REG_GPI_CTRL(0),
dev->gpi_ctrl[0]);
hmc7044_write(dev, HMC7044_REG_GPO_CTRL(0),
dev->gpo_ctrl[0]);
/* Program the output channels */
for (i = 0; i < dev->num_channels; i++) {
chan = &dev->channels[i];
if (chan->num >= HMC7044_NUM_CHAN || chan->disable)
continue;
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
HMC7044_DIV_LSB(chan->divider));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
HMC7044_DIV_MSB(chan->divider));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_8(chan->num),
HMC7044_DRIVER_MODE(chan->driver_mode) |
HMC7044_DRIVER_Z_MODE(chan->driver_impedance) |
(chan->dynamic_driver_enable ?
HMC7044_DYN_DRIVER_EN : 0) |
(chan->force_mute_enable ?
HMC7044_FORCE_MUTE_EN : 0));
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_3(chan->num),
chan->fine_delay & 0x1F);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_4(chan->num),
chan->coarse_delay & 0x1F);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_7(chan->num),
chan->out_mux_mode & 0x3);
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num),
(chan->start_up_mode_dynamic_enable ?
HMC7044_START_UP_MODE_DYN_EN : 0) |
(chan->output_control0_rb4_enable ? NO_OS_BIT(4) : 0) |
(chan->high_performance_mode_dis ?
0 : HMC7044_HI_PERF_MODE) | HMC7044_SYNC_EN |
HMC7044_CH_EN);
}
no_os_mdelay(10);
/* Do a restart to reset the system and initiate calibration */
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
HMC7044_RESTART_DIV_FSM);
no_os_mdelay(1);
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
(dev->high_performance_mode_clock_dist_en ?
HMC7044_HIGH_PERF_DISTRIB_PATH : 0));
no_os_mdelay(1);
return 0;
}
/**
* Initialize the device.
* @param device - The device structure.
* @param init_param - The structure that contains the device initial
* parameters.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t hmc7044_init(struct hmc7044_dev **device,
const struct hmc7044_init_param *init_param)
{
struct hmc7044_dev *dev;
int32_t ret;
unsigned int i;
dev = (struct hmc7044_dev *)malloc(sizeof(*dev));
if (!dev)
return -1;
ret = no_os_spi_init(&dev->spi_desc, init_param->spi_init);
if (ret < 0)
return ret;
dev->is_hmc7043 = init_param->is_hmc7043;
dev->clkin_freq[0] = init_param->clkin_freq[0];
dev->clkin_freq[1] = init_param->clkin_freq[1];
dev->clkin_freq[2] = init_param->clkin_freq[2];
dev->clkin_freq[3] = init_param->clkin_freq[3];
dev->clkin_freq_ccf[0] = init_param->clkin_freq_ccf[0];
dev->clkin_freq_ccf[1] = init_param->clkin_freq_ccf[1];
dev->clkin_freq_ccf[2] = init_param->clkin_freq_ccf[2];
dev->clkin_freq_ccf[3] = init_param->clkin_freq_ccf[3];
dev->vcxo_freq = init_param->vcxo_freq;
dev->pll1_pfd = init_param->pll1_pfd;
dev->pll2_freq = init_param->pll2_freq;
dev->pll1_loop_bw = init_param->pll1_loop_bw;
dev->sysref_timer_div = init_param->sysref_timer_div;
dev->pll1_ref_prio_ctrl = init_param->pll1_ref_prio_ctrl;
dev->clkin0_rfsync_en = init_param->clkin0_rfsync_en;
dev->clkin1_vcoin_en = init_param->clkin1_vcoin_en;
dev->high_performance_mode_clock_dist_en =
init_param->high_performance_mode_clock_dist_en;
dev->rf_reseeder_en = !init_param->rf_reseeder_disable;
dev->sync_pin_mode = init_param->sync_pin_mode;
dev->pulse_gen_mode = init_param->pulse_gen_mode;
dev->in_buf_mode[0] = init_param->in_buf_mode[0];
dev->in_buf_mode[1] = init_param->in_buf_mode[1];
dev->in_buf_mode[2] = init_param->in_buf_mode[2];
dev->in_buf_mode[3] = init_param->in_buf_mode[3];
dev->in_buf_mode[4] = init_param->in_buf_mode[4];
dev->gpi_ctrl[0] = init_param->gpi_ctrl[0];
dev->gpi_ctrl[1] = init_param->gpi_ctrl[1];
dev->gpi_ctrl[2] = init_param->gpi_ctrl[2];
dev->gpi_ctrl[3] = init_param->gpi_ctrl[3];
dev->gpo_ctrl[0] = init_param->gpo_ctrl[0];
dev->gpo_ctrl[1] = init_param->gpo_ctrl[1];
dev->gpo_ctrl[2] = init_param->gpo_ctrl[2];
dev->gpo_ctrl[3] = init_param->gpo_ctrl[3];
dev->num_channels = init_param->num_channels;
dev->channels = (struct hmc7044_chan_spec *)
malloc(sizeof(*dev->channels) * dev->num_channels);
for (i = 0; i < dev->num_channels; i++) {
dev->channels[i].num = init_param->channels[i].num;
dev->channels[i].disable = init_param->channels[i].disable;
dev->channels[i].divider = init_param->channels[i].divider;
dev->channels[i].driver_mode =
init_param->channels[i].driver_mode;
dev->channels[i].high_performance_mode_dis =
init_param->channels[i].high_performance_mode_dis;
dev->channels[i].start_up_mode_dynamic_enable =
init_param->channels[i].start_up_mode_dynamic_enable;
dev->channels[i].dynamic_driver_enable =
init_param->channels[i].dynamic_driver_enable;
dev->channels[i].output_control0_rb4_enable =
init_param->channels[i].output_control0_rb4_enable;
dev->channels[i].force_mute_enable =
init_param->channels[i].force_mute_enable;
dev->channels[i].driver_impedance =
init_param->channels[i].driver_impedance;
dev->channels[i].coarse_delay =
init_param->channels[i].coarse_delay;
dev->channels[i].fine_delay =
init_param->channels[i].fine_delay;
dev->channels[i].out_mux_mode =
init_param->channels[i].out_mux_mode;
}
*device = dev;
if (!dev->is_hmc7043)
return hmc7044_setup(dev);
else
return hmc7043_setup(dev);
}
/**
* Remove the device - release resources.
* @param device - The device structure.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t hmc7044_remove(struct hmc7044_dev *device)
{
int32_t ret;
ret = no_os_spi_remove(device->spi_desc);
free(device->channels);
free(device);
return ret;
}
/*
* Copyright (C) 2009 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
#include <stdio.h>
#include "xparameters.h"
#include "netif/xadapter.h"
#include "platform.h"
#include "platform_config.h"
#if defined (__arm__) || defined(__aarch64__)
#include "xil_printf.h"
#endif
#include "lwip/tcp.h"
#include "xil_cache.h"
#if LWIP_IPV6==1
#include "lwip/ip.h"
#else
#if LWIP_DHCP==1
#include "lwip/dhcp.h"
#endif
#endif
//ADRV
#include "adi_hal.h"
#include "no_os_spi.h"
#include "no_os_error.h"
#include "no_os_delay.h"
#include "parameters.h"
#include "no_os_util.h"
#include "axi_dac_core.h"
#include "axi_adc_core.h"
#include "axi_dmac.h"
#ifndef ALTERA_PLATFORM
#include "xil_cache.h"
#include "xilinx_gpio.h"
#include "xilinx_spi.h"
#else
#include "altera_spi.h"
#include "altera_gpio.h"
#endif
#include "talise.h"
#include "talise_config.h"
#include "app_config.h"
#include "app_clocking.h"
#include "app_jesd.h"
#include "app_transceiver.h"
#include "app_talise.h"
#include "hmc7044.h"
/* defined by each RAW mode application */
void print_app_header();
int start_application();
int transfer_data();
void tcp_fasttmr(void);
void tcp_slowtmr(void);
/* missing declaration in lwIP */
void lwip_init();
#if LWIP_IPV6==0
#if LWIP_DHCP==1
extern volatile int dhcp_timoutcntr;
err_t dhcp_start(struct netif *netif);
#endif
#endif
extern volatile int TcpFastTmrFlag;
extern volatile int TcpSlowTmrFlag;
static struct netif server_netif;
struct netif *echo_netif;
struct adi_hal hal[TALISE_DEVICE_ID_MAX];
taliseDevice_t tal[TALISE_DEVICE_ID_MAX];
#if LWIP_IPV6==1
void print_ip6(char *msg, ip_addr_t *ip)
{
print(msg);
xil_printf(" %x:%x:%x:%x:%x:%x:%x:%x\n\r",
IP6_ADDR_BLOCK1(&ip->u_addr.ip6),
IP6_ADDR_BLOCK2(&ip->u_addr.ip6),
IP6_ADDR_BLOCK3(&ip->u_addr.ip6),
IP6_ADDR_BLOCK4(&ip->u_addr.ip6),
IP6_ADDR_BLOCK5(&ip->u_addr.ip6),
IP6_ADDR_BLOCK6(&ip->u_addr.ip6),
IP6_ADDR_BLOCK7(&ip->u_addr.ip6),
IP6_ADDR_BLOCK8(&ip->u_addr.ip6));
}
#else
void
print_ip(char *msg, ip_addr_t *ip)
{
print(msg);
xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip),
ip4_addr3(ip), ip4_addr4(ip));
}
void
print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
{
print_ip("Board IP: ", ip);
print_ip("Netmask : ", mask);
print_ip("Gateway : ", gw);
}
#endif
#if defined (__arm__) && !defined (ARMR5)
#if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
int ProgramSi5324(void); //?
int ProgramSfpPhy(void); //?
#endif
#endif
#ifdef XPS_BOARD_ZCU102
#ifdef XPAR_XIICPS_0_DEVICE_ID
int IicPhyReset(void);
#endif
#endif
int main()
{
#if LWIP_IPV6==0
ip_addr_t ipaddr, netmask, gw;
#endif
/* the mac address of the board. this should be unique per board */
unsigned char mac_ethernet_address[] =
{ 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
echo_netif = &server_netif;
#if defined (__arm__) && !defined (ARMR5)
#if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
ProgramSi5324();
ProgramSfpPhy();
#endif
#endif
/* Define this board specific macro in order perform PHY reset on ZCU102 */
#ifdef XPS_BOARD_ZCU102
if(IicPhyReset()) {
xil_printf("Error performing PHY reset \n\r");
return -1;
}
#endif
init_platform();
adiHalErr_t err;
int status;
// compute the lane rate from profile settings
// lane_rate = input_rate * M * 20 / L
// where L and M are explained in taliseJesd204bFramerConfig_t comments
uint32_t rx_lane_rate_khz = talInit.rx.rxProfile.rxOutputRate_kHz *
talInit.jesd204Settings.framerA.M * (20 /
no_os_hweight8(talInit.jesd204Settings.framerA.serializerLanesEnabled));
uint32_t rx_div40_rate_hz = rx_lane_rate_khz * (1000 / 40);
uint32_t tx_lane_rate_khz = talInit.tx.txProfile.txInputRate_kHz *
talInit.jesd204Settings.deframerA.M * (20 /
no_os_hweight8(talInit.jesd204Settings.deframerA.deserializerLanesEnabled));
uint32_t tx_div40_rate_hz = tx_lane_rate_khz * (1000 / 40);
uint32_t rx_os_lane_rate_khz = talInit.obsRx.orxProfile.orxOutputRate_kHz *
talInit.jesd204Settings.framerB.M * (20 /
no_os_hweight8(talInit.jesd204Settings.framerB.serializerLanesEnabled));
uint32_t rx_os_div40_rate_hz = rx_os_lane_rate_khz * (1000 / 40);
// compute the local multiframe clock
// serializer: lmfc_rate = (lane_rate * 100) / (K * F)
// deserializer: lmfc_rate = (lane_rate * 100) / (K * 2 * M / L)
// where K, F, L, M are explained in taliseJesd204bFramerConfig_t comments
uint32_t rx_lmfc_rate = (rx_lane_rate_khz * 100) /
(talInit.jesd204Settings.framerA.K * talInit.jesd204Settings.framerA.F);
uint32_t tx_lmfc_rate = (tx_lane_rate_khz * 100) /
(talInit.jesd204Settings.deframerA.K * 2 * talInit.jesd204Settings.deframerA.M /
no_os_hweight8(talInit.jesd204Settings.deframerA.deserializerLanesEnabled));
uint32_t rx_os_lmfc_rate = (rx_os_lane_rate_khz * 100) /
(talInit.jesd204Settings.framerB.K * talInit.jesd204Settings.framerB.F);
uint32_t lmfc_rate = no_os_min(rx_lmfc_rate, rx_os_lmfc_rate);
lmfc_rate = no_os_min(tx_lmfc_rate, lmfc_rate);
struct axi_adc_init rx_adc_init = {
"rx_adc",
RX_CORE_BASEADDR,
TALISE_NUM_CHANNELS
};
struct axi_adc *rx_adc;
struct axi_dac_init tx_dac_init = {
"tx_dac",
TX_CORE_BASEADDR,
TALISE_NUM_CHANNELS,
NULL
};
struct axi_dac *tx_dac;
// struct axi_dmac_init rx_dmac_init = {
// "rx_dmac",
// RX_DMA_BASEADDR,
// IRQ_DISABLED
// };
// struct axi_dmac *rx_dmac;
//
// struct axi_dmac_init tx_dmac_init = {
// "tx_dmac",
// TX_DMA_BASEADDR,
// IRQ_DISABLED
// };
// struct axi_dmac *tx_dmac;
#ifdef DAC_DMA_EXAMPLE
struct no_os_gpio_desc *gpio_plddrbypass;
struct no_os_gpio_init_param gpio_init_plddrbypass;
extern const uint32_t sine_lut_iq[1024];
#endif
#ifndef ALTERA_PLATFORM
struct xil_spi_init_param hal_spi_param = {
#ifdef PLATFORM_MB
.type = SPI_PL,
#else
.type = SPI_PS,
#endif
.flags = SPI_CS_DECODE
};
struct xil_gpio_init_param hal_gpio_param = {
#ifdef PLATFORM_MB
.type = GPIO_PL,
#else
.type = GPIO_PS,
#endif
.device_id = GPIO_DEVICE_ID
};
#else
struct altera_spi_init_param hal_spi_param = {
.type = NIOS_II_SPI,
.base_address = SPI_BASEADDR
};
struct altera_gpio_init_param hal_gpio_param = {
.type = NIOS_II_GPIO,
.device_id = 0,
.base_address = GPIO_BASEADDR
};
hal.extra_gpio = &hal_gpio_param;
#endif
int t;
// struct adi_hal hal[TALISE_DEVICE_ID_MAX];
// taliseDevice_t tal[TALISE_DEVICE_ID_MAX];
for (t = TALISE_A; t < TALISE_DEVICE_ID_MAX; t++) {
hal[t].extra_gpio= &hal_gpio_param;
hal[t].extra_spi = &hal_spi_param;
tal[t].devHalInfo = (void *) &hal[t];
}
hal[TALISE_A].gpio_adrv_resetb_num = TRX_A_RESETB_GPIO;
hal[TALISE_A].spi_adrv_csn = ADRV_CS;
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
hal[TALISE_B].gpio_adrv_resetb_num = TRX_B_RESETB_GPIO;
hal[TALISE_B].spi_adrv_csn = ADRV_B_CS;
#endif
#ifndef ALTERA_PLATFORM
/* Enable the instruction cache. */
Xil_ICacheEnable();
/* Enable the data cache. */
Xil_DCacheEnable();
#endif
printf("Hello\n");
/**********************************************************/
/**********************************************************/
/************ Talise Initialization Sequence *************/
/**********************************************************/
/**********************************************************/
err = clocking_init(rx_div40_rate_hz,
tx_div40_rate_hz,
rx_os_div40_rate_hz,
talInit.clocks.deviceClock_kHz,
lmfc_rate);
if (err != ADIHAL_OK)
goto error_0;
err = jesd_init(rx_div40_rate_hz,
tx_div40_rate_hz,
rx_os_div40_rate_hz);
if (err != ADIHAL_OK)
goto error_1;
err = fpga_xcvr_init(rx_lane_rate_khz,
tx_lane_rate_khz,
rx_os_lane_rate_khz,
talInit.clocks.deviceClock_kHz);
if (err != ADIHAL_OK)
goto error_2;
for (t = TALISE_A; t < TALISE_DEVICE_ID_MAX; t++) {
err = talise_setup(&tal[t], &talInit);
if (err != ADIHAL_OK)
goto error_3;
}
#if defined(ZU11EG) || defined(FMCOMMS8_ZCU102)
printf("Performing multi-chip synchronization...\n");
for(int i=0; i < 12; i++) {
for (t = TALISE_A; t < TALISE_DEVICE_ID_MAX; t++) {
err = talise_multi_chip_sync(&tal[t], i);
if (err != ADIHAL_OK)
goto error_3;
}
}
#endif
ADIHAL_sysrefReq(tal[TALISE_A].devHalInfo, SYSREF_CONT_ON);
jesd_rx_watchdog();
/* Print JESD status */
jesd_status();
/* Initialize the DAC core */
#ifndef ADRV9008_1
status = axi_dac_init(&tx_dac, &tx_dac_init);
if (status) {
printf("axi_dac_init() failed with status %d\n", status);
goto error_3;
}
#endif
/* Initialize the ADC core */
#ifndef ADRV9008_2
status = axi_adc_init(&rx_adc, &rx_adc_init);
if (status) {
printf("axi_adc_init() failed with status %d\n", status);
goto error_3;
}
#endif
#if LWIP_IPV6==0
#if LWIP_DHCP==1
ipaddr.addr = 0;
gw.addr = 0;
netmask.addr = 0;
#else
/* initialize IP addresses to be used */
IP4_ADDR(&ipaddr, 192, 168, 1, 10);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 192, 168, 1, 1);
#endif
#endif
print_app_header();
lwip_init();
#if (LWIP_IPV6 == 0)
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(echo_netif, &ipaddr, &netmask,
&gw, mac_ethernet_address,
PLATFORM_EMAC_BASEADDR)) {
xil_printf("Error adding N/W interface\n\r");
return -1;
}
#else
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(echo_netif, NULL, NULL, NULL, mac_ethernet_address,
PLATFORM_EMAC_BASEADDR)) {
xil_printf("Error adding N/W interface\n\r");
return -1;
}
echo_netif->ip6_autoconfig_enabled = 1;
netif_create_ip6_linklocal_address(echo_netif, 1);
netif_ip6_addr_set_state(echo_netif, 0, IP6_ADDR_VALID);
print_ip6("\n\rBoard IPv6 address ", &echo_netif->ip6_addr[0].u_addr.ip6);
#endif
netif_set_default(echo_netif);
/* now enable interrupts */
platform_enable_interrupts();
/* specify that the network if is up */
netif_set_up(echo_netif);
#if (LWIP_IPV6 == 0)
#if (LWIP_DHCP==1)
/* Create a new DHCP client for this interface.
* Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
* the predefined regular intervals after starting the client.
*/
dhcp_start(echo_netif);
dhcp_timoutcntr = 24;
while(((echo_netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))
xemacif_input(echo_netif);
if (dhcp_timoutcntr <= 0) {
if ((echo_netif->ip_addr.addr) == 0) {
xil_printf("DHCP Timeout\r\n");
xil_printf("Configuring default IP of 192.168.1.10\r\n");
IP4_ADDR(&(echo_netif->ip_addr), 10, 0, 0, 100);
IP4_ADDR(&(echo_netif->netmask), 255, 255, 255, 0);
IP4_ADDR(&(echo_netif->gw), 10, 0, 0, 1);
}
}
ipaddr.addr = echo_netif->ip_addr.addr;
gw.addr = echo_netif->gw.addr;
netmask.addr = echo_netif->netmask.addr;
#endif
print_ip_settings(&ipaddr, &netmask, &gw);
#endif
/* start the application (web server, rxtest, txtest, etc..) */
start_application();
/* receive and process packets */
while (1) {
if (TcpFastTmrFlag) {
tcp_fasttmr();
TcpFastTmrFlag = 0;
}
if (TcpSlowTmrFlag) {
tcp_slowtmr();
TcpSlowTmrFlag = 0;
}
xemacif_input(echo_netif);
transfer_data();
}
error_3:
fpga_xcvr_deinit();
error_2:
jesd_deinit();
error_1:
clocking_deinit();
error_0:
printf("Bye\n");
/* never reached */
cleanup_platform();
return 0;
}
/**
* \file adrv9009/profiles/tx_bw200_ir245p76_rx_bw200_or245p76_orx_bw200_or245p76_dc245p76/talise_config.c
* \brief Contains Talise configuration settings for the Talise API
*
* Copyright 2015-2017 Analog Devices Inc.
* Released under the AD9378-AD9379 API license, for more information see the "LICENSE.txt" file in this zip file.
*
* The top level structure taliseDevice_t talDevice uses keyword
* extern to allow the application layer main() to have visibility
* to these settings.
*
* This file may not be fully complete for the end user application and
* may need to updated for AGC, GPIO, and DAC full scale settings.
* To create a full initialisation routine, the user should also refer to the
* Iron Python initialisation routine generated by the GUI, and also the Talise User Guide.
*
*/
#include "talise_types.h"
#include "talise_config.h"
#include "talise_error.h"
#include "talise_agc.h"
#ifdef ADI_ZYNQ_PLATFORM
#include "zynq_platform.h"
#endif
int16_t txFirCoefs[20] = {33, -77, 123, -158, 171, -112, -155, 1040, -3011, 20121, -3011, 1040, -155, -112, 171, -158, 123, -77, 33, 0};
int16_t rxFirCoefs[48] = {-7, -23, 33, 50, -70, -110, 144, 205, -259, -356, 437, 581, -698, -916, 1082, 1415, -1655, -2209, 2567, 3615, -4351, -7169, 9329, 31129, 31129, 9329, -7169, -4351, 3615, 2567, -2209, -1655, 1415, 1082, -916, -698, 581, 437, -356, -259, 205, 144, -110, -70, 50, 33, -23, -7};
int16_t obsrxFirCoefs[48] = {-7, -21, 31, 48, -67, -106, 124, 164, -275, -334, 440, 552, -694, -872, 1069, 1351, -1633, -2111, 2541, 3477, -4295, -6877, 9433, 30825, 30825, 9433, -6877, -4295, 3477, 2541, -2111, -1633, 1351, 1069, -872, -694, 552, 440, -334, -275, 164, 124, -106, -67, 48, 31, -21, 7};
#ifdef ADI_ZYNQ_PLATFORM /** < Insert Customer Platform HAL State Container here>*/
/*
* Platform Layer SPI settings - this structure is specific to ADI's platform layer code.
* User should replace with their own structure or settings for their hardware
*/
zynqSpiSettings_t spiDev1 = {
.chipSelectIndex = 1,
.writeBitPolarity = 0,
.longInstructionWord = 1,
.CPHA = 0,
.CPOL = 0,
.mode = 0,
.spiClkFreq_Hz = 25000000
};
/*
* Platform Layer settings - this structure is specific to ADI's platform layer code.
* User should replace with their own structure or settings for their hardware
* The structure is held in taliseDevice_t below as a void pointer, allowing
* the customer to pass any information for their specific hardware down to the
* hardware layer code.
*/
zynqAdiDev_t talDevHalInfo = {
.devIndex = 1,
.spiSettings = &spiDev1,
.spiErrCode = 0,
.timerErrCode = 0,
.gpioErrCode = 0,
.logLevel = ADIHAL_LOG_ALL
};
#endif
/**
* TalDevice a structure used by the Talise API to hold the platform hardware
* structure information, as well as an internal Talise API state container
* (devStateInfo) of runtime information used by the API.
**/
taliseDevice_t talDevice = {
#ifdef ADI_ZYNQ_PLATFORM
/* Void pointer of users platform HAL settings to pass to HAL layer calls
* Talise API does not use the devHalInfo member */
.devHalInfo = &talDevHalInfo,
#else
.devHalInfo = NULL, /* < Insert Customer Platform HAL State Container here>*/
#endif
/* devStateInfo is maintained internal to the Talise API, just create the memory */
.devStateInfo = {0}
};
taliseInit_t talInit = {
/* SPI settings */
.spiSettings =
{
.MSBFirst = 1, /* 1 = MSBFirst, 0 = LSBFirst */
.enSpiStreaming = 0, /* Not implemented in ADIs platform layer. SW feature to improve SPI throughput */
.autoIncAddrUp = 1, /* Not implemented in ADIs platform layer. For SPI Streaming, set address increment direction. 1= next addr = addr+1, 0:addr=addr-1 */
.fourWireMode = 1, /* 1: Use 4-wire SPI, 0: 3-wire SPI (SDIO pin is bidirectional). NOTE: ADI's FPGA platform always uses 4-wire mode */
.cmosPadDrvStrength = TAL_CMOSPAD_DRV_2X /* Drive strength of CMOS pads when used as outputs (SDIO, SDO, GP_INTERRUPT, GPIO 1, GPIO 0) */
},
/* Rx settings */
.rx =
{
.rxProfile =
{
.rxFir =
{
.gain_dB = -6, /* filter gain */
.numFirCoefs = 48, /* number of coefficients in the FIR filter */
.coefs = &rxFirCoefs[0]
},
.rxFirDecimation = 2, /* Rx FIR decimation (1,2,4) */
.rxDec5Decimation = 4, /* Decimation of Dec5 or Dec4 filter (5,4) */
.rhb1Decimation = 1, /* RX Half band 1 decimation (1 or 2) */
.rxOutputRate_kHz = 245760, /* Rx IQ data rate in kHz */
.rfBandwidth_Hz = 200000000, /* The Rx RF passband bandwidth for the profile */
.rxBbf3dBCorner_kHz = 200000, /* Rx BBF 3dB corner in kHz */
.rxAdcProfile = {185, 141, 172, 90, 1280, 942, 1332, 90, 1368, 46, 1016, 19, 48, 48, 37, 208, 0, 0, 0, 0, 52, 0, 7, 6, 42, 0, 7, 6, 42, 0, 25, 27, 0, 0, 25, 27, 0, 0, 165, 44, 31, 905}, /* pointer to custom ADC profile */
.rxDdcMode = TAL_RXDDC_BYPASS, /* Rx DDC mode */
.rxNcoShifterCfg =
{
.bandAInputBandWidth_kHz = 0,
.bandAInputCenterFreq_kHz = 0,
.bandANco1Freq_kHz = 0,
.bandANco2Freq_kHz = 0,
.bandBInputBandWidth_kHz = 0,
.bandBInputCenterFreq_kHz = 0,
.bandBNco1Freq_kHz = 0,
.bandBNco2Freq_kHz = 0
}
},
.framerSel = TAL_FRAMER_A, /* Rx JESD204b framer configuration */
.rxGainCtrl =
{
.gainMode = TAL_MGC, /* taliserxGainMode_t gainMode */
.rx1GainIndex = 255, /* uint8_t rx1GainIndex */
.rx2GainIndex = 255, /* uint8_t rx2GainIndex */
.rx1MaxGainIndex = 255, /* uint8_t rx1MaxGainIndex */
.rx1MinGainIndex = 195, /* uint8_t rx1MinGainIndex */
.rx2MaxGainIndex = 255, /* uint8_t rx2MaxGainIndex */
.rx2MinGainIndex = 195 /* uint8_t rx2MinGainIndex */
},
.rxChannels = TAL_RX1RX2, /* The desired Rx Channels to enable during initialization */
},
/* Tx settings */
.tx =
{
.txProfile =
{
.dacDiv = 1, /* The divider used to generate the DAC clock */
.txFir =
{
.gain_dB = 0, /* filter gain */
.numFirCoefs = 20, /* number of coefficients in the FIR filter */
.coefs = &txFirCoefs[0]
},
.txFirInterpolation = 1, /* The Tx digital FIR filter interpolation (1,2,4) */
.thb1Interpolation = 2, /* Tx Halfband1 filter interpolation (1,2) */
.thb2Interpolation = 2, /* Tx Halfband2 filter interpolation (1,2)*/
.thb3Interpolation = 2, /* Tx Halfband3 filter interpolation (1,2)*/
.txInt5Interpolation = 1, /* Tx Int5 filter interpolation (1,5) */
.txInputRate_kHz = 245760, /* Primary Signal BW */
.primarySigBandwidth_Hz = 75000000, /* The Rx RF passband bandwidth for the profile */
.rfBandwidth_Hz = 200000000, /* The Tx RF passband bandwidth for the profile */
.txDac3dBCorner_kHz = 200000, /* The DAC filter 3dB corner in kHz */
.txBbf3dBCorner_kHz = 100000, /* The BBF 3dB corner in kHz */
.loopBackAdcProfile = {243, 143, 181, 90, 1280, 485, 1275, 37, 1317, 23, 797, 35, 48, 48, 30, 174, 0, 0, 0, 0, 44, 0, 7, 6, 42, 0, 7, 6, 42, 0, 25, 27, 0, 0, 25, 27, 0, 0, 165, 44, 31, 905}
},
.deframerSel = TAL_DEFRAMER_A, /* Talise JESD204b deframer config for the Tx data path */
.txChannels = TAL_TX1TX2, //TAL_TX1TX2 /* The desired Tx channels to enable during initialization */
.txAttenStepSize = TAL_TXATTEN_0P05_DB, /* Tx Attenuation step size */
.tx1Atten_mdB = 10000, /* Initial Tx1 Attenuation */
.tx2Atten_mdB = 10000, /* Initial Tx2 Attenuation */
.disTxDataIfPllUnlock = TAL_TXDIS_TX_RAMP_DOWN_TO_ZERO /* Options to disable the transmit data when the RFPLL unlocks. */
},
/* ObsRx settings */
.obsRx =
{
.orxProfile =
{
.rxFir =
{
.gain_dB = -6, /* filter gain */
.numFirCoefs = 48, /* number of coefficients in the FIR filter */
.coefs = &obsrxFirCoefs[0]
},
.rxFirDecimation = 2, /* Rx FIR decimation (1,2,4) */
.rxDec5Decimation = 4, /* Decimation of Dec5 or Dec4 filter (5,4) */
.rhb1Decimation = 1, /* RX Half band 1 decimation (1 or 2) */
.orxOutputRate_kHz = 245760, /* Rx IQ data rate in kHz */
.rfBandwidth_Hz = 200000000, /* The Rx RF passband bandwidth for the profile */
.rxBbf3dBCorner_kHz = 225000, /* Rx BBF 3dB corner in kHz */
.orxLowPassAdcProfile = {185, 141, 172, 90, 1280, 942, 1332, 90, 1368, 46, 1016, 19, 48, 48, 37, 208, 0, 0, 0, 0, 52, 0, 7, 6, 42, 0, 7, 6, 42, 0, 25, 27, 0, 0, 25, 27, 0, 0, 165, 44, 31, 905},
.orxBandPassAdcProfile = {185, 141, 172, 90, 1280, 942, 1332, 90, 1368, 46, 1016, 19, 48, 48, 37, 208, 0, 0, 0, 0, 52, 0, 7, 6, 42, 0, 7, 6, 42, 0, 25, 27, 0, 0, 25, 27, 0, 0, 165, 44, 31, 905},
.orxDdcMode = TAL_ORXDDC_DISABLED, /* ORx DDC mode */
.orxMergeFilter = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
},
.orxGainCtrl =
{
.gainMode = TAL_MGC,
.orx1GainIndex = 255,
.orx2GainIndex = 255,
.orx1MaxGainIndex = 255,
.orx1MinGainIndex = 195,
.orx2MaxGainIndex = 255,
.orx2MinGainIndex = 195
},
.framerSel = TAL_FRAMER_B, /* ObsRx JESD204b framer configuration */
.obsRxChannelsEnable = TAL_ORX1ORX2, /* The desired ObsRx Channels to enable during initialization */
.obsRxLoSource = TAL_OBSLO_RF_PLL /* The ORx mixers can use the TX_PLL */
},
/* Digital Clock Settings */
.clocks =
{
.deviceClock_kHz = 245760, /* CLKPLL and device reference clock frequency in kHz */
.clkPllVcoFreq_kHz = 9830400, /* CLKPLL VCO frequency in kHz */
.clkPllHsDiv = TAL_HSDIV_2P5, /* CLKPLL high speed clock divider */
.rfPllUseExternalLo = 0, /* 1= Use external LO for RF PLL, 0 = use internal LO generation for RF PLL */
.rfPllPhaseSyncMode = TAL_RFPLLMCS_INIT_AND_CONTTRACK /* RFPLL MCS (Phase sync) mode */
},
/* JESD204B settings */
.jesd204Settings =
{
/* Framer A settings */
.framerA =
{
.bankId = 1, /* JESD204B Configuration Bank ID -extension to Device ID (Valid 0..15) */
.deviceId = 0, /* JESD204B Configuration Device ID - link identification number. (Valid 0..255) */
.lane0Id = 0, /* JESD204B Configuration starting Lane ID. If more than one lane used, each lane will increment from the Lane0 ID. (Valid 0..31) */
.M = 4, /* number of ADCs (0, 2, or 4) - 2 ADCs per receive chain */
.K = 32, /* number of frames in a multiframe (default=32), F*K must be a multiple of 4. (F=2*M/numberOfLanes) */
.F = 4, /* F (number of bytes per frame) */
.Np = 16, /* Np (converter sample resolution) */
.scramble = 1, /* scrambling off if framerScramble= 0, if framerScramble>0 scramble is enabled. */
.externalSysref = 1, /* 0=use internal SYSREF, 1= use external SYSREF */
.serializerLanesEnabled = 0x03, /* serializerLanesEnabled - bit per lane, [0] = Lane0 enabled, [1] = Lane1 enabled */
.serializerLaneCrossbar = 0xE4, /* serializerLaneCrossbar */
.lmfcOffset = 31, /* lmfcOffset - LMFC offset value for deterministic latency setting */
.newSysrefOnRelink = 0, /* newSysrefOnRelink */
.syncbInSelect = 0, /* syncbInSelect; */
.overSample = 0, /* 1=overSample, 0=bitRepeat */
.syncbInLvdsMode = 1,
.syncbInLvdsPnInvert = 0,
.enableManualLaneXbar = 0 /* 0=auto, 1=manual */
},
/* Framer B settings */
.framerB =
{
.bankId = 0, /* JESD204B Configuration Bank ID -extension to Device ID (Valid 0..15) */
.deviceId = 0, /* JESD204B Configuration Device ID - link identification number. (Valid 0..255) */
.lane0Id = 0, /* JESD204B Configuration starting Lane ID. If more than one lane used, each lane will increment from the Lane0 ID. (Valid 0..31) */
.M = 2, /* number of ADCs (0, 2, or 4) - 2 ADCs per receive chain */
.K = 32, /* number of frames in a multiframe (default=32), F*K must be a multiple of 4. (F=2*M/numberOfLanes) */
.F = 2, /* F (number of bytes per frame) */
.Np = 16, /* Np (converter sample resolution) */
.scramble = 1, /* scrambling off if framerScramble= 0, if framerScramble>0 scramble is enabled. */
.externalSysref = 1, /* 0=use internal SYSREF, 1= use external SYSREF */
.serializerLanesEnabled = 0x0C, /* serializerLanesEnabled - bit per lane, [0] = Lane0 enabled, [1] = Lane1 enabled */
.serializerLaneCrossbar = 0xE4, /* serializerLaneCrossbar */
.lmfcOffset = 31, /* lmfcOffset - LMFC offset value for deterministic latency setting */
.newSysrefOnRelink = 0, /* newSysrefOnRelink */
.syncbInSelect = 1, /* syncbInSelect; */
.overSample = 0, /* 1=overSample, 0=bitRepeat */
.syncbInLvdsMode = 1,
.syncbInLvdsPnInvert = 0,
.enableManualLaneXbar = 0 /* 0=auto, 1=manual */
},
/* Deframer A settings */
.deframerA =
{
.bankId = 0, /* bankId extension to Device ID (Valid 0..15) */
.deviceId = 0, /* deviceId link identification number. (Valid 0..255) */
.lane0Id = 0, /* lane0Id Lane0 ID. (Valid 0..31) */
.M = 4, /* M number of DACss (0, 2, or 4) - 2 DACs per transmit chain */
.K = 32, /* K #frames in a multiframe (default=32), F*K=multiple of 4. (F=2*M/numberOfLanes) */
.scramble = 1, /* scramble scrambling off if scramble= 0 */
.externalSysref = 1, /* externalSysref 0= use internal SYSREF, 1= external SYSREF */
.deserializerLanesEnabled = 0x0F, /* deserializerLanesEnabled bit per lane, [0] = Lane0 enabled */
.deserializerLaneCrossbar = 0xE4, /* deserializerLaneCrossbar */
.lmfcOffset = 17, /* lmfcOffset LMFC offset value to adjust deterministic latency */
.newSysrefOnRelink = 0, /* newSysrefOnRelink */
.syncbOutSelect = 0, /* SYNCBOUT0/1 select */
.Np = 16, /* Np (converter sample resolution) */
.syncbOutLvdsMode = 1,
.syncbOutLvdsPnInvert = 0,
.syncbOutCmosSlewRate = 0,
.syncbOutCmosDriveLevel = 0,
.enableManualLaneXbar = 0 /* 0=auto, 1=manual */
},
/* Deframer B settings */
.deframerB =
{
.bankId = 0, /* bankId extension to Device ID (Valid 0..15) */
.deviceId = 0, /* deviceId link identification number. (Valid 0..255) */
.lane0Id = 0, /* lane0Id Lane0 ID. (Valid 0..31) */
.M = 0, /* M number of DACss (0, 2, or 4) - 2 DACs per transmit chain */
.K = 32, /* K #frames in a multiframe (default=32), F*K=multiple of 4. (F=2*M/numberOfLanes) */
.scramble = 1, /* scramble scrambling off if scramble= 0 */
.externalSysref = 1, /* externalSysref 0= use internal SYSREF, 1= external SYSREF */
.deserializerLanesEnabled = 0x00, /* deserializerLanesEnabled bit per lane, [0] = Lane0 enabled */
.deserializerLaneCrossbar = 0xE4, /* deserializerLaneCrossbar */
.lmfcOffset = 0, /* lmfcOffset LMFC offset value to adjust deterministic latency */
.newSysrefOnRelink = 0, /* newSysrefOnRelink */
.syncbOutSelect = 1, /* SYNCBOUT0/1 select */
.Np = 16, /* Np (converter sample resolution) */
.syncbOutLvdsMode = 1,
.syncbOutLvdsPnInvert = 0,
.syncbOutCmosSlewRate = 0,
.syncbOutCmosDriveLevel = 0,
.enableManualLaneXbar = 0 /* 0=auto, 1=manual */
},
.serAmplitude = 15, /* Serializer amplitude setting. Default = 15. Range is 0..15 */
.serPreEmphasis = 1, /* Serializer pre-emphasis setting. Default = 1 Range is 0..4 */
.serInvertLanePolarity = 0, /* Serializer Lane PN inversion select. Default = 0. Where, bit[0] = 1 will invert lane [0], bit[1] = 1 will invert lane 1, etc. */
.desInvertLanePolarity = 0, /* Deserializer Lane PN inversion select. bit[0] = 1 Invert PN of Lane 0, bit[1] = Invert PN of Lane 1, etc */
.desEqSetting = 1, /* Deserializer Equalizer setting. Applied to all deserializer lanes. Range is 0..4 */
.sysrefLvdsMode = 1, /* Use LVDS inputs on Talise for SYSREF */
.sysrefLvdsPnInvert = 0 /*0= Do not PN invert SYSREF */
}
};
//Only needs to be called if user wants to setup AGC parameters
static taliseAgcCfg_t rxAgcCtrl = {
4,
255,
195,
255,
195,
30720, /* AGC gain update time in us (125us-250us - based on IQ data rate - set for 125us @ 245.76 Mhz) */
10,
10,
16,
0,
1,
0,
0,
0,
1,
31,
246,
4,
1, /*!<1- bit field to enable the multiple time constants in AGC loop for fast attack and fast recovery to max gain. */
/* agcPower */
{
1, /*!<1-bit field, enables the Rx power measurement block. */
1, /*!<1-bit field, allows using Rx PFIR for power measurement. */
0, /*!<1-bit field, allows to use the output of the second digital offset block in the Rx datapath for power measurement. */
9, /*!<AGC power measurement detect lower 0 threshold. Default = -12dBFS == 5, 7-bit register value where max = 0x7F, min = 0x00 */
2, /*!<AGC power measurement detect lower 1 threshold. Default = (offset) 4dB == 0, 4-bit register value where max = 0xF, min = 0x00 */
4, /*!<AGC power measurement detect lower 0 recovery gain step. Default = 2dB - based on gain table step size, 5-bit register value where max = 0x1F, min = 0x00 */
4, /*!<AGC power measurement detect lower 1 recovery gain step. Default = 4dB - based on gain table step size, 5-bit register value where max = 0x1F, min = 0x00 */
5, /*!< power measurement duration used by the decimated power block. Default = 0x05, 5-bit register value where max = 0x1F, min = 0x00 */
5, /*!<Allows power detection of data for a specific slice of the gain update counter. 16-bit register value (currently not used) */
1, /*!<Allows power detection of data for a specific slice of the gain update counter. 16-bit register value (currently not used) */
5, /*!<Allows power detection of data for a specific slice of the gain update counter. 16-bit register value (currently not used) */
1, /*!<Allows power detection of data for a specific slice of the gain update counter. 16-bit register value (currently not used) */
2, /*!<Default value should be 2*/
0,
0
},
/* agcPeak */
{
205, /*!<1st update interval for the multiple time constant in AGC loop mode, Default:205. */
2, /*!<sets the 2nd update interval for the multiple time constant in AGC loop mode. Calculated as a multiple of agcUnderRangeLowInterval  , Default: 4 */
4, /*!<sets the 3rd update interval for the multiple time constant in AGC loop mode. Calculated as a multiple of agcUnderRangeMidInterval and agcUnderRangeLowInterval, Default: 4 */
39, /*!<AGC APD high threshold. Default=0x1F, 6-bit register value where max=0x3F, min =0x00 */
49, /*!<AGC APD peak detect high threshold. default = 0x1F, 6-bit register value where max = 0x3F, min = 0x00. Set to 3dB below apdHighThresh */
23, /*!<AGC APD peak detect low threshold. default = 3dB below high threshold, 6-bit register value where max =0x3F, min = 0x00 */
19, /*!<AGC APD peak detect low threshold. default = 3dB below high threshold, 6-bit register value where max = 0x3F, min = 0x00 . Set to 3dB below apdLowThresh */
6, /*!<AGC APD peak detect upper threshold count. Default = 0x06 8-bit register value where max = 0xFF, min = 0x20 */
3, /*!<AGC APD peak detect lower threshold count. Default = 0x03, 8-bit register value where max = 0xFF, min = 0x00Â */
4, /*!<AGC APD peak detect attack gain step. Default = 2dB step - based on gain table step size, 5-bit register value, where max = 0x1F, min = 0x00 */
2, /*!<AGC APD gain index step size. Recommended to be same as hb2GainStepRecovery. Default = 0x00, 5-bit register value where max = 0x1F, min = 0x00 */
1, /*!<1-bit field, enables or disables the HB2 overload detector. */
1, /*!<3-bit field. Sets the window of clock cycles (at the HB2 output rate) to meet the overload count. */
1, /*!<4-bit field. Sets the number of actual overloads required to trigger the overload signal. */
181, /*!<AGC decimator output high threshold. Default = 0xB5, 8-bit register value where max = 0xFF, min = 0x00 */
45, /*!<AGC decimator output low threshold. Default = 0x80, 8-bit register value where max = 0xFF, min = 0x00 */
90, /*!<AGC decimator output low threshold. Default = 0x80, 8-bit register value where max = 0xFF, min = 0x00 */
128, /*!<AGC decimator output low threshold. Default = 0x80, 8-bit register value where max = 0xFF, min = 0x00 */
6, /*!<AGC HB2 output upper threshold count. Default = 0x06, 8-bit register value where max = 0xFF, min = 0x20 */
3, /*!<AGC HB2 output lower threshold count. Default = 0x03, 8-bit register value where max = 0xFF, min = 0x00 */
2, /*!<AGC decimator gain index step size. Default = 0x00, 5-bit register value where max = 0x1F, min = 0x00 */
4, /*!<AGC HB2 gain index step size, when the HB2 Low Overrange interval 0 triggers a programmable number of times. Default = 0x08, 5-bit register value where max = 0x1F, min = 0x00 */
8, /*!<AGC HB2 gain index step size, when the HB2 Low Overrange interval 1 triggers a programmable number of times. Default = 0x04, 5-bit register value where max = 0x1F, min = 0x00 */
4, /*!<AGC decimator output attack gain step. Default = 2dB step - based on gain table step size, 5-bit register value, where max = 0x1F, min = 0x00 */
1,
0,
0
}
};
Hello hmc7044 pll1 status29 hmc7044 pll1 status2D XCVR identified. adxcvr init successful : rx_adxcvr XCVR identified. adxcvr init successful : tx_adxcvr XCVR identified. adxcvr init successful : rx_os_adxcvr RX Lane Rate = 9830400 kHz ORX Lane Rate = 4915200 kHz TX Lane Rate = 4915200 kHz starting adxcvr reset adxcvr status error = 0 adxcvr status error = 0 adxcvr reset error error: rx_adxcvr: adxcvr_clk_enable() failed error status : -1 Bye
Regards
