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


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


/* --------------------------------------------------- <VAR DEF> --------------------------------------------------- */


/* -------------------------------------------------- <FUNC DEF> --------------------------------------------------- */
/**********************************************************************************************************************
*  Function: ecpri_pcs_rst
*  Description: eCPRI PCS reset
*  Input: none
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_pcs_rst(void)
{
    /* cancel eCPRI's reset */
    do_write(&JECS_CRG_MANTICORE0_RST_CTRL, do_read_volatile(&JECS_CRG_MANTICORE0_RST_CTRL) | BIT24);
    do_write(&JECS_CRG_MANTICORE1_RST_CTRL, do_read_volatile(&JECS_CRG_MANTICORE1_RST_CTRL) | BIT24);
    do_write(&JECS_CRG_MANTICORE2_RST_CTRL, do_read_volatile(&JECS_CRG_MANTICORE2_RST_CTRL) | BIT24);
    do_write(&JECS_CRG_MANTICORE3_RST_CTRL, do_read_volatile(&JECS_CRG_MANTICORE3_RST_CTRL) | BIT24);
    do_write(&JECS_CRG_MANTICORE4_RST_CTRL, do_read_volatile(&JECS_CRG_MANTICORE4_RST_CTRL) | BIT24);
    do_write(&JECS_CRG_MANTICORE5_RST_CTRL, do_read_volatile(&JECS_CRG_MANTICORE5_RST_CTRL) | BIT24);
    do_write(&JECS_CRG_MANTICORE6_RST_CTRL, do_read_volatile(&JECS_CRG_MANTICORE6_RST_CTRL) | BIT24);
    do_write(&JECS_CRG_MANTICORE7_RST_CTRL, do_read_volatile(&JECS_CRG_MANTICORE7_RST_CTRL) | BIT24);
    do_write(&JECS_CRG_MANTICORE8_RST_CTRL, do_read_volatile(&JECS_CRG_MANTICORE8_RST_CTRL) | BIT24);
    do_write(&ECPRI_RST_CFG_REG, do_read_volatile(&ECPRI_RST_CFG_REG) | BIT24);
}

/**********************************************************************************************************************
*  Function: ecpri_pcs_init
*  Description: eCPRI PCS init
*  Input: 
*    <name>                    <type>                      <desc>
*     skb                       sk_buff *                   socket buffer
*     dev                       net_device *                network device
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_pcs_init(uint32_t ecpri_option)
{
    switch (ecpri_option)
    {
        case ECPRI_OPTION_10G:
            do_write(&MC_PCS_CONTROL_1, BIT13 + BIT6 + (0 << 2)); //0 0 0 0 = 10Gbps
            do_write(&MC_PCS_CONTROL_2, 0); //0 0 0 0 = select 10GBASE-R PCS type
            do_write(&MC_CFG_TX, BIT3 + BIT1); //rx_elastic_buffer_initial_fill 5

            /* solve start packet impact, config loopback mode */
            do_write(&MC_CFG_RX, BIT11 + BIT3 + BIT1); //rx_elastic_buffer_initial_fill 5 + SerDes Loopback

            do_write(&MC_GENERAL_TX, (32 << 7) + BIT3 + BIT0); //64b_xgmii_tx 32 SERDES WIDTH +RESET
            do_write(&MC_GENERAL_RX, (32 << 7) + BIT3 + BIT0); //64b_xgmii_tx 32 SERDES WIDTH +RESET

            do_write(&MC_GENERAL_TX, (32 << 7) + BIT3); //64b_xgmii_tx 32 SERDES WIDTH
            do_write(&MC_GENERAL_RX, (32 << 7) + BIT3); //64b_xgmii_tx 32 SERDES WIDTH
            break;

        case ECPRI_OPTION_25G:
            do_write(&MC_PCS_CONTROL_1, BIT13 + BIT6 + (5 << 2)); //0 1 0 1 = 25Gbps
            do_write(&MC_PCS_CONTROL_2, 0); //0 0 0 0 = select 10GBASE-R PCS type
            do_write(&MC_CFG_TX, BIT3 + BIT1); //rx_elastic_buffer_initial_fill 5

            /* solve start packet impact, config loopback mode */
            do_write(&MC_CFG_RX, BIT11 + BIT3 + BIT1); //rx_elastic_buffer_initial_fill 5 + SerDes Loopback

            do_write(&MC_GENERAL_TX, (32 << 7) + BIT3 + BIT0); //64b_xgmii_tx 32 SERDES WIDTH +RESET
            do_write(&MC_GENERAL_RX, (32 << 7) + BIT3 + BIT0); //64b_xgmii_tx 32 SERDES WIDTH +RESET

            do_write(&MC_GENERAL_TX, (32 << 7) + BIT3); //64b_xgmii_tx 32 SERDES WIDTH
            do_write(&MC_GENERAL_RX, (32 << 7) + BIT3); //64b_xgmii_tx 32 SERDES WIDTH
            break;

        default:
            break;
    }
}

