/*  ============================================================================
 *   Copyright (c) Texas Instruments Inc 2013
 *
 *   Use of this software is controlled by the terms and conditions found in the
 *   license agreement under which this software has been supplied.
 *   ===========================================================================
 */
/** ============================================================================
 Serdes configuration on K2 device
 * =============================================================================
 *  Revision History
 *  ===============
 *  June 1, 2013 Brighton Feng  file created
 *  Dece 1, 2014 Brighton Feng  add SerDes external loopback functions
 * =============================================================================
 */

#ifndef _K2_SERDES_INIT_H_
#define _K2_SERDES_INIT_H_

#include <tistdtypes.h>
#include <stdint.h>
#include <csl_serdes.h>
#include <csl_aif2.h>
#include "K2_common.h"

typedef struct
{
	CSL_SERDES_REF_CLOCK inputRefClock;

	float linkSpeed_GHz; 	/*the max link speed of all lanes at GHz*/

	/*bit 0~5 control the endable/disable of 6 lanes. 0: disable; 1: enable*/
	Uint32 laneEnableMask; 

	CSL_Aif2LinkRate laneRateScale[6]; /*rate scale for up to six lanes*/

	/*bit 0~5 control the endable/disable of loopback on 6 lanes. 0: disable; 1: enable*/
	Uint32  loopBackMask;

} K2_AIF2_SerdesConfig;

/** ============================================================================
 *   @n This API returns the status of the Serdes PLL lock
 *   @b Arguments   base_addr of the Serdes configuration registers
 *   <b> Return Value  </b>  CSL_SERDES_STATUS
 *   @b Example
     K2_SerdesPLLGetStatus(CSL_SRIO_SERDES_CFG_REGS);
 * ===========================================================================
 */
static inline CSL_SERDES_STATUS K2_SerdesPLLGetStatus
(
 uint32_t base_addr
)
{
    CSL_SERDES_STATUS retval;

    /* Check PLL OK Status Bit */
    retval = (CSL_SERDES_STATUS)CSL_FEXTR(*(volatile uint32_t *)(base_addr + 0x1ff4), 28, 28);

    return retval;
}


/** ============================================================================
 *   @n This API returns the status of the Serdes lane status
 *   @b Arguments   base_addr, lane_num
 *   <b> Return Value  </b>  CSL_SERDES_STATUS
 *   @b Example
     CSL_SrioSerdesGetStatus(CSL_SRIO_SERDES_CFG_REGS, 0);
 * ===========================================================================
 */
static inline CSL_SERDES_STATUS K2_SerdesLaneGetStatus
(
 uint32_t base_addr,
 uint32_t lane_num
)
{
    CSL_SERDES_STATUS retval;

    /* Check Lane # OK Status Bits */
    retval = (CSL_SERDES_STATUS)CSL_FEXTR(*(volatile uint32_t *)(base_addr + 0x1ff4), (8 + lane_num), (8 + lane_num));
    retval &= (CSL_SERDES_STATUS)CSL_FEXTR(*(volatile uint32_t *)(base_addr + 0x1ff4), (0 + lane_num), (0 + lane_num));

    return retval;
}

/*Setup one SerDes lane external loopback: RX->TX.
Call this function after normal Serdes initialization*/
static inline void K2_SerDes_lane_external_loopback_enable
(
 uint32_t base_addr,
 uint32_t lane_num
)
{
	/*Set RXCLK_LB_ENA = 0x1 to drive the transmit path with the recovered, receive bit clock. This is 
	required to synchronize transmit and receive paths for PMA layer parallel loopback testing.*/
	CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1)),31,31, 1);

	/*Wait 2us to allow the CDR to fully lock on to the incoming data.*/
	TSC_delay_us(2);

	/*Enable the PMA layer parallel loopback by setting dmux_txb_sel = 0x5 and cktrans_en = 0x1.*/
	CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1)),22,20, 5);
	CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1)),23,23, 1);
}
/*Setup SerDes module external loopback: RX->TX.
Call this function after normal Serdes initialization*/
static inline void K2_SerDes_external_loopback_enable
(
 uint32_t base_addr,
 uint32_t num_lanes
)
{
	int i;

	for(i=0; i<num_lanes; i++)
	{
		/*Set RXCLK_LB_ENA = 0x1 to drive the transmit path with the recovered, receive bit clock. This is 
		required to synchronize transmit and receive paths for PMA layer parallel loopback testing.*/
		CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1)),31,31, 1);
	}
	
	/*Wait 2us to allow the CDR to fully lock on to the incoming data.*/
	TSC_delay_us(2);

	for(i=0; i<num_lanes; i++)
	{
		/*Enable the PMA layer parallel loopback by setting dmux_txb_sel = 0x5 and cktrans_en = 0x1.*/
		CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1)),22,20, 5);
		CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1)),23,23, 1);
	}
}

/*disable one Serdes lane external loopback*/
static inline void K2_SerDes_lane_external_loopback_disable
(
 uint32_t base_addr,
 uint32_t lane_num
)
{
	/*Disable the loopback test by setting DMUX_TX_BSEL = 0x0, CKTRANS_EN = 0x0 and 
	RXCLK_LB_ENA = 0x0.*/
	CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1)),22,20, 0);
	CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1)),23,23, 0);
	CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1)),31,31, 0);

	/*Wait 100 ns for settling*/
	TSC_delay_us(1);
}
/*disable Serdes module external loopback*/
static inline void K2_SerDes_external_loopback_disable
(
 uint32_t base_addr,
 uint32_t num_lanes
)
{
	int i;

	for(i=0; i<num_lanes; i++)
	{
		/*Disable the loopback test by setting DMUX_TX_BSEL = 0x0, CKTRANS_EN = 0x0 and 
		RXCLK_LB_ENA = 0x0.*/
		CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1)),22,20, 0);
		CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1)),23,23, 0);
		CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1)),31,31, 0);
	}
	
	/*Wait 100 ns for settling*/
	TSC_delay_us(1);
}


/*Serdes initialization for AIF2*/
extern void K2_AIF2_Serdes_init(K2_AIF2_SerdesConfig * serdes_cfg);

//for debug
extern void SerDes_sweep();

#endif 

