/**
 * @file csl_serdes.h
 *
 * @brief
 *  Header file for functional layer of CSL SERDES.
 *
 *  It contains the various enumerations, structure definitions and function
 *  declarations
 *
 *  \par
 *  ============================================================================
 *  @n   (C) Copyright 2013, Texas Instruments, Inc.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
*/

/** ============================================================================
 *
 * @defgroup CSL_SERDES
 *
 * @section Introduction
 *
 * @subsection xxx Overview
 * This is the top level SERDES API with enumerations for various supported
   reference clocks, link rates, lane control rates across different modules.
 *
 *
 * @subsection References
 *
 * ============================================================================
 */


#ifndef CSL_SERDES_V0_H_
#define CSL_SERDES_V0_H_


#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#include <ti/csl/soc.h>
#include <ti/csl/csl.h>

/** @addtogroup CSL_SERDES
 @{ */
/** ============================================================================
 *   @n@b CSL_SERDES_REF_CLOCK
 *
 * @brief
 *
 *
 *  SERDES REF CLOCK speed enumerators */
typedef enum
{
    /** 100 MHz */
   CSL_SERDES_REF_CLOCK_100M        =   0,

    /** 122.8 MHz */
   CSL_SERDES_REF_CLOCK_122p88M     =   1,

    /** 125 MHz */
   CSL_SERDES_REF_CLOCK_125M        =   2,

    /** 153.6 MHz */
   CSL_SERDES_REF_CLOCK_153p6M     =    3,

   /** 156.25 MHz */
   CSL_SERDES_REF_CLOCK_156p25M     =   4,

    /** 312.5 MHz */
   CSL_SERDES_REF_CLOCK_312p5M      =   5
} CSL_SERDES_REF_CLOCK;


/** ============================================================================
 * @brief
 *
 *  SERDES LINK RATE speed enumerators */
typedef enum
{
    /** 1.25 GHz */
   CSL_SERDES_LINK_RATE_1p25G        =   0,

    /** 4.9152 GHz */
   CSL_SERDES_LINK_RATE_4p9152G      =   1,

    /** 5 GHz */
   CSL_SERDES_LINK_RATE_5G           =   2,

    /** 6.144 GHz */
   CSL_SERDES_LINK_RATE_6p144G       =   3,

    /** 6.25 GHz */
   CSL_SERDES_LINK_RATE_6p25G        =   4,

   /** 7.3728 GHz */
   CSL_SERDES_LINK_RATE_7p3728G      =   5,

   /** 9.8304 GHz */
   CSL_SERDES_LINK_RATE_9p8304G      =   6,

   /** 10 GHz */
   CSL_SERDES_LINK_RATE_10G          =   7,

   /** 10.3125 GHz */
   CSL_SERDES_LINK_RATE_10p3125G     =   8,

    /** 12.5 GHz */
   CSL_SERDES_LINK_RATE_12p5G        =   9
} CSL_SERDES_LINK_RATE;


/** ============================================================================
 * @brief
 *
 *  SERDES LOOPBACK enumerators */

typedef enum
{
    /** Loopback Enabled */
    CSL_SERDES_LOOPBACK_ENABLED   =  0,

    /** Loopback Disabled */
    CSL_SERDES_LOOPBACK_DISABLED  =  1
} CSL_SERDES_LOOPBACK;


/** ============================================================================
 * @brief
 *
 *  SERDES PLL STATUS enumerators */
typedef enum
{
    /** PLL Not Locked */
    CSL_SERDES_STATUS_PLL_NOT_LOCKED = 0,

    /** PLL Locked */
    CSL_SERDES_STATUS_PLL_LOCKED     = 1
} CSL_SERDES_STATUS;



/** ============================================================================
 * @brief
 *
 *  SERDES INIT RETURN VALUE enumerators */
typedef enum
{
    /** Init Success */
    CSL_SERDES_NO_ERR               = 0,

    /** Invalid Reference Clock */
    CSL_SERDES_INVALID_REF_CLOCK    = 1,

    /** Invalid Lane Rate */
    CSL_SERDES_INVALID_LANE_RATE    = 2
} CSL_SERDES_RESULT;


/** ============================================================================
 * @brief
 *
 *  SERDES LANE CTRL TX/RX RATE enumerators */
typedef enum
{
    /** SERDES Full Rate */
    CSL_SERDES_LANE_FULL_RATE      = 0,

    /** SERDES Half Rate */
    CSL_SERDES_LANE_HALF_RATE      = 1,

    /** SERDES Quarter Rate */
    CSL_SERDES_LANE_QUARTER_RATE   = 2
} CSL_SERDES_LANE_CTRL_RATE;


/** ============================================================================
 * @brief
 *
 *  SERDES LANE CTRL STATUS enumerators */
typedef enum
{
    /** Lane Control Enable Success */
    CSL_SERDES_LANE_ENABLE_NO_ERR           = 0,

    /** Invalid Lane Control Rate */
    CSL_SERDES_LANE_ENABLE_INVALID_RATE     = 1
} CSL_SERDES_LANE_ENABLE_STATUS;


/** ============================================================================
 * @brief
 *
 *  SERDES PHY TYPE enumerators */
typedef enum
{
    /** 10GE SERDES */
    SERDES_10GE = 0,

    /** AIF2 B8 SERDES */
    SERDES_AIF2_B8     = 1,

    /** AIF2 B4 SERDES */
    SERDES_AIF2_B4     = 2,

    /** SRIO SERDES */
    SERDES_SRIO     = 3,

    /** PCIe SERDES */
    SERDES_PCIe     = 4,

    /** Hyperlink SERDES */
    SERDES_HYPERLINK     = 5,

    /** SGMII SERDES */
    SERDES_SGMII     = 6,

    /** DFE SERDES */
    SERDES_DFE       = 7,

    /** IQN SERDES */
    SERDES_IQN       = 8
} csl_serdes_phy_type;