/**********************************************************************************************************************
*  Function: ecpri_pcs_cfg
*  Description: eCPRI PCS config
*  Input: 
*    <name>                    <type>                      <desc>
*     lb_en                     bool                        loopback enable flag
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_pcs_cfg(bool lb_en)
{
    if (lb_en)
    {
        /* solve start packet impact, config loopback mode */
        do_write(&MC_CFG_RX, BIT11 + BIT3 + BIT1); //rx_elastic_buffer_initial_fill 5 + SerDes Loopback
    }
    else
    {
        /* solve start packet impact, recover normal mode */
        do_write(&MC_CFG_RX, BIT3 + BIT1); //rx_elastic_buffer_initial_fill 5
    }

    __ucps2_synch(0);
}

/**********************************************************************************************************************
*  Function: ecpri_mac_init
*  Description: eCPRI MAC init
*  Input: none
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_mac_init(void)
{
    /* discard error/invalid packet */
    do_write(&MC_MAC_CONTROL, (do_read_volatile(&MC_MAC_CONTROL) | BIT6));

    /* max jumbo frame size */
    do_write(&MC_MAXIMUM_FRAME_SIZE, 65535);
}

/**********************************************************************************************************************
*  Function: ecpri_mac_cfg
*  Description: eCPRI MAC config
*  Input: 
*    <name>                    <type>                      <desc>
*     discard_en                bool                        discard packet enable flag
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_mac_cfg(bool discard_en)
{
    if (discard_en)
    {
        /* discard unicast/multicast packet */
        do_write(&MC_MAC_CONTROL, (do_read_volatile(&MC_MAC_CONTROL) & (~(BIT5 + BIT4))));
    }
    else
    {
        /* receive unicast/multicast packet */
        do_write(&MC_MAC_CONTROL, (do_read_volatile(&MC_MAC_CONTROL) | (BIT5 + BIT4)));
    }

    __ucps2_synch(0);
}

/**********************************************************************************************************************
*  Function: ecpri_switch_init
*  Description: eCPRI SWITCH init
*  Input: none
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_switch_init(void)
{
    do_write(&MC_SWITCH_PORT0_CFG_VLAN, do_read_volatile(&MC_SWITCH_PORT0_CFG_VLAN) & (~(BIT12 | BIT13 | BIT14)));
    do_write(&MC_SWITCH_PORT1_CFG_VLAN, do_read_volatile(&MC_SWITCH_PORT1_CFG_VLAN) & (~(BIT12 | BIT13 | BIT14)));
    do_write(&MC_SWITCH_PORT2_CFG_VLAN, do_read_volatile(&MC_SWITCH_PORT2_CFG_VLAN) & (~(BIT12 | BIT13 | BIT14)));

    //do_write(&MC_SWITCH_PORT0_PORT_MAC_2, 0x000A);
    //do_write(&MC_SWITCH_PORT1_PORT_MAC_2, 0x000A);
    //do_write(&MC_SWITCH_PORT2_PORT_MAC_2, 0x000A);

    //do_write(&MC_SWITCH_PORT0_PORT_MAC_1, 0x09080706);
    //do_write(&MC_SWITCH_PORT1_PORT_MAC_1, 0x09080716);
    //do_write(&MC_SWITCH_PORT2_PORT_MAC_1, 0x09080726);

    /* enable vid 2 port 0~2 */
    while ((do_read_volatile(&MC_SWITCH_OP_CTRL) & 0xF) != 0);
    do_write(&MC_SWITCH_PORT_MASK_1, 0xffffffff);
    do_write(&MC_SWITCH_PORT_MASK_2, 0xffffffff);
    do_write(&MC_SWITCH_VLAN_ID, 0x10);
    do_write(&MC_SWITCH_OP_CTRL, 0x110);

