This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Question about X-MODE and long distant transmission of SN65DP159

Other Parts Discussed in Thread: SN65DP159

hi,everyone,

In my project, I use SN65DP159 and Xilinx FPGA XC7K410T to design a 4K2K/60Hz monitor with DisplayPort interface. SN65DP159 works in a special mode called X-Mode according to TI's application document <<SLLA358>>, and my hardware design is complied with this document. the monitor can works normally with a DP cable which is less than 2 meters connected to a PC. but if I change to a 5-meters cable, the monitor has no display output. The new cable is tested OK when connect a PC to a samsung 4K2K monitor. So it looks like the SN65DP159 does not work. the attachment is the source code for SN65DP159 including dp159.h, dp159.c, main.h, main.c. I want to know whether the configuration for SN65DP159 is correct or not? How to modify the configuration about SN65DP159 to satisfy long distance signal transmission?

thanks.


/*******************************************************************************
*
* Copyright (C) 2015 Xilinx, Inc. All rights reserved.
* ____ ____
* / /\/ /
* /___/ \ / Vendor: Xilinx
* \ \ \/
* \ \
* / /
* /___/ /\
* \ \ / \
* \___\/\___\
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
*******************************************************************************/

#ifndef DP159_H_
#define DP159_H_

/*****************************************************************************/
// Following variables need to be mapped to right instances from xparameters.h
#define DP159_BASE_ADDR XPAR_IIC_0_BASEADDR
#define DP159_IIC_ID XPAR_IIC_0_DEVICE_ID
#define TIMER_CLK_FREQ XPAR_TMRCTR_0_CLOCK_FREQ_HZ
///
/*****************************************************************************/

XStatus Init_dp159_IIC ();

//Following are DP159 related parameters
////////////////////////////////////////////////////////////////////////////////
//
// Set the DEF_LOCK_WAIT value to a large number. This will allow the DP159
// control to remain in the read-lock-status state for long enough for the
// DP159 to attain lock in the following condition:
//
// 1) The VOD of the source device is low, such that the DP159 essentially
// sees no clock signal at all. (This occurs especially with a PG1.1
// V3 device which has the EQ bypass-circuitry, which squashes the
// input signal.
//
// 2) The DPRX XILINX_MIN_VOLTAGE_SWING_SET has the vswing-sweep-count set
// to a value greater than 1 (which it should be). In this case, the
// DPRX will not request a greater VOD from the source until after a
// few iterations.
//
////////////////////////////////////////////////////////////////////////////////

#define DEF_LOCK_WAIT 512 // 255
// Wait a really long time (up to ~30ms)
//
// Each reg-read iteration takes about 100us @ 400kbps IIC.
//
// Interesting...if a large value is used here (128), then the DP159 PLL
// will always eventually lock (may take several msecs). But the Xilinx
// DP sink may sometimes set the VOD level to just 0, which causes bit
// errors to be seen by both the DP159 and Xilinx sink.
//
// But using a smaller value (e.g., 5) will essentially force the Xilinx
// part to crank up the VOD, which will allow the link to work without
// bit errors.

#define DEF_EQ_LEV 8 // 6 // 8
#define AUX_RD_INTERVAL_100U 0
#define AUX_RD_INTERVAL_4M 1
#define AUX_RD_INTERVAL_8M 2
#define AUX_RD_INTERVAL_12M 3
#define AUX_RD_INTERVAL_16M 4
#define DEF_PLL_CTRL_CR 0x33 // 0x33
#define DEF_PLL_CTRL_PD_HBR2 0x30 // 0x31
#define DEF_PLL_CTRL_PD_HBR 0x30 // 0x31
#define DEF_PLL_CTRL_PD_RBR 0x30 // 0x31
#define DEF_EXP_RES 0x00 // 0x00
#define DEF_CPI_CR 0x3F // 0x3F
#define DEF_CPI_PD_HBR2 0x5F // 43d 0x15
#define DEF_CPI_PD_HBR 0x27 // 39d 0x20 0x10
#define DEF_CPI_PD_RBR 0x1F // 31d 0x18 0x0C
#define DEF_AUX_RD_INTERVAL AUX_RD_INTERVAL_4M // AUX_RD_INTERVAL_8M // AUX_RD_INTERVAL_100U
// NOTE: Some DP source devices (e.g., most Intel drivers) do not
// necessarily obey the AUX_RD_INTERVAL setting, but will instead
// use a much smaller value (closer to the 100us/400us of setting 0).
// However, the code provided here still allows the Xilinx DPRX to
// work with these sources. Furhter, use of the AUX_RD_INTERVAL_8M
// value allows the Xilinx DPRX to work reliably with the
// DSI86 as source (which does obey the AUX_RD_INTERVAL setting).
// (For some reason, the DPRX will sometimes not successfully
// train with the DSI86 source when AUX_RD_INTERVAL is set below
// 8ms with SSC on.)
#define LBW_HBR2 XDP_RX_OVER_LINK_BW_SET_540GBPS // 0x14 = 20 -> 20 * 270 Mbps = 5.40 Gbps
#define LBW_HBR XDP_RX_OVER_LINK_BW_SET_270GBPS // 0x0A = 10 -> 10 * 270 Mbps = 2.70 Gbps
#define LBW_RBR XDP_RX_OVER_LINK_BW_SET_162GBPS // 0x06 = 6 -> 6 * 270 Mbps = 1.62 Gbps
#define LBW_RNDM 0xFF //
#define L_EX 0xFFFF // csrAV list terminator
#define DEF_TP1_LOCK_DELAY 275 // 300 // in uSec
#define ASCII_CTRL_C 0x03 // Control-C key
#define ASCII_ESC 0x1B // Escape Key
#define CT_TIMEOUT_US 999000 // 999 msec
#define CT_TIMEOUT_CNT (CT_TIMEOUT_US * (TIMER_CLK_FREQ/1000000))
#define TSTATE_UNK 15
#define TSTATE_OFF 10
#define TSTATE_DIS 0
#define TSTATE_TBW 1
#define TSTATE_TP1 2
// #define TSTATE_TP1A 22
#define TSTATE_TP2 3
#define TSTATE_RUN 4
#define DP159_IIC_SLAVE 0x5E
#define TICS_PER_SEC 1 // Timer interrupt every sec
#define TIMER_CNTR_0 0
#define TIMER_PERIOD (TIMER_CLK_FREQ / TICS_PER_SEC)
#define TIMER_RESET_VALUE TIMER_PERIOD // (TIMER_PERIOD - 1) // Timer interrupt every sec
typedef unsigned int UINT32; /**< unsigned 32-bit */

#endif /* DP159_H_ */

/*******************************************************************************
*
* Copyright (C) 2015 Xilinx, Inc. All rights reserved.
* ____ ____
* / /\/ /
* /___/ \ / Vendor: Xilinx
* \ \ \/
* \ \
* / /
* /___/ /\
* \ \ / \
* \___\/\___\
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
*******************************************************************************/

/* This file contains all the routines, functions declarations needed for
* DP159 programming.
* There are four major functions used to program the DP159
* 1. reset_dp159 : This is used to set/reset the dp159
* 2. initial_prog_dp159 : This function does the initial programming of dp159
* This is used only once when elf is first run.
* 3. tp1_prog_dp159 : This function is used when TP1 interrupt is seen.
* This would be called every time a TP1 interrupt is seen
* 4. tp2_prog_dp159 : This function is used when TP2, TP3 interrupt is seen.
* This would be called every time a TP2,TP3 interrupt is
* seen.
*
* To write to any register of dp159, "write_csr" function is used. This
* function simply writes the data to the specified address using AXI IIC in
* dynamic mode. The arguments passed to "write_csr" are addr & data.
* To read from any register of dp159, "read_csr" function is used. This
* function returns the data from the specified address. The argument
* passed to this function is addr.
*
* User can use dp159.c and dp159.h after ensuring the correct values for
* XPAR_IIC_0_BASEADDR, XPAR_IIC_0_DEVICE_ID, XPAR_TMRCTR_0_CLOCK_FREQ_HZ
* from xparameters.h
*
*/


#include "xil_types.h"
#include "xil_types.h"
#include "xtmrctr.h"
#include "xiic.h"
#include "xdp_hw.h"
#include "xparameters.h"
#include "dp159.h"

void reset_dp159(int reset);
void initial_prog_dp159 (void);
void tp1_prog_dp159 (XTmrCtr *InstancePtr, u8 link_lanecnt, u16 link_bw);
void tp2_prog_dp159 (XTmrCtr *InstancePtr, u8 link_lanecnt, u16 link_bw);
void disconnect_prog_dp159 (void);
int write_csr (u8 addr, u8 data);
u8 read_csr (u8 addr);

typedef struct {
u32 tic; // Seconds (interrupt) count (only field in structure: u32 Interrupts)
u32 sub; // Timer count
} time_info;


// Programmable/updateable constants
u16 cpi_cr = DEF_CPI_CR;
u16 cpi_pd_hbr2 = DEF_CPI_PD_HBR2;
u16 cpi_pd_hbr = DEF_CPI_PD_HBR;
u16 cpi_pd_rbr = DEF_CPI_PD_RBR;
u16 lock_wait = DEF_LOCK_WAIT;
u16 pll_ctrl_cr = DEF_PLL_CTRL_CR;
u16 pll_ctrl_pd_hbr2 = DEF_PLL_CTRL_PD_HBR2;
u16 pll_ctrl_pd_hbr = DEF_PLL_CTRL_PD_HBR;
u16 pll_ctrl_pd_rbr = DEF_PLL_CTRL_PD_RBR;
u16 exp_res = DEF_EXP_RES; // 0 or 1
u16 eq_lev = DEF_EQ_LEV;
u16 en_char_align = 1;
u16 aux_rd_interval = DEF_AUX_RD_INTERVAL;
u16 tp1_fixed_delay = DEF_TP1_LOCK_DELAY;
u16 use_lock_cmplt = 1;
u16 def_num_lanes = 4;
u16 monitor_bert = 1;
u32 def_phy_config = 0x03800000; // XILINX_DISPLAYPORT_RX_PHY_RESET 0x01000000
u32 tp1_handler_cnt_hbr2 = 0;
u32 tp1_handler_cnt_hbr = 0;
u32 tp1_handler_cnt_rbr = 0;
u32 tp23_handler_cnt_hbr2 = 0;
u32 tp23_handler_cnt_hbr = 0;
u32 tp23_handler_cnt_rbr = 0;
u32 bw_handler_cnt = 0;
u32 disconnect_cnt = 0;
time_info bw_start_time;
time_info tp1_start_time;
time_info tp23_start_time;
time_info tlost_start_time;
time_info tdone_start_time;
u8 training_done_lost_ints_on = 1;
u8 lock_status = 0;
u8 tstate = TSTATE_UNK;
u8 ecnt_0 = 0;
u8 ecnt_1 = 0;
u16 err_cnt = 0;
static u32 lock_cnt ; // = 0;
u8 ReadBuffer[8]; // Read buffer for reading a page.
u8 WriteBuffer[8]; // Read buffer for reading a page.
volatile u32 tics;


time_info tp1a_start_time;
u8 dp159_page = 0;
XIic dp159_IIC; // DP159 IIC interface

