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

Parents
  • Are you facing issue with this specific profile only ?

    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"

    Can you check if your HwReset() sequence is fine and as recommended?

    "Power on Reset, After the clock chip and power supplies are stable, the RESETB signal needs to be pulled down for 1ms, and then pulled up. Wait for 100us and then start to initialize the chip"

Reply
  • Are you facing issue with this specific profile only ?

    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"

    Can you check if your HwReset() sequence is fine and as recommended?

    "Power on Reset, After the clock chip and power supplies are stable, the RESETB signal needs to be pulled down for 1ms, and then pulled up. Wait for 100us and then start to initialize the chip"

Children

Before You Switch


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