/*  ============================================================================
 *   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
 * =============================================================================
 */
#include <stdio.h>
#include <stdint.h>
#include <cslver.h>
#include <csl_serdes_aif2.h>
#include "K2_Serdes_init.h"

char * SerdesErrorStr[]=
{
	"SERDES no error",
	"SERDES error: invalid input reference clock speed!",
	"SERDES error: invalid link speed!"
};

/*Serdes initialization for AIF2*/
void K2_AIF2_Serdes_init(K2_AIF2_SerdesConfig * serdes_cfg)
{
	int i;
	CSL_SERDES_LINK_RATE linkSpeed;
	Uint32 uiResult;

#if 0
	// Disable pll before configuring the SerDes registers
	if(serdes_cfg->laneEnableMask&0xF) //lane 0~3
		CSL_AIF2SerdesShutdown(CSL_AIF_SERDES_B8_CFG_REGS);
	if(serdes_cfg->laneEnableMask&0x30) //lane 4~5
		CSL_AIF2SerdesShutdown(CSL_AIF_SERDES_B4_CFG_REGS);
#endif

	if(serdes_cfg->linkSpeed_GHz== 4.9152f)
	{
		linkSpeed= CSL_SERDES_LINK_RATE_4p9152G;
	}
	else if(serdes_cfg->linkSpeed_GHz== 6.144f)
	{
		linkSpeed= CSL_SERDES_LINK_RATE_6p144G;
	}
	else
		printf("Error: link speed %.4fGbps is not supported by AIF2\n",serdes_cfg->linkSpeed_GHz);
	
#if (CSL_VERSION_ID<=0x0200000F) 	//for old CSL
	if(serdes_cfg->laneEnableMask&0xF) //lane 0~3
	{
		uiResult= CSL_AIF2SerdesInit(CSL_AIF_SERDES_B8_CFG_REGS,
			serdes_cfg->inputRefClock, linkSpeed);
		if(uiResult)
			printf("  %s\n", SerdesErrorStr[uiResult]);
	}
	
	if(serdes_cfg->laneEnableMask&0x30) //lane 4~5
	{
		uiResult= CSL_AIF2SerdesInit(CSL_AIF_SERDES_B4_CFG_REGS,
			serdes_cfg->inputRefClock, linkSpeed);
		if(uiResult)
			printf("  %s\n", SerdesErrorStr[uiResult]);
	}
#else 	//for new CSL
	if(serdes_cfg->laneEnableMask&0xF) //lane 0~3
	{
		uiResult= CSL_AIF2SerdesInitB8(CSL_AIF_SERDES_B8_CFG_REGS,
			serdes_cfg->inputRefClock, linkSpeed);
		if(uiResult)
			printf("  %s\n", SerdesErrorStr[uiResult]);
	}
	
	if(serdes_cfg->laneEnableMask&0x30) //lane 4~5
	{
		uiResult= CSL_AIF2SerdesInitB4(CSL_AIF_SERDES_B4_CFG_REGS,
			serdes_cfg->inputRefClock, linkSpeed);
		if(uiResult)
			printf("  %s\n", SerdesErrorStr[uiResult]);
	}
#endif
	
	for(i=0; i<4; i++) //Serdes B8
	{
		if((serdes_cfg->laneEnableMask>>i)&1)
		{
			CSL_AIF2SerdesLaneConfig(CSL_AIF_SERDES_B8_CFG_REGS,
				serdes_cfg->inputRefClock, linkSpeed, i);
		}
	}
	for(i=4; i<6; i++) //Serdes B4
	{
		if((serdes_cfg->laneEnableMask>>i)&1)
		{
			CSL_AIF2SerdesLaneConfig(CSL_AIF_SERDES_B4_CFG_REGS,
				serdes_cfg->inputRefClock, linkSpeed, i-4);
		}
	}

	if(serdes_cfg->laneEnableMask&0xF) //lane 0~3
		CSL_AIF2SerdesComEnable(CSL_AIF_SERDES_B8_CFG_REGS);
	if(serdes_cfg->laneEnableMask&0x30) //lane 4~5
		CSL_AIF2SerdesComEnable(CSL_AIF_SERDES_B4_CFG_REGS);

#if (CSL_VERSION_ID<=0x0200000D) 	//for old CSL
	for(i=0; i<6; i++)
	{
		if((serdes_cfg->laneEnableMask>>i)&1)
		{
			CSL_AIF2SerdesLaneEnable(CSL_AIF_CFG_REGS,
				i, serdes_cfg->laneRateScale[i]);
		}
	}

	for(i=0; i<4; i++) //Serdes B8
	{
		if((serdes_cfg->loopBackMask>>i)&1)
		{
			CSL_AIF2SerdesLoopbackEnable(CSL_AIF_SERDES_B8_CFG_REGS,
				i, CSL_SERDES_LOOPBACK_ENABLED);
		}
		else
		{
			CSL_AIF2SerdesLoopbackEnable(CSL_AIF_SERDES_B8_CFG_REGS,
				i, CSL_SERDES_LOOPBACK_DISABLED);
		}
	}
	for(i=4; i<6; i++) //Serdes B4
	{
		if((serdes_cfg->loopBackMask>>i)&1)
		{
			CSL_AIF2SerdesLoopbackEnable(CSL_AIF_SERDES_B4_CFG_REGS,
				i-4, CSL_SERDES_LOOPBACK_ENABLED);
		}
		else
		{
			CSL_AIF2SerdesLoopbackEnable(CSL_AIF_SERDES_B4_CFG_REGS,
				i-4, CSL_SERDES_LOOPBACK_DISABLED);
		}
	}

	// Enable Serdes PLL, and Wait the SerDes PLL lock
	if(serdes_cfg->laneEnableMask&0xF) //lane 0~3
	{
		CSL_AIF2SerdesPllEnableB8(CSL_AIF_CFG_REGS);
		while(CSL_SERDES_STATUS_PLL_NOT_LOCKED==CSL_AIF2SerdesGetStatusB8(CSL_AIF_CFG_REGS));
	}
	if(serdes_cfg->laneEnableMask&0x30) //lane 4~5
	{
		CSL_AIF2SerdesPllEnableB4(CSL_AIF_CFG_REGS);
		while(CSL_SERDES_STATUS_PLL_NOT_LOCKED==CSL_AIF2SerdesGetStatusB4(CSL_AIF_CFG_REGS));
	}
#else 	//for new CSL
	for(i=0; i<4; i++) //Serdes B8
	{
		if((serdes_cfg->laneEnableMask>>i)&1)
		{
			CSL_AIF2SerdesLaneEnable(CSL_AIF_CFG_REGS,
				CSL_AIF_SERDES_B8_CFG_REGS,
				i, serdes_cfg->laneRateScale[i]);
		}

		if((serdes_cfg->loopBackMask>>i)&1)
		{
			CSL_AIF2SerdesLoopbackEnable(CSL_AIF_SERDES_B8_CFG_REGS,
				i, CSL_SERDES_LOOPBACK_ENABLED);
		}
		else
		{
			CSL_AIF2SerdesLoopbackEnable(CSL_AIF_SERDES_B8_CFG_REGS,
				i, CSL_SERDES_LOOPBACK_DISABLED);
		}
	}
	for(i=4; i<6; i++) //Serdes B4
	{
		if((serdes_cfg->laneEnableMask>>i)&1)
		{
			CSL_AIF2SerdesLaneEnable(CSL_AIF_CFG_REGS,
				CSL_AIF_SERDES_B4_CFG_REGS,
				i, serdes_cfg->laneRateScale[i]);
		}

		if((serdes_cfg->loopBackMask>>i)&1)
		{
			CSL_AIF2SerdesLoopbackEnable(CSL_AIF_SERDES_B4_CFG_REGS,
				i-4, CSL_SERDES_LOOPBACK_ENABLED);
		}
		else
		{
			CSL_AIF2SerdesLoopbackEnable(CSL_AIF_SERDES_B4_CFG_REGS,
				i-4, CSL_SERDES_LOOPBACK_DISABLED);
		}
	}

	// Enable Serdes PLL, and Wait the SerDes PLL lock
	if(serdes_cfg->laneEnableMask&0xF) //lane 0~3
	{
		CSL_AIF2SerdesPllEnableB8(CSL_AIF_CFG_REGS, CSL_AIF_SERDES_B8_CFG_REGS);
		while(CSL_SERDES_STATUS_PLL_NOT_LOCKED==CSL_AIF2SerdesGetStatusB8(CSL_AIF_CFG_REGS));
	}
	if(serdes_cfg->laneEnableMask&0x30) //lane 4~5
	{
		CSL_AIF2SerdesPllEnableB4(CSL_AIF_CFG_REGS, CSL_AIF_SERDES_B4_CFG_REGS);
		while(CSL_SERDES_STATUS_PLL_NOT_LOCKED==CSL_AIF2SerdesGetStatusB4(CSL_AIF_CFG_REGS));
	}
#endif

	/* The TX byte clock from either B8 or B4 SERDES link will be selected as 
	sys_clk once the PLL has acquired lock.*/
	if(0==(serdes_cfg->laneEnableMask&0xF)) //Serdes B8 is not used
		CSL_AIF2SerdesClkSelB4(CSL_AIF_CFG_REGS);

	//AIF2 Links Clock Enable
	for(i=0; i < 6; i++)
	{
		if((serdes_cfg->laneEnableMask>>i)&1)
			CSL_AIF2LinkClkEnable(CSL_AIF_CFG_REGS, i);
		else
			CSL_AIF2LinkClkDisable(CSL_AIF_CFG_REGS, i);
	}
}

#if 0
#include <ti/csl/src/ip/serdes_sb/V0/csl_serdes_debug.h>

//for debug
void SerDes_sweep()
{
	int i;
    sweep sweepcmc1;
    uint32_t lane_num, testtime, C1coeff_start, C1coeff_end, CMcoeff_start, CMcoeff_end;

    CSL_SERDES_RESET_CMULANES_PHYA(CSL_HYPERLINK_0_SERDES_CFG_REGS);

    lane_num = 0;
    testtime = 160;
    C1coeff_start = 0;
    C1coeff_end = 33;
    CMcoeff_start = 0;
    CMcoeff_end = 3;

    sweepcmc1 = CSL_SERDES_SWEEP_CM_C1_PHYA(CSL_HYPERLINK_0_SERDES_CFG_REGS, lane_num, testtime, C1coeff_start, C1coeff_end, CMcoeff_start, CMcoeff_end);
    
    for(i=0; i < ((C1coeff_end-C1coeff_start)*(CMcoeff_end-CMcoeff_start)); i++)
    {
       printf("C1 = %d, CM = %d, BER = %d\n", sweepcmc1.C1[i], sweepcmc1.CM[i], sweepcmc1.ber[i]);
    }

}
#endif

