/**********************************************************************************************************************
*  Copyright (C), 2022-2026, SMARTLOGIC TECHNOLOGY LTD.
*  File Name: ecpri_driver.s.c
*  Create Date: 23/08/18
*  Description: eCPRI Driver Module Source File
*  Change History: 
*      <author>      <time>      <version>   <desc>
*    1. ShangH      23/08/18        1.0       Build this module
**********************************************************************************************************************/


/* -------------------------------------------------- <INC FILE> --------------------------------------------------- */
#include "ecpri_driver.h"


/* --------------------------------------------------- <VAR DEF> --------------------------------------------------- */
/* eCPRI link status */
bool g_ecpri_link_status = false;

/* eCPRI PMA last & current link status */
bool g_ecpri_pma_link_status_last = false;
bool g_ecpri_pma_link_status_curr = false;

uint32_t g_ecpri_pma_link_cnt1 = 0;
uint32_t g_ecpri_pma_link_cnt2 = 0;


/* -------------------------------------------------- <FUNC DEF> --------------------------------------------------- */
/**********************************************************************************************************************
*  Function: ecpri_init
*  Description: eCPRI init
*  Input: 
*    <name>                    <type>                      <desc>
*     ecpri_option              uint32_t                    eCPRI option
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_init(uint32_t ecpri_option)
{
#ifdef PALLADIUM_TEST
    uint32_t flag = 1;
    debug_write(ECPRI_DBG_IDX1(0), flag); /* ECS_RFM1: 0xB7E31000(0) */
#endif

    /* input para check */
    if ((ECPRI_OPTION_10G != ecpri_option) && (ECPRI_OPTION_25G != ecpri_option))
    {
        return;
    }

    phy_para_init(PROTOCOL_ECPRI, ecpri_option);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(0), flag); /* ECS_RFM1: 0xB7E31000(0) */
#endif

    ecpri_ip_init(ecpri_option);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(0), flag); /* ECS_RFM1: 0xB7E31000(0) */
#endif

    cpri_ecprimode_init();
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(0), flag); /* ECS_RFM1: 0xB7E31000(0) */
#endif

    ecpri_mtimer_init(LTE_SCS_ID, 10);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(0), flag); /* ECS_RFM1: 0xB7E31000(0) */
#endif
}

/**********************************************************************************************************************
*  Function: ecpri_cprimode_init
*  Description: CPRI mode of eCPRI init
*  Input: none
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_cprimode_init(void)
{
    // 扩皮模式下，ecpri timer使用cpri_div33_tx_clk，与cpri core clk同源
    ecpri_timer_cprimode_clk_init();

    ecpri_mtimer_init(LTE_SCS_ID, 10);
}

/**********************************************************************************************************************
*  Function: ecpri_clk_init
*  Description: eCPRI clock init
*  Input: 
*    <name>                    <type>                      <desc>
*     ecpri_option              uint32_t                    eCPRI option
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_clk_init(uint32_t ecpri_option)
{
    switch (ecpri_option)
    {
        case (ECPRI_OPTION_10G):
            do_write(&JECS_CRG_PLLSEL, do_read_volatile(&JECS_CRG_PLLSEL) | (BIT31 + BIT19 + BIT18 + BIT17 + BIT16 + BIT11 + BIT5));
            do_write(&JECS_CRG_CLK_CTRL6, 0x521000); //SYSAPB /2  apb_aclk_i
            //switch_core_clk_i,
            //switch_sch_clk_i,
            do_write(&JECS_CRG_CLK_CTRL7, 0x520000); //jecs_pma_tx0_ropll_div33_clk
            //ecpri_switch_mae_core_clk
            do_write(&JECS_CRG_CLK_CTRL8, 0x520000); //jecs_pma_tx0_ropll_div33_clk
            //ecpri_pcs_xgmii_tx_clk
            do_write(&JECS_CRG_CLK_CTRL9, 0x521000); //jecs_pma_tx0_ropll_div33_clk
            //ecpri_pcs_xgmii_rx_clk
            do_write(&JECS_CRG_CLK_CTRL0, 0x521000); //jecs_pma_rx0_div33_clk
            do_write(&JECS_CRG_CLK_CTRL1, 0x520000);
            do_write(&JECS_CRG_CLK_CTRL10, 0x520000);
            break;

        case (ECPRI_OPTION_25G):
            do_write(&JECS_CRG_PLLSEL, do_read_volatile(&JECS_CRG_PLLSEL) | (BIT19 + BIT18 + BIT17 + BIT16 + BIT11 + BIT5));
            do_write(&JECS_CRG_CLK_CTRL6, 0x521000); //SYSAPB /2  apb_aclk_i
            //switch_core_clk_i,
            //switch_sch_clk_i,
            do_write(&JECS_CRG_CLK_CTRL7, 0x521000); //jecs_pma_tx0_ropll_div33_clk
            //ecpri_switch_mae_core_clk
            do_write(&JECS_CRG_CLK_CTRL8, 0x521000); //jecs_pma_tx0_ropll_div33_clk
            //ecpri_pcs_xgmii_tx_clk
            do_write(&JECS_CRG_CLK_CTRL9, 0x521000); //jecs_pma_tx0_ropll_div33_clk
            //ecpri_pcs_xgmii_rx_clk
            do_write(&JECS_CRG_CLK_CTRL0, 0x521000); //jecs_pma_rx0_div33_clk
            do_write(&JECS_CRG_CLK_CTRL1, 0x520000);
            do_write(&JECS_CRG_CLK_CTRL10, 0x520000);
            break;

        default:
            break;
    }
}

/**********************************************************************************************************************
*  Function: ecpri_ip_init
*  Description: eCPRI IP init
*  Input: 
*    <name>                    <type>                      <desc>
*     ecpri_option              uint32_t                    eCPRI option
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_ip_init(uint32_t ecpri_option)
{
#ifdef PALLADIUM_TEST
    uint32_t flag = 1;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    ecpri_clk_init(ecpri_option);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    ecpri_pma_rst();
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    ecpri_pma_init(ecpri_option);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    ecpri_pma_rxtx_init(ecpri_option);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    ecpri_pcs_rst();
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    ecpri_roec_init();
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    ecpri_pcs_init(ecpri_option);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    ecpri_mac_init();
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    ecpri_switch_init();
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    ecpri_pma_rx_adapt();
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif

    do_write(SERDES_INIT_FLAG_ADDR, 1);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(1), flag); /* ECS_RFM1: 0xB7E31004(1) */