#if 0
    /* config insert MAC for RX direction */
    while ((do_read_volatile(&MC_SWITCH_OP_CTRL) & 0xF) != 0);
    do_write(&MC_SWITCH_PORT_MASK_1, 0x4);
    do_write(&MC_SWITCH_PORT_MASK_2, 0x0);
    do_write(&MC_SWITCH_FDB_MAC_INSERT_1, 0x000A0908);
    //do_write(&MC_SWITCH_FDB_MAC_INSERT_2, ((0x0726 << 16) + 0xF));
    do_write(&MC_SWITCH_FDB_MAC_INSERT_2, ((0x0726 << 16) + 0x1));
    do_write(&MC_SWITCH_OP_CTRL, 0x100);

    /* config insert MAC for RX direction */
    while ((do_read_volatile(&MC_SWITCH_OP_CTRL) & 0xF) != 0);
    do_write(&MC_SWITCH_PORT_MASK_1, 0x2);
    do_write(&MC_SWITCH_PORT_MASK_2, 0x0);
    /* unicast */
    do_write(&MC_SWITCH_FDB_MAC_INSERT_1, 0x000A0908);
    //do_write(&MC_SWITCH_FDB_MAC_INSERT_2, ((0x0716 << 16) + 0xF));
    do_write(&MC_SWITCH_FDB_MAC_INSERT_2, ((0x0716 << 16) + 0x1));
    do_write(&MC_SWITCH_OP_CTRL, 0x100);

    /* config insert MAC for RX direction */
    while ((do_read_volatile(&MC_SWITCH_OP_CTRL) & 0xF) != 0);
    do_write(&MC_SWITCH_PORT_MASK_1, 0x2);
    do_write(&MC_SWITCH_PORT_MASK_2, 0x0);
    /* multicast */
    do_write(&MC_SWITCH_FDB_MAC_INSERT_1, 0x011B1900);
    //do_write(&MC_SWITCH_FDB_MAC_INSERT_2, ((0x0000 << 16) + 0xF));
    do_write(&MC_SWITCH_FDB_MAC_INSERT_2, ((0x0000 << 16) + 0x1));
    do_write(&MC_SWITCH_OP_CTRL, 0x100);

    /* config insert MAC for RX direction */
    //while ((do_read_volatile(&MC_SWITCH_OP_CTRL) & 0xF) != 0);
    //do_write(&MC_SWITCH_PORT_MASK_1, 0x1);
    //do_write(&MC_SWITCH_PORT_MASK_2, 0x0);
    //do_write(&MC_SWITCH_FDB_MAC_INSERT_1, 0x000A0908);
    //do_write(&MC_SWITCH_FDB_MAC_INSERT_2, ((0x0706 << 16) + 0xF));
    //do_write(&MC_SWITCH_FDB_MAC_INSERT_2, ((0x0706 << 16) + 0x1));
    //do_write(&MC_SWITCH_OP_CTRL, 0x100);
#else
    /* config TRAP for RX direction(PORT0->PORT1) */
    do_write(&MC_SWITCH_PORT0_CFG_TRAP, 0x00000101);
