/**  
 * @file csl_serdes_ethernet.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_ETHERNET SERDES ETHERNET
 * @ingroup CSL_SERDES_API
 *
 * @section Introduction
 *
 * @subsection xxx Overview
 * This module deals with setting up SERDES configuration for ETHERNET. The API flow should be as follows:   \n
 *
 * CSL_EthernetSerdesInit (base_addr, ref_clock, rate);
 *
 * CSL_EthernetSerdesLaneConfig (base_addr, ref_clock, rate, lane_num);
 *
 * CSL_EthernetSerdesComEnable (base_addr);
 *
 * CSL_EthernetSerdesLaneEnable (base_addr, lane_num, link_rate, loopback_mode, lane_ctrl_rate);
 *
 * CSL_EthernetSerdesPllEnable (base_addr);
 *
 * CSL_EthernetSerdesGetStatus (base_addr, num_lanes);
 *
 *                         OR
 *
 * CSL_EthernetSerdesGetPLLStatus (base_addr);
 *
 * CSL_EthernetSerdesGetLaneStatus (base_addr, lane_num); Individual lane status
 * @subsection References
 *    
 * ============================================================================
 */ 

#include <csl_serdes.h>

extern void csl_wiz8_sb_refclk125MHz_10bit_5Gbps(uint32_t base_addr);
extern void csl_wiz8_sb_refclk156p25MHz_10bit_5Gbps(uint32_t base_addr);

/** @addtogroup CSL_SERDES_ETHERNET
 @{ */
/** ============================================================================
 *   @n@b CSL_EthernetSerdesInit
 *
 *   @b Description
 *   @n This API initializes the Serdes CMU and COMLANE registers.
 *
 *   @b Arguments   base_addr, ref_clock, rate
 *
 *   <b> Return Value  </b>  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
 
    csl_retval = CSL_EthernetSerdesInit(CSL_NETCP_SERDES_CFG_REGS, CSL_SERDES_REF_CLOCK_156p25M, CSL_SERDES_LINK_RATE_1p25G);

    @endverbatim
 * ===========================================================================
 */       
CSL_IDEF_INLINE CSL_SERDES_RESULT CSL_EthernetSerdesInit
(
 uint32_t  base_addr,
 CSL_SERDES_REF_CLOCK  ref_clock,
 CSL_SERDES_LINK_RATE  rate
)
{
    if (!(ref_clock == CSL_SERDES_REF_CLOCK_125M || ref_clock == CSL_SERDES_REF_CLOCK_156p25M))
    {
        return CSL_SERDES_INVALID_REF_CLOCK;
    }
    
    if (ref_clock == CSL_SERDES_REF_CLOCK_125M && rate == CSL_SERDES_LINK_RATE_1p25G)
    {   
        csl_wiz8_sb_refclk125MHz_10bit_5Gbps(base_addr);
    }
    
    else if (ref_clock == CSL_SERDES_REF_CLOCK_156p25M && rate == CSL_SERDES_LINK_RATE_1p25G)
    {
        csl_wiz8_sb_refclk156p25MHz_10bit_5Gbps(base_addr);
    }
    
    if (rate != CSL_SERDES_LINK_RATE_1p25G)
    {
        return CSL_SERDES_INVALID_LANE_RATE;
    }
    
    return CSL_SERDES_NO_ERR;
}

/** ============================================================================
 *   @n@b CSL_EthernetSerdesLaneConfig
 *
 *   @b Description
 *   @n This API is currently deprecated and the functionality is integrated into CSL_EthernetSerdesInit API. It is currently used for backwards compatibility.
 *
 *   @b Arguments   base_addr, ref_clock, rate, lane_num
 *
 *   <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_EthernetSerdesLaneConfig(CSL_NETCP_SERDES_CFG_REGS, CSL_SERDES_REF_CLOCK_156p25M, CSL_SERDES_LINK_RATE_1p25G, 1);

    @endverbatim
 * ===========================================================================
 */        
CSL_IDEF_INLINE void CSL_EthernetSerdesLaneConfig
(
 uint32_t base_addr,
 CSL_SERDES_REF_CLOCK ref_clock,
 CSL_SERDES_LINK_RATE rate,
 uint32_t lane_num
)
{
    return;
}