XStatus Init_dp159_IIC ()
{
XStatus Status;
XIic_Config *ConfigPtr_dp159_IIC; // Pointer to configuration data

// Initialize the IIC driver so that it is ready to use.
ConfigPtr_dp159_IIC = XIic_LookupConfig (DP159_IIC_ID);
if (ConfigPtr_dp159_IIC == NULL) {
return XST_FAILURE;
}

Status = XIic_CfgInitialize (&dp159_IIC, ConfigPtr_dp159_IIC, ConfigPtr_dp159_IIC->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

return XST_SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////

int iic_dp159 (void) {
int Status;
Status = XIic_DynInit (DP159_BASE_ADDR);
if (Status != XST_SUCCESS) {
xil_printf ("\r\nI2C Init 0 Failed");
return XST_FAILURE;
}
return 0;
}

////////////////////////////////////////////////////////////////////////////////

u8 read_csr (u8 addr) { // return CSR value
unsigned bytesSent=0;
// Just use polled method...
WriteBuffer[0] = addr;
bytesSent = XIic_DynSend (DP159_BASE_ADDR, DP159_IIC_SLAVE, WriteBuffer, 1, XIIC_REPEATED_START);
if (bytesSent != 1) xil_printf ("\r\nREAD_CSR failure ADDR:%0X SENT:%d\r\n", addr, bytesSent);
bytesSent = XIic_DynRecv (DP159_BASE_ADDR, DP159_IIC_SLAVE, ReadBuffer, 1);
if (bytesSent != 1) xil_printf ("\r\nREAD_CSR failure ADDR:%0X RCVD:%d\r\n", addr, bytesSent);
else if (addr == 0xFF) dp159_page = ReadBuffer[0];
return ReadBuffer[0];

}

int write_csr (u8 addr, u8 data) { // return number of bytes sent

// Use IIC in dynamic mode
int i;
WriteBuffer[0] = addr;
WriteBuffer[1] = data;

unsigned bytesSent=0;

if (addr == 0xFF) data &= 0x1; // limit page to 0 or 1
i = 0;
while (bytesSent = XIic_DynSend (DP159_BASE_ADDR, DP159_IIC_SLAVE, WriteBuffer, 2, XIIC_STOP),
bytesSent != 2 && i++<2) { // try twice
xil_printf ("\r\nWRITE_CSR failure ADDR:%0X DATA:%0X SENT:%d\r\n", addr, data, bytesSent);
}
if (addr == 0xFF) {
dp159_page = data;
}
return bytesSent;
}

////////////////////////////////////////////////////////////////////////////////
// This function is used to drive the reset/oen pin of dp159
// the reset/oen pin is driven using the GPO output of axi_iic

void reset_dp159 (int reset) {
if (reset){
*(volatile UINT32*)(DP159_BASE_ADDR + 0x124) = 0x0;
} else {
*(volatile UINT32*)(DP159_BASE_ADDR + 0x124) = 0x1;
}
}


////////////////////////////////////////////////////////////////////////////////
// DP RX uses the forwarded clock from DP159. Hence, the final configuration of
// DP159 happens only when cable is plugged in.
// The initial_prog_dp159 does the initial programming of DP159
// Subsequent programming happens when TP1 and TP2/3 interrupts are received
// TP1 and TP2,3 are generated only when cable is plugged in

void initial_prog_dp159 (void) {
xil_printf ("\r\nInitializing DP159...");
write_csr (0xFF, 0x00); // Select Page 0
write_csr (0x09, 0x36); // Enable X-Mode
write_csr (0x0A, 0x7B); // Disable HPD_SNK pass-thru to HPD_SRC. Enable AUX
// write_csr (0x0D, 0xC0); // Clock on AUX is 1/40 datarate and enabled.
write_csr (0x0D, 0x80); // Clock on AUX is 1/20 datarate and enabled.

write_csr (0x0C, 0x6D); // Set TX Swing to MAX
// write_csr (0x0C, 0x00); // Set TX Swing to NOM
if (en_char_align) {
write_csr (0x10, 0x00); // Turn off pattern verifier
} else {
write_csr (0x10, 0x11); // Len = PRBS23, Sel = PRBS mode to turn off char-alignment !!!!!!!!
}
write_csr (0x16, 0xF1); // Enable DP_TST_EN (disable char-alignment on all lanes)
write_csr (0xFF, 0x01); // Select Page 1
// CONFIGURE PLL BLOCK
write_csr (0x00, 0x02); // Enable Bandgap.
tstate = TSTATE_OFF;
write_csr (0x04, 0x80); // PLL_FBDIV is 40
write_csr (0x05, 0x00); //
write_csr (0x08, 0x00); //
write_csr (0x0D, 0x02); // Selects Lane0 for clock.
write_csr (0x0E, 0x03); // CDR_CONFIG[4:0]. FIXED, LN0.
write_csr (0x01, 0x01); // CP_EN is PLL mode
write_csr (0x02, cpi_cr); // CP_CURRENT
write_csr (0x0B, pll_ctrl_cr); // Test. May not use.
write_csr (0xA1, 0x02); // Oscillator enable.
write_csr (0xA4, 0x02); // Override enables.
// CONFIGURE TX BLOCK
write_csr (0x10, 0xF0); // ENTX Disable
write_csr (0x11, 0x30); // TX_RATE is Full Rate, TX_TERM = 75 to 150 , TX_INVPAIR = None
write_csr (0x14, 0x00); // HDMI_TWPST1 is 0dB de-emphasis
write_csr (0x12, 0x03); // SLEW_CTRL is Normal, SWING is 600mV.
write_csr (0x13, 0xFF); // FIR_UPD. Load TX settings
write_csr (0x13, 0x00); //

// CONFIGURE RX BLOCK
write_csr (0x30, 0xE0); // Disable Receivers
write_csr (0x32, 0x00); // PD_RXINT
write_csr (0x31, 0x00); // RX_RATE is Full
// write_csr (0x4D, 0x28); // EQFTC = 2 and EQLEV = 8
write_csr (0x4D, (eq_lev & 0x0F)); // EQFTC = 1 and EQLEV = 2
// write_csr (0x4C, 0x03); // Enable Adaptive EQ
write_csr (0x4C, 0x01); // Enable Fixed EQ (must not use adaptive when RX is disabled)
write_csr (0x34, 0x01); // Enable Offset Correction (gated by rx_ld) !!!!
// write_csr (0x3C, 0x04); // Change default of CDR settle
write_csr (0x32, 0xF0); // Load Rx Settings
write_csr (0x32, 0x00); //
write_csr (0x33, 0xF0); // Load EQ settings
// write_csr (0x33, 0x00); // JMS - Just leave EQ_LD on continuously ??????????????
// write_csr (0x30, 0xE0); // Enable lane 0 analog only
write_csr (0xFF, 0x00); // Select Page 0
write_csr (0x0A, 0x3B); // Enable HPD_SNK pass thru to HPD_SRC. Retimer.
write_csr (0xFF, 0x01); // Select Page 1
xil_printf ("..done !!\r\n");
}


void tp1_prog_dp159 (XTmrCtr *InstancePtr, u8 link_lanecnt, u16 link_bw) {

// Get time that handler was entered
tp1_start_time.tic = tics;
tp1_start_time.sub = XTmrCtr_GetValue (InstancePtr, TIMER_CNTR_0);

// config_dp159 (TSTATE_TP1); // Note: this routine sets the link_bw and link_lanecnt vars
tstate = TSTATE_TP1;
if (link_bw == LBW_HBR2) tp1_handler_cnt_hbr2++;
if (link_bw == LBW_HBR) tp1_handler_cnt_hbr++;
if (link_bw == LBW_RBR) tp1_handler_cnt_rbr++;
u8 rtxen, eqreg, tsten;
// xil_printf("\r\n link_lanecnt = %d",link_lanecnt);
rtxen = (link_lanecnt == 1) ? 0xE1 : (link_lanecnt == 2) ? 0xC3 : 0x0F;
eqreg = ((link_bw == LBW_HBR2) ? 0x0 : (link_bw == LBW_HBR ) ? 0x1 : 0x2 ) << 4 | (eq_lev & 0x0F);
tsten = (link_lanecnt == 1) ? 0x11 : (link_lanecnt == 2) ? 0x31 : 0xF1; // rval = (((((0x01 << link_lanecnt)-1) & 0xF)<<4) | 0x01);
// 1 : 0x11, 2 : 0x31, 4 : 0xF1
// Add all BW_handler processing here...
write_csr(0x00, 0x02 ); // Enable Bandgap, DISABLE PLL, clear A_LOCK_OVR (to reset it)
write_csr(0x01, 0x01 ); // CP_EN = PLL (reference) mode
write_csr(0x0B, pll_ctrl_cr); // Set PLL control
write_csr(0x02, cpi_cr ); // Set CP_CURRENT
write_csr(0x30, rtxen ); // Enable RX lanes
write_csr(0x00, 0x03 ); // Enable Bandgap, ENABLE PLL, clear A_LOCK_OVR
write_csr(0x4C, 0x01 ); // Enable fixed EQ (to reset adaptive EQ logic)
write_csr(0x4D, eqreg ); // Set EQFTC and EQLEV (fixed EQ)

// Wait for PLL lock...
lock_cnt = 0;
lock_status = 0;
if (use_lock_cmplt) {
ReadBuffer[0] = 0;
while (ReadBuffer[0] == 0 && lock_cnt < lock_wait) {
read_csr (0x00);
ReadBuffer[0] = ReadBuffer[0] & 0x40; // 0x80;
lock_cnt++;
}
lock_status = (ReadBuffer[0] != 0);
} else {
// Just wait a fixed delay
u32 c1, c2, c3;
c1 = XTmrCtr_GetValue (InstancePtr, TIMER_CNTR_0); // Starting count of timer
c2 = (tp1_fixed_delay * (TIMER_CLK_FREQ/1000000)); // delta count equal to tp1_fixed_delay us
while (c3 = XTmrCtr_GetValue (InstancePtr, TIMER_CNTR_0),
(((c1 - c3) + TIMER_PERIOD) % TIMER_PERIOD) < c2) ;
}

// Get time that DP159 PLL was locked
tp1a_start_time.tic = tics;
tp1a_start_time.sub = XTmrCtr_GetValue (InstancePtr, TIMER_CNTR_0);

u16 cpi, pll_ctrl;
if (link_bw == LBW_HBR2) {
// lock_cnt_hbr2 = lock_cnt;
cpi = cpi_pd_hbr2;
pll_ctrl = pll_ctrl_pd_hbr2;
} else if (link_bw == LBW_HBR ) {
// lock_cnt_hbr = lock_cnt;
cpi = cpi_pd_hbr;
pll_ctrl = pll_ctrl_pd_hbr;
} else {
// lock_cnt_rbr = lock_cnt;
cpi = cpi_pd_rbr;
pll_ctrl = pll_ctrl_pd_rbr;
}
write_csr (0x10, rtxen); // Enable TX lanes
write_csr (0x00, (0x23 | ((exp_res & 0x1)<<2))); // Enable PLL and Bandgap, set A_LOCK_OVR, and set expand LPRES
write_csr (0x02, cpi ); // CP_CURRENT
write_csr (0x0B, pll_ctrl ); // Set PLL control
write_csr (0x01, 0x02 ); // CP_EN is PD mode
write_csr (0xFF, 0x00 ); // Select page 0
if (en_char_align) {
write_csr (0x16, tsten); // Set DP_TST_EN per #lanes, latch FIFO errors
write_csr (0x10, 0x00); // Disable PV (allows char-align and 8b10 decode to operate)
} else {
write_csr (0x16, 0xF1); // Set DP_TST_EN on all lanes to disable char-alignment
write_csr (0x10, 0x11); // Len = PRBS23, Sel = PRBS mode to turn off char-alignment !!!!!!!!
}
write_csr (0xFF, 0x01); // Select page 1
}


void tp2_prog_dp159 (XTmrCtr *InstancePtr, u8 link_lanecnt, u16 link_bw) {
tp23_start_time.tic = tics;
tp23_start_time.sub = XTmrCtr_GetValue (InstancePtr, TIMER_CNTR_0);
if (link_bw == LBW_HBR2) tp23_handler_cnt_hbr2++;
else if (link_bw == LBW_HBR) tp23_handler_cnt_hbr++;
else tp23_handler_cnt_rbr++;
// config_dp159 (TSTATE_TP2);
tstate = TSTATE_TP2;
// tp23_start_training_lane_0_set = dprx_reg_read (XILINX_DISPLAYPORT_RX_DPCD_TRAINING_LANE_0_SET);
// tp23_start_training_lane_1_set = dprx_reg_read (XILINX_DISPLAYPORT_RX_DPCD_TRAINING_LANE_1_SET);
// tp23_start_training_lane_2_set = dprx_reg_read (XILINX_DISPLAYPORT_RX_DPCD_TRAINING_LANE_2_SET);
// tp23_start_training_lane_3_set = dprx_reg_read (XILINX_DISPLAYPORT_RX_DPCD_TRAINING_LANE_3_SET);
write_csr (0x4C, 0x03); // Enable Adaptive EQ
write_csr (0xFF, 0x00); // Select page 0
write_csr (0x15, 0x18); // Clear BERT counters and TST_INTQ latches -- Self-clearing in DP159
// write_csr (0xFF, 0x01); // Select page 1
// write_csr (0xFF, 0x00); // Select page 0
err_cnt = read_csr (0x18); // Read core BERT counter [7:0]
err_cnt += ((read_csr(0x19) & 0xF) << 8); // Read core BERT counter [11:8]
write_csr (0xFF, 0x01); // Select page 1
}

void disconnect_prog_dp159 (void) {
disconnect_cnt++;

// config_dp159 (TSTATE_DIS);
// tstate = TSTATE_DIS;

// if (tstate == TSTATE_RUN) {
write_csr (0x00, 0x02); // Enable Bandgap, disable PLL, clear A_LOCK_OVR
write_csr (0x34, 0x01); // Enable Offset Correction (when RX next enabled) !!!!
write_csr (0x02, cpi_cr); // Set CP_CURRENT
write_csr (0x01, 0x01); // CP_EN = PLL (reference) mode
write_csr (0x0B, pll_ctrl_cr); // Set PLL control
write_csr (0x4D, (eq_lev & 0x0F)); // EQFTC = 1 and EQLEV = 2
write_csr (0x4C, 0x01); // Enable fixed EQ (use fixed when RX disabled)
write_csr (0x33, 0xF0); // Load EQ settings // JMS - make sure EQ load is always set
write_csr (0x10, 0xF0); // Disable TX (all lanes)
write_csr (0x30, 0xE0); // Enable RX Lane 0 analog only
// write_csr (0x33, 0x00); //
// }
}

/*******************************************************************************
*
* Copyright (C) 2015 Xilinx, Inc. All rights reserved.
* ____ ____
* / /\/ /
* /___/ \ / Vendor: Xilinx
* \ \ \/
* \ \
* / /
* /___/ /\
* \ \ / \
* \___\/\___\
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
*******************************************************************************/

#ifndef _MAIN_H_
#define _MAIN_H_

#include "main_def.h"

extern volatile u32 tics;

extern int vblank_count;
extern int training_done_count;
extern int training_lost_count;
extern u8 link_bw;
extern u8 training_done_lost_ints_on;
extern u16 aux_rd_interval;
extern u16 def_num_lanes;

extern XTmrCtr TimerCounterInst;
extern XTmrCtr TimerCounterInst1;
extern time_info tp1_start_time;
extern time_info tp23_start_time;
extern time_info bw_start_time;
extern time_info tlost_start_time;
extern time_info tdone_start_time;

extern void disconnect_prog_dp159 (void);
extern u32 next_lt_capture (int caller);

extern u8 tstate;
extern u32 def_phy_config;
extern u16 err_cnt;

#endif

/*******************************************************************************
*
* Copyright (C) 2015 Xilinx, Inc. All rights reserved.
* ____ ____
* / /\/ /
* /___/ \ / Vendor: Xilinx
* \ \ \/
* \ \
* / /
* /___/ /\
* \ \ / \
* \___\/\___\
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
*******************************************************************************/


#define VERSIONID "__JMS.20A__Latest__"

/**************************** Pre-processor directives *******************************/

#include "assert.h"
#include "time.h"
#include "unistd.h"
#include "math.h"
#include "stdlib.h"

#include "xil_cache.h"
#include "stdio.h"
#include "xparameters.h"
#include "xil_types.h"
#include "xil_assert.h"
#include "xtmrctr.h"
#include "xintc.h"
#include "xlib_string.h"

#include "xiic.h"
#include "xdp.h"
#include "main.h"
#include "xcresample.h"
#include "xrgb2ycrcb.h"
#include "xvtc.h"
#include "xaxivdma.h"
#include "xosd.h"
#include "ivk_osd.h"
#include "ivk_video_resolution.h"
#include "video_pipe.h"
#include "dp159.h"

#include "../common/xhdcp1x_example/inc/xhdcp1x_example.h"
#include "../common/xhdcp1x_example/inc/xhdcp1x_debug.h"
#include "../keymgmt/inc/eeprom.h"

//#include "../hdcp/inc/hdcp.h"
//#include "../hdcp/inc/hdcp_cipher.h"
//#include "../hdcp/inc/hdcp_config.h"
//#include "../hdcp/inc/hdcp_xilcmd.h"

//#include "../keymgmt/inc/keymgmt.h"
#include "../keymgmt/inc/eeprom.h"

/**************************** Constant Definitions *******************************/
#ifdef XPAR_XHDCP_NUM_INSTANCES
#define ENABLE_HDCP_IN_DESIGN 1
#else
#define ENABLE_HDCP_IN_DESIGN 0
#endif

#define REDUCED_BLANKING 1

/* Note, It needs to change based on the number of interface of keygen,
* and base address of each should be specified
*/
#if XPAR_HDCP_SUBSYSTEM_HDCP_KEYMNGMT_BLK_1_BASEADDR
unsigned int gKeyMGMTBaseAddress[1] = {XPAR_HDCP_SUBSYSTEM_HDCP_KEYMNGMT_BLK_1_BASEADDR};
int gIsKeyWrittenInEeeprom = FALSE;
#else
unsigned int gKeyMGMTBaseAddress[2] = {(unsigned int)NULL, (unsigned int)NULL};
#endif

/**************************** Type Definitions *******************************/

typedef u8 AddressType;

typedef struct {
u8 addr;
u8 data;
u8 init;
} HDMI_REG;

typedef struct {
u8 type;
u8 version;
u8 length;
u8 audio_coding_type;
u8 audio_channel_count;
u8 sampling_frequency;
u8 sample_size;
u8 level_shift;
u8 downmix_inhibit;
u8 channel_allocation;
u16 info_length;
} XilAudioInfoFrame;

typedef struct {
u16 addr;
u16 data;
} csrAV;

struct dma_chan_parms {
u32 Dma_Base_Addr;
u32 Perf_Dma_Base_Addr;
u32 AXIVDMA_DEVICE_ID;
u32 Tx_Intr;
u32 Rx_Intr;
u32 RD_ADDR_BASE;
u32 WR_ADDR_BASE;
u32 TX_BD_ADDR_BASE;
u32 RX_BD_ADDR_BASE;
u32 BlockStartOffset;
u32 BlockHoriz;
u32 BlockVert;
XAxiVdma AxiVdma;
XAxiVdma_DmaSetup ReadCfg;
XAxiVdma_DmaSetup WriteCfg;
XAxiVdma_Config *Config;
XAxiVdma_FrameCounter FrameCfg;
};

typedef enum {
ONLY_READ=1,
ONLY_WRITE,
BOTH
} vdma_run_mode;

typedef struct {
unsigned char lane_count;
unsigned char link_rate;
} lane_link_rate_struct;

/**************************** Global Structures *******************************/

u16 resolutions[RESOLUTIONS][VIDEO_TIMING_PARAMS] = {
// vav, vfp, vsw, vbp, vsp, hav, hfp, hsw, hbp, hsp
{ 480, 3, 4, 13, 1, 640, 16, 64, 80, 1 }, // 0:VIDEO_RESOLUTION_VGA
{ 480, 9, 6, 30, 1, 720, 16, 62, 60, 1 }, // 1:VIDEO_RESOLUTION_NTSC
{ 600, 1, 4, 23, 1, 800, 40, 128, 88, 1 }, // 2:VIDEO_RESOLUTION_SVGA
{ 768, 3, 6, 29, 1, 1024, 24, 136, 160, 1 }, // 3:VIDEO_RESOLUTION_XGA
{ 720, 5, 5, 20, 1, 1280, 110, 40, 220, 1 }, // 4:VIDEO_RESOLUTION_720P
{ 1024, 1, 3, 26, 1, 1280, 48, 184, 200, 1 }, // 5:VIDEO_RESOLUTION_SXGA
{ 1080, 4, 5, 36, 1, 1920, 88, 44, 148, 1 }, // 6:VIDEO_RESOLUTION_1080P
{ 1200, 1, 3, 46, 1, 1600, 64, 192, 304, 1 } // 7:VIDEO_RESOLUTION_UXGA
};

struct dma_chan_parms dma_struct[NUMBER_OF_DMAS_MAX];

lane_link_rate_struct lane_link_table[]=
{
{XDP_RX_OVER_LANE_COUNT_SET_1,XDP_RX_OVER_LINK_BW_SET_162GBPS},
{XDP_RX_OVER_LANE_COUNT_SET_2,XDP_RX_OVER_LINK_BW_SET_162GBPS},
{XDP_RX_OVER_LANE_COUNT_SET_4,XDP_RX_OVER_LINK_BW_SET_162GBPS},
{XDP_RX_OVER_LANE_COUNT_SET_1,XDP_RX_OVER_LINK_BW_SET_270GBPS},
{XDP_RX_OVER_LANE_COUNT_SET_2,XDP_RX_OVER_LINK_BW_SET_270GBPS},
{XDP_RX_OVER_LANE_COUNT_SET_4,XDP_RX_OVER_LINK_BW_SET_270GBPS},
{XDP_RX_OVER_LANE_COUNT_SET_1,XDP_RX_OVER_LINK_BW_SET_540GBPS},
{XDP_RX_OVER_LANE_COUNT_SET_2,XDP_RX_OVER_LINK_BW_SET_540GBPS},
{XDP_RX_OVER_LANE_COUNT_SET_4,XDP_RX_OVER_LINK_BW_SET_540GBPS},
};

HDMI_REG hdmi_iic[NUMBER_OF_HDMI_REGS] =
{
{0x41, 0x00, 0x10}, // Power Down Control
// R0x41[ 6] = PowerDown = 0 (power-up)
{0xD6, 0x00, 0xC0}, // HPD Control
// R0xD6[7:6] = HPD Control = 11 (always high)
{0x15, 0x00, 0x01}, // Input YCbCr 4:2:2 with separate syncs
{0x16, 0x00, 0x3C}, // Output format 444, Input Color Depth = 8
// R0x16[ 7] = Output Video Format = 0 (444)
// R0x16[5:4] = Input Video Color Depth = 11 (8 bits/color)
// R0x16[3:2] = Input Video Style = 11 (style 3)
// R0x16[ 1] = DDR Input Edge = 0 (falling edge)
// R0x16[ 0] = Output Color Space = 0 (RGB)
{0x18, 0x00, 0xAB}, // Color Space Conversion
// R0x18[ 7] = CSC enable = 1 (CSC enabled)
// R0x18[6:5] = CSC Scaling Factor = 01 (+/- 2.0, -8192 - 8190)
// R0x18[4:0] = CSC coefficient A1[12:8]
{0x19, 0x00, 0x37}, // R0x19[7:0] = CSC coefficient A1[ 7:0]
{0x1A, 0x00, 0x08}, // R0x1A[ 5] = CSC coefficient update
// R0x1A[4:0] = CSC coefficient A2[12:8]
{0x1B, 0x00, 0x00}, // R0x1B[7:0] = CSC coefficient A2[ 7:0]
{0x1C, 0x00, 0x00}, // R0x1C[4:0] = CSC coefficient A3[12:8]
{0x1D, 0x00, 0x00}, // R0x1D[7:0] = CSC coefficient A3[ 7:0]
{0x1E, 0x00, 0x1A}, // R0x1E[4:0] = CSC coefficient A4[12:8]
{0x1F, 0x00, 0x86}, // R0x1F[7:0] = CSC coefficient A4[ 7:0]
{0x20, 0x00, 0x1A}, // R0x20[4:0] = CSC coefficient B1[12:8]
{0x21, 0x00, 0x49}, // R0x21[7:0] = CSC coefficient B1[ 7:0]
{0x22, 0x00, 0x08}, // R0x22[4:0] = CSC coefficient B2[12:8]
{0x23, 0x00, 0x00}, // R0x23[7:0] = CSC coefficient B2[ 7:0]
{0x24, 0x00, 0x1D}, // R0x24[4:0] = CSC coefficient B3[12:8]
{0x25, 0x00, 0x3F}, // R0x25[7:0] = CSC coefficient B3[ 7:0]
{0x26, 0x00, 0x04}, // R0x26[4:0] = CSC coefficient B4[12:8]
{0x27, 0x00, 0x22}, // R0x27[7:0] = CSC coefficient B4[ 7:0]
{0x28, 0x00, 0x00}, // R0x28[4:0] = CSC coefficient C1[12:8]
{0x29, 0x00, 0x00}, // R0x29[7:0] = CSC coefficient C1[ 7:0]
{0x2A, 0x00, 0x08}, // R0x2A[4:0] = CSC coefficient C2[12:8]
{0x2B, 0x00, 0x00}, // R0x2B[7:0] = CSC coefficient C2[ 7:0]
{0x2C, 0x00, 0x0E}, // R0x2C[4:0] = CSC coefficient C3[12:8]
{0x2D, 0x00, 0x2D}, // R0x2D[7:0] = CSC coefficient C3[ 7:0]
{0x2E, 0x00, 0x19}, // R0x2E[4:0] = CSC coefficient C4[12:8]
{0x2F, 0x00, 0x14}, // R0x2F[7:0] = CSC coefficient C4[ 7:0]
{0x48, 0x00, 0x08}, // Video Input Justification
// R0x48[4:3] = Video Input Justification = 01 (right justified)
{0x55, 0x00, 0x00}, // Set RGB in AVinfo Frame
// R0x55[6:5] = Output Format = 00 (RGB)
{0x56, 0x00, 0x28}, // Aspect Ratio
// R0x56[5:4] = Picture Aspect Ratio = 10 (16:9)
// R0x56[3:0] = Active Format Aspect Ratio = 1000 (Same as Aspect Ratio)
{0x98, 0x00, 0x03}, // ADI Recommended Write
{0x9A, 0x00, 0xE0}, // ADI Recommended Write
{0x9C, 0x00, 0x30}, // PLL Filter R1 Value
{0x9D, 0x00, 0x61}, // Set clock divide
{0xA2, 0x00, 0xA4}, // ADI Recommended Write
{0xA3, 0x00, 0xA4}, // ADI Recommended Write
{0xAF, 0x00, 0x04}, // HDMI/DVI Modes
// R0xAF[ 7] = HDCP Enable = 0 (HDCP disabled)
// R0xAF[ 4] = Frame Encryption = 0 (Current frame NOT HDCP encrypted)
// R0xAF[3:2] = 01 (fixed)
// R0xAF[ 1] = HDMI/DVI Mode Select = 0 (DVI Mode)
{0xE0, 0x00, 0xD0}, // Must be set to 0xD0 for proper operation
{0xF9, 0x00, 0x00} // Fixed I2C Address (This should be set to a non-conflicting I2C address)
};

u8 si570_reg_value[NUM_MODES][NUM_CLOCK_REGS] = {
// {7, 8, 9, 10, 11, 12} //- As per Si570 Datasheet
// {228, 66, 169, 64, 64, 21} // 48 KHz - 24.576 MHz (512*fs)
// {165, 66, 169, 64, 64, 21} // 48 KHz - 24.576 MHz (512*fs)
{0xE4, 0x42, 0xA9, 0x40, 0x40, 0x15}
};

/**************************** Variable Definitions *******************************/

u32 FRAME_HORIZONTAL_LEN = 0x1680; //1920*3
u32 FRAME_VERTICAL_LEN = 0x438; //1080
u32 FRAME_LENGTH = 0x1FAA000;
u32 SUBFRAME_HORIZONTAL_SIZE;
u32 SUBFRAME_VERTICAL_SIZE;

/* Instance for Interrupt controller */
static XIntc Intc;
XIic IicInstance;
u8 UpdateBuffer[sizeof (AddressType) + PAGE_SIZE];
/* Write buffer for writing a page. */
u8 WriteBuffer[sizeof (AddressType) + PAGE_SIZE];
u8 ReadBuffer[PAGE_SIZE];
u8 DataBuf[PAGE_SIZE];
/* Flag to check completion of Transmission */
volatile u8 TransmitComplete;
/* Flag to check completion of Reception */
volatile u8 ReceiveComplete;
XTmrCtr TimerCounterInst;
XTmrCtr TimerCounterInst1;
int vblank_count = 0;
int training_done_count = 0;
int training_lost_count = 0;
/* Flag to check completion of Transmission */
volatile u8 TransmitComplete;
/* Flag to check completion of Reception */
volatile u8 ReceiveComplete;
int timer_value;
UINT32 dp_msa_hres;
UINT32 dp_msa_vres;
UINT8 reset_vid_cores = 1;
UINT8 prog_vid_cores;
int quad_sel;
u8 vblank_cnt;
u16 vblank_timer=0;
u8 enable_mst_flag=0;
XDp DprxInstance;
extern u32 dpcd_training_ok,
dpcd_training_not_ok;
u32 link_lanecnt = 0;
u8 link_bw = 0;
#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC XIntc
#define INTC_HANDLER XIntc_InterruptHandler
#else
#define INTC XScuGic
#define INTC_HANDLER XScuGic_InterruptHandler
#endif /* XPAR_INTC_0_DEVICE_ID */

u32 user_lane_count;
u32 user_link_rate;
u8 VBlankEnable;
u8 VBlankCount;
XIntc InterruptController;
int once =0;

/**************************** Function Prototypes *******************************/

unsigned char inbyte ();
void reset_dp159(int reset);
void initial_prog_dp159 (void);
void tp1_prog_dp159 (XTmrCtr *InstancePtr, u8 link_lanecnt, u16 link_bw);
void tp2_prog_dp159 (XTmrCtr *InstancePtr, u8 link_lanecnt, u16 link_bw);
int iic_dp159 (void);
void select_link_lane(void);
void DisableInterruptSystem ();
static void SendHandler (XIic * InstancePtr);
static void ReceiveHandler (XIic * InstancePtr);
static void StatusHandler (XIic * InstancePtr, int Event);
XStatus init_platform (void);
XStatus InitializeIIC();
XStatus init_timer (XTmrCtr *TmrCtrInstancePtr);
XStatus init_timer1 (XTmrCtr *TmrCtrInstancePtr);
void debug_info ();
int set_vidpipe();
int write_si570();
int IicLowLevelDynEeprom();
static void Dprx_InterruptHandlerVmChange(void *InstancePtr);
static void Dprx_InterruptHandlerPowerState(void *InstancePtr);
static void Dprx_InterruptHandlerNoVideo(void *InstancePtr);
static void Dprx_InterruptHandlerVBlank(void *InstancePtr);
static void Dprx_InterruptHandlerTrainingLost(void *InstancePtr);
static void Dprx_InterruptHandlerVideo(void *InstancePtr);
static void Dprx_InterruptHandlerTrainingDone(void *InstancePtr);
static void Dprx_InterruptHandlerTp1(void *InstancePtr);
static void Dprx_InterruptHandlerBwChange(void *InstancePtr);
static void Dprx_InterruptHandlerTp1(void *InstancePtr);
static void Dprx_InterruptHandlerTp2(void *InstancePtr);
static void Dprx_InterruptHandlerUnplug(void *InstancePtr);
static u32 Dprx_SetupInterruptHandler(XDp *InstancePtr, INTC *IntcPtr,
u16 IntrId, u16 DpIntrId,
u16 IICIntrId, u16 tmrIntrId);
void app_help_new();

/******************************************************************************/
/**
* This is the main() function.
*
* @param None.
*
* @return 0.
*
*******************************************************************************/
int main (void) {
Xil_DCacheFlush();
Xil_ICacheDisable ();
Xil_DCacheDisable ();

u32 data, addr;
int i, j;
UINT8 enable_dtg_flag=1;
char cmd_key_sub;
char cmd_key;
unsigned int command;
#if ENABLE_HDCP_IN_DESIGN
u32 hdcpCmdInProgress = 0;
#endif

/* Setting up video pipeline components such as cresampler etc
* these are needed for forwarding video from DP to HDMI on KC705
*/
DPVidPipe_Setup();

XDp_Config *ConfigPtr;
ConfigPtr = XDp_LookupConfig(DP_DEVICE_ID);
if (!ConfigPtr) {
xil_printf(
"No DP RX found for ID %d\r\n", DP_DEVICE_ID);
return XST_FAILURE;
}
XDp_CfgInitialize(&DprxInstance, ConfigPtr, ConfigPtr->BaseAddr);
XDp_RxSetLaneCount(&DprxInstance, ConfigPtr->MaxLaneCount);
XDp_RxSetLinkRate(&DprxInstance, ConfigPtr->MaxLinkRate);

/* Reset the DP159 (deasserts OE via GPIO) */
reset_dp159 (1);

tics = 0;
Xil_ICacheEnable ();
Xil_DCacheEnable ();

dbg_printf ("\033[H\033[J"); // clears the screen
dbg_printf ("\r\n");
dbg_printf ("-------------------------------------------------------------------------------\r\n");
dbg_printf (" DisplayPort Sink Policy Maker\r\n");
dbg_printf (" Press '?'for Menu \r\n");
dbg_printf ("-------------------------------------------------------------------------------\r\n");
int Status;

/* Setting up timer, iic cores */
Status = InitializeIIC();
// Status = init_timer(&TimerCounterInst);

/* Display help before initializing platform and devices */
app_help_new();

/* Setting up Interrupt handler */
Dprx_SetupInterruptHandler(&DprxInstance, &InterruptController,
INTC_DEVICE_ID, DP_INTERRUPT_ID,
IIC_INTERRUPT_ID, TMRCTR_INTERRUPT_ID);

Status = init_platform ();

/* Initial Programming of DP159 */
/* This is needed even before the cable is plugged in */
Status = Init_dp159_IIC ();

/* Getting DP159 out of reset */
reset_dp159 (0);
/* It is advisable to program DP159 using dynamic mode of IIC */
/* Setting IIC in dynamic mode */
Status = iic_dp159 ();

/* Calling the initial programming sequence of DP159 */
initial_prog_dp159 ();

/* Programming HDMI on KC705
* This is needed to display the video on Monitor
* connected to HDMI port of KC705. This display is
* always in 1920x1080p mode
*/
for( i = 0; i < 6; i++ ) {
UpdateBuffer[i] = si570_reg_value[0][i];
}
write_si570();

Status = IicLowLevelDynEeprom();

if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
xil_printf("KC705 HDMI Configuration is done !\n\r");

/* Writing the Capability and BKSV values much before.
* With this we can move HDCP_init to Training done handler
* This is needed to be done as HDCP_init cannot be
* called as lnk_clk is not stable until the
* source is plugged in
*/
#if ENABLE_HDCP_IN_DESIGN
hdcp_disabled_trig =0;

KEYMGMT_Init();
XHdcp1xExample_Init();
XHdcp1xExample_Enable();

#else
hdcp_disabled_trig =1;
xil_printf ("Important: HDCP is always disabled in DP RX!!\r\n");
#endif

xil_printf ("Initializing DisplayPort RX...\r\n");
/* Calling in XDp_Initialize function from driver
* The driver function is modified for DP159.
* These changes would be reflected future Vivado releases
*/
Status = XDp_Initialize(&DprxInstance);
if (Status != XST_SUCCESS) {
xil_printf ("\r\n!!!!!! DP Rx Init failed !!!!!!\r\n");
return XST_FAILURE;
}
XDp_WriteReg(DprxInstance.Config.BaseAddr, XDP_RX_LINK_ENABLE, 0x0);
/* Enabling only TP1, TP2, TP3 interrupts */
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XDP_RX_INTERRUPT_MASK, ~0x00070000);
/* Program the timeout delay */
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XDP_RX_BS_IDLE_TIME, 0x3B9ACA00);

/* Following is an EDID table that can be used to properties of DP RX
* EDIDs can be thought of as support display modes
*/
UINT8 edid[256] = {
/* Samsung 4k2k edid - this EDID supports 4k2k @ 60 Hz */
// 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x4C, 0x2D, 0x80, 0x0B, 0x00, 0x00, 0x00, 0x00,
// 0x34, 0x17, 0x01, 0x04, 0xB5, 0x3D, 0x23, 0x78, 0x3A, 0x5F, 0xB1, 0xA2, 0x57, 0x4F, 0xA2, 0x28,
// 0x0F, 0x50, 0x54, 0xBF, 0xEF, 0x80, 0x71, 0x4F, 0x81, 0x00, 0x81, 0xC0, 0x81, 0x80, 0xA9, 0xC0,
// 0xB3, 0x00, 0x95, 0x00, 0xD1, 0x00, 0x4D, 0xD0, 0x00, 0xA0, 0xF0, 0x70, 0x3E, 0x80, 0x30, 0x20,
// 0x35, 0x00, 0x5F, 0x59, 0x21, 0x00, 0x00, 0x1A, 0x56, 0x5E, 0x00, 0xA0, 0xA0, 0xA0, 0x29, 0x50,
// 0x30, 0x20, 0x35, 0x00, 0x5F, 0x59, 0x21, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x38,
// 0x4B, 0x1E, 0x86, 0x36, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC,
// 0x00, 0x55, 0x32, 0x38, 0x44, 0x35, 0x39, 0x30, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x9F,
// 0x02, 0x03, 0x0C, 0xF0, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x02, 0x3A, 0x80, 0x18,
// 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, 0x45, 0x00, 0x5F, 0x59, 0x21, 0x00, 0x00, 0x1E, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97

/* This EDID is more friendly for pug-in, plug-out robustness, but doesn't support 4k2k @ 60 Hz. */
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x17, 0x01, 0x04, 0xa5, 0x3c, 0x22, 0x78, 0x00, 0x1d, 0xf5, 0xae, 0x4f, 0x35, 0xb3, 0x25,
0x0d, 0x50, 0x54, 0x21, 0x08, 0x00, 0x81, 0x00, 0xb3, 0x00, 0xd1, 0x00, 0xd1, 0xc0, 0xa9, 0x40,
0x81, 0x80, 0x01, 0x01, 0x01, 0x01, 0xbe, 0x6e, 0x00, 0x68, 0xf1, 0x70, 0x5a, 0x80, 0x64, 0x58,
0x8a, 0x00, 0xba, 0x89, 0x21, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0xff, 0x00, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x58,
0x49, 0x4c, 0x20, 0x44, 0x50, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd,
0x00, 0x31, 0x56, 0x1d, 0x71, 0x1e, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xea,
0x02, 0x03, 0x0e, 0xc1, 0x41, 0x90, 0x23, 0x09, 0x1f, 0x07, 0x83, 0x01, 0x00, 0x00, 0x02, 0x3a,
0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x55, 0x50, 0x21, 0x00, 0x00, 0x1e,
0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c, 0x25, 0x00, 0x55, 0x50, 0x21, 0x00,
0x00, 0x9e, 0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00, 0x55, 0x50,
0x21, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a, 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00,
0x55, 0x50, 0x21, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb
};

xil_printf("Setting EDID...");
for(i=0;i<256;i=i+16){
for(j=i;j<(i+16);j++){
*(volatile UINT32*)(XPAR_VID_EDID_0_BASEADDR + (j)) = edid[i+1];
}
}
for(i=0;i<256;i++){
*(volatile UINT32*)(XPAR_VID_EDID_0_BASEADDR + (i)) = edid[i];
}
xil_printf("...done\r\n");
xil_printf("DP RX Capability is set to: Link BW = %x, Lane Count = %x\r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr,
XDP_RX_OVER_LINK_BW_SET),
(XDp_ReadReg(DprxInstance.Config.BaseAddr,
XDP_RX_OVER_LANE_COUNT_SET))&0x7);
xil_printf ("DP RX Initialization completed.\r\n");
XDp_WriteReg(DprxInstance.Config.BaseAddr, XDP_RX_LINK_ENABLE, 0x1);
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XDP_RX_INTERRUPT_MASK, 0xFE00FFFF);
cmd_key =0;