#endif

    do_write(&MC_SWITCH_CFG_MAE, 0xFFFF0002);

    do_write(&MC_SWITCH_FLOOD_MASK_1, 0xFFFFFFF8);

    /* config TRAP for TX direction(PORT1->PORT0) */
    do_write(&MC_SWITCH_PORT1_CFG_TRAP, 0x00000001);
}

/**********************************************************************************************************************
*  Function: ecpri_pcs_link_status_get
*  Description: eCPRI PCS link status get
*  Input: none
*  Output: none
*  Return: link status - true: link up; false: link down.
*  Others: none
**********************************************************************************************************************/
bool ecpri_pcs_link_status_get(void)
{
    bool link_status = false;

    /* check PCS receive link status is link up or not */
    if (0 != (do_read_volatile(&MC_PCS_STATUS_1) & BIT2))
    {
        link_status = true;
    }

    return link_status;
}

/**********************************************************************************************************************
*  Function: ecpri_mac_stats_start
*  Description: eCPRI MAC statistic start
*  Input: none
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_mac_stats_start(void)
{
    /* start MAC statistic */
    do_write(&MC_STATISTIC_CONFIGURATION, do_read_volatile(&MC_STATISTIC_CONFIGURATION) & (~BIT4));
}

/**********************************************************************************************************************
*  Function: ecpri_mac_stats_stop
*  Description: eCPRI MAC statistic stop
*  Input: none
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_mac_stats_stop(void)
{
    /* stop MAC statistic */
    do_write(&MC_STATISTIC_CONFIGURATION, do_read_volatile(&MC_STATISTIC_CONFIGURATION) | BIT4);
}

/**********************************************************************************************************************
*  Function: ecpri_mac_stats_clear
*  Description: eCPRI MAC statistic clear
*  Input: none
*  Output: none
*  Return: none
*  Others: none
**********************************************************************************************************************/
void ecpri_mac_stats_clear(void)
{
    /* clear MAC statistic */
    do_write(&MC_STATISTIC_CONFIGURATION, do_read_volatile(&MC_STATISTIC_CONFIGURATION) | BIT0);
}

/**********************************************************************************************************************
*  Function: ecpri_mac_stats_get
*  Description: eCPRI MAC statistic get
*  Input: none
*  Output: 
*    <name>                    <type>                      <desc>
*     ecpri_mac_stats_ptr       EcpriMacStats_t *           eCPRI MAC statistic pointer
*  Return: operation result - success or failure.
*  Others: none
**********************************************************************************************************************/
int32_t ecpri_mac_stats_get(EcpriMacStats_t *ecpri_mac_stats_ptr)
{
    /* input para check */
    if (NULL == ecpri_mac_stats_ptr)
    {
        debug_write(ECPRI_DBG_IDX1(36), ERROR); /* ECS_RFM1: 0xB7E31090(36) */
        return ERROR;
    }

    /* get receive packets of different length and total bytes */
    memcpy_ucp((void *)&ecpri_mac_stats_ptr->rx_pkts_64b, 
               (void *)&MC_STAT_TOT_RX_64B_PKTS, 
               ECPRI_MAC_STATS_CONSEC_REG_NUM1 * sizeof(uint32_t));

    /* get receive packets of CRC error */
    ecpri_mac_stats_ptr->rx_pkts_crc_err = do_read_volatile(&MC_STAT_RX_BAD_CRC_PKTS);

    /* get receive packets of unicast/multicast/broadcast */
    memcpy_ucp((void *)&ecpri_mac_stats_ptr->rx_pkts_uc, 
               (void *)&MC_STAT_TOT_RX_UC_PKTS, 
               ECPRI_MAC_STATS_CONSEC_REG_NUM2 * sizeof(uint32_t));

    /* get receive packets of discard/overflow */
    memcpy_ucp((void *)&ecpri_mac_stats_ptr->rx_pkts_discard, 
               (void *)&MC_STAT_TOT_RX_DISCARD_PKTS, 
               ECPRI_MAC_STATS_CONSEC_REG_NUM3 * sizeof(uint32_t));

    /* get send packets of different length and total bytes */
    memcpy_ucp((void *)&ecpri_mac_stats_ptr->tx_pkts_64b, 
               (void *)&MC_STAT_TOT_TX_64B_PKTS_1, 
               ECPRI_MAC_STATS_CONSEC_REG_NUM1 * sizeof(uint32_t));

    return SUCCESS;
}