#define CSL_SERDES_MAX_LANES                4
#define CSL_SERDES_MAX_TAPS                 5
#define CSL_SERDES_MAX_COMPARATORS          5
#define CSL_SERDES_TBUS_SIZE                155
#define CSL_SERDES_PHY_A_1LANE_QUAD_MUX     0x4ebe
#define CSL_SERDES_PHY_A_2LANE_NO_MUX       0x4eb8
#define CSL_SERDES_PHY_A_2LANE_QUAD_MUX     0x4ebc
#define CSL_SERDES_PHY_A_4LANE_NO_MUX       0x4eb9
#define CSL_SERDES_PHY_A_4LANE_QUAD_MUX     0x4ebd
#define CSL_SERDES_PHY_B_2LANE_NO_MUX       0x4eba

/** ============================================================================
 * @brief
 *
 *  SERDES PHY Test Bus Structure */
typedef struct CSL_SERDES_TBUS_DUMP
{
    uint32_t    taddr[CSL_SERDES_TBUS_SIZE];
    uint32_t    tbus_data[CSL_SERDES_TBUS_SIZE];
} CSL_SERDES_TBUS_DUMP_T;



/** ============================================================================
 * @brief
 *
 *  SERDES PHY Center DFE TAPs and Data Sample Comparators Structure */
