/**  
 * @file csl_serdes_pcie.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_PCIE SERDES PCIE
 * @ingroup CSL_SERDES_API
 *
 * @section Introduction
 *
 * @subsection xxx Overview
 * This module deals with setting up SERDES configuration for PCIE. The API flow should be as follows:   \n
 *
 * CSL_PCIeSerdesInit (base_addr, ref_clock, rate);
 *
 * CSL_PCIeSerdesLaneConfig (base_addr, ref_clock, rate, lane_num);
 *
 * CSL_PCIeSerdesComEnable (base_addr);
 *
 * CSL_PCIeSerdesSetLoopback (base_addr, lane_num, loopback_mode);
 *
 * CSL_PCIeSerdesLaneEnable (base_addr, num_lanes);
 *
 * CSL_PCIeSerdesSetLaneRate (base_addr, lane_ctrl_rate);
 *
 * CSL_PCIeSerdesGetStatus (base_addr, num_lanes);
 *
 *                      OR 
 *
 * CSL_PCIeSerdesGetPLLStatus (base_addr);
 *
 * CSL_PCIeSerdesGetLaneStatus (base_addr, lane_num); (For individual lane status)
 *
 * @subsection References
 *    
 * ============================================================================
 */ 

#include <csl_serdes.h>

extern void csl_wiz8_sb_refclk100MHz_pci_5Gbps(uint32_t base_addr);

/** @brief
 *
 *  PCIE SERDES LANE CTRL TX/RX RATE enumerators.
 */
typedef enum
{
    /** PCIE GEN 1 */
    CSL_SERDES_PCIE_GEN_1 = 0,

    /** PCIE GEN 2 */
    CSL_SERDES_PCIE_GEN_2 = 1
} CSL_SERDES_PCIE_LANE_RATE;

/** @addtogroup CSL_SERDES_PCIE
 @{ */
/** ============================================================================
 *   @n@b CSL_PCIeSerdesInit
 *
 *   @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_PCIeSerdesInit(CSL_PCIE_SERDES_CFG_REGS, CSL_SERDES_REF_CLOCK_100M, CSL_SERDES_LINK_RATE_5G);

    @endverbatim
 * ===========================================================================
 */ 
CSL_IDEF_INLINE CSL_SERDES_RESULT CSL_PCIeSerdesInit
(
 uint32_t  base_addr,
 CSL_SERDES_REF_CLOCK  ref_clock,
 CSL_SERDES_LINK_RATE  rate
)
{
    if (ref_clock != CSL_SERDES_REF_CLOCK_100M)
    {
        return CSL_SERDES_INVALID_REF_CLOCK;
    }
    
    if (ref_clock == CSL_SERDES_REF_CLOCK_100M && rate == CSL_SERDES_LINK_RATE_5G)
    {   
        csl_wiz8_sb_refclk100MHz_pci_5Gbps(base_addr);
    }
    
    if (rate != CSL_SERDES_LINK_RATE_5G)
    {
        return CSL_SERDES_INVALID_LANE_RATE;
    }
    
    return CSL_SERDES_NO_ERR;
}

/** ============================================================================
 *   @n@b CSL_PCIeSerdesLaneConfig
 *
 *   @b Description
 *   @n This API configures the Serdes Lanes
 *
 *   @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_PCIeSerdesLaneConfig(CSL_PCIE_SERDES_CFG_REGS, CSL_SERDES_REF_CLOCK_100M, CSL_SERDES_LINK_RATE_5G, 1);

    @endverbatim
 * ===========================================================================
 */        
CSL_IDEF_INLINE void CSL_PCIeSerdesLaneConfig
(
 uint32_t base_addr,
 CSL_SERDES_REF_CLOCK ref_clock,
 CSL_SERDES_LINK_RATE rate,
 uint32_t lane_num
)
{
    return;
}
        
