#include <stdlib.h>
#include "osp_cfgfile.h"
#include "osp_mem.h"
#include "err_num.h"
#include "ucp_printf.h"
#include "ucp_tick.h"
#include "osp_io.h"
#include "spu_log.h"

#define OSP_CFG_FLAG_OK     (0xA0A0A0A0)    /* ARM与APE约定，读完配置文件标识             */

#define OSP_CFG_PHY_SIZE    (0x4000000)     /* 根据内存规划64M */

#define OSP_CFG_INFO_ONE    (sizeof(osp_file_reg))  /* 一个文件信息的大小 */

#define OSP_CFG_OFFSET      (8)             /* 4字节：FLAG；   4字节：NUM */
#define OSP_CFG_NUM         (4)
#define OSP_CFG_INFO_ADDR   (OSP_CFG_PHY_ADDR+OSP_CFG_OFFSET)    /* 前4个字节是放配置文件个数 */
#define OSP_CFG_INFO_SIZE   (OSP_CFG_INFO_ONE*APE_CFG_FILE_NUM)     /* 配置文件信息的总大小 */

#define OSP_CFG_FILE_ADDR   (OSP_CFG_INFO_ADDR + OSP_CFG_INFO_SIZE) /* 配置文件的地址 */
#define OSP_CFG_FILE_SIZE   (OSP_CFG_PHY_SIZE - OSP_CFG_INFO_SIZE - OSP_CFG_OFFSET)   /* 配置文件的总大小 */

osp_file_reg *g_cfgfile_head = NULL;    /* 配置文件 */
int8_t        g_cfgfile_num  = 0;       /* 配置文件个数 */

int osp_get_cfgfile(char* name, uint32_t *pbuf, int* psize)
{
#ifdef UCP_TICK_ENABLE
    uint32_t clockBegin,clockEnd;
    int32_t  clockCnt;
    rdmcycle(&clockBegin);
#endif

    static uint8_t s_flag = 0;  /* 0:osp_cfgfile_read； 1:直接读 */
    uint8_t i = 0;
    int   ret = 0;
    osp_file_reg * head;

    /* 第一次调用时，去DDR里取配置文件的相关信息 */
    if (0 == s_flag)
    {
        s_flag++;
        ret = osp_cfgfile_read();
        if (OSP_OK != ret)
        {
            return ret;
        }
    }

    if(strlen(name) > APE_CFG_FILE_NAME_LEN)
    {
        return -OSP_PAR_ILL;
    }
    for(i=0; i< g_cfgfile_num; i++)
    {
        head = g_cfgfile_head + i;
        UCP_PRINT_LOG("i = 0x%x, addr = 0x%x, len = 0x%x \r\n", i, head->phy_addr, head->len);
        UCP_PRINT_LOG("name = %s \r\n", head->name);
        if(0 == strcmp(head->name, name))
        {
            *pbuf = head->phy_addr;
            *psize = head->len;
#ifdef OSP_DEBUG_TEST
            debug_write(OSP_DEBUG_POT(g_ape_id, 105), head->len);
            debug_write(OSP_DEBUG_POT(g_ape_id, 106), head->phy_addr);
#endif
#ifdef UCP_TICK_ENABLE
            rdmcycle(&clockEnd);
            clockCnt = clockEnd - clockBegin;
            debug_write(OSP_DEBUG_POT(g_ape_id, 204), clockCnt);
#endif
            return 0;
        }
    }  
#ifdef UCP_TICK_ENABLE
    rdmcycle(&clockEnd);
    clockCnt = clockEnd - clockBegin;
    debug_write(OSP_DEBUG_POT(g_ape_id, 204), clockCnt);
#endif

    return -(OSP_NO_FILE);
}

/*  */
void osp_cfgfile_rev(osp_file_reg *head, int num)
{
    /* head是个DDR地址 */
    memcpy_ucp((g_cfgfile_head+g_cfgfile_num), (head), sizeof(osp_file_reg) * num);
    //memcpy(g_cfgfile_head+g_cfgfile_num, head, sizeof(osp_file_reg) * num);
    g_cfgfile_num += num;
#ifdef OSP_DEBUG_TEST
    debug_write(OSP_DEBUG_POT(g_ape_id, 103), g_cfgfile_head->len);
    debug_write(OSP_DEBUG_POT(g_ape_id, 104), g_cfgfile_head->phy_addr);
#endif

    return;
}

/* 握手完成后，代表ARM侧已经把配置文件信息读到DDR了，故直接指定地址读取配置文件 */
int osp_cfgfile_read()
{
    /* 配置文件分两区域，第一区域是头信息，第二区域是配置文件本身 */
    /* 头信息那前4字节是配置文件的个数 */
    uint32_t cfg_num  = 0;
    uint32_t cfg_flag = 0;
    osp_file_reg *head = NULL;

    cfg_flag = do_read_volatile(OSP_CFG_PHY_ADDR);
#ifdef OSP_DEBUG_TEST
    debug_write(OSP_DEBUG_POT(g_ape_id, 101), cfg_flag);
#endif
    if (OSP_CFG_FLAG_OK != cfg_flag)
    {
        UCP_PRINT_ERROR("osp_cfgfile_read flag[0x%x]", cfg_flag);
        return -OSP_ERROR;
    }

    cfg_num = do_read_volatile(OSP_CFG_PHY_ADDR + OSP_CFG_NUM);
    UCP_PRINT_LOG("cfg_num = %x\r\n", cfg_num);
#ifdef OSP_DEBUG_TEST
    debug_write(OSP_DEBUG_POT(g_ape_id, 102), cfg_num);
#endif
    head = (osp_file_reg*)(OSP_CFG_INFO_ADDR);

    if(0 != cfg_num)
    {
        osp_cfgfile_rev(head, (int)cfg_num);
    }

    return OSP_OK;
}

/* 配置文件模块初始化函数 */
int  osp_cfgfile_init(void)
{
    g_cfgfile_head = (osp_file_reg *)osp_malloc(sizeof(osp_file_reg) * APE_CFG_FILE_NUM);
    if(NULL == g_cfgfile_head)
    {
        UCP_PRINT_ERROR("osp_cfgfile_init osp_malloc failed\r\n");
        return -OSP_MEM_FULL;
    }

    memset(g_cfgfile_head, 0, (sizeof(osp_file_reg) * APE_CFG_FILE_NUM));
    g_cfgfile_num = 0;

    return 0;
}

