/* =========================================================================
 *  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.
 *  <<< PFE Restricted Software >>>
 *
 * ========================================================================= */

/**
 * @addtogroup  dxgr_OAL_MM
 * @{
 *
 * @file        oal_mm_autosar.c
 * @brief       The oal_mm module source file (AUTOSAR).
 * @details     This file contains AUTOSAR-specific memory management implementation.
 *
 */

/*==================================================================================================
*                              SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define PFE_SRC_VERSION_CHECK 43100440

#include "pfe_cfg.h"
#include "oal.h"
#include "oal_mm.h"
#include "hal.h"
#include "blalloc.h"
#include "pfe_platform_cfg.h"

#define IS_POWER_OF_2(n) (((n) != 0U) && (((n) & ((n) - 1U)) == 0U))

/**
 * @brief   CANC heap alignment
 */
#define CANC_HEAP_ALIGNMENT 4096U

/*  Calculate number of 16B chunks needed in MCAL driver for Tx headers.
    TODO Remove this heap - Tx headers should be placed somewhere else, ideally in Tx buffers */
#define BD_MEM_HEAP_CHUNK_CNT (ETH_43_PFE_MAX_TXBD_CNT + 2U)

#define TX_BUF_MEM_HEAP_SIZE (12800U)

/*==================================================================================================
                                       GLOBAL VARIABLES
==================================================================================================*/

/* CACHE ENABLED MEMORY */
#define ETH_43_PFE_START_SEC_VAR_CLEARED_UNSPECIFIED
#include "Eth_43_PFE_MemMap.h"

/*
    Heap for oal_mm_malloc()/oal_mm_free() and related allocator
    Content: General data
    Chunk size = 2^4 = 16
*/
__attribute__((aligned(16))) uint8_t heap[PFE_CFG_HEAP_SIZE_KB * 1024U];
#define ETH_43_PFE_STOP_SEC_VAR_CLEARED_UNSPECIFIED
#include "Eth_43_PFE_MemMap.h"

#define ETH_43_PFE_START_SEC_VAR_INIT_UNSPECIFIED
#include "Eth_43_PFE_MemMap.h"
BLALLOC_STATIC_INST(heap_allocator, sizeof(heap), 4U);
#define ETH_43_PFE_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Eth_43_PFE_MemMap.h"

#define ETH_43_PFE_START_SEC_VAR_CLEARED_UNSPECIFIED_BD_MEM
#include "Eth_43_PFE_MemMap.h"
/*
    Heap for memory named "bd_mem"
    Content: buffer descriptors and Tx headers
    Chunk size = 2^4 = 16
*/
__attribute__((aligned(CANC_HEAP_ALIGNMENT))) uint8_t bd_mem_heap[((uint32_t)BD_MEM_HEAP_CHUNK_CNT * 16U)];
#define ETH_43_PFE_STOP_SEC_VAR_CLEARED_UNSPECIFIED_BD_MEM
#include "Eth_43_PFE_MemMap.h"

#define ETH_43_PFE_START_SEC_VAR_INIT_UNSPECIFIED
#include "Eth_43_PFE_MemMap.h"
BLALLOC_STATIC_INST(bd_mem_heap_allocator, sizeof(bd_mem_heap), 5U);
#define ETH_43_PFE_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Eth_43_PFE_MemMap.h"

#define ETH_43_PFE_START_SEC_VAR_CLEARED_UNSPECIFIED_BUF_MEM
#include "Eth_43_PFE_MemMap.h"
/*
    Heap for memory named "tx_buf_mem"
    Content: Tx buffers
    Chunk size = 64B
*/
__attribute__((aligned(CANC_HEAP_ALIGNMENT))) uint8_t tx_buf_mem_heap[(uint32_t)TX_BUF_MEM_HEAP_SIZE];
#define ETH_43_PFE_STOP_SEC_VAR_CLEARED_UNSPECIFIED_BUF_MEM
#include "Eth_43_PFE_MemMap.h"

#ifdef PFE_CFG_PFE_MASTER

/*==================================================================================================
                                   LOCAL FUNCTION PROTOTYPES
==================================================================================================*/

#define ETH_43_PFE_START_SEC_CODE
#include "Eth_43_PFE_MemMap.h"

static void *oal_mm_malloc_bd_mem(const addr_t size, const uint32_t align);
static void *oal_mm_malloc_tx_buf(const uint32_t align);

/*==================================================================================================
                                       LOCAL FUNCTIONS
==================================================================================================*/

#define ETH_43_PFE_STOP_SEC_CODE
#include "Eth_43_PFE_MemMap.h"

#endif /* PFE_CFG_PFE_MASTER */

#define ETH_43_PFE_START_SEC_CODE
#include "Eth_43_PFE_MemMap.h"

/* Allocate contiguous aligned and non-cache-able memory region from named memory pool */
static void *oal_mm_malloc_bd_mem(const addr_t size, const uint32_t align)
{
    addr_t addr;

    if (0U != align)
    {
        if(FALSE == IS_POWER_OF_2(align))
        {
            NXP_LOG_ERROR("Wrong alignment request\n");
            return NULL;
        }
        if (0U != ((uint32_t)bd_mem_heap & (align - 1U)))
        {
            NXP_LOG_ERROR("Wrong alignment of bd_mem\n");
            return NULL;
        }
    }

    if (EOK != blalloc_alloc_offs(&bd_mem_heap_allocator, size, align, &addr))
    {
        NXP_LOG_ERROR("Unknown named memory requested from bd_mem\n");
        return NULL;
    }
    else
    {
        return (void *)(addr + (addr_t)bd_mem_heap);
    }
}