#if ENABLE_HDCP_IN_DESIGN
hdcpCmdInProgress = 0;
#endif

while(1) {
if(reset_vid_cores) {
reset_vid_cores=0;
XDp_RxDtgDis(&DprxInstance);
reset_vidpipe();
}

if (prog_vid_cores) {
prog_vid_cores=0;
XDp_RxDtgDis(&DprxInstance);
set_vidpipe();
XDp_RxDtgEn(&DprxInstance);
}

#if ENABLE_HDCP_IN_DESIGN
/* HDCP loop */
XHdcp1xExample_Poll();
cmd_key = xil_getc(0xff);
/* Check for HDCP command */
#if (HDCP_CONFIG_KEY_MGMT_BLK)
if ((hdcpCmdInProgress==TRUE)) || (CommandKey == 'h') || (CommandKey == 'k'))
#else
if ((cmd_key == 'h') || (hdcpCmdInProgress==TRUE))
#endif
{
/* xil_printf ("%c",CommandKey); */
hdcpCmdInProgress = XHdcp1xDebug_ProcessKey(cmd_key);
if (hdcpCmdInProgress == FALSE){
goto HDCPCmdDone;
}
continue;
}
#else
cmd_key = xil_getc(0xff);
#endif

#if ENABLE_HDCP_IN_DESIGN
HDCPCmdDone:
#endif
if(cmd_key != 0) { /* If character is received from UART console */
xil_printf("%c\r\n",cmd_key);

switch (cmd_key)
{
/* Following a,b,c,d options are used
* to select a quadrant of 4K video
* The HDMI video is capable of displaying
* only 1080p, so a 4K DP video can be displayed
* using 4 different quadrants (each at a time)
* This can be thought of as splitting
* 4K video into 4 parts
*/
case 'a':
quad_sel=0;
XDp_RxDtgDis(&DprxInstance);
set_vidpipe();
XDp_RxDtgEn(&DprxInstance);
break;

case 'b':
quad_sel=1;
XDp_RxDtgDis(&DprxInstance);
set_vidpipe();
XDp_RxDtgEn(&DprxInstance);
break;

case 'c':
quad_sel=2;
XDp_RxDtgDis(&DprxInstance);
set_vidpipe();
XDp_RxDtgEn(&DprxInstance);
break;

case 'd':
quad_sel=3;
XDp_RxDtgDis(&DprxInstance);
set_vidpipe();
XDp_RxDtgEn(&DprxInstance);
break;

case '?' :
/* Displays the help menu when "?" is pressed */
app_help_new();
break;

case '1' :
/* Option 1 is used to change the DP capabilities */
select_link_lane();
xil_printf ("\r\n **Important: Please ensure to unplug & "
"plug the cable after the capabilities have "
"been changed **\r\n");
cmd_key_sub = xil_getc(0);
command = atoi(&cmd_key_sub);
xil_printf("You have selected command=%d \n\r",command);
if((command>=0)&&(command<9))
{
user_lane_count = lane_link_table[command].lane_count;
user_link_rate = lane_link_table[command].link_rate;
if(lane_link_table[command].lane_count >
DprxInstance.Config.MaxLaneCount)
{
xil_printf("This Lane Count is not supported by Sink \n\r");
xil_printf("Max Supported Lane Count is 0x%x \n\r",
DprxInstance.Config.MaxLaneCount);
xil_printf("Training at Supported Lane count \r\n");
user_lane_count = DprxInstance.Config.MaxLaneCount;
}
if(lane_link_table[command].link_rate >
DprxInstance.Config.MaxLinkRate)
{
xil_printf("This link rate is not supported by Sink \n\r");
xil_printf("Max Supported Link Rate is 0x%x \n\r",
DprxInstance.Config.MaxLinkRate);
xil_printf("Training at supported Link Rate\r\n");
user_link_rate = DprxInstance.Config.MaxLinkRate;
}
XDp_RxSetLinkRate(&DprxInstance, user_link_rate);
XDp_RxSetLaneCount(&DprxInstance, user_lane_count);
xil_printf("\r\n RX Link & Lane Capability is set to %x, %x",
user_link_rate, user_lane_count);
Status = XDp_Initialize (&DprxInstance);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
}
else
{
xil_printf("!!!Warning: You have selected wrong option"
" for lane count and link rate =%d \n\r",command);
break;
}
break;

case '4':
/* This only resets the video pipe */
xil_printf("\r\nResetting RX Video pipeline....done !\r\n");
XDp_RxDtgDis(&DprxInstance);
set_vidpipe();
XDp_RxDtgEn(&DprxInstance);
break;

case 'w':
dbg_printf("\n\rEnter 4 hex characters: Sink Write address 0x");
addr = xil_gethex(4);
dbg_printf("\n\rEnter 4 hex characters: Sink Write Data 0x");
data = xil_gethex(4);
XDp_WriteReg(DprxInstance.Config.BaseAddr,addr, data);
break;

case 'r':
{
dbg_printf("\n\rEnter 4 hex characters: Sink Read address 0x");
addr = xil_gethex(4);
data = XDp_ReadReg(DprxInstance.Config.BaseAddr, addr);
dbg_printf("\n\rSink Read Addr %04x Read Data: %04x\n\r",
(XILINX_DISPLAYPORT_RX_BASE_ADDRESS+addr), data);
break;
}
case 's':
{
xil_printf("DP RX Bandwidth is set to = %x \r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_DPCD_LINK_BW_SET));
xil_printf("DP RX Lane Count is set to = %x \r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_DPCD_LANE_COUNT_SET));
xil_printf("[LANE0_1 Status] = %x ",
XDp_ReadReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_DPCD_LANE01_STATUS));
if(XDp_ReadReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_DPCD_LANE_COUNT_SET)>2)
{
xil_printf(", [LANE2_3 Status] = %x",
XDp_ReadReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_DPCD_LANE23_STATUS));
}
dbg_printf("\r\n DP Symbol Error Registers: %x; %x \r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_SYM_ERR_CNT01),
(XDp_ReadReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_SYM_ERR_CNT23)));
break;
}
case '2':
debug_info();
break;

