/**
 * @file sample_code_TSR_init.c
 * @brief Configure GENF signal and route to SYNC0_OUT pin for AM64x
 *
 * This sample code demonstrates how to:
 * 1. Configure CPTS GENF (Generic Function) output at a specific frequency (40 KHz)
 * 2. Route the GENF signal to SYNC0_OUT pin using Timesync Router
 *
 * Timesync Router Configuration (AM64x):
 *   - Input: CPSW0_GENF0 = 21 (per cslr_intr_timesync_event_introuter0.h)
 *   - Output: SYNC0_OUT = 24 (per AM64x TRM)
 */

#include <stdio.h>
#include <stdint.h>
#include <kernel/dpl/ClockP.h>
#include <networking/enet/core/include/enet.h>
#include <networking/enet/core/include/per/cpsw.h>
#include <networking/enet/core/include/mod/cpsw_cpts.h>
#include <drivers/hw_include/csl_types.h>
#include <drivers/hw_include/cslr_soc.h>
#include <drivers/hw_include/am64x_am243x/cslr_intr_timesync_event_introuter0.h>
#include <drivers/sciclient.h>

/* GENF Configuration Parameters */
#define GENF_OUTPUT_FREQ_HZ         (40000U)     /* 40 KHz output frequency */
#define CPTS_RFTCLK_FREQ_HZ         (200000000U) /* 200 MHz reference clock for AM64x */
#define GENF_INDEX                  (0U)         /* Use GENF0 */
#define GENF_POLARITY_HIGH          (1U)
#define GENF_POLARITY_LOW           (0U)

/* Timesync Router Configuration for AM64x */
#define TIMESYNC_INTRTR0_BASE       (CSL_TIMESYNC_EVENT_INTROUTER0_CFG_BASE)
#define TIMESYNC_IN_CPSW0_GENF0     (CSLR_TIMESYNC_EVENT_INTROUTER0_IN_CPSW0_CPTS_GENF0_0)  /* = 21 */
#define TIMESYNC_OUT_SYNC0_PIN      (24U)        /* Output to SYNC0_OUT pin (AM64x TRM) */

/**
 * @brief Configure CPTS GENF (Generic Function) output
 *
 * @param hEnet     Enet driver handle
 * @param freqHz    Desired output frequency in Hz
 * @param enable    Enable (true) or disable (false) GENF
 * @return int32_t  ENET_SOK on success
 */
int32_t ConfigureGenF(Enet_Handle hEnet, uint32_t freqHz, bool enable)
{
    int32_t status;
    uint32_t coreId = EnetSoc_getCoreId();
    Enet_IoctlPrms prms;
    CpswCpts_SetFxnGenInArgs genFArgs;
    uint64_t tsCompVal;
    uint32_t genFLength;

    /* Guard against disable path calling with freqHz=0 */
    if (freqHz == 0U)
    {
        freqHz = 1U;  /* length will be overridden to 0 in the else branch below */
    }

    /* Calculate GENF parameters based on desired frequency */
    /* GENF toggles every 'length' RFTCLK cycles, so length = half-period */
    /* Length = RFTCLK_FREQ / (OUTPUT_FREQ * 2) */
    genFLength = CPTS_RFTCLK_FREQ_HZ / (freqHz * 2U);

    /* Get current CPTS timestamp to set initial compare value */
    uint64_t currentTs = 0;
    ENET_IOCTL_SET_OUT_ARGS(&prms, &currentTs);
    ENET_IOCTL(hEnet, coreId, ENET_TIMESYNC_IOCTL_GET_CURRENT_TIMESTAMP, &prms, status);

    if (status != ENET_SOK)
    {
        printf("Failed to get current timestamp: %d\n", status);
        return status;
    }

    /* Set compare value to current timestamp + 1 second to start in future */
    tsCompVal = currentTs + 1000000000ULL; /* Add 1 second in nanoseconds */

    /* Configure GENF parameters */
    genFArgs.index = GENF_INDEX;
    genFArgs.length = genFLength;
    genFArgs.compare = tsCompVal;
    genFArgs.polarityInv = GENF_POLARITY_HIGH;
    genFArgs.ppmVal  = 0U;
    genFArgs.ppmDir  = CPSW_CPTS_GENF_PPM_ADJDIR_DECREASE;
    genFArgs.ppmMode = ENET_TIMESYNC_ADJMODE_DISABLE;

    if (enable)
    {
        printf("Configuring GENF%d:\n", GENF_INDEX);
        printf("  Output Frequency: %u Hz\n", freqHz);
        printf("  Length: %u RFTCLK cycles\n", genFLength);
        printf("  Compare Value: %llu ns\n", tsCompVal);
        printf("  Polarity: %s\n", genFArgs.polarityInv ? "High" : "Low");

        /* Set GENF configuration */
        ENET_IOCTL_SET_IN_ARGS(&prms, &genFArgs);
        ENET_IOCTL(hEnet, coreId, CPSW_CPTS_IOCTL_SET_GENF, &prms, status);

        if (status != ENET_SOK)
        {
            printf("Failed to configure GENF: %d\n", status);
            return status;
        }

        printf("GENF%d configured and enabled successfully\n", GENF_INDEX);
    }
    else
    {
        /* Disable GENF by setting length to 0 */
        genFArgs.length = 0;
        ENET_IOCTL_SET_IN_ARGS(&prms, &genFArgs);
        ENET_IOCTL(hEnet, coreId, CPSW_CPTS_IOCTL_SET_GENF, &prms, status);

        printf("GENF%d disabled\n", GENF_INDEX);
    }

    return status;
}