/** ============================================================================
 *   @n@b CSL_PCIeSerdesComEnable
 *
 *   @b Description
 *   @n This API enables the Serdes CMU and COMLANE
 *
 *   @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_PCIeSerdesComEnable(CSL_PCIE_SERDES_CFG_REGS);

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

/** ============================================================================
 *   @n@b CSL_PCIeSerdesSetLoopback
 *
 *   @b Description
 *   @n This API enables internal loopback and also brings the TX PLL out of reset
 *
 *   @b Arguments   base_addr, lane_num, loopback_mode
 *
 *   <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_PCIeSerdesSetLoopback(CSL_PCIE_SERDES_CFG_REGS, 0, CSL_SERDES_LOOPBACK_ENABLED);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_PCIeSerdesSetLoopback
(
 uint32_t base_addr,
 uint32_t lane_num,
 CSL_SERDES_LOOPBACK loopback_mode
)
{
     /* 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);

    if (loopback_mode == CSL_SERDES_LOOPBACK_ENABLED)
    {
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x200*(lane_num+1)),31,24, 0x40);
    }       
}

/** ============================================================================
 *   @n@b CSL_PCIeSerdesLaneEnable
 *
 *   @b Description
 *   @n This API enables the PCIE Lanes
 *
 *   @b Arguments   base_addr, num_lanes
 *
 *   <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_PCIeSerdesLaneEnable(CSL_PCIE_SLV_CFG_REGS, 1);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_PCIeSerdesLaneEnable
(
 uint32_t base_addr,
 uint32_t num_lanes
)
{
    if(num_lanes == 1)
    {
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x180C), 9, 8, 0x1);
    }
    
    else if (num_lanes == 2)
    {
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x180C), 9, 8, 0x2);
    }
}

/** ============================================================================
 *   @n@b CSL_PCIeSerdesLaneDisable
 *
 *   @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_PCIeSerdesLaneDisable(CSL_PCIE_SERDES_CFG_REGS, 0);

    @endverbatim
 * ===========================================================================
 */ 
CSL_IDEF_INLINE void CSL_PCIeSerdesLaneDisable
(
 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_PCIeSerdesLaneReset
 *
 *   @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_PCIeSerdesLaneReset(CSL_PCIE_SERDES_CFG_REGS, 0);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_PCIeSerdesLaneReset
(
 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_PCIeSerdesSetLaneRate
 *
 *   @b Description
 *   @n This API sets the Lane Rate for PCIE
 *
 *   @b Arguments   base_addr, lane_ctrl_rate
 *
 *   <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_PCIeSerdesSetLaneRate(CSL_PCIE_SLV_CFG_REGS, CSL_SERDES_PCIE_GEN_2);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE void CSL_PCIeSerdesSetLaneRate
(
 uint32_t base_addr,
 CSL_SERDES_PCIE_LANE_RATE lane_ctrl_rate
)
{
    if (lane_ctrl_rate == CSL_SERDES_PCIE_GEN_2)
    {
        CSL_FINSR(*(volatile uint32_t *)(base_addr + 0x180C),17,17, 0x1);
    }
}

/** ============================================================================
 *   @n@b CSL_PCIeSerdesGetStatus
 *
 *   @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_PCIeSerdesGetStatus(CSL_PCIE_SERDES_CFG_REGS, 1);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE CSL_SERDES_STATUS CSL_PCIeSerdesGetStatus
(
 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 SD Status Bits */
    for (i=0; i < num_lanes; i++)
    {
        retval &= (CSL_SERDES_STATUS)CSL_FEXTR(*(volatile uint32_t *)(base_addr + 0x1ff4), (0 + i), (0 + i));
    }

    return retval;
}


/** ============================================================================
 *   @n@b CSL_PCIeSerdesGetPLLStatus
 *
 *   @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_PCIeSerdesGetPLLStatus(CSL_PCIE_SERDES_CFG_REGS);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE CSL_SERDES_STATUS CSL_PCIeSerdesGetPLLStatus
(
 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_PCIeSerdesGetLaneStatus
 *
 *   @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_PCIeSerdesGetLaneStatus(CSL_SRIO_SERDES_CFG_REGS, 0);

    @endverbatim
 * ===========================================================================
 */
CSL_IDEF_INLINE CSL_SERDES_STATUS CSL_PCIeSerdesGetLaneStatus
(
 uint32_t base_addr,
 uint32_t lane_num
)
{
    CSL_SERDES_STATUS retval;

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

    return retval;
}

/** ============================================================================
 *   @n@b CSL_PCIeSerdesGetMuxStatus
 *
 *   @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_PCIeSerdesGetMuxStatus(CSL_CSISC2_3_SERDES_CFG_REGS, 1);

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

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

    /* Disables and Resets SERDES for each lane */
    for(i=0; i<2; i++)
    {
        CSL_PCIeSerdesLaneDisable(base_addr, i);
        CSL_PCIeSerdesLaneReset(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);
}
/* @} */