case '5':
enable_dtg_flag = (enable_dtg_flag)?0:1;
if(enable_dtg_flag) {
set_vidpipe();
XDp_RxDtgEn(&DprxInstance);
xil_printf("- DisplayPort RX - DTG Enabled -\n\r");
}
else {
XDp_RxDtgDis(&DprxInstance);
xil_printf("- DisplayPort RX - DTG Disabled -\n\r");
}
break;

case '3':
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_PHY_RESET, 0x03);
/* Remove the PHY reset */
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_PHY_RESET, 0x3800000);
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_HPD_INTERRUPT,0xFBB80001);
xil_printf("\r\n- HPD Toggled for 3ms! -\n\r");
break;

default:
break;
} //end of switch statement
} //end of {if(cmd_key != 0)}
}

DisableInterruptSystem ();
return 0;
}

////////////////////////////////////////////////////////////////////////////////
XStatus init_platform (void) {
XStatus xil_status;

dbg4_printf ("Initializing platform");
xil_status = init_timer (&TimerCounterInst);
if (xil_status != XST_SUCCESS) {
xil_printf ("Timer0 init failed\r\n");
}

xil_status = init_timer1 (&TimerCounterInst1);
if (xil_status != XST_SUCCESS) {
xil_printf("Timer1 init failed\r\n");
}

configure_vdma(DDR_MEMORY, DDR_MEMORY);

if (xil_status != XST_SUCCESS) {
return XST_FAILURE;
}

return 0;
}