typedef struct CSL_SERDES_TAP_OFFSETS
{
    uint32_t   tap1_offsets[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
    uint32_t   tap2_offsets[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
    uint32_t   tap3_offsets[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
    uint32_t   tap4_offsets[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
    uint32_t   tap5_offsets[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
    uint32_t   cmp_offsets[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_COMPARATORS];
    uint32_t   izerocmp[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_COMPARATORS];
    uint32_t   izerotap1[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
    uint32_t   izerotap2[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
    uint32_t   izerotap3[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
    uint32_t   izerotap4[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
    uint32_t   izerotap5[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];

} CSL_SERDES_TAP_OFFSETS_T;

/** ============================================================================
 * @brief
 *
 *  SERDES PHY DFE Set FLags Structure */
typedef struct CSL_SERDES_SET_EQ_FLAG
{
    uint32_t vreg_enable;
    uint32_t cdfe_enable;
    uint32_t offset_enable;
    uint32_t att_start;
    uint32_t boost_start;
}CSL_SERDES_SET_EQ_FLAG_T;

/** ============================================================================
 * @brief
 *
 *  SERDES PHY Transmitter Coefficients Structure */
typedef struct CSL_SERDES_TX_COEFF
{
    uint32_t tx_att;
    uint32_t tx_vreg;
    uint32_t cm_coeff;
    uint32_t c1_coeff;
    uint32_t c2_coeff;
}CSL_SERDES_TX_COEFF_T;


/** ============================================================================
 *   @n@b CSL_SerdesWriteTbusAddr
 *
 *   @b Description
 *   @n Function to write to the Serdes Test Bus Address
 *
 *   @b Arguments
 *   @verbatim
        base_addr     Serdes IP base address
        iSelect       To select the specific Test Bus based on the PHY type
        iOffset       To write the specific offset address in the TBUS
 *
 *   <b> Return Value  </b>
 *   @n  None
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_SerdesWriteTbusAddr(uint32_t base_addr,
                                             int32_t    iSelect,
                                             int32_t    iOffset)
  {
  int32_t isPhyA;
  int32_t isNotFourLaner;

  isNotFourLaner=(*(volatile uint32_t *)(base_addr + 0x1fc0)>>16)&0x0ffff;
  isPhyA    = (isNotFourLaner != CSL_SERDES_PHY_B_2LANE_NO_MUX);

  if ((isNotFourLaner==CSL_SERDES_PHY_A_4LANE_NO_MUX)
       ||(isNotFourLaner==CSL_SERDES_PHY_A_4LANE_QUAD_MUX))
      {
          isNotFourLaner=0;
      }
  else
      {
          isNotFourLaner=1;
      }
  if ((iSelect)&&(isNotFourLaner))
      {
          iSelect++;
      }

 if (isPhyA) /* PHY-A detected */
    {
       CSL_FINSR(*(volatile uint32_t *)(base_addr+0x0008), 31,24,
                                        (uint32_t)((iSelect) << 5) + iOffset);
    }
  else /* PHY-B detected */
    {
       CSL_FINSR(*(volatile uint32_t *)(base_addr+0x00fc), 26,16,
                                        ((iSelect) << 8) + iOffset);
    }
  }


/** ============================================================================
 *   @n@b CSL_SerdesReadTbusVal
 *
 *   @b Description
 *   @n Function to read the Serdes Test Bus (tbus) value
 *
 *   @b Arguments
 *   @verbatim
        base_addr     Serdes IP base address
 *
 *   <b> Return Value  </b>
 *   @n  None
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE uint32_t CSL_SerdesReadTbusVal(uint32_t base_addr)
{
      int32_t isPhyA;
      int32_t isNotFourLaner;
      uint32_t iTmp;

      isNotFourLaner=(*(volatile uint32_t *)(base_addr + 0x1fc0)>>16)&0x0ffff;
      isPhyA    = (isNotFourLaner != CSL_SERDES_PHY_B_2LANE_NO_MUX);

       if(isPhyA)
       {
          iTmp  = (*(volatile uint32_t *)(base_addr + 0x0ec) >> 24) & 0x0ff;
          iTmp |=((*(volatile uint32_t *)(base_addr + 0x0fc) >> 16) & 0x00f00);
       }
       else
       {
          iTmp  = (*(volatile uint32_t *)(base_addr + 0x0f8) >> 16) & 0x0fff;
       }
       return(iTmp);
}


/** ============================================================================
 *   @n@b CSL_SerdesReadSelectedTbus
 *
 *   @b Description
 *   @n Function to read out selected 8-bit TBUS value
 *
 *   @b Arguments
 *   @verbatim
        base_addr     Serdes IP base address
        iSelect       To select the specific Test Bus based on the PHY type
        iOffset       To write the specific offset address in the TBUS
 *
 *   <b> Return Value  </b>
 *   @n  Returns 8-bit TBUS field value
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE uint32_t CSL_SerdesReadSelectedTbus(uint32_t base_addr,
                                                    int32_t     iSelect,
                                                    int32_t     iOffset)
{
    CSL_SerdesWriteTbusAddr(base_addr,iSelect,iOffset);   /* Set tbus address */
    return(CSL_SerdesReadTbusVal(base_addr));             /* Get TBUS Value */
}


/** ============================================================================
 *   @n@b csl_serdes_tbus_dump
 *
 *   @b Description
 *   @n Function to read out the entire TBUS
 *
 *   @b Arguments
 *   @verbatim
        base_addr     Serdes IP base address
        *pTbusDump    Pointer to the array structure for storing the tbus values
        phy_type      Serdes PHY type enumerator
 *
 *   <b> Return Value  </b>
 *   @n  Returns
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void csl_serdes_tbus_dump(uint32_t                   base_addr,
                                          CSL_SERDES_TBUS_DUMP_T     *pTbusDump,
                                          csl_serdes_phy_type        phy_type)
{

    uint32_t i,j;
    uint32_t count = 0;


    if (phy_type == SERDES_10GE)
    {
        for(i = 0; i < 6; i++)
        {
            for (j = 0; j < 67; j++)
            {
                pTbusDump->taddr[count] = (i << 8) | j;
                CSL_FINSR(*(volatile uint32_t *)(base_addr+0x00fc), 26, 16,
                pTbusDump->taddr[count]);
                pTbusDump->tbus_data[count] = CSL_SerdesReadTbusVal(base_addr);
                count++;
            }
        }
    }

    else
    {
        for(i = 0; i < 5; i++)
            {
                for (j = 0; j < 31; j++)
                {
                    pTbusDump->taddr[count] = (i << 5) | j;
                    CSL_FINSR(*(volatile uint32_t *)(base_addr+0x0008), 31, 24,
                    pTbusDump->taddr[count]);
                    pTbusDump->tbus_data[count] = (*(uint32_t *) (base_addr + 0x00EC));
                    pTbusDump->tbus_data[count] = (pTbusDump->tbus_data[count] & 0xFF000000) >> 24;
                    pTbusDump->tbus_data[count] = pTbusDump->tbus_data[count] |
                    (((*(uint32_t *) (base_addr + 0x00FC)) >> 16) & 0x00000F00);
                }
        }

    }

}


/** ============================================================================
 *   @n@b CSL_SERDES_CONFIG_CM_C1_C2
 *
 *   @b Description
 *   @n This API is used for configuring the Serdes Transmitter CM, C1,
     C2 coefficients.
 *
 *   @b Arguments
 *   @verbatim
        base_addr                   Serdes IP base address
        lane_num                    Serdes lane number configured
        CMcoeff, C1coeff, C2coeff   Transmit Pre & Post Cursor De-Emphasis values
        phy_type                    Serdes PHY type enumerator
 *
 *   <b> Return Value  </b>
 *   @n  None
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim

     CSL_SERDES_CONFIG_CM_C1_C2(CSL_HYPERLINK_0_SERDES_CFG_REGS, 0, 6, 3, 2,
     SERDES_HYPERLINK);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_SERDES_CONFIG_CM_C1_C2(uint32_t            base_addr,
                                                uint32_t            lane_num,
                                                uint32_t            CMcoeff,
                                                uint32_t            C1coeff,
                                                uint32_t            C2coeff,
                                                csl_serdes_phy_type phy_type)
{

 if(phy_type != SERDES_10GE)
 {
     CSL_FINSR(*(volatile uint32_t *)(base_addr+(lane_num*0x200)+0x200+0x8),15,12,CMcoeff);
     CSL_FINSR(*(volatile uint32_t *)(base_addr+(lane_num*0x200)+0x200+0x8),4,0,C1coeff);
     CSL_FINSR(*(volatile uint32_t *)(base_addr+(lane_num*0x200)+0x200+0x8),11,8,C2coeff);
 }
 else
 {
     CSL_FINSR(*(volatile uint32_t *)(base_addr +(lane_num*0x200)+0x200+0x8),11,8,CMcoeff);
     CSL_FINSR(*(volatile uint32_t *)(base_addr +(lane_num*0x200)+0x200+0x8),4,0,C1coeff);
     CSL_FINSR(*(volatile uint32_t *)(base_addr +(lane_num*0x200)+0x200+0x8),7,5,C2coeff);
     CSL_FINSR(*(volatile uint32_t *)(base_addr +(lane_num*0x200)+0x200+0x4),18,18,C2coeff>>3);
 }

}


/** ============================================================================
 *   @n@b CSL_Serdes_Deassert_Reset
 *
 *   @b Description
 *   @n Function to de-assert reset on the SERDES PHY
 *
 *   @b Arguments
 *   @verbatim
        base_addr       Serdes IP base address
        phy_type        Serdes PHY type enumerator
        isBlock         Waits for LANE OK to complete after deasserting the reset
        num_lanes       Number of lanes configured
 *
 *   <b> Return Value  </b>
 *   @n  Returns CSL_SERDES_RESULT
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE CSL_SERDES_RESULT CSL_Serdes_Deassert_Reset(uint32_t            base_addr,
                                                            csl_serdes_phy_type phy_type,
                                                            uint32_t            isBlock,
                                                            uint32_t            num_lanes)
{
    int32_t iTmp, i;
    CSL_SERDES_STATUS retval = CSL_SERDES_STATUS_PLL_LOCKED;

    /* Toggle Bit 29 of LANE_28 */
    if(phy_type == SERDES_10GE)
    {
     for(i=0;i<num_lanes;i++)
     {
         /* set pma_cmu_sel to 1 */
         CSL_FINSR(*(volatile uint32_t *)(base_addr + (i * 0x200) + 0x200 + 0x60),0,0, 0x1);
         /* release resets */
         CSL_FINSR(*(volatile uint32_t *)(base_addr + (i * 0x200) + 0x200 + 0x28),29,29, 0x0);

     }
    }
   else
   {
        for(i=0;i<num_lanes;i++)
        {
            /* release resets */
            CSL_FINSR(*(volatile uint32_t *)(base_addr + (i * 0x200) + 0x200 + 0x28),29,29, 0x0);
        }
   }

    if(isBlock){
        if(phy_type != SERDES_PCIe)
        {

                do{
                    retval = CSL_SERDES_STATUS_PLL_LOCKED;

                    for(i=0; i < num_lanes; i++)
                    {
                        if(phy_type == SERDES_10GE)
                        {
                            /* 2-lane PHY-B lane-OK */
                            retval &= (CSL_SERDES_STATUS)CSL_FEXTR(*(volatile uint32_t *)
                            (base_addr + 0xa00 + 0x1f8), (29+i), (29+i));
                        }
                        else
                        {
                            /*4-lane PHY-A lane-OK */
                            retval &= (CSL_SERDES_STATUS)CSL_FEXTR(*(volatile uint32_t *)
                            (base_addr + 0xa00 + 0x1f8), (28+i), (28+i));
                        }
                    }
                }while(retval != CSL_SERDES_STATUS_PLL_LOCKED);
        }
        else
        {
              for(i=0;i<num_lanes;i++)
              {
                   iTmp = (CSL_SerdesReadSelectedTbus(base_addr, i+1, 0x02) & 0x0010) >> 4;
                   while(iTmp!=0)
                   iTmp = (CSL_SerdesReadSelectedTbus(base_addr, i+1, 0x02) & 0x0010) >> 4;
              }
        }
    }
    return CSL_SERDES_NO_ERR;

}


/** ============================================================================
 *   @n@b CSL_Serdes_Assert_Reset
 *
 *   @b Description
 *   @n Function to assert reset on the SERDES PHY
 *
 *   @b Arguments
 *   @verbatim
        base_addr       Serdes IP base address
        phy_type        Serdes PHY type enumerator
 *
 *   <b> Return Value  </b>
 *   @n  None
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_Serdes_Assert_Reset(uint32_t               base_addr,
                                             csl_serdes_phy_type    phy_type)
{

    /* TOGGLE Bit 29 of LANE_28 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + (0 * 0x200) + 0x200 + 0x28),29,15, 0x4260);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + (1 * 0x200) + 0x200 + 0x28),29,15, 0x4260);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + (2 * 0x200) + 0x200 + 0x28),29,15, 0x4260);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + (3 * 0x200) + 0x200 + 0x28),29,15, 0x4260);


}


/** ============================================================================
 *   @n@b CSL_SerdesGetAverageOffsets
 *
 *   @b Description
 *   @n Function to calculate the Serdes average comparator/tap offset values
 *
 *   @b Arguments
 *   @verbatim
        base_addr       Serdes IP base address
        num_lanes       Number of Lanes to be configured
        phy_type        Serdes PHY type enumerator
        *pTapOffsets    Pointer to the tap offsets structure to store the
                        average DFE offset values
 *
 *   <b> Return Value  </b>
 *   @n  None
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim
 *
 *   CSL_SerdesGetAverageOffsets(base_addr, num_lanes, phy_type, &pTapOffsets);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_SerdesGetAverageOffsets(uint32_t                   base_addr,
                                                 uint32_t                   num_lanes,
                                                 csl_serdes_phy_type        phy_type,
                                                 CSL_SERDES_TAP_OFFSETS_T   *pTapOffsets)
{

  uint32_t i,j,lane_num,comp_no;
  uint32_t iMinCmp[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_COMPARATORS];
  uint32_t iMaxCmp[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_COMPARATORS];
  uint32_t iMinTap1[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iMaxTap1[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iMinTap2[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iMaxTap2[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iMinTap3[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iMaxTap3[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iMinTap4[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iMaxTap4[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iMinTap5[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iMaxTap5[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iZeroCmpCnt[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_COMPARATORS];
  uint32_t iZeroTap1Cnt[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iZeroTap2Cnt[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iZeroTap3Cnt[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iZeroTap4Cnt[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t iZeroTap5Cnt[CSL_SERDES_MAX_LANES][CSL_SERDES_MAX_TAPS];
  uint32_t cmp_offset_tmp,tap1_offset_tmp,tap2_offset_tmp,tap3_offset_tmp;
  uint32_t tap4_offset_tmp,tap5_offset_tmp;

/* Reset the variables */
for(i=0;i<num_lanes;i++)
    for(j=0;j<CSL_SERDES_MAX_TAPS;j++)
    {
          pTapOffsets->cmp_offsets[i][j] =0;
          pTapOffsets->tap1_offsets[i][j]=0;
          pTapOffsets->tap2_offsets[i][j]=0;
          pTapOffsets->tap3_offsets[i][j]=0;
          pTapOffsets->tap4_offsets[i][j]=0;
          pTapOffsets->tap5_offsets[i][j]=0;
          iMinCmp[i][j] =0x0ffffff; iMaxCmp[i][j] =0;
          iMinTap1[i][j]=0x0ffffff; iMaxTap1[i][j]=0;
          iMinTap2[i][j]=0x0ffffff; iMaxTap2[i][j]=0;
          iMinTap3[i][j]=0x0ffffff; iMaxTap3[i][j]=0;
          iMinTap4[i][j]=0x0ffffff; iMaxTap4[i][j]=0;
          iMinTap5[i][j]=0x0ffffff; iMaxTap5[i][j]=0;
          iZeroCmpCnt[i][j] =0;
          iZeroTap1Cnt[i][j]=0;
          iZeroTap2Cnt[i][j]=0;
          iZeroTap3Cnt[i][j]=0;
          iZeroTap4Cnt[i][j]=0;
          iZeroTap5Cnt[i][j]=0;
    }

/* Find Average values for 100 retries */
for(i=0;i<100;i++)
{
    uint32_t iTmp;

    CSL_Serdes_Assert_Reset(base_addr, phy_type);
    CSL_Serdes_Deassert_Reset(base_addr, phy_type, 1, num_lanes);

    iTmp= *(volatile uint32_t *)(base_addr + 0x1fc0 + 0x34);
    iTmp >>= 8;
    iTmp &= 0x0f;

    if(phy_type==SERDES_10GE)
    {
        for(lane_num=0;lane_num<num_lanes;lane_num++)
        {
            for(comp_no=1;comp_no<CSL_SERDES_MAX_COMPARATORS;comp_no++)
            {
                /*Set comparator number */
                /* Write comparator value */
                CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0a00 + 0x8c),23,21,comp_no);

                CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0fc),26,16,
                0x11+((lane_num+2)<<8));/* Set tbus address */
                cmp_offset_tmp=(CSL_SerdesReadTbusVal(base_addr) & 0x0ff0)>>4;

                CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0fc),26,16,
                0x11+((lane_num+2)<<8));/* Set tbus address */
                tap1_offset_tmp=(CSL_SerdesReadTbusVal(base_addr) & 0x000f)<<3;

                CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0fc),26,16,
                0x12+((lane_num+2)<<8));/* Set tbus address */
                tap1_offset_tmp = tap1_offset_tmp | ((CSL_SerdesReadTbusVal(base_addr) & 0x0e00)>>9);
                tap2_offset_tmp = (CSL_SerdesReadTbusVal(base_addr) & 0x01f8)>>3;
                tap3_offset_tmp=(CSL_SerdesReadTbusVal(base_addr) & 0x007)<<3;

                CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0fc),26,16,
                0x13+((lane_num+2)<<8));/* Set tbus address */
                tap3_offset_tmp= tap3_offset_tmp | ((CSL_SerdesReadTbusVal(base_addr) & 0xe00)>>9);
                tap4_offset_tmp=(CSL_SerdesReadTbusVal(base_addr) & 0x01f8)>>3;
                tap5_offset_tmp=(CSL_SerdesReadTbusVal(base_addr) & 0x0007)<<3;

                CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0fc),26,16,
                0x14+((lane_num+2)<<8));/* Set tbus address */
                tap5_offset_tmp=tap5_offset_tmp | ((CSL_SerdesReadTbusVal(base_addr) & 0x0e00)>>9);

                  /* take a running count of comparator and tap offsets for num_resets number of runs */
                  pTapOffsets->cmp_offsets[lane_num][comp_no] =
                  pTapOffsets->cmp_offsets[lane_num][comp_no]+cmp_offset_tmp;
                  pTapOffsets->tap1_offsets[lane_num][comp_no] =
                  pTapOffsets->tap1_offsets[lane_num][comp_no]+tap1_offset_tmp;
                  pTapOffsets->tap2_offsets[lane_num][comp_no] =
                  pTapOffsets->tap2_offsets[lane_num][comp_no]+tap2_offset_tmp;
                  pTapOffsets->tap3_offsets[lane_num][comp_no] =
                  pTapOffsets->tap3_offsets[lane_num][comp_no]+tap3_offset_tmp;
                  pTapOffsets->tap4_offsets[lane_num][comp_no] =
                  pTapOffsets->tap4_offsets[lane_num][comp_no]+tap4_offset_tmp;
                  pTapOffsets->tap5_offsets[lane_num][comp_no] =
                  pTapOffsets->tap5_offsets[lane_num][comp_no]+tap5_offset_tmp;

                  if (cmp_offset_tmp>iMaxCmp[lane_num][comp_no])
                  iMaxCmp[lane_num][comp_no]=cmp_offset_tmp;
                  if (cmp_offset_tmp<iMinCmp[lane_num][comp_no])
                  iMinCmp[lane_num][comp_no]=cmp_offset_tmp;
                  if (tap1_offset_tmp>iMaxTap1[lane_num][comp_no])
                  iMaxTap1[lane_num][comp_no]=tap1_offset_tmp;
                  if (tap1_offset_tmp<iMinTap1[lane_num][comp_no])
                  iMinTap1[lane_num][comp_no]=tap1_offset_tmp;
                  if (tap2_offset_tmp>iMaxTap2[lane_num][comp_no])
                  iMaxTap2[lane_num][comp_no]=tap2_offset_tmp;
                  if (tap2_offset_tmp<iMinTap2[lane_num][comp_no])
                  iMinTap2[lane_num][comp_no]=tap2_offset_tmp;
                  if (tap3_offset_tmp>iMaxTap3[lane_num][comp_no])
                  iMaxTap3[lane_num][comp_no]=tap3_offset_tmp;
                  if (tap3_offset_tmp<iMinTap3[lane_num][comp_no])
                  iMinTap3[lane_num][comp_no]=tap3_offset_tmp;
                  if (tap4_offset_tmp>iMaxTap4[lane_num][comp_no])
                  iMaxTap4[lane_num][comp_no]=tap4_offset_tmp;
                  if (tap4_offset_tmp<iMinTap4[lane_num][comp_no])
                  iMinTap4[lane_num][comp_no]=tap4_offset_tmp;
                  if (tap5_offset_tmp>iMaxTap5[lane_num][comp_no])
                  iMaxTap5[lane_num][comp_no]=tap5_offset_tmp;
                  if (tap5_offset_tmp<iMinTap5[lane_num][comp_no])
                  iMinTap5[lane_num][comp_no]=tap5_offset_tmp;
                  if (cmp_offset_tmp==0)
                  {
                  pTapOffsets->izerocmp[lane_num][comp_no] =i;
                  iZeroCmpCnt[lane_num][comp_no]++;
                  }
                  if (tap1_offset_tmp==0)
                  {
                  pTapOffsets->izerotap1[lane_num][comp_no]=i;
                  iZeroTap1Cnt[lane_num][comp_no]++;
                  }
                  if (tap2_offset_tmp==0)
                  {
                  pTapOffsets->izerotap2[lane_num][comp_no]=i;
                  iZeroTap2Cnt[lane_num][comp_no]++;
                  }
                  if (tap3_offset_tmp==0)
                  {
                  pTapOffsets->izerotap3[lane_num][comp_no]=i;
                  iZeroTap3Cnt[lane_num][comp_no]++;
                  }
                  if (tap4_offset_tmp==0)
                  {
                  pTapOffsets->izerotap4[lane_num][comp_no]=i;
                  iZeroTap4Cnt[lane_num][comp_no]++;
                  }
                  if (tap5_offset_tmp==0)
                  {
                  pTapOffsets->izerotap5[lane_num][comp_no]=i;
                  iZeroTap5Cnt[lane_num][comp_no]++;
                  }
                }
                }
              }
     else
      {
          for(lane_num=0;lane_num<num_lanes;lane_num++)
            {
            for(comp_no=1; comp_no<CSL_SERDES_MAX_COMPARATORS; comp_no++)
            {
                /* Set comparator number */
                /* Write comparator value */
                CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0a00 + 0x8c),23,21, comp_no);
                /* Set tbus address */
                 CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x008),31,24, 0x12+((lane_num+1)<<5));
                 cmp_offset_tmp=(CSL_SerdesReadTbusVal(base_addr) & 0x0ff0)>>4;

                 /* Take a running count of comparator and tap offsets for
                 num_resets number of runs */
                 pTapOffsets->cmp_offsets[lane_num][comp_no] =
                 pTapOffsets->cmp_offsets[lane_num][comp_no]+cmp_offset_tmp;
             }
            }
      }
    }

  /* Get average value for each comparator and tap offset */
  if(phy_type==SERDES_10GE)
  {
    for(lane_num=0; lane_num<num_lanes; lane_num++)
      {
      for(comp_no=1; comp_no<CSL_SERDES_MAX_COMPARATORS; comp_no++)
        {
            /* Set comparator number */
            pTapOffsets->cmp_offsets[lane_num][comp_no]  =
            pTapOffsets->cmp_offsets[lane_num][comp_no]/100;
            pTapOffsets->tap1_offsets[lane_num][comp_no] =
            pTapOffsets->tap1_offsets[lane_num][comp_no]/100;
            pTapOffsets->tap2_offsets[lane_num][comp_no] =
            pTapOffsets->tap2_offsets[lane_num][comp_no]/100;
            pTapOffsets->tap3_offsets[lane_num][comp_no] =
            pTapOffsets->tap3_offsets[lane_num][comp_no]/100;
            pTapOffsets->tap4_offsets[lane_num][comp_no] =
            pTapOffsets->tap4_offsets[lane_num][comp_no]/100;
            pTapOffsets->tap5_offsets[lane_num][comp_no] =
            pTapOffsets->tap5_offsets[lane_num][comp_no]/100;
        }
      }
    }
   else
    {
    for(lane_num=0; lane_num<num_lanes; lane_num++)
      {
      for(comp_no=1;comp_no<CSL_SERDES_MAX_COMPARATORS;comp_no++)
        {
          /* Set comparator number */
          pTapOffsets->cmp_offsets[lane_num][comp_no] =
          pTapOffsets->cmp_offsets[lane_num][comp_no]/100;
        }
      }
    }
  }

