/*
 *  Copyright 2019-2022 NXP
 *
 *  NXP Confidential. This software is owned or controlled by NXP and may only
 *  be used strictly in accordance with the applicable license terms. By
 *  expressly accepting such terms or by downloading, installing, activating
 *  and/or otherwise using the software, you are agreeing that you have read,
 *  and that you agree to comply with and are bound by, such license terms. If
 *  you do not agree to be bound by the applicable license terms, then you may
 *  not retain, install, activate or otherwise use the software.
 *
 *  This file contains sample code only. It is not part of the production code deliverables.
 *
 */
/**
* @brief    Hardware configuration for detached minihif driver.
* @details  Function configure_minihif_hw configures a HIF interface, an EMAC, and logical interfaces
*           to be used from DETACHED minihif driver running in another application.
*
*           This code is expected to run in the application containing also PFE MCAL driver. It calls
*           some PFE specific API from the MCAL driver. It also needs includes from MCAL driver,
*           including the pfe_cfg.h and pfe_platform_cfg.h.
*
*   @addtogroup EXAMPLE_APP
*   @{
*/

/* Minihif API */
#include "pfe_minihif_drv.h"
#include "pfe_platform.h"

/* Option to enable/disable errata ERR051211 workaround (default is enabled) */
#define PFE_HIF_ERRATA_ERR051211_WORKAROUND_ENABLED TRUE

/* Keep in sync with detached MINIHIF application */
#define MINI_RX_RING_VA     ((void *)(0x34110000U))
#define MINI_TX_RING_VA     ((void *)(0x34111000U))
#define MINI_RX_WB_RING_VA  ((void *)(0x34112000U))
#define MINI_TX_WB_RING_VA  ((void *)(0x34112800U))

#if (TRUE == PFE_HIF_ERRATA_ERR051211_WORKAROUND_ENABLED)
/* Due to HW issue, we will reserve more 72 BDs for Rx ring for errata ERR051211 workaround */
#define MINI_RX_BD_LENGTH   (32U + 72U)
#else
#define MINI_RX_BD_LENGTH   (32U)
#endif  /* PFE_HIF_ERRATA_ERR051211_WORKAROUND_ENABLED */

#define MINI_TX_BD_LENGTH   16U

#define ETH_43_PFE_START_SEC_VAR_CLEARED_UNSPECIFIED
#include "Eth_43_PFE_MemMap.h"

static pfe_minihif_drv_t minihif = {0U};

#define ETH_43_PFE_STOP_SEC_VAR_CLEARED_UNSPECIFIED
#include "Eth_43_PFE_MemMap.h"

#define ETH_43_PFE_START_SEC_CONST_8
#include "Eth_43_PFE_MemMap.h"

/* usage scope: configure_emacs */
static const char_t log_if_name[] = "minihif";

#define ETH_43_PFE_STOP_SEC_CONST_8
#include "Eth_43_PFE_MemMap.h"

#define ETH_43_PFE_START_SEC_CODE
#include "Eth_43_PFE_MemMap.h"

static errno_t configure_emacs(pfe_ct_phy_if_id_t hif_id, pfe_ct_phy_if_id_t emac_id);

/*  Note that minihif initialization requires prior MCAL driver initialization,
    call function Eth_43_PFE_Init first. */
void configure_minihif_hw(void)
{

    if(EOK != pfe_minihif_drv_create(&minihif, MINIHIF_HW_USE, FALSE))
    {
        NXP_LOG_ERROR("Minihifs creation failed\n");
        return;
    }

    if( (EOK != pfe_minihif_drv_attach_ring(&minihif, TRUE, MINI_RX_RING_VA, MINI_RX_WB_RING_VA, MINI_RX_BD_LENGTH))
     || (EOK != pfe_minihif_drv_attach_ring(&minihif, FALSE, MINI_TX_RING_VA, MINI_TX_WB_RING_VA, MINI_TX_BD_LENGTH))
      )
    {
        NXP_LOG_ERROR("MINIHIF - fixed buffers configuration failed\n");
        return;
    }

    if (EOK != pfe_minihif_drv_init(&minihif))
    {
        NXP_LOG_ERROR("minihif_drv_init failed\n");
        return;
    }

    if (EOK != configure_emacs(pfe_minihif_get_hif_id(&minihif), PFE_PHY_IF_ID_EMAC1))
    {
        NXP_LOG_ERROR("HIF driver EMAC config failed\n");
        return;
    }

    if (EOK != pfe_minihif_drv_start_rx(&minihif))
    {
        NXP_LOG_ERROR("HIF driver reception start failed\n");
        return;
    }
    if (EOK != pfe_minihif_drv_start_tx(&minihif))
    {
        NXP_LOG_ERROR("HIF driver transmission start failed\n");
        return;
    }
}

