#include <asf.h>

#ifndef VXR_INTERFACE_H_
#define VXR_INTERFACE_H_

#define VXR_ADDR			(0x72u) // For use with UNSHIFTED address type, 0b0111.001W, where W is the read/write bit

#define RC_DEFAULT_TIMEOUT		50	// delay waiting for "command active" to go low. RTT is ~10kHz, so this is roughly a 5ms timeout
#define RC_PROGRAM_TIMEOUT		150 // ~15ms
#define RC_ERASE_TIMEOUT		5000 // ~500ms

/* Interface is called "RC" for Remote Control
 * All interactions are through special debug registers
 */
#define RC_TRIGGER_ADDR		(0x002000FCu)
#define RC_COMMAND_ADDR		(0x00200110u)
#define RC_OFFSET_ADDR		(0x00200114u)
#define RC_LENGTH_ADDR		(0x00200118u)
#define RC_DATA0_ADDR		(0x00200120u) // up to 32 data bytes (8 words), spaced by 4. Next is 0x00200124, 0x00200128, ... 0x0020013C
#define RC_DATA_INCR		(4u)
#define NUM_VXR_DATA_REGS	(32u)
#define NUM_VXR_DATA_WORDS	(NUM_VXR_DATA_REGS/RC_DATA_INCR)

#define RC_TRIGGER_VALUE	(0x000000F2u)

/* Command word is a bitfield:
 * [22:16] = command
 * [23] = active (0: no command running, 1: command is in active state)
 * [31:24] = result (0: no error, anything non-zero is an error)
 */
#define RC_COMMAND_COMMAND_Pos		16
#define RC_COMMAND_COMMAND_Msk		(0x7Fu << RC_COMMAND_COMMAND_Pos) 
#define RC_COMMAND_COMMAND(value)	((RC_COMMAND_COMMAND_Msk & ((value) << RC_COMMAND_COMMAND_Pos)))
#define RC_COMMAND_ACTIVE_Pos		23
#define RC_COMMAND_ACTIVE			(1 << RC_COMMAND_ACTIVE_Pos)
#define RC_COMMAND_RESULT_Pos		24
#define RC_COMMAND_RESULT_Msk		(0xFFu << RC_COMMAND_RESULT_Pos)
#define RC_COMMAND_RESULT(value)	((RC_COMMAND_RESULT_Msk & ((value) << RC_COMMAND_RESULT_Pos)))

typedef enum rc_cmds {
	Enable_RC = 1,
	Disable_RC = 2,
	Write_Flash = 0x20,
	Erase_Flash = 0x14,
	Send_Flash_Cmd = 0x25,
	Read_SPI_Flash = 0x30,
	Get_FW_Chksum = 0x11,
	Memory_Write = 0x21,
	Memory_Read = 0x31,
	MIPI_Write = 0x70,
	MIPI_Write_Buffered = 0x71,
	I2C_Write = 0x72,
	MIPI_Read = 0x73,
	MIPI_Read_From_Buffer = 0x74,
	I2C_Read = 0x75
} RC_Command_T;

typedef enum rc_errors {
	RC_Success = 0,
	RC_Invalid_Arg = 1,
	RC_Unsupported = 2,
	RC_Unknown_Error = 3,
	RC_Iface_Disabled = 4,
	RC_Bus_Error = 5,
	RC_Timeout_Error = 6
} RC_Error_T;

typedef enum vxr_flash_tag {
	Vxr_Tag_Config_0,
	Vxr_Tag_Config_1,
	Vxr_Tag_Firmware_0,
	Vxr_Tag_Firmware_1
} Vxr_Flash_Tag_T;

typedef struct rc_vid_fmt {
	uint16_t Htotal;	// Total horizontal pixels including blanking
	uint16_t Vtotal;	// Total vertical pixels including blanking
	uint16_t Hactive;	// Active horizontal pixels
	uint16_t Vactive;	// Active vertical pixels
	uint8_t  ColorBPC;	// Color depth in bits per pixel
	uint16_t Frame_100;	// Frame rate in Hz multiplied by 100 
} Video_Format_T;

RC_Error_T VXR_Reset(void);
RC_Error_T VXR_Start_Interface(void);
RC_Error_T VXR_Stop_Interface(void);
RC_Error_T VXR_Read_Register(uint32_t regaddr, uint32_t* result);
RC_Error_T VXR_Write_Register(uint32_t regaddr, uint32_t data);

/* Flash addresses in the VXR7200 */
#define VXR_CONFIG_0_START			(0x00000u)
#define VXR_CONFIG_0_TAG_START		(0x07FF0u)
#define VXR_CONFIG_0_TAG_END		(0x07FFFu)
#define VXR_CONFIG_0_END			(VXR_CONFIG_0_TAG_END)

#define VXR_FIRMWARE_0_START		(0x08000u)
#define VXR_FIRMWARE_0_TAG_START	(0x1FFF0u)
#define VXR_FIRMWARE_0_TAG_END		(0x1FFFFu)
#define VXR_FIRMWARE_0_END			(VXR_FIRMWARE_0_TAG_END)

#define VXR_CONFIG_1_START			(0x20000u)
#define VXR_CONFIG_1_TAG_START		(0x27FF0u)
#define VXR_CONFIG_1_TAG_END		(0x27FFFu)
#define VXR_CONFIG_1_END			(VXR_CONFIG_1_TAG_END)

