Post Go back to editing

Issue with "adxcvr_clk_enable()" in SDK reference design

Category: Software
Product Number: ADRV9009
Software Version: vivado 2018.3, sdk2018.3

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, &reg_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, &reg_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

Thread Notes

Before You Switch


Switching languages will make ADI Explorer unavailable. Resume your session by switching back to English and reopening ADI Explorer.