

#include <stdio.h>
#include "xil_printf.h"
#include "xiic.h"
//#include "xuartlite.h"
#include "xparameters.h"
#include "xil_cache.h"
#include "sleep.h"
#include "si5348_registers.h"
#include "i2c.h"
#include "spi.h"
#include "hmc7044.h"
#include "ad9208.h"
#include "jesd204b_drv.h"

#define DDR4_BASE_ADDR	XPAR_DDR4_0_BASEADDR
#define DDR4_END_ADDR	XPAR_DDR4_0_HIGHADDR
#define DDR4_SIZE		DDR4_END_ADDR - DDR4_BASE_ADDR


extern si5348_revd_register_t const si5348_revd_registers[];

/* I2C */
XIic i2c;
#define I2C_DEVICE_ID				XPAR_AXI_IIC_0_DEVICE_ID
#define SI5348B_D_GM_I2C_ADDRESS	0x6C
#define EEPROM_I2C_ADDRESS			0x50
#define EEPROM_MAC_ADDR 			0xFA

/* SPI */
#define ADC_SPI_DEV			XPAR_SPI_1_DEVICE_ID
#define HMC_SPI_DEV			XPAR_SPI_0_DEVICE_ID

/* GPIO */
#define HOST0_MAC_GPIO_BASE			XPAR_GPIO_0_BASEADDR
#define HOST1_MAC_GPIO_BASE			XPAR_GPIO_1_BASEADDR
#define AXI_GPIO_BASE				XPAR_GPIO_2_BASEADDR
#define GPIO_HMC_RESET_PIN			0
#define GPIO_JESD_RESETN_PIN		1
#define GPIO_UDP_RESET_PIN			2

#define MAC_HIGH_GPIO_OFFSET		0x0 // 32 bits
#define MAC_LOW_GPIO_OFFSET			0x8 // 16 bits

/* JESD204B RX */
#define JESD204B_RX_BASE			XPAR_JESD204B_RX_AXI_0_BASEADDR

/* UART */
//#define UART_DEVICE_ID 				XPAR_UARTLITE_0_DEVICE_ID
//XUartLite uart;

u8 default_mac[6] = {0xdf, 0xc1, 0xce, 0xc0, 0xdf, 0xc0};

void write_gpio(uint32_t base, uint32_t pin, uint32_t value)
{
	uint32_t *ptr;

	/* tristate off */
	ptr  = (uint32_t*)(base + 0x04);
	*ptr &= ~(1 << pin);

	/* gpio value */
	ptr = (uint32_t*)base;
	if(value){
		*ptr |= (1 << pin);
	}else{
		*ptr &= ~(1 << pin);
	}

}

int i2c_write_config(u32 base_addr, u8 i2c_addr, si5348_revd_register_t const *config, int cnt)
{
	int write_cnt = 0;
	while(write_cnt < cnt)
	{
		if(write_cnt == 3)
		{
			sleep(1);
		}
    	i2c_send_byte(base_addr, i2c_addr, 0x01, config[write_cnt].address >> 8);
    	i2c_send_byte(base_addr, SI5348B_D_GM_I2C_ADDRESS, config[write_cnt].address & 0xff, config[write_cnt].value);
		write_cnt++;
	}
	return write_cnt;
}

int i2c_read_mac(u32 base_addr, u8 i2c_addr, uint8_t *mac)
{
	int read_cnt = 0;
	read_cnt = i2c_rcv_bytes(base_addr, i2c_addr, EEPROM_MAC_ADDR, mac, 6);
	return read_cnt;
}

void setup_mac(u8 *mac0, u8 *mac1)
{
	/* HOST 0 */
	u32 *ptr = (u32*)(HOST0_MAC_GPIO_BASE + MAC_HIGH_GPIO_OFFSET);
	*ptr = (mac0[0] << 24) | (mac0[1] << 16) | (mac0[2] << 8) | (mac0[3]);
	ptr = (u32*)(HOST0_MAC_GPIO_BASE + MAC_LOW_GPIO_OFFSET);
	*ptr = (mac0[4] << 8) | (mac0[5]);


	/* HOST 1 */
	ptr = (u32*)(HOST1_MAC_GPIO_BASE + MAC_HIGH_GPIO_OFFSET);
	*ptr = (mac1[0] << 24) | (mac1[1] << 16) | (mac1[2] << 8) | (mac1[3]);
	ptr = (u32*)(HOST1_MAC_GPIO_BASE + MAC_LOW_GPIO_OFFSET);
	*ptr = (mac1[4] << 8) | (mac1[5]);

}