/**
 * @brief Configure Timesync Router to route GENF to SYNC0_OUT pin
 *
 * @param inputSrc   Timesync router input source
 * @param outputDest Timesync router output destination
 * @return int32_t   CSL_PASS on success
 */
int32_t ConfigureTimesyncRouter(uint32_t inputSrc, uint32_t outputDest)
{
    int32_t status = CSL_PASS;
    volatile uint32_t *routerReg;

    printf("Configuring Timesync Router:\n");
    printf("  Input Source: %u (CPSW0_GENF0 per TI SCI doc)\n", inputSrc);
    printf("  Output Dest: %u (SYNC0_OUT per AM64x TRM)\n", outputDest);

    /* Configure interrupt router register */
    /* Router register address = BASE + (output * 4) */
    routerReg = (volatile uint32_t *)(TIMESYNC_INTRTR0_BASE + (outputDest * 4));

    /* Write input source to output mapping */
    *routerReg = inputSrc;

    /* Verify configuration */
    if (*routerReg == inputSrc)
    {
        printf("Timesync Router configured successfully\n");
        printf("  GENF0 (input 21) -> SYNC0_OUT (output 24) routing active\n");
    }
    else
    {
        printf("ERROR: Timesync Router configuration failed\n");
        printf("  Expected: 0x%08X, Read: 0x%08X\n", inputSrc, *routerReg);
        status = CSL_EFAIL;
    }

    return status;
}

/**
 * @brief CPTS event notification callback (called from ISR context)
 *
 * Invoked by the CPTS interrupt handler for every event read from the FIFO.
 * For GENF, CPSW_CPTS_EVENTTYPE_TS_COMP fires on each compare match (i.e.
 * each toggle of the GENF output).
 *
 * @param cbArg     Argument passed at registration time
 * @param eventInfo CPTS event details (type, timestamp, port, etc.)
 */
static void App_cptsEventCb(void *cbArg, CpswCpts_Event *eventInfo)
{
    /* This callback runs in interrupt context — no blocking calls, no printf. */
    if (eventInfo->eventType == CPSW_CPTS_EVENTTYPE_TS_COMP)
    {
        /* GENF compare match: output has toggled.
         * eventInfo->tsVal holds the 64-bit CPTS timestamp of the toggle.
         * Signal a task or set a flag here; do not call printf or any
         * blocking/locking API from this context. */
    }
}

/**
 * @brief Register CPTS event callback for GENF ISR notification
 *
 * @param hEnet Enet driver handle
 * @return int32_t ENET_SOK on success
 */
int32_t InitializeCPTS_WithGenF(Enet_Handle hEnet)
{
    int32_t status;
    uint32_t coreId = EnetSoc_getCoreId();
    Enet_IoctlPrms prms;
    CpswCpts_RegisterStackInArgs regStackInArgs;

    regStackInArgs.eventNotifyCb    = App_cptsEventCb;
    regStackInArgs.eventNotifyCbArg = NULL;   /* pass app context here if needed */

    ENET_IOCTL_SET_IN_ARGS(&prms, &regStackInArgs);
    ENET_IOCTL(hEnet, coreId, CPSW_CPTS_IOCTL_REGISTER_STACK, &prms, status);

    if (status != ENET_SOK)
    {
        printf("Failed to register CPTS event callback: %d\n", status);
        return status;
    }

    printf("CPTS event callback registered\n");
    return ENET_SOK;
}

/**
 * @brief Main function to setup GENF and route to SYNC0_OUT
 *
 * @param hEnet Enet driver handle (from gptp_cpsw_app)
 * @return int32_t Status code
 */