////////////////////////////////////////////////////////////////////////////////
/* Timer Interrupt Handler */
void TimerCounterHandler (XTmrCtr * CallBackRef, int ID) {
// int ii = 0;
tics++;
}

////////////////////////////////////////////////////////////////////////////////
XStatus init_timer (XTmrCtr *TmrCtrInstancePtr) {
XStatus Status;
Status = XTmrCtr_Initialize (&TimerCounterInst, TIMER_CNTR_0);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XTmrCtr_SetHandler (&TimerCounterInst, (XTmrCtr_Handler)TimerCounterHandler, &TimerCounterInst);
XTmrCtr_SetOptions (&TimerCounterInst, TIMER_CNTR_0,
XTC_DOWN_COUNT_OPTION |
XTC_INT_MODE_OPTION |
XTC_AUTO_RELOAD_OPTION
);
XTmrCtr_SetResetValue (&TimerCounterInst, TIMER_CNTR_0, TIMER_RESET_VALUE);
XTmrCtr_Start (&TimerCounterInst, TIMER_CNTR_0);
return XST_SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////
XStatus init_timer1 (XTmrCtr *TmrCtrInstancePtr) {
XStatus Status;

Status = XTmrCtr_Initialize (&TimerCounterInst1, TIMER_CNTR_1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XTmrCtr_SetResetValue (&TimerCounterInst1, TIMER_CNTR_1, TIMER_RESET_VALUE);
XTmrCtr_Start (&TimerCounterInst1, TIMER_CNTR_1);

return XST_SUCCESS;
}

int only_once =0;
int cable_unplugged =0;

static void Dprx_ResetVideoOutput(void *InstancePtr)
{
XDp_RxDtgDis(InstancePtr);
set_vidpipe();
XDp_RxDtgEn(InstancePtr);
}

/******************************************************************************/
/**
* This function will present the resolution of the incoming video stream.
*
* @param InstancePtr is a pointer to the XDp instance.
*
* @return None.
*
* @note The resolution will be rounded up to the nearest resolution
* present in the XVidC_VideoTimingModes table.
*
*******************************************************************************/
static void Dprx_DetectResolution(void *InstancePtr)
{
u32 DpHres, DpVres;
u32 GetResCount = 0;

do {
DpHres = (XDp_ReadReg(((XDp *)InstancePtr)->Config.BaseAddr,
XDP_RX_MSA_HRES));
DpVres = (XDp_ReadReg(((XDp *)InstancePtr)->Config.BaseAddr,
XDP_RX_MSA_VHEIGHT));
GetResCount++;
XDp_WaitUs(InstancePtr, 1000);
} while (((DpHres == 0) || (DpVres == 0)) && (GetResCount < 2000));
dp_msa_hres = DpHres;
dp_msa_vres = DpVres;
xil_printf("*** Detected resolution: %d x %d ***\n\r", DpHres, DpVres);

}

/******************************************************************************/
/**
* This function is the callback function for when a video mode change interrupt
* occurs.
*
* @param InstancePtr is a pointer to the XDp instance.
*
* @return None.
*
* @note None.
*
*******************************************************************************/
static void Dprx_InterruptHandlerVmChange(void *InstancePtr)
{
u32 Status;
xil_printf("> Interrupt: video mode change.\n\r");

#if REDUCED_BLANKING
Status = XDp_RxCheckLinkStatus(InstancePtr);

if(Status != XST_SUCCESS) {

}
else {
/* **** Check for reduced blanking **** */
u32 HBlank, HTotal, HRes, Bpp, LaneCount, ColorMode; //HSyncPulseWidth;
float CompareValue = 0.0;
HTotal = (XDp_ReadReg(DprxInstance.Config.BaseAddr, XDP_RX_MSA_HTOTAL));
HRes = (XDp_ReadReg(DprxInstance.Config.BaseAddr, XDP_RX_MSA_HRES));

// HSyncPulseWidth = (XDp_ReadReg(DpRxInst.Config.BaseAddr, XDP_RX_HSYNC_WIDTH)
// & XDP_RX_HSYNC_WIDTH_PULSE_WIDTH_MASK);

Bpp = (XDp_ReadReg(DprxInstance.Config.BaseAddr , XDP_RX_MSA_MISC0) & 0x000000E0)>>5;

if(Bpp == 0) {
Bpp = 6;
}
else if (Bpp == 1) {
Bpp = 8;
}
else if (Bpp == 2) {
Bpp = 10;
}
else if (Bpp == 3) {
Bpp = 12;
}
else if (Bpp == 4) {
Bpp = 16;
}

ColorMode = (XDp_ReadReg(DprxInstance.Config.BaseAddr , XDP_RX_MSA_MISC0) & 0x00000006)>>1;
if (ColorMode == 01) { //i.e. color mode is YUV422
Bpp *= 2;
}
else {
Bpp *= 3;
}

// xil_printf("BPP = %d \r\n",Bpp);

LaneCount = XDp_ReadReg(DprxInstance.Config.BaseAddr, XDP_RX_DPCD_LANE_COUNT_SET);

HBlank = (HTotal - HRes); // + HSyncPulseWidth;

CompareValue = 0.2 * (float)HTotal;
// printf("HBlank - %d, 0.2*HTotal = %lf \r\n", HBlank, CompareValue);

if(((float)HBlank < CompareValue) && (HBlank == 80 || HBlank == 160)) {
if( (((HRes*Bpp)/LaneCount)%8 !=0)) {
XDp_WriteReg(DprxInstance.Config.BaseAddr, XDP_RX_LINE_RESET_DISABLE, 0x0);
}
else {
XDp_WriteReg(DprxInstance.Config.BaseAddr, XDP_RX_LINE_RESET_DISABLE, 0x1);
xil_printf("_Reduced_Blanking_XDP_RX_LINE_RESET_DISABLE = %x\r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr, XDP_RX_LINE_RESET_DISABLE));
}
}
else {
XDp_WriteReg(DprxInstance.Config.BaseAddr, XDP_RX_LINE_RESET_DISABLE, 0x0);
}
}

#endif

/* Status = XDp_RxCheckLinkStatus(InstancePtr);
if ((Status == XST_SUCCESS) && (VBlankCount >= 20)) {
do {
Dprx_DetectResolution(InstancePtr);
} while ((dp_msa_hres == 0) && (dp_msa_vres == 0));
Dprx_ResetVideoOutput(InstancePtr);
} */
vblank_count = 0;
training_done_count = 0;
training_lost_count = 0;
}

/******************************************************************************/
/**
* This function is the callback function for when the power state interrupt
* occurs.
*
* @param InstancePtr is a pointer to the XDp instance.
*
* @return None.
*
* @note None.
*
*******************************************************************************/
static void Dprx_InterruptHandlerPowerState(void *InstancePtr)
{
// xil_printf("\r\n> Interrupt: power state "
// "change request.\n");
}

/******************************************************************************/
/**
* This function is the callback function for when a no video interrupt occurs.
*
* @param InstancePtr is a pointer to the XDp instance.
*
* @return None.
*
* @note None.
*
*******************************************************************************/
static void Dprx_InterruptHandlerNoVideo(void *InstancePtr)
{
// xil_printf("\r\n> Interrupt: no-video flags in "
// "the VBID field after active video "
// "has been received.\n");
}

/******************************************************************************/
/**
* This function is the callback function for when a vertical blanking interrupt
* occurs.
*
* @param InstancePtr is a pointer to the XDp instance.
*
* @return None.
*
* @note None.
*
*******************************************************************************/
static void Dprx_InterruptHandlerVBlank(void *InstancePtr)
{
u32 Status;
u32 GetResCount;
if (VBlankEnable) {
VBlankCount++;
/* Wait until 20 frames have been received before forwarding
* or outputting any video stream. */
if (VBlankCount >= 20) {
VBlankEnable = 0;
GetResCount = 0;
XDp_RxInterruptDisable(InstancePtr,
XDP_RX_INTERRUPT_MASK_VBLANK_MASK);
Status = XDp_RxCheckLinkStatus(InstancePtr);
if (Status == XST_SUCCESS) {
do {
Dprx_DetectResolution(InstancePtr);
GetResCount++;
} while (((dp_msa_hres == 0) && (dp_msa_vres == 0))
&& (GetResCount < 10));
Dprx_ResetVideoOutput(InstancePtr);
}
}
}
}

/******************************************************************************/
/**
* This function is the callback function for when a training lost interrupt
* occurs.
*
* @param InstancePtr is a pointer to the XDp instance.
*
* @return None.
*
* @note None.
*
*******************************************************************************/
static void Dprx_InterruptHandlerTrainingLost(void *InstancePtr)
{
xil_printf("> Interrupt: training lost !\n\r");
reset_vid_cores=1;
#if ENABLE_HDCP_IN_DESIGN
if (hdcp_disabled_trig == 0 && cable_unplugged == 0)
{
XHdcp1x_SetPhysicalState(XHdcp1xExample_Get(0), FALSE);
}
#endif
training_lost_count++;
VBlankCount = 0;
}

/******************************************************************************/
/**
* This function is the callback function for when a valid video interrupt
* occurs.
*
* @param InstancePtr is a pointer to the XDp instance.
*
* @return None.
*
* @note None.
*
*******************************************************************************/
static void Dprx_InterruptHandlerVideo(void *InstancePtr)
{
//xil_printf("\r\n> Interrupt: a valid video frame is detected on main link.\n");
}

u32 training_done_lane01;
u32 training_done_lane23;
u32 training_done_lanecnt;
u32 all_trained;
/******************************************************************************/
/**
* This function is the callback function for when a training done interrupt
* occurs.
*
* @param InstancePtr is a pointer to the XDp instance.
*
* @return None.
*
* @note None.
*
*******************************************************************************/
static void Dprx_InterruptHandlerTrainingDone(void *InstancePtr)
{
training_done_lane01 = XDp_ReadReg(DprxInstance.Config.BaseAddr,XILINX_DISPLAYPORT_RX_DPCD_LANE01_STATUS);
training_done_lane23 = XDp_ReadReg(DprxInstance.Config.BaseAddr,XILINX_DISPLAYPORT_RX_DPCD_LANE23_STATUS);
training_done_lanecnt = XDp_ReadReg(DprxInstance.Config.BaseAddr,XILINX_DISPLAYPORT_RX_DPCD_LANE_COUNT_SET);
xil_printf("> Interrupt: Training done(0x%x;0x%x).\n\r",training_done_lane01,training_done_lane23);
reset_vid_cores=0;
only_once = 1;
cable_unplugged = 0;
#if ENABLE_HDCP_IN_DESIGN
if (hdcp_disabled_trig == 0 && cable_unplugged == 0)
{
XHdcp1x_SetLaneCount(XHdcp1xExample_Get(0),
XDp_ReadReg(DprxInstance.Config.BaseAddr,XILINX_DISPLAYPORT_RX_DPCD_LANE_COUNT_SET));
XHdcp1x_SetPhysicalState(XHdcp1xExample_Get(0), TRUE);
xil_printf ("Important: HDCP Capability enabled in DP RX !!\r\n");
}
#endif
}

/******************************************************************************/
/**
* This function is the callback function for when a bandwidth change interrupt
* occurs.
*
* @param InstancePtr is a pointer to the XDp instance.
*
* @return None.
*
* @note None.
*
*******************************************************************************/
static void Dprx_InterruptHandlerBwChange(void *InstancePtr)
{
xil_printf("> Interrupt: bandwidth change.\n\r");
#if ENABLE_HDCP_IN_DESIGN
if (hdcp_disabled_trig == 0 && cable_unplugged == 0)
{
XHdcp1x_SetPhysicalState(XHdcp1xExample_Get(0), FALSE);
}
#endif
}

/* Whenever TP1 is received the DP159 is programmed for
* respective link and lane. Here it waits till DP159 is
* locked. At this point the forwarded link clock is
* stable.
* Once this is done, the GT is reset.
*/
static void Dprx_InterruptHandlerTp1(void *InstancePtr) {
/* Called at start of clock-recovery phase of link training.
* The TP1 (clock pattern) is being, or is about to be, received.
*/

link_lanecnt = XDp_ReadReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_DPCD_LANE_COUNT_SET);
link_bw = XDp_ReadReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_DPCD_LINK_BW_SET);

/* this function is present in dp159.c file */
tp1_prog_dp159 (&TimerCounterInst, link_lanecnt, link_bw);

if(link_lanecnt==1)
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_PHY_POWER_DOWN, 0xE);
else if (link_lanecnt==2)
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_PHY_POWER_DOWN, 0xC);
else
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_PHY_POWER_DOWN, 0x0);