/** ============================================================================
 *   @n@b CSL_Serdes_Override_Cmp_Tap_Offsets
 *
 *   @b Description
 *   @n Force Serdes comparator and tap offsets to override value
 *
 *   @b Arguments
 *   @verbatim
        base_addr       Serdes IP base address
        lane_num        Lane Number to be configured
        comp_no         Comparator number overriden
        *pTapOffsets    Pointer to the tap offsets structure
 *
 *   <b> Return Value  </b>
 *   @n  None
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim
 *
 *   CSL_Serdes_Override_Cmp_Tap_Offsets(base_addr, lane_num,comp_no, pTapOffsets);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_Serdes_Override_Cmp_Tap_Offsets(uint32_t                   base_addr,
                                                         uint32_t                   lane_num,
                                                         uint32_t                   comp_no,
                                                         CSL_SERDES_TAP_OFFSETS_T   *pTapOffsets)
{

    /*set dfe_shadow_lane_sel */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0a00 + 0xF0),27,26, lane_num+1);
    /*set cmp_offset_ovr_en to 1 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0a00 + 0x98),24,24,1);
    /* Set rxeq_ovr_en to 0x1 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x2c),2,2, 0x1);
    /* set rxeq_dfe_cmp_sel_ovr to comp_no */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x30),7,5, comp_no);
    /* set dfe_tap_ovr_en to 1 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x5c),31,31,(uint32_t)1);

    /* set cmp_offset_ovr to i */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0a00 + 0x9C),7,0,
    pTapOffsets->cmp_offsets[lane_num][comp_no]);
    /* set tap overrides */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),30,24,
    pTapOffsets->tap1_offsets[lane_num][comp_no]);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x5c),5,0,
    pTapOffsets->tap2_offsets[lane_num][comp_no]);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x5c),13,8,
    pTapOffsets->tap3_offsets[lane_num][comp_no]);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x5c),21,16,
    pTapOffsets->tap4_offsets[lane_num][comp_no]);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x5c),29,24,
    pTapOffsets->tap5_offsets[lane_num][comp_no]);

    /* set rxeq_ovr_latch_o = 0x1 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x2c),10,10, 0x1);
    /* set rxeq_ovr_latch_o = 0x0 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x2c),10,10, 0x0);

    /* set cmp_offset_ovr_en to 0 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x0a00 + 0x98),24,24,0);
    /* Set rxeq_ovr_en to 0x0 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x2c),2,2, 0x0);
    /* set dfe_tap_ovr_en to 0 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x5c),31,31,(uint32_t)0);

}

/** ============================================================================
 *   @n@b CSL_Serdes_Override_Cmp_Tap_Offsets_CDFE
 *
 *   @b Description
 *   @n Force Serdes comparator and tap offsets to override value for CDFE
        adaptation
 *
 *   @b Arguments
 *   @verbatim
        base_addr       Serdes IP base address
        lane_num        Lane Number to be configured
        fsm_select      Comparator FSM select field
        comp_no         Comparator number overriden for CDFE adaptation
        *pTapOffsets    Pointer to the tap offsets structure
 *
 *   <b> Return Value  </b>
 *   @n  None
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim
 *
 *  CSL_Serdes_Override_Cmp_Tap_Offsets_CDFE(base_addr, lane_num, fsm_select, comp_no, pTapOffsets);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_Serdes_Override_Cmp_Tap_Offsets_CDFE(uint32_t                  base_addr,
                                                              uint32_t                  lane_num,
                                                              uint32_t                  fsm_select,
                                                              uint32_t                  comp_no,
                                                              CSL_SERDES_TAP_OFFSETS_T *pTapOffsets)
{

    /* Enable overrides */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),16,16, 0x1);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),16,16, 0x1);

    /* Enable comp offset cal */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),18,18, 0x1);
    /* set gcfsm_cmp_sel to comp_no */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x4c),5,2, fsm_select);

    /* Set comparator offset */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),24,17,
    pTapOffsets->cmp_offsets[lane_num][comp_no]);

    /* latch in value */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x1);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x0);

    /* Disable comp offset cal */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),18,18, 0x0);
    /* Enable tap offset cal */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),17,17, 0x1);

    /* Enable tap 1 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),23,19, 0x1);
    /* set tap offset */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),23,17,
    pTapOffsets->tap1_offsets[lane_num][comp_no]);
    /* latch in value */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x1);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x0);

    /* Enable tap 2 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),23,19, 0x2);
    /* set tap offset */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),22,17,
    pTapOffsets->tap2_offsets[lane_num][comp_no]);
    /* latch in value */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x1);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x0);

    /* Enable tap 3 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),23,19, 0x4);
    /* set tap offset */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),22,17,
    pTapOffsets->tap3_offsets[lane_num][comp_no]);
    /* latch in value */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x1);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x0);

    /* Enable tap 4 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),23,19, 0x8);
    /* set tap offset */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),22,17,
    pTapOffsets->tap4_offsets[lane_num][comp_no]);
    /* latch in value */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x1);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x0);

    /* Enable tap 5 */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),23,19, 0x10);
    /* set tap offset */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),22,17,
    pTapOffsets->tap5_offsets[lane_num][comp_no]);
    /* latch in value */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x1);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),29,29, 0x0);

    /* Disable overrides */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),16,16, 0x0);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x48),16,16, 0x0);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),18,18, 0x0);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x58),17,17, 0x0);
}