#endif
}

/**********************************************************************************************************************
*  Function: ecpri_ip_recfg
*  Description: eCPRI IP reconfig
*  Input: none
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_ip_recfg(void)
{
#ifdef PALLADIUM_TEST
    uint32_t flag = 1;
    debug_write(ECPRI_DBG_IDX1(2), flag); /* ECS_RFM1: 0xB7E31008(2) */
#endif

    /* eCPRI PCS config loopback mode */
    ecpri_pcs_cfg(true);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(2), flag); /* ECS_RFM1: 0xB7E31008(2) */
#endif

    /* eCPRI MAC config discard mode */
    ecpri_mac_cfg(true);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(2), flag); /* ECS_RFM1: 0xB7E31008(2) */
#endif

    ecpri_pma_rx_adapt();
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(2), flag); /* ECS_RFM1: 0xB7E31008(2) */
#endif

    /* eCPRI MAC config receive mode */
    ecpri_mac_cfg(false);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(2), flag); /* ECS_RFM1: 0xB7E31008(2) */
#endif

    /* eCPRI PCS config normal mode */
    ecpri_pcs_cfg(false);
#ifdef PALLADIUM_TEST
    flag++;
    debug_write(ECPRI_DBG_IDX1(2), flag); /* ECS_RFM1: 0xB7E31008(2) */
#endif
}

