/*****************************************************************************
 函 数 名  : hifireset_loadhifibin
 功能描述  : 加载hifi映像
 输入参数  : 无
 输出参数  : 无
 返 回 值  : int
*****************************************************************************/
int hifireset_loadhifibin(void)
{
            /* load hifi */
    if (TRUE == check_secure_mode())
    {
        printk(KERN_INFO"RESET LOADHIFI: It's secure mode\n");

        if (execute_load_hifi((int)HIFI_SAFE_LOAD, (unsigned long)HIFI_SHARE_ADDR_BASE))
        {
            return BSP_RESET_ERROR;
        }
    }
    else
    {
        printk(KERN_INFO"RESET LOADHIFI: It's un-secure mode\n");
        if (execute_load_hifi((int)HIFI_UNSAFE_LOAD, (unsigned long)HIFI_SHARE_ADDR_BASE))
        {
            return BSP_RESET_ERROR;
        }
    }

    return BSP_RESET_OK;
}
int __init loadmodem_init(void)
{
#ifndef CONFIG_ARM64
    #define MODEM_IMAGE_ADDR (0x3E00)
    unsigned int buff_phy = MODEM_IMAGE_ADDR;
    DSP_IMAGE_HEAD_STRU *header = NULL;
    MODEM_IMAGE_BUFFER_FLAG_STRU *buffer_flag = NULL;
    char *modem_loadaddr = NULL;
    int ret, i;
    char *tmp_addr = NULL;
    char *modem_baseaddr = NULL;
    char *gudsp_load_addr = NULL;
    char *gudsp_flag_addr = NULL;
    char *gudsp_head_addr = NULL;
    char *gudsp_bin_addr = NULL;
    char *modem_sec_imageaddr = NULL;
    unsigned int head_len = 0;
    unsigned int bin_len = 0;

    if (!is_async_loadmodem())
        return 0;

    /* Dont protect modem memory */
    /*platform_ddr_protect_init(0);*/

    modem_baseaddr = (char *)ioremap_nocache(MODEM_SYS_MEM_ADDR, MODEM_SYS_MEM_SIZE);
    gudsp_load_addr = (char *)ioremap_nocache(ECS_GUDSP_LOAD_ADDR, ECS_GUDSP_LOAD_SIZE);
    gudsp_flag_addr = gudsp_load_addr;
    gudsp_head_addr = gudsp_flag_addr + GUDSP_IMAGE_FLAG_SIZE;
    gudsp_bin_addr = gudsp_head_addr + GUDSP_IMAGE_HEAD_SIZE;
    modem_sec_imageaddr = modem_baseaddr + MODEM_IMAGE_ADDR - VRL_SIZE;

    buffer_flag = (MODEM_IMAGE_BUFFER_FLAG_STRU*)gudsp_flag_addr;
    buffer_flag->ulProtectWord1 = 0x5A5A5A5A;
    buffer_flag->ulSecNum = 0;
    buffer_flag->ulHeadAddr = (unsigned int)GUDSP_IMAGE_HEAD_ADDR;
    buffer_flag->ulProtectWord2 = 0xA5A5A5A5;

    modem_loadaddr = modem_baseaddr + MODEM_IMAGE_ADDR;
    header = (DSP_IMAGE_HEAD_STRU *)modem_loadaddr;

    /*printk(KERN_ERR "%s:modem_loadaddr: %p modem_baseaddr:%p \n",__FUNCTION__, modem_loadaddr, modem_baseaddr);*/

    /* secure check */
    if (check_secure_mode()){
        ret = check_image_in_ram((unsigned int *)modem_sec_imageaddr);
        if (ret == 0){
            printk(KERN_INFO "%s:secure check ok \n",__FUNCTION__);
        }else{
            printk(KERN_ERR "%s:secure check error \n",__FUNCTION__);
            goto error;
        }
    }

    for(i = 0; i < header->uwSecNum; i++)
    {

        /* If attribute is BUFFER, move to buffer */
        if (header->astSections[i].enLoadAttrib == DSP_IMAGE_SEC_LOAD_BUFFER )
        {
            if((GUDSP_IMAGE_HEAD_SIZE < head_len + sizeof(DSP_IMAGE_SEC_STRU))
                || (GUDSP_IMAGE_BUFFER_SIZE < bin_len + header->astSections[i].uwSize)
                || (GUDSP_IMAGE_SECTION_MAX <= buffer_flag->ulSecNum))
            {
                printk(KERN_ERR "load to buffer failed, section's size beyond buffer's size.\n");
                return -1;
            }

            memcpy((void*)(gudsp_bin_addr + bin_len), (void*)(modem_loadaddr + header->astSections[i].uwSrcOffset),
                                        header->astSections[i].uwSize);
            header->astSections[i].uwSrcOffset = (unsigned int)GUDSP_IMAGE_BIN_ADDR + bin_len;
            memcpy((void*)(gudsp_head_addr + head_len), (void*)(&header->astSections[i]),
                                        sizeof(DSP_IMAGE_SEC_STRU));

            head_len += sizeof(DSP_IMAGE_SEC_STRU);
            bin_len += header->astSections[i].uwSize;
            buffer_flag->ulSecNum++;

            //printk(KERN_ERR "%s:section buffer: %p\n",__FUNCTION__,tmp_addr);
        }
        /* If attribute is STATIC/MODEM_ENTRY, move to addr to run */
        else if ((header->astSections[i].enLoadAttrib == DSP_IMAGE_SEC_LOAD_MODEM_ENTRY )
            || (header->astSections[i].enLoadAttrib == DSP_IMAGE_SEC_LOAD_STATIC ))
        {
            tmp_addr = modem_baseaddr + header->astSections[i].uwDesOffset;
            printk(KERN_INFO"%s:section: %p \n",__FUNCTION__, tmp_addr);
            if (header->astSections[i].uwDesOffset != buff_phy + header->astSections[i].uwSrcOffset){
                memmove(tmp_addr,
                   (modem_loadaddr + header->astSections[i].uwSrcOffset),
                    header->astSections[i].uwSize);
                //printk(KERN_ERR "%s:copy %p to %p size 0x%x \n",__FUNCTION__, (buff_phy + header->astSections[i].uwSrcOffset), header->astSections[i].uwDesOffset,header->astSections[i].uwSize);
                //printk(KERN_ERR "%s:copy %p to %p size 0x%x \n",__FUNCTION__, (modem_loadaddr + header->astSections[i].uwSrcOffset), tmp_addr, header->astSections[i].uwSize);
            }
        }
        /* else do nothing */
        else
        {
            /* do nothing */
        }

    }
    printk(KERN_INFO"Load modem done.\n");
    /* unreset modem */ 
    start_modem();
#else
    TEEC_Result result = SEC_ERROR;

    /*64bit secure check */
    /*Do the SecureOs locally for modem 
    if the result is ok then start the modem
    else start the kernel but hold the modem
    */
    result = TEEK_start_modem();
    if (result == TEEC_SUCCESS)
    {
	printk(KERN_INFO "%s:secure check ok \n",__FUNCTION__);
    }
    else
    {
        printk(KERN_ERR "%s:secure check error \n",__FUNCTION__);
        goto error;
    }
#endif

error:
#ifndef CONFIG_ARM64
    iounmap(modem_baseaddr);
    iounmap(gudsp_load_addr);
#endif

    return 0;
}