/* Issue CPLL reset */
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_PHY_RESET, 0x03);
/* Remove the PHY reset */
XDp_WriteReg(DprxInstance.Config.BaseAddr,
XILINX_DISPLAYPORT_RX_PHY_RESET, 0x3800000);
VBlankEnable = 1;
XDp_RxInterruptEnable(InstancePtr,
XDP_RX_INTERRUPT_MASK_VBLANK_MASK);
VBlankCount = 0;

XDp_RxInterruptEnable(InstancePtr, 0x81FFFFFF);
/* Enable other interrupts
* XDp_RxInterruptEnable(InstancePtr, 0x8007FFFF);
*/

}

/* Following DP159 programming is done when TP2,3 interrupt is received */
static void Dprx_InterruptHandlerTp2(void *InstancePtr)
{
/* this function is present in dp159.c file */
tp2_prog_dp159 (&TimerCounterInst, link_lanecnt, link_bw);

}

static void Dprx_InterruptHandlerUnplug(void *InstancePtr)
{
if (only_once ==1 ) {
xil_printf ("> Interrupt: Cable Unplugged !! Resetting PHY...\r\n");
only_once =0;
cable_unplugged =1;
disconnect_prog_dp159();
XDp_WriteReg(DprxInstance.Config.BaseAddr,XILINX_DISPLAYPORT_RX_PHY_RESET, 0x03);
XDp_WriteReg(DprxInstance.Config.BaseAddr,XILINX_DISPLAYPORT_RX_PHY_RESET, 0x3800000);
//Disabling all Interrupts
XDp_RxInterruptDisable(InstancePtr, 0x8000FFFF);
#if ENABLE_HDCP_IN_DESIGN
XHdcp1x_SetPhysicalState(XHdcp1xExample_Get(0), FALSE);
#endif
}

}

/* Function to setup Interrupt handler module */
static u32 Dprx_SetupInterruptHandler(XDp *InstancePtr, XIntc *IntcPtr,
u16 IntrId, u16 DpIntrId, u16 IICIntrId, u16 tmrIntrId)
{
u32 Status;

/* Initialize interrupt controller driver. */

#ifdef XPAR_INTC_0_DEVICE_ID
Status = XIntc_Initialize(IntcPtr, IntrId);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
#else
XScuGic_Config *IntcConfig;

IntcConfig = XScuGic_LookupConfig(IntrId);
Status = XScuGic_CfgInitialize(IntcPtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XScuGic_SetPriorityTriggerType(IntcPtr, DpIntrId, 0xA0, 0x1);
#endif /* XPAR_INTC_0_DEVICE_ID */

XDp_RxSetIntrVmChangeHandler(InstancePtr,
Dprx_InterruptHandlerVmChange, InstancePtr);
XDp_RxSetIntrPowerStateHandler(InstancePtr,
Dprx_InterruptHandlerPowerState, InstancePtr);
XDp_RxSetIntrNoVideoHandler(InstancePtr,
Dprx_InterruptHandlerNoVideo, InstancePtr);
XDp_RxSetIntrVBlankHandler(InstancePtr,
Dprx_InterruptHandlerVBlank, InstancePtr);
XDp_RxSetIntrTrainingLostHandler(InstancePtr,
Dprx_InterruptHandlerTrainingLost, InstancePtr);
XDp_RxSetIntrVideoHandler(InstancePtr,
Dprx_InterruptHandlerVideo, InstancePtr);
XDp_RxSetIntrTrainingDoneHandler(InstancePtr,
Dprx_InterruptHandlerTrainingDone, InstancePtr);
XDp_RxSetIntrBwChangeHandler(InstancePtr,
Dprx_InterruptHandlerBwChange, InstancePtr);
XDp_RxSetIntrTp1Handler(InstancePtr,
Dprx_InterruptHandlerTp1, InstancePtr);
XDp_RxSetIntrTp2Handler(InstancePtr,
Dprx_InterruptHandlerTp2, InstancePtr);
XDp_RxSetIntrUnplugHandler(InstancePtr,
Dprx_InterruptHandlerUnplug, InstancePtr);

Status = XIntc_Connect(IntcPtr, IICIntrId, (XInterruptHandler) XIic_InterruptHandler, &IicInstance); //&dp159_IIC);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

// Timer Interrupt
Status = XIntc_Connect (IntcPtr, tmrIntrId, (XInterruptHandler) XTmrCtr_InterruptHandler, &TimerCounterInst);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device. */
#ifdef XPAR_INTC_0_DEVICE_ID
Status = XIntc_Connect(IntcPtr, DpIntrId,
(XInterruptHandler)XDp_InterruptHandler, InstancePtr);
#else
Status = XScuGic_Connect(IntcPtr, DpIntrId,
(Xil_InterruptHandler)XDp_InterruptHandler, InstancePtr);
#endif /* XPAR_INTC_0_DEVICE_ID */
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Start the interrupt controller. */
#ifdef XPAR_INTC_0_DEVICE_ID
Status = XIntc_Start(IntcPtr, XIN_REAL_MODE);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XIntc_Enable(IntcPtr, IICIntrId);
XIntc_Enable(IntcPtr, tmrIntrId);
XIntc_Enable(IntcPtr, DpIntrId);
#else
XScuGic_Enable(IntcPtr, DpIntrId);
#endif /* XPAR_INTC_0_DEVICE_ID */


/* Initialize the exception table. */
Xil_ExceptionInit();

/* Register the interrupt controller handler with the exception
* table. */
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)INTC_HANDLER, IntcPtr);

/* Enable exceptions. */
Xil_ExceptionEnable();

return XST_SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////
void DisableInterruptSystem () {
XIntc_Disconnect (&Intc, IIC_INTERRUPT_ID);
XIntc_Disconnect (&Intc, TMRCTR_INTERRUPT_ID);
}

////////////////////////////////////////////////////////////////////////////////
void debug_info()
{
UINT32 temp=0, temp1=0;
UINT8 lane_count=1;
UINT8 link_rate=1;
UINT32 rec_pixel_freq=0.0;
u8 dp_rx_user_fifo_status;
UINT32 link_rate_factor;
UINT32 mvid;
UINT32 nvid;
UINT32 hres;
UINT32 vres;
UINT32 dpcd_training_ok=0, dpcd_training_not_ok=0;

#if 1

lane_count = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_DPCD_LANE_COUNT_SET);
link_rate = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_DPCD_LINK_BW_SET);
temp = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_DPCD_LANE01_STATUS);
temp1 = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_DPCD_LANE23_STATUS);

if(lane_count==4)
{
if(temp!=0x77 || temp1!=0x77)
{
dpcd_training_not_ok++;
}
else
{
dpcd_training_ok++;
}
}

if(lane_count==2)
{
if(temp!=0x77)
{
dpcd_training_not_ok++;
}
else
{
dpcd_training_ok++;
}
}

if(lane_count==1)
{
if((temp&0x07)!=0x07)
{
dpcd_training_not_ok++;
}
else
{
dpcd_training_ok++;
}
}

xil_printf("\r\n::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\r\n");
xil_printf(" XILINX DISPLAYPORT RX\r\n");
xil_printf("[DP RX] Lane_Count= 0x%x, Link_Rate= 0x%x \r\n", lane_count, link_rate);
xil_printf("[DPCD_TRAINING_STATS] OK= 0x%x, NOT_OK= 0x%x\r\n", dpcd_training_ok, dpcd_training_not_ok);
xil_printf("------------------------------------ STREAM1 ----------------------------------\r\n");
mvid = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MVID);
nvid = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_NVID);
hres = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HRES);
vres = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VHEIGHT);
link_rate_factor = link_rate * 27.0;
rec_pixel_freq = ((link_rate_factor * mvid)/nvid);
xil_printf("---> Hspol = %d, Hswidth = %d, Hstart = %d, Htotal= %d\r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSPOL),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSWIDTH),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSTART),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HTOTAL)
);
xil_printf("---> Vspol = %d, Vswidth = %d, Vstart = %d, Vtotal= %d\r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSPOL),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSWIDTH),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSTART),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VTOTAL)
);

dp_rx_user_fifo_status = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_USER_FIFO_OVERFLOW);

xil_printf("---> HRES = %d; VRES = %d\r\n", hres, vres);
xil_printf("---> RX_AUX_CLOCK_DIVIDER = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_AUX_CLOCK_DIVIDER));
xil_printf("---> RX_OVERRIDE_TRAINING_LANE0_SET = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_OVERRIDE_TRAINING_LANE0_SET));
xil_printf("---> RX_OVERRIDE_TRAINING_LANE1_SET = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_OVERRIDE_TRAINING_LANE1_SET));
xil_printf("---> RX_OVERRIDE_TRAINING_LANE2_SET = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_OVERRIDE_TRAINING_LANE2_SET));
xil_printf("---> RX_OVERRIDE_TRAINING_LANE3_SET = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_OVERRIDE_TRAINING_LANE3_SET));
xil_printf("---> RX_MSA_VBID = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VBID));
xil_printf("---> RX_MSA_MVID = 0x%x\r\n", mvid);
xil_printf("---> RX_MSA_NVID = 0x%x\r\n", nvid);
xil_printf("---> Recovered Video Pixel Frequency (approx) = %1.3d MHz\r\n", rec_pixel_freq);
xil_printf("---> RX_MSA_MISC0 = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MISC0));
xil_printf("---> RX_MSA_MISC1 = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MISC1));
xil_printf("---> RX_USER_FIFO_OVERFLOW = 0x%x\r\n", dp_rx_user_fifo_status);
xil_printf("---> RX_USER_PIXEL_WIDTH = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_USER_PIXEL_WIDTH));
xil_printf("---> RX_PHY_STATUS = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_PHY_STATUS));
xil_printf("---> RX_DPCD_ENHANCED_FRAME_EN = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_DPCD_ENHANCED_FRAME_EN));
xil_printf("---> RX_DTG_ENABLE = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_DTG_ENABLE));

if(enable_mst_flag)
{
xil_printf("------------------------------------ STREAM2 ----------------------------------\r\n");
mvid = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MVID_STREAM2);
nvid = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_NVID_STREAM2);
link_rate_factor = link_rate * 27.0;
rec_pixel_freq = ((link_rate_factor * mvid)/nvid);

xil_printf("---> Hres = %d, Hspol = %d, Hswidth = %d, Hstart = %d, Htotal= %d\r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HRES_STREAM2),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSPOL_STREAM2),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSWIDTH_STREAM2),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSTART_STREAM2),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HTOTAL_STREAM2)
);

xil_printf("; Vres = %d, Vspol = %d, Vswidth = %d, Vstart = %d, Vtotal= %d\r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VHEIGHT_STREAM2),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSPOL_STREAM2),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSWIDTH_STREAM2),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSTART_STREAM2),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VTOTAL_STREAM2)
);

dp_rx_user_fifo_status = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_USER_FIFO_OVERFLOW);

xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_VBID = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VBID_STREAM2));
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_MVID = 0x%x\r\n", mvid);
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_NVID = 0x%x\r\n", nvid);
xil_printf("---> Recovered Video Pixel Frequency (approx) = %1.3d MHz\r\n", rec_pixel_freq);
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_MISC0 = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MISC0_STREAM2));
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_MISC1 = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MISC1_STREAM2));
xil_printf("---> XILINX_DISPLAYPORT_RX_USER_FIFO_OVERFLOW = 0x%x\r\n", dp_rx_user_fifo_status);

xil_printf("------------------------------------ STREAM3 ----------------------------------\r\n");
mvid = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MVID_STREAM3);
nvid = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_NVID_STREAM3);
link_rate_factor = link_rate * 27.0;
rec_pixel_freq = ((link_rate_factor * mvid)/nvid);

xil_printf("---> Hres = %d, Hspol = %d, Hswidth = %d, Hstart = %d, Htotal= %d\r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HRES_STREAM3),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSPOL_STREAM3),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSWIDTH_STREAM3),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSTART_STREAM3),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HTOTAL_STREAM3)
);

xil_printf("; Vres = %d, Vspol = %d, Vswidth = %d, Vstart = %d, Vtotal= %d\r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VHEIGHT_STREAM3),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSPOL_STREAM3),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSWIDTH_STREAM3),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSTART_STREAM3),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VTOTAL_STREAM3)
);

dp_rx_user_fifo_status = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_USER_FIFO_OVERFLOW);

xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_VBID = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VBID_STREAM3));
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_MVID = 0x%x\r\n", mvid);
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_NVID = 0x%x\r\n", nvid);
xil_printf("---> Recovered Video Pixel Frequency (approx) = %1.3d MHz\r\n", rec_pixel_freq);
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_MISC0 = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MISC0_STREAM3));
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_MISC1 = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MISC1_STREAM3));
xil_printf("---> XILINX_DISPLAYPORT_RX_USER_FIFO_OVERFLOW = 0x%x\r\n", dp_rx_user_fifo_status);