/**********************************************************************************************************************
*  Function: ecpri_ant_cfg
*  Description: eCPRI antenna config
*  Input: 
*    <name>                    <type>                      <desc>
*     ant_id                    uint8_t                     antenna index
*     slot_type                 uint8_t                     slot type
*     sym_id                    uint8_t                     symbol index
*     pkt_addr                  uint32_t                    packet address
*     pkt_len                   uint16_t                    packet length
*  Output: none
*  Return: operation result - success or failure.
*  Others: none
**********************************************************************************************************************/
int32_t ecpri_ant_cfg(uint8_t ant_id, uint8_t slot_type, uint8_t sym_id, uint32_t pkt_addr, uint16_t pkt_len)
{
    /* antenna number */
    uint8_t ant_num = ECPRI_10G_ANT_NUM;
    /* config index */
    uint32_t cfg_id = 0;

    /* update antenna number */
    if (ECPRI_OPTION_25G == get_protocol_opt())
    {
        ant_num = ECPRI_25G_ANT_NUM;
    }

    /* input para check */
    if ((ant_num <= ant_id) || (ECPRI_SLOT_TYPE <= slot_type) || (ECPRI_SYM_NUM <= sym_id))
    {
        debug_write(ECPRI_DBG_IDX1(20), (uint32_t)ERROR); /* ECS_RFM1: 0xB7E31050(20) */
        debug_write(ECPRI_DBG_IDX1(24), ant_num); /* ECS_RFM1: 0xB7E31060(24) */
        debug_write(ECPRI_DBG_IDX1(25), ant_id); /* ECS_RFM1: 0xB7E31064(25) */
        debug_write(ECPRI_DBG_IDX1(26), slot_type); /* ECS_RFM1: 0xB7E31068(26) */
        debug_write(ECPRI_DBG_IDX1(27), sym_id); /* ECS_RFM1: 0xB7E3106C(27) */

        return ERROR;
    }

    /* input para check */
    if ((0 == pkt_addr) || (0 == pkt_len))
    {
        debug_write(ECPRI_DBG_IDX1(20), (uint32_t)ERROR); /* ECS_RFM1: 0xB7E31050(20) */
        debug_write(ECPRI_DBG_IDX1(28), pkt_addr); /* ECS_RFM1: 0xB7E31070(28) */
        debug_write(ECPRI_DBG_IDX1(29), pkt_len); /* ECS_RFM1: 0xB7E31074(29) */

        return ERROR;
    }

    /* config index */
    cfg_id = ant_id * ECPRI_SLOT_TYPE * ECPRI_SYM_NUM + slot_type * ECPRI_SYM_NUM + sym_id;

    /* config packet address */
    do_write((void *)(ECPRI_ANT_BUF_ADDR + cfg_id * ECPRI_SYM_INFO_LEN), pkt_addr);

    /* config packet length */
    do_write((void *)(ECPRI_ANT_BUF_ADDR + cfg_id * ECPRI_SYM_INFO_LEN + sizeof(uint32_t)), pkt_len);

    debug_write(ECPRI_DBG_IDX1(20), (uint32_t)SUCCESS); /* ECS_RFM1: 0xB7E31050(20) */
    debug_write(ECPRI_DBG_IDX1(24), ant_num); /* ECS_RFM1: 0xB7E31060(24) */
    debug_write(ECPRI_DBG_IDX1(25), ant_id); /* ECS_RFM1: 0xB7E31064(25) */
    debug_write(ECPRI_DBG_IDX1(26), slot_type); /* ECS_RFM1: 0xB7E31068(26) */
    debug_write(ECPRI_DBG_IDX1(27), sym_id); /* ECS_RFM1: 0xB7E3106C(27) */
    debug_write(ECPRI_DBG_IDX1(28), pkt_addr); /* ECS_RFM1: 0xB7E31070(28) */
    debug_write(ECPRI_DBG_IDX1(29), pkt_len); /* ECS_RFM1: 0xB7E31074(29) */

    return SUCCESS;
}

/**********************************************************************************************************************
*  Function: ecpri_link_status_get
*  Description: eCPRI link status get
*  Input: none
*  Output: none
*  Return: link status - true: link up; false: link down.
*  Others: none
**********************************************************************************************************************/
bool ecpri_link_status_get(void)
{
    return g_ecpri_link_status;
}

/**********************************************************************************************************************
*  Function: ecpri_link_status_check
*  Description: eCPRI link status check
*  Input: none
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_link_status_check(void)
{
    /* get current eCPRI PMA link status */
    g_ecpri_pma_link_status_curr = ecpri_pma_link_status_get();

    if ((!g_ecpri_pma_link_status_last) && g_ecpri_pma_link_status_curr)
    {
        ecpri_ip_recfg();

        g_ecpri_link_status = ecpri_pcs_link_status_get();

        g_ecpri_pma_link_cnt1++;
        debug_write(ECPRI_DBG_IDX1(32), g_ecpri_pma_link_cnt1); /* ECS_RFM1: 0xB7E31080(32) */
    }
    else if (g_ecpri_pma_link_status_last && g_ecpri_pma_link_status_curr)
    {
        g_ecpri_link_status = ecpri_pcs_link_status_get();
        if (!g_ecpri_link_status)
        {
            ecpri_ip_recfg();

            g_ecpri_link_status = ecpri_pcs_link_status_get();

            g_ecpri_pma_link_cnt2++;
            debug_write(ECPRI_DBG_IDX1(33), g_ecpri_pma_link_cnt2); /* ECS_RFM1: 0xB7E31084(33) */
        }
    }
    else
    {
        g_ecpri_link_status = false;
    }

    /* update last eCPRI PMA link status */
    g_ecpri_pma_link_status_last = g_ecpri_pma_link_status_curr;
}