/** ============================================================================
 *   @n@b CSL_SerdesWriteAverageOffsets
 *
 *   @b Description
 *   @n Function to write out the average RX comparator offsets during
        every SERDES initialization
 *
 *   @b Arguments
 *   @verbatim
        base_addr       Serdes IP base address
        num_lanes       Number of lanes to be configured
        phy_type        Serdes PHY enumerator
        *pTapOffsets    Pointer to the tap offsets structure
 *
 *   <b> Return Value  </b>
 *   @n  None
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n  None
 *
 *   @b Example
 *   @verbatim
 *
 *   CSL_SerdesWriteAverageOffsets(base_addr, num_lanes, phy_type, &pTapOffsets);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_SerdesWriteAverageOffsets(uint32_t                 base_addr,
                                                   uint32_t                 num_lanes,
                                                   csl_serdes_phy_type      phy_type,
                                                   CSL_SERDES_TAP_OFFSETS_T *pTapOffsets)
{

    uint32_t i,lane_num,comp_no;

    /* Rewrite average comparator and tap offsets to comparators/taps */
    if(phy_type==SERDES_10GE)
    {
        for(lane_num=0;lane_num<num_lanes;lane_num++)
        {
         i = 1;
         for(comp_no=1; comp_no<CSL_SERDES_MAX_COMPARATORS; comp_no++)
            {/* Set comparator number */
            CSL_Serdes_Override_Cmp_Tap_Offsets(base_addr, lane_num,comp_no, pTapOffsets);
            CSL_Serdes_Override_Cmp_Tap_Offsets_CDFE(base_addr, lane_num, i, comp_no, pTapOffsets);
            i = i*2;
            }
        }
    }

    else
    {
        for(lane_num=0;lane_num<num_lanes;lane_num++)
        {
            for(comp_no=1; comp_no<CSL_SERDES_MAX_COMPARATORS; comp_no++)
            {/* Set comparator number */
            CSL_Serdes_Override_Cmp_Tap_Offsets(base_addr,lane_num,comp_no, pTapOffsets);
            }
        }
    }
}