/** ============================================================================
 *   @n@b CSL_EthernetSerdesComEnable
 *
 *   @b Description
 *   @n This API is currently deprecated and the functionality is integrated into CSL_EthernetSerdesInit API. It is currently used for backwards compatibility.
 *
 *   @b Arguments   base_addr
 *
 *   <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_EthernetSerdesComEnable(CSL_NETCP_SERDES_CFG_REGS);

    @endverbatim
 * ===========================================================================
 */ 
CSL_IDEF_INLINE void CSL_EthernetSerdesComEnable
(
 uint32_t base_addr
)
{
   return;
}


/** ============================================================================
 *   @n@b CSL_EthernetSerdesLaneEnable
 *
 *   @b Description
 *   @n This API enables the Serdes CMU and COMLANE
 *
 *   @b Arguments   base_addr, lane_num, loopback_mode, lane_ctrl_rate
 *
 *   <b> Return Value  </b>  CSL_SERDES_LANE_ENABLE_STATUS
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n CSL_SERDES_LANE_FULL_RATE is not supported for Ethernet.
 *
 *   @b Example
 *   @verbatim
 
     CSL_EthernetSerdesLaneEnable(CSL_NETCP_SERDES_CFG_REGS, 0, CSL_SERDES_LOOPBACK_DISABLED, CSL_SERDES_LANE_QUARTER_RATE);

    @endverbatim
 * ===========================================================================
 */ 
CSL_IDEF_INLINE CSL_SERDES_LANE_ENABLE_STATUS CSL_EthernetSerdesLaneEnable
(
 uint32_t base_addr,
 uint32_t lane_num,
 CSL_SERDES_LOOPBACK loopback_mode,
 CSL_SERDES_LANE_CTRL_RATE lane_ctrl_rate
)
{
     /* Bit 28 Toggled. Bring it out of Reset TX PLL for all lanes */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x28),29,29, 0x0);
    
    /* Set Lane Control Rate */
    if (lane_ctrl_rate == CSL_SERDES_LANE_FULL_RATE)
    {
        return CSL_SERDES_LANE_ENABLE_INVALID_RATE;
    }
    
    if (lane_ctrl_rate == CSL_SERDES_LANE_QUARTER_RATE)
    {
        *(volatile uint32_t *)(base_addr + 0x1fe0 + 4*lane_num) = 0xF800F8C0;
    }

    if (lane_ctrl_rate == CSL_SERDES_LANE_HALF_RATE)
    {
        *(volatile uint32_t *)(base_addr + 0x1fe0 + 4*lane_num) = 0xF480F4E0;
    }	
    
    /* Set NES bit if Loopback Enabled */
    if (loopback_mode == CSL_SERDES_LOOPBACK_ENABLED)
    {
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1)),31,24, 0x40);
    }

    return CSL_SERDES_LANE_ENABLE_NO_ERR;    
}

/** ============================================================================
 *   @n@b CSL_EthernetSerdesLaneDisable
 *
 *   @b Description
 *   @n This API disables the Serdes Lanes
 *
 *   @b Arguments   base_addr, lane_num
 *
 *   <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_EthernetSerdesLaneDisable(CSL_NETCP_SERDES_CFG_REGS, 0);

    @endverbatim
 * ===========================================================================
 */ 
CSL_IDEF_INLINE void CSL_EthernetSerdesLaneDisable
(
 uint32_t base_addr,
 uint32_t lane_num
)
{
    /* Puts Lane # in Low Power Mode */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x1fe0 + 4*lane_num),30,29, 0x0);
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x1fe0 + 4*lane_num),14,13, 0x0);
}

/** ============================================================================
 *   @n@b CSL_EthernetSerdesLaneReset
 *
 *   @b Description
 *   @n This API resets the Serdes Lanes
 *
 *   @b Arguments   base_addr, lane_num
 *
 *   <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_EthernetSerdesLaneReset(CSL_NETCP_SERDES_CFG_REGS, 0);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_EthernetSerdesLaneReset
(
 uint32_t base_addr,
 uint32_t lane_num
)
{
    /* Reset RX PLL */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1) + 0x28),29,29, 0x1);
}

/** ============================================================================
 *   @n@b CSL_EthernetSerdesPllEnable
 *
 *   @b Description
 *   @n This API enables the PLL
 *
 *   @b Arguments   base_addr
 *
 *   <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_EthernetSerdesPllEnable(CSL_NETCP_SERDES_CFG_REGS);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_EthernetSerdesPllEnable
(
 uint32_t base_addr
)
{
    /* Set PLL Enable Val */
    *(volatile uint32_t *)(base_addr + 0x1ff4) = 0xe0000000;
}