#define USE_PLL1
//#define USE_TEST_PATTERN
//#define USE_PRBS_TEST

int main()
{
	u8 reg_val = 0;
	u8 mac0[6];
	u8 mac1[6];
	XSpi  adc_spi;
	XSpi  hmc_spi;
	uint16_t adc_chip_id, adc_vendor_id;
	struct jesd204b_dev *jesd204b_dev;

	xil_printf("*** RDMA & ADC test application ***\n\r");

	if(spi_init(&adc_spi, ADC_SPI_DEV)){
		xil_printf("Failed to initialize ADC SPI\n\r");
		goto failed;
	}


	if(spi_init(&hmc_spi, HMC_SPI_DEV)){
		xil_printf("Failed to initialize HMC SPI\n\r");
		goto failed;
	}

	XSpi_SetSlaveSelect(&adc_spi, 1);
	XSpi_SetSlaveSelect(&hmc_spi, 1);

	/* Reset HMC and JESD and UDP */
	write_gpio(AXI_GPIO_BASE, GPIO_JESD_RESETN_PIN, 0);
	write_gpio(AXI_GPIO_BASE, GPIO_HMC_RESET_PIN, 1);
	write_gpio(AXI_GPIO_BASE, GPIO_UDP_RESET_PIN, 1);


	/* get hosts mac addresses */
	if(i2c_read_mac(XPAR_AXI_IIC_0_BASEADDR, EEPROM_I2C_ADDRESS, mac0) != sizeof(mac0))
	{
		memcpy(mac0, default_mac, sizeof(mac0));
	}
	memcpy(mac1, mac0, sizeof(mac0));
	mac1[5] = mac1[5] + 1;
	setup_mac(mac0, mac1);

	/****** Initialize Clock manager  ********/
	/* Write configuration to clock manager */
    i2c_write_config(XPAR_AXI_IIC_0_BASEADDR, SI5348B_D_GM_I2C_ADDRESS, si5348_revd_registers, SI5348_REVD_REG_CONFIG_NUM_REGS);

	/****** Initialize HMC - clock distribution ********/

	/* Switch HMC reset off */
	usleep(1000);
	write_gpio(AXI_GPIO_BASE, GPIO_HMC_RESET_PIN, 0);
	usleep(1000);

	spi_write_reg(&hmc_spi, 0x0000, 0x01);
	spi_write_reg(&hmc_spi, 0x0000, 0x00);
	/* Write configuration */
	if(hmc_write_conf(&hmc_spi)){
		xil_printf("Failed to write HMC configuration\n\r");
	}else{
		xil_printf("HMC configuration was successfully written\n\r");
	}


	spi_write_reg(&hmc_spi, 0x0002, 0x04);
	usleep(100000);
	/* Restart PLL */
	spi_write_reg(&hmc_spi, 0x0001, 0x62);
//	usleep(1000)
#ifdef USE_PLL1
	spi_write_reg(&hmc_spi, 0x0001, 0x60);
#else
	spi_write_reg(&hmc_spi, 0x0001, 0x70);
#endif
	usleep(1000000);

	/* Wait until HMC is locked */
#ifdef USE_PLL1
	do{
		spi_rw_reg(&hmc_spi, 0x82, &reg_val, 0);
	}while((reg_val & 0x02) == 0);
#endif

	/************ Initialize ADC *************/

	/* Soft reset */
	if(spi_write_reg(&adc_spi, AD_SPI_CONFIG_A_REG, 0x81)){
		xil_printf("Unable to write ADC register\n\r");
		goto failed;
	}

	/* Wait some time after reset - 10ms */
	usleep(10000);

	/* Get chip and vendor ID - to get any output */
	if(adc_get_chip_vendor_id(&adc_spi, &adc_chip_id, &adc_vendor_id)){
		xil_printf("Unable to read ADC chip and vendor ID\n\r");
		goto failed;
	}
	xil_printf("ADC vendor id: %04x, chip id: %04x\n\r", adc_chip_id, adc_vendor_id);

	/* Power down lanes */
	if(spi_write_reg(&adc_spi, AD_LANE_PWDN_REG, 0xff)){
		xil_printf("Unable to write ADC register\n\r");
		goto failed;
	}

	/* Set ADC registers */
	if(adc_write_conf(&adc_spi)){
		xil_printf("Unable to write configuration to ADC\n\r");
		goto failed;
	}

#ifdef USE_TEST_PATTERN
	/* Set user test pattern */
	if(adc_write_user_test_pattern(&adc_spi)){
		xil_printf("Unable to write ADC test pattern\n\r");
		goto failed;
	}

	/* ADC test pattern */
	if(spi_write_reg(&adc_spi, 0x0550, 0x0f)){
		xil_printf("Unable to write ADC register\n\r");
		goto failed;
	}
#endif

#ifdef	USE_PRBS_TEST
	/* Lane test pattern */
	if(spi_write_reg(&adc_spi, 0x0573, 0xd3)){
		xil_printf("Unable to write ADC register\n\r");
		goto failed;
	}
#endif
	/* Power up lanes */
	if(spi_write_reg(&adc_spi, AD_LANE_PWDN_REG, 0x00)){
		xil_printf("Unable to write ADC register\n\r");
		goto failed;
	}

	/* Perform after reset initialization */
	if(adc_after_reset_init(&adc_spi)){
		xil_printf("Unable to perform ADC after reset initialization\n\r");
		goto failed;
	}

	/* Wait until ADC PLL is locked */
	if(spi_rw_reg(&adc_spi, AD_PLL_STAT_REG, &reg_val, 0)){
		xil_printf("ADC SPI read failed\n\r");
		goto failed;
	}

	while(!(reg_val & 0x80)){
		xil_printf("ADC PLL not locked\n\r");
		usleep(500000);
		if(spi_rw_reg(&adc_spi, AD_PLL_STAT_REG, &reg_val, 0)){
			xil_printf("ADC SPI read failed\n\r");
		}
	}

	/* Enable JESD */
	write_gpio(AXI_GPIO_BASE, GPIO_JESD_RESETN_PIN, 1);
	usleep(1000);


	/***************** Initialize JESD core ***************/
	jesd204b_dev = jesd204b_init((void *)JESD204B_RX_BASE, 1, 32, 8);
	if (jesd204b_dev == NULL) {
		xil_printf("Cannot init JESD204B Core\r\n");
		goto failed;
	}

	/* Print basic info */
	jesd204b_print(jesd204b_dev);
	/* Take it out of global reset*/
	jesd204b_glbl_reset(jesd204b_dev, 0);
	/* Start proper acquisition */
	jesd204b_start(jesd204b_dev);

	/* Enable UDP */
	write_gpio(AXI_GPIO_BASE, GPIO_UDP_RESET_PIN, 0);

    while(1)
    {

		if(spi_rw_reg(&hmc_spi, 0x82, &reg_val, 0)){
			xil_printf("HMC SPI read failed\n\r");
		}else{
			xil_printf("HMC %04x: %02x\n\r", 0x82, reg_val);
		}

		if(spi_rw_reg(&adc_spi, AD_PLL_STAT_REG, &reg_val, 0)){
			xil_printf("ADC SPI read failed\n\r");
		}else{
			xil_printf("ADC %04x: %02x\n\r", AD_PLL_STAT_REG, reg_val);
		}

    	i2c_send_byte(XPAR_AXI_IIC_0_BASEADDR, SI5348B_D_GM_I2C_ADDRESS, 0x01, 0x00);
    	i2c_rcv_byte(XPAR_AXI_IIC_0_BASEADDR, SI5348B_D_GM_I2C_ADDRESS, 0x05, &reg_val);
    	reg_val = 0;

//   		jesd204b_print_status(jesd204b_dev);
//   		xil_printf("\n\r");
    	sleep(2);
    }

failed:
	while(1){
		xil_printf("Failed\n\r");
		sleep(5);
	};

    return 0;
}