xil_printf("------------------------------------ STREAM4 ----------------------------------\r\n");
mvid = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MVID_STREAM4);
nvid = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_NVID_STREAM4);
link_rate_factor = link_rate * 27.0;
rec_pixel_freq = ((link_rate_factor * mvid)/nvid);

xil_printf("---> Hres = %d, Hspol = %d, Hswidth = %d, Hstart = %d, Htotal= %d\r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HRES_STREAM4),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSPOL_STREAM4),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSWIDTH_STREAM4),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HSTART_STREAM4),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HTOTAL_STREAM4)
);

xil_printf("; Vres = %d, Vspol = %d, Vswidth = %d, Vstart = %d, Vtotal= %d\r\n",
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VHEIGHT_STREAM4),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSPOL_STREAM4),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSWIDTH_STREAM4),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VSTART_STREAM4),
XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VTOTAL_STREAM4)
);

dp_rx_user_fifo_status = XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_USER_FIFO_OVERFLOW);

xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_VBID = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VBID_STREAM4));
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_MVID = 0x%x\r\n", mvid);
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_NVID = 0x%x\r\n", nvid);
xil_printf("---> Recovered Video Pixel Frequency (approx) = %1.3d MHz\r\n", rec_pixel_freq);
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_MISC0 = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MISC0_STREAM4));
xil_printf("---> XILINX_DISPLAYPORT_RX_MSA_MISC1 = 0x%x\r\n", XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_MISC1_STREAM4));
xil_printf("---> XILINX_DISPLAYPORT_RX_USER_FIFO_OVERFLOW = 0x%x\r\n", dp_rx_user_fifo_status);


}//end mst_enable_flag