/** ============================================================================
 *   @n@b CSL_SerdesTXSetEqualizer
 *
 *   @b Description
 *   @n This API sets the Serdes TX Output Swing Voltage and Center DFE values
 *
 *   @b Arguments
 *   @verbatim
        base_addr      Serdes IP base address
        num_lanes      Number of lanes to be configured
        phy_type       Serdes PHY enumerator
        tx_coeff       Transmit Coefficients structure
        set_eq_flags   Structure to set the Equalizer Flags (Voltage Regulator,
                       CDFE Enable and Offset Compensation Enable)
 *
 *   <b> Return Value  </b>  None
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n None
 *
 *   @b Example
 *   @verbatim

     CSL_SerdesTXSetEqualizer(CSL_XGE_SERDES_CFG_REGS, 2, SERDES_10GE, set_eq_flags);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_SerdesTXRXSetEqualizer(uint32_t                    base_addr,
                                                uint32_t                    num_lanes,
                                                csl_serdes_phy_type         phy_type,
                                                CSL_SERDES_SET_EQ_FLAG_T    set_eq_flags)
{
    uint32_t i;

    if(set_eq_flags.vreg_enable)
    {
        /* Set TX Output Swing Voltage */
        for(i=0; i<num_lanes; i++)
        {
          /* pma_ln_vreg */
          CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x18),25,24, 0x2);
          /* pma_ln_vregh */
          CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x18),27,26, 0x2);
        }
    }

    if(set_eq_flags.cdfe_enable)
    {
        if(phy_type == SERDES_10GE)
        {

            /* Enables the Center DFE */
            for(i=0; i<num_lanes; i++)
            {
                /* cdfe_en_o */
                CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x94),24,24, 0x1);
            }

            /* Setting the initial cdfe value */
            /* cdfe_rate3_init_cal_en[7:0] */
            CSL_FINSR(*(volatile uint32_t *)(base_addr + 0xA00 + 0x108),23,16, 0xFF);
            /* turn on ei exit recal */
            /* cdfe_rate3_recal_o[7:0] */
            CSL_FINSR(*(volatile uint32_t *)(base_addr + 0xA00 + 0x10c),7,0, 0xFF);

            for(i=0; i<num_lanes; i++)
            {
                /* enable ei exit cal for cdfe */
                CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x98),2,2, 0x0);
                /* enable cdfe_ln_force_cal for cdfe */
                CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x98),0,0, 0x1);
            }

            /* Setting the RX Tap Value */
            /* rxeq_rate3_dfe_tap_pd[4:0] */
            CSL_FINSR(*(volatile uint32_t *)(base_addr + 0xA00 + 0xbc),28,24, 0x00);
        }
    }

    /* Set ATT and BOOST start values for each lane */
    for(i=0; i<num_lanes; i++)
    {
        /* att start -1 for short channel */
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x8c),11,8, set_eq_flags.att_start);
        /* boost start -3 for short channel */
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x8c),15,12, set_eq_flags.boost_start);
    }

}