/*  Example of configuration of EMAC and Rx dispatching in case the EMAC is also
    used from MCAL driver (or any other PFE driver).

    It shows creation and configuration of logical interface attached to EMAC1 to specify which
    packets shall be received via minihif's HIF. This can be changed and extended to receive
    from more EMACs simultaneously (create another logical interface for another EMAC) and even
    to receive on more HIF's simultaneously (using multiple minihif instances). The EMAC on
    which the packet was received can be determined from Rx header (16 bytes at the beginning of
    Rx buffer, typedef pfe_ct_hif_rx_hdr_t). Note that the order of attaching logical interfaces
    to EMAC matters, last attached get processed first. MCAL driver creates its own logical
    interface for each EMAC it uses, then logical interface can be added here for minihif. Then
    this configuration determines which packets will be received through minihif and MCAL driver
    will receive the rest. This function also enables the EMAC. To just enable EMAC for transmit
    use function enable_emac() below.
    Note that this can affect the MCAL driver that uses the same EMAC. Specifically the addition
    of a MAC address. If the match rules are not configured to accept all inbound traffic at that
    address, then the MCAL driver will receive the packets that were not accepted here. The same
    will happen if the promiscuous mode is enabled here.
*/
static errno_t configure_emacs(pfe_ct_phy_if_id_t hif_id, pfe_ct_phy_if_id_t emac_id)
{
    void *pfe_platform;
    pfe_phy_if_t *phy_if_emac;
    pfe_phy_if_t *phy_if_hif;
    pfe_log_if_t *log_if_emac;
    uint8 mac_addr[6] = {0xd8, 0xcb, 0x8a, 0xa3, 0x7d, 0xcf};
    pfe_ct_if_m_rules_t match_rules = IF_MATCH_NONE;
    pfe_ct_if_m_args_t match_arguments; /* BIG endian here */

    /*  Get PFE platform data from MCAL driver */
    pfe_platform = Eth_43_PFE_GetPlatform();
    if (NULL_PTR == pfe_platform)
    {
        return -1;
    }
    /*  Get a physical interface for the EMAC we want to use */
    phy_if_emac = pfe_platform_get_phy_if_by_id(pfe_platform, emac_id);
    if (NULL_PTR == phy_if_emac)
    {
        return -1;
    }
    /*  Get the physical interface for our HIF channel */
    if (NULL_PTR == (phy_if_hif = pfe_platform_get_phy_if_by_id(pfe_platform, hif_id)))
    {
        return -1;
    }

    /*  Allows Rx packet dispatching based on logical interfaces, which is the approach used here */
    if (E_OK != pfe_phy_if_set_op_mode(phy_if_emac, IF_OP_FLEX_ROUTER))
    {
        return -1;
    }

    /*  Create a logical interface that will be used to dispatch packets from the EMAC */
    if (NULL_PTR == (log_if_emac = pfe_log_if_create(phy_if_emac, log_if_name)))
    {
        return -1;
    }

    /*  Set one or more rules to specify traffic received by our driver */
    /*  For more options see pfe_ct.h, pfe_ct_if_m_rules_t and pfe_ct_if_m_args_t */
#if 0 /* Select based on destination MAC address */
    memcpy(match_arguments.dmac, mac_addr, 6U);
    match_rules |= IF_MATCH_DMAC;
#endif
#if 0 /* Select based on VLAN ID */
    match_arguments.ethtype = cpu_to_be16(333U); /* Converted to BIG endian */
    match_rules |= IF_MATCH_VLAN;
#endif
#if 0 /* Select based on EtherType */
    match_arguments.ethtype = cpu_to_be16(0x0806); /* ARP, converted to BIG endian */
    match_rules |= IF_MATCH_ETHTYPE;
#endif
#if 1 /* Enable broadcast */
    match_rules |= IF_MATCH_TYPE_BCAST;
#endif
    /*  Apply the rules */
    if (E_OK != pfe_log_if_set_match_rules(log_if_emac, match_rules, &match_arguments))
    {
        return -1;
    }
    /*  If multiple match rules are configured, this determines whether they are logically AND-ed or OR-ed */
#if 0
    if (E_OK != pfe_log_if_set_match_and(log_if_emac))
#else
    if (E_OK != pfe_log_if_set_match_or(log_if_emac))
#endif
    {
        return -1;
    }

    /*  Attach the logical interface to the EMAC */
    if (E_OK != pfe_platform_register_log_if(pfe_platform, log_if_emac))
    {
        return -1;
    }
    /*  Make sure that EMAC ingress traffic will be forwarded to our HIF channel(s) */
    if (E_OK != pfe_log_if_add_egress_if(log_if_emac, phy_if_hif))
    {
        return -1;
    }

#if 1 /* Use MAC address */
    /*  The MAC address is propagated to EMAC to allow reception of packets with this destination address */
    /*  It does not affect match rules, so you might want to also configure match rule for this destination
        address (if using different MAC address for each driver or each driver instance) */
    if (E_OK != pfe_log_if_add_mac_addr(log_if_emac, mac_addr, hif_id))
    {
        return -1;
    }
#else /* Use promiscuous mode */
    /*  It is also propagated to the EMAC */
    /*  This will make the logical interface receive all packets regardless match rules */
    if (E_OK != pfe_log_if_promisc_enable(log_if_emac))
    {
        return -1;
    }
#endif

    /*  At last enable the logical interface. This also enables underlying physical interface (EMAC)
        if it wasn't enabled before */
    if (E_OK != pfe_log_if_enable(log_if_emac))
    {
        return -1;
    }
    return EOK;
}

#define ETH_43_PFE_STOP_SEC_CODE
#include "Eth_43_PFE_MemMap.h"