xil_printf("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\r\n");
xil_printf(" AXI VDMA - REG DIRECT MODE\r\n");
xil_printf("---> MM2S DMA Control = 0x%x\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x00));
xil_printf("---> MM2S DMA Status = 0x%x\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x04));
XAxiVdma_WriteReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x04, 0xFFFFFFFF); //Write 1 to clear
xil_printf("---> MM2S VSize = %d\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x50));
xil_printf("---> MM2S HSize = %d\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x54));
xil_printf("---> MM2S FDly Stride = %d\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x58));
xil_printf("---> MM2S Start Addr1 = 0x%x\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x5C));
xil_printf("---> MM2S Start Addr2 = 0x%x\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x60));
xil_printf("---> MM2S Start Addr3 = 0x%x\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x64));
xil_printf("---> S2MM DMA Control = 0x%x\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x30));
xil_printf("---> S2MM DMA Status = 0x%x\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x34));
XAxiVdma_WriteReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0x34, 0xFFFFFFFF); //Write 1 to clear
xil_printf("---> S2MM VSize = %d\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0xA0));
xil_printf("---> S2MM HSize = %d\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0xA4));
xil_printf("---> S2MM FDly Stride = %d\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0xA8));
xil_printf("---> S2MM Start Addr1 = 0x%x\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0xAC));
xil_printf("---> S2MM Start Addr2 = 0x%x\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0xB0));
xil_printf("---> S2MM Start Addr3 = 0x%x\r\n", XAxiVdma_ReadReg(XPAR_AXI_VDMA_STREAM1_BASEADDR, 0xB4));
xil_printf("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\r\n");
#endif
}

void app_help_new()
{
print("-----------------------------------------------------\n\r");
print("-- DisplayPort RX Demo Menu --\n\r");
print("-----------------------------------------------------\n\r");
print("\n\r");
print(" Select option\n\r");
print(" 1 = Change Lane and Link capabilities\n\r");
print(" 2 = Link, MSA and Error Status\n\r");
print(" 3 = Toggle HPD\n\r");
print(" 4 = Reset Video Pipeline \n\r");
print(" 5 = Enable/disable DTG\n\r");
print(" w = Sink register write\n\r");
print(" r = Sink register read\n\r");
print(" s = Link Status info\n\r");
print(" a = Select Top Left of CEA 4K frame (Output Display=1080p)\n\r");
print(" b = Select Top Right of CEA 4K frame (Output Display=1080p)\n\r");
print(" c = Select Bottom Left of CEA 4K frame (Output Display=1080p)\n\r");
print(" d = Select Bottom Right of CEA 4K frame (Output Display=1080p)\n\r");
#if ENABLE_HDCP_IN_DESIGN
print(" h = Type HDCP commands <hdcp enable 0; hdcp disable 0; hdcp display 0>\n\r");
#endif
print(" \r\nAt any time, press ? to display this menu again\n\r");
print("\n\r");
print("-----------------------------------------------------\n\r");
}

void select_link_lane(void)
{
print("-----------------------------------------------------\n\r");
print("-- Select the Link and Line Capabilities --\n\r");
print("-----------------------------------------------------\n\r");
xil_printf("Choose RX capability for Lane count and Link rate\n\r"
"0 --> Set RX capability @ 1.62G 1 lane\n\r"
"1 --> Set RX capability @ 1.62G 2 lanes\n\r"
"2 --> Set RX capability @ 1.62G 4 lanes\n\r"
"3 --> Set RX capability @ 2.7G 1 lane\n\r"
"4 --> Set RX capability @ 2.7G 2 lanes\n\r"
"5 --> Set RX capability @ 2.7G 4 lanes\n\r"
"6 --> Set RX capability @ 5.4G 1 lane\n\r"
"7 --> Set RX capability @ 5.4G 2 lanes\n\r"
"8 --> Set RX capability @ 5.4G 4 lanes\n\r");
print("\n\r");
print("-----------------------------------------------------\n\r");
}

XStatus InitializeIIC()
{

XStatus Status;
/* Pointer to configuration data */
XIic_Config *ConfigPtr_IIC;

/* Initialize the IIC driver so
* that it is ready to use.
*/
ConfigPtr_IIC = XIic_LookupConfig(IIC_ID);
if (ConfigPtr_IIC == NULL) {
return XST_FAILURE;
}

Status = XIic_CfgInitialize(&IicInstance, ConfigPtr_IIC, ConfigPtr_IIC->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}

/*****************************************************************************/
/**
* This Send handler is called asynchronously from an interrupt
* context and indicates that data in the specified buffer has been sent.
*
* @param InstancePtr is not used, but contains a pointer to the IIC
* device driver instance which the handler is being called for.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void SendHandler(XIic * InstancePtr)
{
TransmitComplete = 0;
}

/*****************************************************************************/
/**
* This Receive handler is called asynchronously from an interrupt
* context and indicates that data in the specified buffer has been Received.
*
* @param InstancePtr is not used, but contains a pointer to the IIC
* device driver instance which the handler is being called for.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void ReceiveHandler(XIic * InstancePtr)
{
ReceiveComplete = 0;
}

/*****************************************************************************/
/**
* This Status handler is called asynchronously from an interrupt
* context and indicates the events that have occurred.
*
* @param InstancePtr is a pointer to the IIC driver instance for which
* the handler is being called for.
* @param Event indicates the condition that has occurred.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void StatusHandler(XIic * InstancePtr, int Event)
{

}

int hdmiWriteData(u16 ByteCount)
{
int Status;

/* Set the defaults. */
TransmitComplete = 1;
IicInstance.Stats.TxErrors = 0;

/* Start the IIC device. */
Status = XIic_Start(&IicInstance);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Send the Data. */
Status = XIic_MasterSend(&IicInstance, WriteBuffer, ByteCount);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Wait till the transmission is completed. */
while ((TransmitComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) {
/* This condition is required to be checked in the case where we
* are writing two consecutive buffers of data to the EEPROM.
* The EEPROM takes about 2 milliseconds time to update the data
* internally after a STOP has been sent on the bus.
* A NACK will be generated in the case of a second write before
* the EEPROM updates the data internally resulting in a
* Transmission Error.
*/

if (IicInstance.Stats.TxErrors != 0) {

/* Enable the IIC device. */
Status = XIic_Start(&IicInstance);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

if (!XIic_IsIicBusy(&IicInstance)) {
/* Send the Data. */
Status = XIic_MasterSend(&IicInstance,
WriteBuffer,
ByteCount);
if (Status == XST_SUCCESS) {
IicInstance.Stats.TxErrors = 0;
}
else {
}
}
}
}

/* Stop the IIC device. */
Status = XIic_Stop(&IicInstance);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

return XST_SUCCESS;
}

/* *********************************************************
* EepromReadData2 with address added as an input parameter
* *********************************************************
*/
int EepromReadData2(AddressType addr, u8 *BufferPtr, u16 ByteCount)
{
int Status;
AddressType Address;
Address = addr;

/* Set the Defaults.*/
ReceiveComplete = 1;

/* Position the Pointer in EEPROM. */
if (sizeof(Address) == 1) {
WriteBuffer[0] = (u8) (Address);
}
else {
WriteBuffer[0] = (u8) (Address >> 8);
WriteBuffer[1] = (u8) (Address);
}

Status = hdmiWriteData(sizeof(Address));
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Start the IIC device. */
Status = XIic_Start(&IicInstance);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Receive the Data. */
Status = XIic_MasterRecv(&IicInstance, BufferPtr, ByteCount);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Wait till all the data is received. */
while ((ReceiveComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) {
// XIic_InterruptHandler(&IicInstance);
}

/* Stop the IIC device. */
Status = XIic_Stop(&IicInstance);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

return XST_SUCCESS;
}

u8 EepromWriteByte(AddressType Address, u8 *BufferPtr, u8 ByteCount) {
u8 SentByteCount;
u8 WriteBuffer[sizeof(Address) + PAGE_SIZE];
u32 StatusReg;
u8 Index;

/* A temporary write buffer must be used which contains both the address
* and the data to be written, put the address in first based upon the
* size of the address for the EEPROM
*/
if (sizeof(AddressType) == 2) {
WriteBuffer[0] = (u8) (Address >> 8);
WriteBuffer[1] = (u8) (Address);
} else if (sizeof(AddressType) == 1) {
WriteBuffer[0] = (u8) (Address);
EepromIicAddr |= (EEPROM_TEST_START_ADDRESS >> 8) & 0x7;
}

/* Put the data in the write buffer following the address. */
for (Index = 0; Index < ByteCount; Index++) {
WriteBuffer[sizeof(Address) + Index] = BufferPtr[Index];
}

/* Write a page of data at the specified address to the EEPROM. */
SentByteCount = XIic_DynSend(IIC_BASE_ADDRESS, EepromIicAddr, WriteBuffer,
sizeof(Address) + ByteCount, XIIC_STOP);

while (((StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS,
XIIC_SR_REG_OFFSET)) & (XIIC_SR_RX_FIFO_EMPTY_MASK
| XIIC_SR_TX_FIFO_EMPTY_MASK | XIIC_SR_BUS_BUSY_MASK))
!= (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK)) {
//wait
}

/* Return the number of bytes written to the EEPROM. */
return SentByteCount - sizeof(Address);
}


int IicLowLevelDynEeprom() {
u8 BytesRead;
u32 StatusReg;
u8 Index;
int i;
int Status;
EepromIicAddr = IIC_SWITCH_ADDRESS;

/* Initialize the IIC Core. */
Status = XIic_DynInit(IIC_BASE_ADDRESS);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Make sure all the Fifo's are cleared and Bus is Not busy. */
while (((StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS,
XIIC_SR_REG_OFFSET)) & (XIIC_SR_RX_FIFO_EMPTY_MASK
| XIIC_SR_TX_FIFO_EMPTY_MASK | XIIC_SR_BUS_BUSY_MASK))
!= (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK)) {

}

/* Initialize the data to written and the read buffer. */
for (Index = 0; Index < PAGE_SIZE; Index++) {
WriteBuffer[Index] = Index;
ReadBuffer[Index] = 0;
DataBuf[Index] = 0;
}

/* Write to the IIC SWITCH. */
EepromIicAddr = IIC_SWITCH_ADDRESS; /* Alternate use of Write routine */
WriteBuffer[0] = 0x20;
BytesRead = EepromWriteByte(0x20, DataBuf, 0);

/* Write Initialization Sequence to ADV7511. */
EepromIicAddr = IIC_ADV7511_ADDRESS;
for (Index = 0; Index < NUMBER_OF_HDMI_REGS; Index++) {
BytesRead = EepromWriteByte(hdmi_iic[Index].addr,&hdmi_iic[Index].init, 1);
if(BytesRead < 1) {
// xil_printf("Issue in writing to EEPROM");
}
for(i = 0; i<50000; i++);
}
for (Index = 0; Index < NUMBER_OF_HDMI_REGS; Index++) {
BytesRead = EepromWriteByte(hdmi_iic[Index].addr,&hdmi_iic[Index].init, 1);
if(BytesRead < 1) {
// xil_printf("Issue in writing to EEPROM");
}
for(i = 0; i<50000; i++);
}

return XST_SUCCESS;
}


int write_si570()
{
u32 Index;
int Status;
AddressType Address = EEPROM_TEST_START_ADDRESS;
AddressType addr;

XIic_SetSendHandler(&IicInstance, &IicInstance,
(XIic_Handler) SendHandler);
XIic_SetRecvHandler(&IicInstance, &IicInstance,
(XIic_Handler) ReceiveHandler);
XIic_SetStatusHandler(&IicInstance, &IicInstance,
(XIic_StatusHandler) StatusHandler);

if (sizeof(Address) == 1) {
WriteBuffer[0] = (u8) (Address);
}
else {
WriteBuffer[0] = (u8) (Address >> 8);
WriteBuffer[1] = (u8) (Address);
ReadBuffer[Index] = 0;
}

Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_SEND_TYPE,
IIC_SWITCH_ADDRESS);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/* Write to the IIC Switch. */
WriteBuffer[0] = 0x01; //Select Bus0 - U1

Status = hdmiWriteData(1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Set the Slave address to the SI570 */
Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_SEND_TYPE,
IIC_SI570_ADDRESS);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Write to the SI570 */
/* Set frequency back to default power-up value
* In this case 156.250000 MHz
*/
/* Freeze DCO bit in Reg 137 */
WriteBuffer[0] = 137;
WriteBuffer[1] = 0x10;
Status = hdmiWriteData(sizeof(Address) + 1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Recall the 156.2500000 value from NVM
* by setting RECALL (bit 0) = 1 in Reg 135
*/
WriteBuffer[0] = 135;
WriteBuffer[1] = 0x01;
Status = hdmiWriteData(sizeof(Address) + 1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Un-Freeze DCO bit in Reg 137 */
WriteBuffer[0] = 137;
WriteBuffer[1] = 0x00;
Status = hdmiWriteData(sizeof(Address) + 1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Assert New Frequency bit in Reg 135 */
WriteBuffer[0] = 135;
WriteBuffer[1] = 0x40;
Status = hdmiWriteData(sizeof(Address) + 1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Wait 10 ms */
int kk;
for(kk= 0; kk<100000; kk++);

/* Update to user requested frequency */
/* Freeze DCO bit in Reg 137 */
WriteBuffer[0] = 137;
WriteBuffer[1] = 0x10;

Status = hdmiWriteData(sizeof(Address) + 1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

Status = hdmiWriteData(sizeof(Address) + 1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Set New Frequency to 400 MHz when starting from 156.25 MHz */
WriteBuffer[0] = 7;
WriteBuffer[1] = UpdateBuffer[0];
WriteBuffer[2] = UpdateBuffer[1];
WriteBuffer[3] = UpdateBuffer[2];
WriteBuffer[4] = UpdateBuffer[3];
WriteBuffer[5] = UpdateBuffer[4];
WriteBuffer[6] = UpdateBuffer[5];

Status = hdmiWriteData(sizeof(Address) + 6);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Un-Freeze DCO bit in Reg 137 */
WriteBuffer[0] = 137;
WriteBuffer[1] = 0x00;

Status = hdmiWriteData(sizeof(Address) + 1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Assert New Frequency bit in Reg 135 */
WriteBuffer[0] = 135;
WriteBuffer[1] = 0x40;

Status = hdmiWriteData(sizeof(Address) + 1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Read from the SI570 */
addr = 7;
Status = EepromReadData2(addr, ReadBuffer, 6);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

/* Display Read Buffer */
for (Index = 0; Index < 6; Index++) {
/* xil_printf("ReadBuffer[%02d] = %02X\r\n", Index, ReadBuffer[Index]); */
}

return XST_SUCCESS;
}

/***************************************************************************
* WriteSetup: It will configure the VDMA for write.
* *
* dma_chan_parms: This is structure pointer that stores the
* handle for DMA instances.
*
* *
***************************************************************************/
static int WriteSetup(struct dma_chan_parms define_function[NUMBER_OF_DMAS])
{
int i;
u32 Addr;
int Status;
int n;
UINT32 dp_hres;
UINT32 dp_vres;

dp_vres=dp_msa_vres;
dp_hres=dp_msa_hres;

while((dp_vres==0)||(dp_hres==0))
{
dp_vres=(XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VHEIGHT));
dp_hres=(XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HRES));
}
/* xil_printf("%s: hres = %d, vres = %d \r\n", __func__, dp_hres, dp_vres); */

for (n = 0; n < NUMBER_OF_DMAS; n++)
{
define_function[n].WriteCfg.VertSizeInput = dp_vres;
define_function[n].WriteCfg.HoriSizeInput = dp_hres * 3;

define_function[n].WriteCfg.Stride = VDMA_STRIDE_1080;

/* This example does not test frame delay */
define_function[n].WriteCfg.FrameDelay = 0;

define_function[n].WriteCfg.EnableCircularBuf = 1;
/* No Gen-Lock */
define_function[n].WriteCfg.EnableSync = 1; /* Gen-Lock */

define_function[n].WriteCfg.PointNum = 0; /* No Gen-Lock */
define_function[n].WriteCfg.EnableFrameCounter = 0; /* Endless transfers */

/* We are not doing parking */
define_function[n].WriteCfg.FixedFrameStoreAddr = 0;

Status = XAxiVdma_DmaConfig(&define_function[n].AxiVdma, XAXIVDMA_WRITE, &define_function[n].WriteCfg);
if (Status != XST_SUCCESS)
{
return XST_FAILURE;
}

/* Initialize buffer addresses
*
* Use physical addresses
*/
Addr = define_function[n].WR_ADDR_BASE +
define_function[n].BlockStartOffset;

for(i = 0; i < NUMBER_OF_WRITE_FRAMES; i++) {
/* xil_printf ("Wr Addr is %x\r\n", Addr); */
define_function[n].WriteCfg.FrameStoreStartAddr[i] = Addr;

/* Flushing the DDR */
int clear_id;
char *mem = (char *)Addr;
for(clear_id=0;clear_id<1080;clear_id++) {
memset(mem,0,(1920*3));
mem += VDMA_STRIDE_1080;
}

Addr += FRAME_LENGTH ;
}

/* Set the buffer addresses for transfer in the DMA engine
*/
Status = XAxiVdma_DmaSetBufferAddr(&define_function[n].AxiVdma,
XAXIVDMA_WRITE,
define_function[n].WriteCfg.FrameStoreStartAddr);
if (Status != XST_SUCCESS)
{
xil_printf("Write channel set buffer address failed %d\r\n", Status);
return XST_FAILURE;
}

}

return XST_SUCCESS;
}

/***************************************************************************
* configure_vdma: It will configure the VDMA.
* *
* start_read_addr:Starting address of the read frame.
* start_write_addr: Starting address of the write frame.
*
* *
***************************************************************************/
int configure_vdma(unsigned int start_read_addr, unsigned int start_write_addr)
{
int i,Status;

for(i=0;i<XPAR_XAXIVDMA_NUM_INSTANCES;i++)
{
dma_struct[i].Config = XAxiVdma_LookupConfig(i);
if (!dma_struct[i].Config)
{
xil_printf("No video DMA found for ID %d\n\r", i);
return 1;
}
/* Initialize DMA engine */
Status = XAxiVdma_CfgInitialize(&dma_struct[i].AxiVdma,
dma_struct[i].Config,
dma_struct[i].Config->BaseAddress);
if (Status != XST_SUCCESS)
{
xil_printf("Initialization failed %d\n\r", Status);
return 1;
}

/* User Must Set Values For Each Struct */

/* Device ID */
dma_struct[i].AXIVDMA_DEVICE_ID = i;
/* Read Base Address */
dma_struct[i].RD_ADDR_BASE = start_read_addr +
i*BOUNDRY_1_VDMA_FRAME;
/* Write Base Address */
dma_struct[i].WR_ADDR_BASE = start_write_addr +
i*BOUNDRY_1_VDMA_FRAME ;

dma_struct[i].BlockStartOffset = SUBFRAME_START_OFFSET;
dma_struct[i].BlockHoriz = SUBFRAME_HORIZONTAL_SIZE;
dma_struct[i].BlockVert = SUBFRAME_VERTICAL_SIZE;

}

return 0;
}

/***************************************************************************
* ReadSetup: It will configure the VDMA for read.
* *
* dma_chan_parms: This is structure pointer that stores the
* handle for DMA instances.
* *
***************************************************************************/
static int ReadSetup(struct dma_chan_parms define_function[NUMBER_OF_DMAS])
{
int i;
u32 Addr;
int Status;
int n;
UINT32 dp_hres;
UINT32 dp_vres;
UINT32 addr_offset_4k2kquad=0;

dp_vres=dp_msa_vres;
dp_hres=dp_msa_hres;
while((dp_vres==0)||(dp_hres==0))
{
dp_vres=(XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_VHEIGHT));
dp_hres=(XDp_ReadReg(DprxInstance.Config.BaseAddr, XILINX_DISPLAYPORT_RX_MSA_HRES));

}
/* xil_printf("%s: hres = %d, vres = %d \r\n", __func__, dp_hres, dp_vres); */

for (n = 0; n < NUMBER_OF_DMAS; n++)
{
define_function[n].ReadCfg.VertSizeInput = SUBFRAME_VERTICAL_SIZE;
define_function[n].ReadCfg.HoriSizeInput = SUBFRAME_HORIZONTAL_SIZE;

define_function[n].ReadCfg.Stride = VDMA_STRIDE_1080;

define_function[n].ReadCfg.FrameDelay = 1; /* This example does not test frame delay */

define_function[n].ReadCfg.EnableCircularBuf = 1;
define_function[n].ReadCfg.EnableSync = 0; /* Gen-Lock */

define_function[n].ReadCfg.PointNum = 0; /* No Gen-Lock */
define_function[n].ReadCfg.EnableFrameCounter = 0; /* Endless transfers */

define_function[n].ReadCfg.FixedFrameStoreAddr = 0; /* We are not doing parking */

Status = XAxiVdma_DmaConfig(&define_function[n].AxiVdma, XAXIVDMA_READ, &define_function[n].ReadCfg);
if (Status != XST_SUCCESS) {
xil_printf("Read channel config failed %d\n\r", Status);
return XST_FAILURE;
}
/* Initialize buffer addresses
*
* These addresses are physical addresses
*/
if ((dp_vres==2160) && (dp_hres==3840)) //Only for CEA 4k2k
{
if(quad_sel==1)
addr_offset_4k2kquad = 1920*3;
else if (quad_sel==2)
addr_offset_4k2kquad = 1920*3 *2* 1080;
else if (quad_sel==3)
addr_offset_4k2kquad = 1920*3 *2* 1080 + 1920*3;
else
addr_offset_4k2kquad = 0;
xil_printf("\r\n 4K2K Quad Select = %d\r\n",quad_sel+1);
} else {
addr_offset_4k2kquad = 0;
}

Addr = define_function[n].RD_ADDR_BASE + define_function[n].BlockStartOffset;

for(i = 0; i < NUMBER_OF_READ_FRAMES; i++) {
/* xil_printf ("Rd Addr is %x\r\n", Addr); */

define_function[n].ReadCfg.FrameStoreStartAddr[i] = Addr + addr_offset_4k2kquad;
#if 0
if ((dp_vres<1080) && (dp_hres<1920)){
dst_data_fill = (unsigned int *)Addr;
for(data_fill=0;data_fill<(0x5EEC00);)
{
dst_data_fill[data_fill] = 0xDEADBEEF;
data_fill++;
dst_data_fill[data_fill] = 0xDEADBEEF;
data_fill++;
dst_data_fill[data_fill] = 0xDEADBEEF;
data_fill++;
dst_data_fill[data_fill] = 0xDEADBEEF;
data_fill++;
}
}
#endif
Addr += FRAME_LENGTH ;
}
/* Set the buffer addresses for transfer in the DMA engine
* The buffer addresses are physical addresses
*/
Status = XAxiVdma_DmaSetBufferAddr(&define_function[n].AxiVdma, XAXIVDMA_READ,
define_function[n].ReadCfg.FrameStoreStartAddr);
if (Status != XST_SUCCESS) {
xil_printf("Read channel set buffer address failed %d\n\r", Status);
return XST_FAILURE;
}
}
return XST_SUCCESS;
}

/***************************************************************************
* StartTransfer: It will start the VDMA.
* *
* XAxiVdma*: It is instance of VDMA that needs to be started.
*
* *
***************************************************************************/
int StartTransfer(XAxiVdma * InstancePtr, vdma_run_mode mode)
{
int Status;

if((mode==BOTH)||(mode==ONLY_WRITE))
{
Status = XAxiVdma_DmaStart(InstancePtr, XAXIVDMA_WRITE);
if (Status != XST_SUCCESS) {
xil_printf("Start Write transfer failed %d\r\n", Status);

return XST_FAILURE;
}
}
if((mode==BOTH)||(mode==ONLY_READ))
{
Status = XAxiVdma_DmaStart(InstancePtr, XAXIVDMA_READ);
if (Status != XST_SUCCESS) {
xil_printf("Start read transfer failed %d\n\r", Status);

return XST_FAILURE;
}
}
return XST_SUCCESS;
}

unsigned int delay = 0;
/***************************************************************************
* set_vidpipe: It will set the video pipeline for the streaming data
* received over the Display Port RX to go over the HDMI port of KC705
* to the external sink.
* *
***************************************************************************/
int set_vidpipe()
{
int frame_width, frame_height;
int Status,reg_value;
int resolution = 6;//, i=0;
u32 Framesize;

delay=0;

/* Fixing the resolution to 1080p */
resolution = 6;

/*** Resetting Vid Pipe`& updating video params ***/
reset_vidpipe();

FRAME_HORIZONTAL_LEN = (u32) (resolutions[resolution][5] * 3); //in bytes. Pixel is fixed to 32 bits
FRAME_VERTICAL_LEN = (u32) resolutions[resolution][0];
SUBFRAME_HORIZONTAL_SIZE = FRAME_HORIZONTAL_LEN;
SUBFRAME_VERTICAL_SIZE = FRAME_VERTICAL_LEN;
FRAME_LENGTH = 0x1FAA000 ;

/*** Update params ***/
frame_width = ivk_vres_get_width(resolution);
frame_height = ivk_vres_get_height(resolution);
Framesize = frame_height<<16|frame_width;

/*** Init All Vid Pipe cores ***/
vtc_config(resolution);
ivk_osd_init( resolution );
call_cre(&DprxInstance, Framesize);
call_rgb2ycrcb(&DprxInstance, Framesize);

// configure_vdma(DDR_MEMORY, DDR_MEMORY);

/*** Setup the write channel ***/
Status = WriteSetup(dma_struct);

if (Status != XST_SUCCESS)
{
prog_vid_cores = 1;
return 1;
}

/*** Setup the read channel ***/
Status = ReadSetup(dma_struct);
if (Status != XST_SUCCESS)
{
return 1;
}
xil_printf("VDMA initialization done !\r\n");

/*** Enable Video Pipe cores ***/
/* Enabling only the VTC Generator */
reg_value = XVtc_ReadReg(XPAR_VTC_0_BASEADDR , XVTC_CTL);
reg_value |=0x1;
reg_value &=~0x8;
XVtc_WriteReg(XPAR_VTC_0_BASEADDR , XVTC_CTL, reg_value);

/* Enable OSD */
ivk_osd_enable();
/* Enable CRESAMPLE & RGB2YCBCr*/
//Enable_Rgb_Cresample();

/* Enable VDMA */
StartTransfer(&dma_struct[0].AxiVdma,ONLY_READ);
StartTransfer(&dma_struct[0].AxiVdma ,ONLY_WRITE);

return 0;
}