/** ============================================================================
 *   @n@b CSL_Serdes_DFE_OffsetCalibration
 *
 *   @b Description
 *   @n This API calibrates the Serdes DFE by finding the averaging offsets &
        applies the offset compensation patch to the CDFE
 *
 *   @b Arguments
 *   @verbatim
        base_addr   Serdes IP base address
        num_lanes   Number of lanes to be configured
        phy_type    Serdes PHY enumerator
        tx_coeff    Transmit Coefficients structure

 *   <b> Return Value  </b>  None
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n None
 *
 *   @b Example
 *   @verbatim

 CSL_Serdes_DFE_OffsetCalibration(CSL_XGE_SERDES_CFG_REGS, 2, SERDES_10GE, tx_coeff);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_Serdes_DFE_OffsetCalibration(uint32_t              base_addr,
                                                      uint32_t              num_lanes,
                                                      csl_serdes_phy_type   phy_type,
                                                      CSL_SERDES_TX_COEFF_T tx_coeff)
{
    CSL_SERDES_TAP_OFFSETS_T pTapOffsets;
    CSL_SERDES_RESULT       status;
    uint32_t i, count;

    /* Force SERDES Signal Detect LO (Reset CDR, Att and Boost) */
    for(i=0; i<num_lanes; i++)
    {
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x04),2,1, 0x2);
    }

    /* Wait a minimum of 10us */
    count = 0;
    while(1)
        {
            count++;
            if (count > 10000)
            break;
        }

    /* Offset Compensation Patch */
    CSL_SerdesGetAverageOffsets(base_addr,num_lanes, phy_type, &pTapOffsets);


    /* Assert Reset to apply the TX FIR coefficients */
    CSL_Serdes_Assert_Reset(base_addr, phy_type);

    /* Set TX Swing Value */
    for(i=0; i<num_lanes; i++)
    {
        if (phy_type == SERDES_10GE)
        {
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x04),29,26, tx_coeff.tx_att);
        }
        else
        {
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x04),28,25, tx_coeff.tx_att);
        }
    }

    /* Set Regulator Setting for TX Driver */
    for(i=0; i<num_lanes; i++)
    {
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x84),7,5, tx_coeff.tx_vreg);
    }


    /* Apply the TX FIR coefficients to the lanes */
    for(i=0; i<num_lanes; i++)
    {
        CSL_SERDES_CONFIG_CM_C1_C2(base_addr, i, tx_coeff.cm_coeff,
        tx_coeff.c1_coeff, tx_coeff.c2_coeff, phy_type);
    }

    status = CSL_Serdes_Deassert_Reset(base_addr, phy_type, 1, num_lanes);

    /* To eliminate compiler warnings */
    status = status;

    /* Offset Compensation Patch */
    CSL_SerdesWriteAverageOffsets(base_addr, num_lanes, phy_type, &pTapOffsets);

    /* Wait a minimum of 10us */
    count = 0;
    while(1)
        {
            count++;
            if (count > 10000)
            break;
        }

    for(i=0;i<num_lanes;i++)
    {
     /* Allow SERDES to re-acquire Signal Detect */
     CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(i+1) + 0x04),2,1, 0x0);
    }


    /* Wait a minimum of 10us */
    count = 0;
    while(1)
        {
            count++;
            if (count > 10000)
            break;
        }

}

#ifdef __cplusplus
}
#endif

#endif
/* @} */