/**********************************************************************************************************************
*  Function: ecpri_switch_stats_get
*  Description: eCPRI SWITCH statistic get
*  Input: none
*  Output: 
*    <name>                    <type>                      <desc>
*     port                      uint8_t                     port ID
*     ecpri_switch_stats_ptr    EcpriSwitchStats_t *        eCPRI SWITCH statistic pointer
*  Return: operation result - success or failure.
*  Others: none
**********************************************************************************************************************/
int32_t ecpri_switch_stats_get(uint8_t port, EcpriSwitchStats_t *ecpri_switch_stats_ptr)
{
    uint32_t *rx_pkts_fltr_ptr      = (uint32_t *)(&MC_SWITCH_PORT0_STAT_PKT_FLTR_RX);
    uint32_t *rx_pkts_voq_nq_ptr    = (uint32_t *)(&MC_SWITCH_PORT0_STAT_PKT_VOQ_NQ);
    uint32_t *tx_pkts_voq_dq_ptr    = (uint32_t *)(&MC_SWITCH_PORT0_STAT_PKT_VOQ_DQ);
    uint32_t *rx_pkts_voq_drop_ptr  = (uint32_t *)(&MC_SWITCH_PORT0_STAT_PKT_VOQ_DROP);
    uint32_t *rx_bytes_voq_nq_ptr   = (uint32_t *)(&MC_SWITCH_PORT0_STAT_BYTES_VOQ_NQ);
    uint32_t *tx_bytes_voq_dq_ptr   = (uint32_t *)(&MC_SWITCH_PORT0_STAT_BYTES_VOQ_DQ);
    uint32_t *rx_bytes_voq_drop_ptr = (uint32_t *)(&MC_SWITCH_PORT0_STAT_BYTES_VOQ_DROP);
    uint32_t *rx_pkts_uc_ptr        = (uint32_t *)(&MC_SWITCH_PORT0_STAT_UCAST_PKT_RX);
    uint32_t *rx_pkts_buf_ovfl_ptr  = (uint32_t *)(&MC_SWITCH_PORT0_STAT_PKT_BUF_OVFL);

    /* input para check */
    if ((ECPRI_SWITCH_PORT_NUM <= port) || (NULL == ecpri_switch_stats_ptr))
    {
        debug_write(ECPRI_DBG_IDX1(37), ERROR); /* ECS_RFM1: 0xB7E31094(37) */
        return ERROR;
    }

    switch (port)
    {
        case ECPRI_SWITCH_PORT1:
            rx_pkts_fltr_ptr      = (uint32_t *)(&MC_SWITCH_PORT1_STAT_PKT_FLTR_RX);
            rx_pkts_voq_nq_ptr    = (uint32_t *)(&MC_SWITCH_PORT1_STAT_PKT_VOQ_NQ);
            tx_pkts_voq_dq_ptr    = (uint32_t *)(&MC_SWITCH_PORT1_STAT_PKT_VOQ_DQ);
            rx_pkts_voq_drop_ptr  = (uint32_t *)(&MC_SWITCH_PORT1_STAT_PKT_VOQ_DROP);
            rx_bytes_voq_nq_ptr   = (uint32_t *)(&MC_SWITCH_PORT1_STAT_BYTES_VOQ_NQ);
            tx_bytes_voq_dq_ptr   = (uint32_t *)(&MC_SWITCH_PORT1_STAT_BYTES_VOQ_DQ);
            rx_bytes_voq_drop_ptr = (uint32_t *)(&MC_SWITCH_PORT1_STAT_BYTES_VOQ_DROP);
            rx_pkts_uc_ptr        = (uint32_t *)(&MC_SWITCH_PORT1_STAT_UCAST_PKT_RX);
            rx_pkts_buf_ovfl_ptr  = (uint32_t *)(&MC_SWITCH_PORT1_STAT_PKT_BUF_OVFL);
            break;

        case ECPRI_SWITCH_PORT2:
            rx_pkts_fltr_ptr      = (uint32_t *)(&MC_SWITCH_PORT2_STAT_PKT_FLTR_RX);
            rx_pkts_voq_nq_ptr    = (uint32_t *)(&MC_SWITCH_PORT2_STAT_PKT_VOQ_NQ);
            tx_pkts_voq_dq_ptr    = (uint32_t *)(&MC_SWITCH_PORT2_STAT_PKT_VOQ_DQ);
            rx_pkts_voq_drop_ptr  = (uint32_t *)(&MC_SWITCH_PORT2_STAT_PKT_VOQ_DROP);
            rx_bytes_voq_nq_ptr   = (uint32_t *)(&MC_SWITCH_PORT2_STAT_BYTES_VOQ_NQ);
            tx_bytes_voq_dq_ptr   = (uint32_t *)(&MC_SWITCH_PORT2_STAT_BYTES_VOQ_DQ);
            rx_bytes_voq_drop_ptr = (uint32_t *)(&MC_SWITCH_PORT2_STAT_BYTES_VOQ_DROP);
            rx_pkts_uc_ptr        = (uint32_t *)(&MC_SWITCH_PORT2_STAT_UCAST_PKT_RX);
            rx_pkts_buf_ovfl_ptr  = (uint32_t *)(&MC_SWITCH_PORT2_STAT_PKT_BUF_OVFL);
            break;

        default:
            break;
    }

    /* get TRX packets/bytes of filtered */
    memcpy_ucp((void *)&ecpri_switch_stats_ptr->rx_pkts_fltr, 
               (void *)rx_pkts_fltr_ptr, 
               ECPRI_SWITCH_STATS_CONSEC_REG_NUM1 * sizeof(uint32_t));

    /* get TRX packets/bytes of enqueued/dequeued/dropped */
    ecpri_switch_stats_ptr->rx_pkts_voq_nq = do_read_volatile(rx_pkts_voq_nq_ptr);
    ecpri_switch_stats_ptr->tx_pkts_voq_dq = do_read_volatile(tx_pkts_voq_dq_ptr);
    ecpri_switch_stats_ptr->rx_pkts_voq_drop = do_read_volatile(rx_pkts_voq_drop_ptr);
    ecpri_switch_stats_ptr->rx_bytes_voq_nq = do_read_volatile(rx_bytes_voq_nq_ptr);
    ecpri_switch_stats_ptr->tx_bytes_voq_dq = do_read_volatile(tx_bytes_voq_dq_ptr);
    ecpri_switch_stats_ptr->rx_bytes_voq_drop = do_read_volatile(rx_bytes_voq_drop_ptr);

    /* get TRX packets/bytes of unicast/multicast/broadcast */
    memcpy_ucp((void *)&ecpri_switch_stats_ptr->rx_pkts_uc, 
               (void *)rx_pkts_uc_ptr, 
               ECPRI_SWITCH_STATS_CONSEC_REG_NUM2 * sizeof(uint32_t));

    /* get receive packets/bytes of buffer-overflow/error dropped */
    memcpy_ucp((void *)&ecpri_switch_stats_ptr->rx_pkts_buf_ovfl, 
               (void *)rx_pkts_buf_ovfl_ptr, 
               ECPRI_SWITCH_STATS_CONSEC_REG_NUM3 * sizeof(uint32_t));

    return SUCCESS;
}