#define VXR_FIRMWARE_1_START		(0x28000u)
#define VXR_FIRMWARE_1_TAG_START	(0x3FFF0u)
#define VXR_FIRMWARE_1_TAG_END		(0x3FFFFu)
#define VXR_FIRMWARE_1_END			(VXR_FIRMWARE_1_TAG_END)


/* Functions to get / set specific information on the VXR7200 */
#define EDID_RAM_ADDRESS	(0x3000u)
#define EDID_TX0_RAM_ADDRESS (0x3200u) // MST left eye
#define EDID_TX1_RAM_ADDRESS (0x3380u) // MST right eye
#define TX0_PPS_ADDRESS		(0x0780u)
#define TX1_PPS_ADDRESS		(0x0800u)

#define RX_ML_PHY_ERR_COUNTERS_0	(0x22011Cu)
#define RX_ML_PHY_ERR_COUNTERS_1	(0x220120u)
#define RX_ML_PHY_ERR_COUNTERS_2	(0x220124u)
#define RX_ML_PHY_ERR_COUNTERS_3	(0x220128u)

#define TX0_VID_MODE_ADDRESS	(0x310040u)
#define TX1_VID_MODE_ADDRESS	(0x350040u)
#define TXn_VID_MODE_ENABLED	(1 << 11)

#define PPS_OFFSET			(5u) // PPS data starts at byte 5 (so 0x785 or 0x805)
#define PPS_LENGTH			(88u)

#define RX_FRM0_MSA_TOTALS_ADDRESS	(0x220830u) // Total H/V on receive buffer for TX0 (15:0 = H, 31:16 = V)
#define RX_FRM1_MSA_TOTALS_ADDRESS	(0x220C30u) // same for TX1
#define		RX_FRMn_MSA_HTOTAL_Msk		(0x0000FFFFu)
#define		RX_FRMn_MSA_HTOTAL_Pos		(0u)
#define		RX_FRMn_MSA_VTOTAL_Msk		(0xFFFF0000u)
#define		RX_FRMn_MSA_VTOTAL_Pos		(16u)
#define RX_FRM0_MSA_ACTIVE_ADDRESS	(0x220838u) // Active H/V for TX0 (15:0 = H, 31:16 = V)
#define RX_FRM1_MSA_ACTIVE_ADDRESS	(0x220C38u) // Active H/V for TX1
#define		RX_FRMn_MSA_HACTIVE_Msk		(0x0000FFFFu)
#define		RX_FRMn_MSA_HACTIVE_Pos		(0u)
#define		RX_FRMn_MSA_VACTIVE_Msk		(0xFFFF0000u)
#define		RX_FRMn_MSA_VACTIVE_Pos		(16u)
#define RX_FRM0_BPC_ADDRESS			(0x220854u) // Color depth for TX0 (4:0 = bits per component)
#define RX_FRM1_BPC_ADDRESS			(0x220C54u) // Color depth for TX1
#define		RX_FRMn_BPC_Msk				(0x0000001Fu)
#define		RX_FRMn_BPC_Pos				(0u)
#define RX_INT_CLK_REG				(0x200008u) // Used to determine internal clock. (25:16) = intclk / 10,000
#define		RX_INT_CLK_Msk				(0x03FF0000u)
#define		RX_INT_CLK_Pos				(16u)
#define RX_PIXCLK_MULT_REG			(0x220804u) // Used with divider to determine frame rate (7:0)
#define		RX_PIXCLK_MULT_Msk			(0x000000FFu)
#define		RX_PIXCLK_MULT_Pos			(0u)
#define RX_PIXCLK_DIV_REG			(0x220814u) // Used with multiplier to determine frame rate (31:0)
#define		RX_PIXCLK_DIV_Msk			(0xFFFFFFFFu)
#define		RX_PIXCLK_DIV_Pos			(0u)
// Note:	received frame rate = intclk*RX_PIXCLK_MULT_REG[7:0]*100 / RX_PIXCLK_DIV_REG
//			where intclk = RX_INT_CLK_REG[25:16] * 10000


RC_Error_T VXR_Check_Connection(void);
RC_Error_T VXR_Set_EDID(const uint8_t* new_edid, uint16_t edid_size);
RC_Error_T VXR_Get_PPS_TXn(uint8_t* rec_pps, uint8_t TX_Sel);
bool VXR_Get_TXn_Video_Status(uint8_t TX_Sel);
RC_Error_T VXR_Get_Rx_Video_Format(Video_Format_T* fmt);
RC_Error_T VXR_Calc_Checksum(uint32_t start_addr, uint32_t len, uint32_t* result);
RC_Error_T VXR_Program_Firmware(uint32_t start_addr, uint32_t len, const uint8_t* buf);
RC_Error_T VXR_Erase_Firmware_Bank(uint8_t bank_num);
RC_Error_T VXR_Erase_Firmware_Sector(uint8_t sector_num);
bool VXR_Tag_Valid(Vxr_Flash_Tag_T region);
RC_Error_T VXR_Get_Firmware_Name(uint8_t* fwname);
RC_Error_T VXR_Get_Rx_Error_Counter(uint8_t DP_Lane_Num, uint16_t* errcount);
RC_Error_T VXR_Disable_DSC(void);

#endif // VXR_INTERFACE_H_
