/* ======================================================================
 *   Copyright (C) 2022 Texas Instruments Incorporated
 *
 *   All rights reserved. Property of Texas Instruments Incorporated.
 *   Restricted rights to use, duplicate or disclose this code are
 *   granted through contract.
 *
 *   The program may not be used without the written permission
 *   of Texas Instruments Incorporated or against the terms and conditions
 *   stipulated in the agreement under which this program has been
 *   supplied.
 * ==================================================================== */

/**
 *   \file  cpsw_cpts.h
 *
 *   \brief
 *      Header file for CPTS module of CPSW subsystem.
 *
 */


#ifndef CPSW_CPTS_H_
#define CPSW_CPTS_H_

#ifdef __cplusplus
extern "C" {
#endif

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

#define ETH_START_SEC_CODE
#include "Eth_MemMap.h"
#include "hw_types.h"
#define ETH_STOP_SEC_CODE
#include "Eth_MemMap.h"


/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */

/**
 *  \Note This type definations are not part of Platform_Types.h of TI compiler
 *        Defining here to use 64-bit variables in CPTS driver and time sync
 *        APIs.
 */
typedef unsigned long long uint64;
typedef signed long long sint64;

/**
 *  \brief EtherType for the Precision Time Protocol (IEEE 1588).
 *   This is used by CPTS (time sync hardware) for timestamping received or
 *   transmitted packets.
 */
#define CPSW_ETHTYPE_PTP1588                 (0x88F7U)

/**
 *  \Note Below are reset values used for VLAN tags which are used to configure
 *        time stamping on VLAN enabled packets. INNER is first level tag and
 *        OUTER is level2. If you want to use different, change below macros.
 */
#define CPSW_VLAN_LTYPE_VLAN_OUTER          (0x000088A8U)
#define CPSW_VLAN_LTYPE_VLAN_INNER          (0x00008100U)

/** \brief Sequence ID offset and other configuration for PORT */
#define CPSW_P_TS_SEQ_ID_OFFSET                   (0x0000001EU)
#define CPSW_P_TS_MSG_TYPE_EN                     (0x00000000U)
#define CPSW_P_SA_LO_MACSRCADDR0                  (0x00000000U)
#define CPSW_P_SA_LO_MACSRCADDR1                  (0x00000000U)
#define CPSW_P_SA_LO                              (0x00000000U)

/** \brief Macros for time conversions */
#define NSEC_PER_SEC                                (1000000000U)
#define TIME_SYNC_SECONDSHIGH_MASK                  (0x0000FFFF00000000ULL)
#define TIME_SYNC_SECONDS_MASK                      (0xFFFFFFFFU)

/**\brief 802.1AS Packets offsets - make sure offsets match to HW configuration*/
#define TIME_SYNC_OFFSET_PTP_SOURCE_UUID            (22U) /* PTPv1 only */
#define TIME_SYNC_OFFSET_PTP_SEQUENCE_ID            (30U)
#define TIME_SYNC_OFFSET_PTP_CONTROL                (32U) /* PTPv1 only */

/** \brief Enable CPTS debug statistic */
#define CPTS_DEBUG_ENABLED           (STD_OFF)


/** \brief CPTS Event Type Enumeration */
typedef enum
{
    CPTS_EVENT_TIME_STAMP_PUSH          = 0x00U,
    CPTS_EVENT_TIME_STAMP_ROLLOVER      = 0x01U,
    CPTS_EVENT_TIME_STAMP_HALF_ROLLOVER = 0x02U,
    CPTS_EVENT_HARDWARE_TIME_STAMP_PUSH = 0x03U,
    CPTS_EVENT_ETHERNET_RECEIVE         = 0x04U,
    CPTS_EVENT_ETHERNET_TRANSMIT        = 0x05U,
	CPTS_EVENT_TIME_STAMP_COMPARE       = 0x06U,
	CPTS_EVENT_TIME_STAMP_HOST_TRANSMIT = 0x07U,
    CPTS_EVENT_INVALID                  = 0xFFFFFFFFU
} Eth_CptsEventType;

/**
 * \brief  CPTS Ethernet Message Type Enumeration
 */
typedef enum
{
    CPTS_MESSAGE_SYNC                   = 0x00U,
    CPTS_MESSAGE_DELAY_REQ              = 0x01U,
    CPTS_MESSAGE_PDELAY_REQ             = 0x02U,
    CPTS_MESSAGE_PDELAY_RESP            = 0x03U,
    CPTS_MESSAGE_FOLLOW_UP              = 0x08U,
    CPTS_MESSAGE_DELAY_RESP             = 0x09U,
    CPTS_MESSAGE_PDELAY_RESP_FOLLOW_UP  = 0x0AU,
    CPTS_MESSAGE_ANNOUNCE               = 0x0BU,
    CPTS_MESSAGE_SIGNALING              = 0x0CU,
    CPTS_MESSAGE_MANAGEMENT             = 0x0DU,
    CPTS_MESSAGE_INVALID                = 0xFFFFFFFFU
} Eth_CptsMessageType;

/**
 * \brief  CPTS Event Structure
 */
typedef struct Eth_CPTSEVENT_
{
    uint64                  timeStamp;
    Eth_CptsEventType       eventType;
    Eth_CptsMessageType     messageType;
    uint16                  sequenceId;
    uint16                  portNumber;
    struct Eth_CPTSEVENT_  *pNextEvent;
} Eth_CptsEvent;

/**
 *  \brief Enum of mac ports to use for CPTS packets
 */
typedef enum
{
    ETH_CPTS_PORT_SELECTION_MAC_NONE        = 0x00U,
    ETH_CPTS_PORT_SELECTION_MAC_1           = 0x01U,
    ETH_CPTS_PORT_SELECTION_MAC_2           = 0x02U,
    ETH_CPTS_PORT_SELECTION_MAC_BOTH        = 0x03U,
    ETH_CPTS_PORT_SELECTION_INVALID         = 0xFFFFFFFFU
} Eth_CptsPortSelection;

/**
 * \brief  CPTS Event Queue Structure
 */
typedef struct
{
    uint32        count;
    /**< Count of elements in the buffer descriptor queue */
    Eth_CptsEvent      *pHead;
    /**<< Pointer to the front of the buffer descriptor queue */
    Eth_CptsEvent      *pTail;
    /**<< Pointer to the back of the buffer descriptor queue */
} Eth_CptsEventQueue;

/**
 * \brief  CPTS timer counter Structure
 */
typedef struct
{
    uint32 mult;
    /**< Numerator to convert input clock ticks into nanoseconds */
    uint32 shift;
    /**< Denominator to convert input clock ticks into nanoseconds */
    Eth_TimeStampType deltaTimeStamp;
    /**< Time diff w.r.t global time  in nanoseconds */
    boolean deltaSign;
    /**< Time diff sign (Positive (True) / negative (False) time) */
    float32 rateRatio;
    /**< ratio of the frequency of the grandmaster in relation to the frequency
     * of the Local Clock */
} Eth_CptsTimeCounter;

#if defined(CPTS_DEBUG_ENABLED)
typedef struct
{
    uint32            tsSwPushEventCount;
    uint32            tsRolloverEventCount;
    uint32            tsHalfRolloverEventCount;
    uint32            tsHwPushEventCount[4];
    uint32            tsEthernetRxEventCount;
    uint32            tsEthernetTxEventCount;
    uint32            unhandledEventCount;
    uint32            getTimeFail;
    uint32            matchNotFound;
    uint32            eventPushWait;
    uint32            eventHandleCnt;
    uint32            eventProcessed[255U];
} Eth_CptsStats;
#endif

/**
 * \brief  CPTS Instance Structure
 */
typedef struct
{
    uint8                     portNum;
    /**< MAC port CPTS enabled on */
    uint32                    cpswBaseAddr;
    /**< Field to hold the base address of CPSW module */
    uint32                    cptsInputFreq;
    /**< Field to hold the value of the CPTS timestamp counter frequency */
    uint32                    upperTimeStamp;
    /**< Field to hold the upper 32-bits of the HW timestamp */
    Eth_CptsEventQueue             freeQueue;
    /**< Queue of events that are not in use */
    Eth_CptsEventQueue             activeQueue;
    /**< Queue of events that are in use */
    uint32                    tsPushInFIFO;
    /**< Flag to indicate that a SW push event is already active */
    uint32                    checkForMisalignment;
    /**< Flag to indicate an alignment check is required */
    Eth_CptsTimeCounter           timeCounter;
    /**< CPTS time counter structure */
    Eth_CptsConfigType         cptsCfg;
    /**< CPTS config provided by the application*/
} Eth_CptsStateObj;

/*---------------------------------------------------------------------------*\
|                         Global Variable Declarations                        |
\*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*\
|                   Global Inline Function Definitions                        |
\*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*\
|                         Global Function Declarations                        |
\*---------------------------------------------------------------------------*/

/**
 * \brief CPTS module open function
 */
Std_ReturnType Eth_cptsInit(uint32 baseAddr,
                            Eth_CptsStateObj *pCptsStateObj,
                            const Eth_CptsConfigType *pCptsConfig,
                            uint8 portIdx);

/**
 * \brief CPTS module close function
 */
void Eth_cptsDeInit(Eth_CptsStateObj* pCptsStateObj);


/**
 * \brief   CPTS_handleEvents is intended to be called in an ISR context
 *          This is an internal driver function and should not be called
 *          by an application or user.
 */
void Eth_cptsHandleEvents(Eth_CptsStateObj* pCptsStateObj);

/**
 * \brief   Load new timestamp into CPTS module.
 */
void Eth_cptsTimeStampLoad(Eth_CptsStateObj *pCptsStateObj, uint64 timeStamp);

/**
 * \brief   Read CPTS counter and return time in nanoseconds.
 */
Std_ReturnType Eth_cptsCounterRead(Eth_CptsStateObj *pCptsStateObj, uint64 *nsec);

/**
 * \brief   Convert time in Eth_TimeStampType to nanoseconds.
 */
uint64 Eth_cptsSysTime2ns(Eth_TimeStampType *pTimeStamp);

#if 0
/**
 * \brief   Convert time in Eth_TimeStampType to CPTS cycles.
 */
uint64 Eth_cptsSysns2Cycles(uint64 nsec, Eth_CptsTimeCounter *tc);
#endif

/**
 * \brief   Get rate ration from ingress and origin time stamp deltas.
 */
float32 Eth_cptsGetRateRatio(Eth_TimeIntDiffType *pIngressTsDelta,
                            Eth_TimeIntDiffType *pOriginTsDelta);

/**
 * \brief   Get time in Eth_TimeStampType from nanoseconds .
 */
void Eth_cptsGetSysTime(Eth_CptsStateObj *pCptsStateObj,
                        uint64 *nsec,
                        Eth_TimeStampType *pTimeStamp);

/**
 * \brief   Read CPTS Ethernet RX or TX event.
 */
Std_ReturnType Eth_cptsCounterReadEthEvent(Eth_CptsStateObj *pCptsStateObj,
                                           uint64 *nsec,
                                           Eth_CptsEvent     *pEeventTemplate);

/**
 * \brief   Read CPTS event pend raw status.
 */
uint32 Eth_cptsEventPendStatus(uint32 baseAddr);

/**
 * \brief   Compute new delta with given offset between time stamp grandmaster
 *          and local time stamp.
 */
void Eth_cptsFindComputeOffsetDelta (Eth_CptsStateObj *pCptsStateObj,
                                     Eth_TimeIntDiffType *pNewIntDiff);
/*---------------------------------------------------------------------------*\
|                                 End of File                                 |
\*---------------------------------------------------------------------------*/

#ifdef __cplusplus
}
#endif

#endif /* CPSW_CPTS_H_ */