/** ============================================================================
 *   @n@b CSL_EthernetSerdesGetStatus
 *
 *   @b Description
 *   @n This API returns the status of the PLL lock
 *
 *   @b Arguments   base_addr, num_lanes
 *
 *   <b> Return Value  </b>  CSL_SERDES_STATUS
 *
 *   <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_EthernetSerdesGetStatus(CSL_NETCP_SERDES_CFG_REGS, 4);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE CSL_SERDES_STATUS CSL_EthernetSerdesGetStatus
(
 uint32_t base_addr,
 uint32_t num_lanes
)
{
    uint32_t i;
    CSL_SERDES_STATUS retval;

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

    /* Check Lane # OK Status Bits */
    for (i=0; i < num_lanes; i++)
    {
        retval &= (CSL_SERDES_STATUS)CSL_FEXTR(*(volatile uint32_t *)(base_addr + 0x1ff4), (8 + i), (8 + i));
    }

    return retval;
}

/** ============================================================================
 *   @n@b CSL_EthernetSerdesGetPLLStatus
 *
 *   @b Description
 *   @n This API returns the status of the PLL lock
 *
 *   @b Arguments   base_addr
 *
 *   <b> Return Value  </b>  CSL_SERDES_STATUS
 *
 *   <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_EthernetSerdesGetPLLStatus(CSL_NETCP_SERDES_CFG_REGS);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE CSL_SERDES_STATUS CSL_EthernetSerdesGetPLLStatus
(
 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@b CSL_EthernetSerdesGetLaneStatus
 *
 *   @b Description
 *   @n This API returns the status of the Lanes
 *
 *   @b Arguments   base_addr, lane_num
 *
 *   <b> Return Value  </b>  CSL_SERDES_STATUS
 *
 *   <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_EthernetSerdesGetLaneStatus(CSL_NETCP_SERDES_CFG_REGS, 0);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE CSL_SERDES_STATUS CSL_EthernetSerdesGetLaneStatus
(
 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));   

    return retval;
}


/** ============================================================================
 *   @n@b CSL_EthernetSerdesGetMuxStatus
 *
 *   @b Description
 *   @n This API returns the status of the MUXed Serdes Lane PLL lock
 *
 *   @b Arguments   base_addr, num_lanes
 *
 *   <b> Return Value  </b>  CSL_SERDES_STATUS
 *
 *   <b> Pre Condition </b>
 *   @n  None
 *
 *   <b> Post Condition </b>
 *   @n  None
 *
 *   @b Reads
 *   @n None
 *
 *  <b> Usage Constraints: </b>
 *  @n This API is applicable only for the case of MUXed SERDES (Example: K2L platform)
 *
 *   @b Example
 *   @verbatim
 
     CSL_EthernetSerdesGetMuxStatus(CSL_CSISC2_3_SERDES_CFG_REGS, 2);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE CSL_SERDES_STATUS CSL_EthernetSerdesGetMuxStatus
(
 uint32_t base_addr,
 uint32_t num_lanes
)
{
    uint32_t i;
    CSL_SERDES_STATUS retval = CSL_SERDES_STATUS_PLL_LOCKED;

    /* Check LANEx_PLL_LOCK bit in LANE_PLL_STS register */
    for (i=0; i < num_lanes; i++)
    {
        retval &= (CSL_SERDES_STATUS)CSL_FEXTR(*(volatile uint32_t *)(base_addr + 0x1fd4), (3 + 4*i), (3 + 4*i));
    }

    return retval;
}


/** ============================================================================
 *   @n@b CSL_EthernetSerdesShutdown
 *
 *   @b Description
 *   @n This API shuts down the Serdes by Disabling and Resetting the Serdes
 *
 *   @b Arguments   base_addr
 *
 *   <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_EthernetSerdesShutdown(CSL_NETCP_SERDES_CFG_REGS);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_EthernetSerdesShutdown
(
 uint32_t base_addr
) 
{
    uint32_t i=0;

    /* Disables and Resets SERDES for each lane */
    for(i=0; i<4; i++)
    {
        CSL_EthernetSerdesLaneDisable(base_addr, i);
    }
    
    /* Disable CMU TX PLL */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x1FC0 + 0x34), 30, 29, 0x0);

    /* Bit 28 of CMU_10 Toggled. Reset TX PLL for all lanes */
    CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x10), 28, 28, 0x1);
}
/* @} */