int32_t SetupGenFWithSync0Out(Enet_Handle hEnet)
{
    int32_t status;

    printf("\n====== GENF to SYNC0_OUT Configuration (AM64x) ======\n\n");

    /* Step 1: Initialize CPTS */
    status = InitializeCPTS_WithGenF(hEnet);
    if (status != ENET_SOK)
    {
        printf("ERROR: CPTS initialization failed\n");
        return status;
    }

    /* Step 2: Configure GENF output frequency */
    status = ConfigureGenF(hEnet, GENF_OUTPUT_FREQ_HZ, true);
    if (status != ENET_SOK)
    {
        printf("ERROR: GENF configuration failed\n");
        return status;
    }

    /* Step 3: Configure Timesync Router to route GENF to SYNC0_OUT */
    status = ConfigureTimesyncRouter(TIMESYNC_IN_CPSW0_GENF0,
                                     TIMESYNC_OUT_SYNC0_PIN);
    if (status != CSL_PASS)
    {
        printf("ERROR: Timesync Router configuration failed\n");
        return ENET_EFAIL;
    }

    printf("\n====== Configuration Complete ======\n");
    printf("GENF0 signal (%u Hz) is now output on SYNC0_OUT pin\n",
           GENF_OUTPUT_FREQ_HZ);
    printf("Timesync Router: Input 21 (CPSW0_GENF0) -> Output 24 (SYNC0_OUT)\n\n");

    return ENET_SOK;
}

/**
 * @brief Update GENF frequency dynamically
 *
 * @param hEnet  Enet driver handle
 * @param newFreqHz New frequency in Hz
 * @return int32_t Status code
 */
int32_t UpdateGenFFrequency(Enet_Handle hEnet, uint32_t newFreqHz)
{
    printf("Updating GENF frequency to %u Hz\n", newFreqHz);
    return ConfigureGenF(hEnet, newFreqHz, true);
}

/**
 * @brief Disable GENF output
 *
 * @param hEnet Enet driver handle
 * @return int32_t Status code
 */
int32_t DisableGenF(Enet_Handle hEnet)
{
    printf("Disabling GENF output\n");
    return ConfigureGenF(hEnet, 0, false);
}

/* Example integration into gptp_cpsw_app main function */

void gptp_app_main_function(void)
{
    Enet_Handle hEnet;
    int32_t status;

    /* ... existing gptp_cpsw_app initialization code ... */

    /* After ENET is opened and initialized */
    status = SetupGenFWithSync0Out(hEnet);
    if (status != ENET_SOK)
    {
        printf("Failed to setup GENF with SYNC0_OUT\n");
    }

    /* Optional: Update frequency after some time */
    ClockP_sleep(10); /* Sleep 10 seconds */
    UpdateGenFFrequency(hEnet, 100000); /* Change to 100 kHz */

    /* ... rest of application ... */

    /* Before cleanup */
    DisableGenF(hEnet);
}


/*
 * Integration Notes for AM64x gptp_cpsw_app:
 * ===========================================
 *
 * 1. Add this file to your project build system
 *
 * 2. Call SetupGenFWithSync0Out() after ENET is initialized:
 *    - After Enet_open() succeeds
 *    - After CPTS is initialized
 *
 * 3. Pinmux Configuration:
 *    - Ensure SYNC0_OUT pin is configured in SysConfig
 *    - Pin should be muxed to TIMESYNC function
 *    - For AM64x: SYNC0_OUT can be mapped to available GPIO pins
 *
 * 4. Hardware Verification:
 *    - Use oscilloscope to measure signal on SYNC0_OUT pin
 *    - Expected: 40 KHz square wave (default configuration)
 *
 * 5. Frequency Calculation:
 *    - GENF toggles every 'length' RFTCLK cycles (length = half-period)
 *    - GENF Length = RFTCLK_FREQ / (Desired_Freq * 2)
 *    - For 40 KHz: 200,000,000 / (40,000 * 2) = 2500
 *    - For 100 KHz: 200,000,000 / (100,000 * 2) = 1000
 *    - For 1 MHz: 200,000,000 / (1,000,000 * 2) = 100
 *
 * 6. Timesync Router Configuration (AM64x specific):
 *    - Input 21: CPSW0_CPTS_GENF0 (CSLR_TIMESYNC_EVENT_INTROUTER0_IN_CPSW0_CPTS_GENF0_0)
 *      Note: Input 16 is CPTS0 (standalone) GENF0, NOT CPSW0
 *    - Output 24: SYNC0_OUT (per AM64x TRM)
 *    - Register offset: BASE + (24 * 4) = BASE + 0x60
 */