/* Allocate contiguous aligned and non-cache-able memory region from named memory pool */
static void *oal_mm_malloc_tx_buf(const uint32_t align)
{
    if (0U != align)
    {
        if(FALSE == IS_POWER_OF_2(align))
        {
            NXP_LOG_ERROR("Wrong alignment request\n");
            return NULL;
        }
        if (0U != ((uint32_t)tx_buf_mem_heap & (align - 1U)))
        {
            NXP_LOG_ERROR("Wrong alignment of tx_buf_mem\n");
            return NULL;
        }
    }

    return (void *)&tx_buf_mem_heap[0];
}

/*==================================================================================================
                                       GLOBAL FUNCTIONS
==================================================================================================*/

/**
 * Standard memory allocation
 */
void *oal_mm_malloc(const addr_t size)
{
    addr_t addr;

    if (EOK != blalloc_alloc_offs(&heap_allocator, size, 0U, &addr))
    {
        return NULL;
    }
    else
    {
        return (void *)(addr + (addr_t)heap);
    }
}

/* Allocate contiguous aligned and non-cache-able memory region from named memory pool */
void *oal_mm_malloc_contig_named_aligned_nocache(const char_t *pool, const addr_t size, const uint32_t align)
{
    if(0 == strcmp(pool, "bd_mem"))
    {
        return oal_mm_malloc_bd_mem(size, align);
    }
    else if(0 == strcmp(pool, "tx_buf_mem"))
    {
        return oal_mm_malloc_tx_buf(align);
    }
    else
    {
        return NULL;
    }
}

/* Allocate contiguous aligned and cache-enabled memory region from named memory pool */
void *oal_mm_malloc_contig_named_aligned_cache(const char_t *pool, const addr_t size, const uint32_t align)
{   /* If memory is cached or not is determined by memory pool name */
    return oal_mm_malloc_contig_named_aligned_nocache(pool, size, align);
}

/**
 *  Try to find physical address associated with mapped virtual range
 */
void *oal_mm_virt_to_phys_contig(void *vaddr)
{
    /* 1:1 mapping */
    return vaddr;
}

/**
 *  Release contig memory
 */
void oal_mm_free_contig(const void *vaddr)
{
    if (((addr_t)vaddr >= (addr_t)bd_mem_heap) && ((addr_t)vaddr < ((addr_t)bd_mem_heap + sizeof(bd_mem_heap))))
    {
        blalloc_free_offs(&bd_mem_heap_allocator, (addr_t)((addr_t)vaddr - (addr_t)bd_mem_heap));
    }
    else
    {
        NXP_LOG_ERROR("Attempt to release unknown memory\n");
    }
}

/**
 * Standard memory release
 */
void oal_mm_free(const void *vaddr)
{
    if (((addr_t)vaddr >= (addr_t)heap) && ((addr_t)vaddr < ((addr_t)heap + sizeof(heap))))
    {
        blalloc_free_offs(&heap_allocator, (addr_t)((addr_t)vaddr - (addr_t)heap));
    }
    else
    {
        NXP_LOG_ERROR("Attempt to release unknown memory\n");
    }
}

/**
 *  Try to find physical address associated with mapped virtual range
 */
void *oal_mm_virt_to_phys(void *vaddr)
{/* Mapped 1:1 */
    return vaddr;
}

/**
 * Get virtual address based on physical address. Function assumes that region containing the 'paddr'
 * is already mapped within current process' address space.
 */
void *oal_mm_phys_to_virt(void *paddr)
{/* Mapped 1:1 */
    return paddr;
}

void *oal_mm_dev_map(void *paddr, const addr_t len)
{/* Mapped 1:1 */
    (void)len;
    return paddr;
}

void *oal_mm_dev_map_cache(void *paddr, const addr_t len)
{/* Mapped 1:1 */
    (void)len;
    return paddr;
}

errno_t oal_mm_dev_unmap(void *paddr, const addr_t len)
{
    (void)paddr;
    (void)len;
    return EOK;
}

void oal_mm_cache_inval(const void *vaddr, const void *paddr, const addr_t len)
{
    (void)vaddr;
    (void)paddr;
    (void)len;
}

void oal_mm_cache_flush(const void *vaddr, const void *paddr, const addr_t len)
{
    (void)vaddr;
    (void)paddr;
    (void)len;
}

uint32_t oal_mm_cache_get_line_size(void)
{
    return HAL_CACHE_LINE_SIZE;
}

errno_t oal_mm_init(const void *dev)
{
    errno_t ret = EOK;

    (void)dev;

    ret = blalloc_init(&heap_allocator);
    if (EOK != ret)
    {
        NXP_LOG_ERROR("Standard heap allocator init failed\n");
    }

    ret = blalloc_init(&bd_mem_heap_allocator);
    if (EOK != ret)
    {
        NXP_LOG_ERROR("\"bd_mem\" allocator init failed\n");
    }

    return ret;
}

void oal_mm_shutdown(void)
{
    blalloc_fini(&heap_allocator);
}

#define ETH_43_PFE_STOP_SEC_CODE
#include "Eth_43_PFE_MemMap.h"

/** @}*/
