// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
/*
 * Copyright (c) 2023 MediaTek Inc.
 */

#include <command.h>
#include <common.h>
#include <stdio.h>
#include <debug_impl.h>
#include <MsTypes.h>
//#include <ShareType.h>
#include <malloc.h>

#include <CommonDataType.h>
#include <dmalloc.h>
#include <read_text.h>
#include <demura.h>
#include <ms_utils.h>

//#include <apiPNL.h>
#include <MDrvDemura.h>
#include <halDemura.h>
#include <convert_entry.h>
#include "vendor.h"
#include "crc_libs.h"
#include "demura_config.h"

#define SAMPLE_DAT_START    2*(481*271+1)     // Byte
#define SAMPLE_DAT_LEN      4096     // Byte
#define FLASH_MAX_SIZE   (1024 * 1024)

#if(FORCE_TO_4_LAYER)
static MS_U8 SDC_Select_Layer[4] = {2,4,5,6};
#endif

typedef union
{
    MS_U32 block_data;
    unsigned char data[4];

    struct
    {
        int nReserved:8;
        int b3:6;
        int b2:6;
        int b1:6;
        int b0:6;
    };
}DATA;

static MS_BOOL Gen_Sf_Signature(SDC_Demura_Header *phdr)
{
    char   strbuf[1024];
    MS_U32 sample_crc32;
    MS_U8  *buffer;

    buffer = phdr->lut_buffer;

    sample_crc32 = MDrv_CRC32_Cal_DeMura(buffer + SAMPLE_DAT_START, SAMPLE_DAT_LEN);
    if (sample_crc32 == 0xffffFFFF)
    {
        UBOOT_ERROR("MDrv_CRC32_Cal_DeMura error\n");
        return FALSE;
    }
    memset(strbuf, 0, sizeof(strbuf));
    snprintf(strbuf, sizeof(strbuf)-1, "0x%x:0x%x", phdr->TABLE_CRC, sample_crc32);
    env_set(ENV_DEMURA_SIG, strbuf);
    env_save();
    return TRUE;
}


MS_BOOL If_Need_Decode(void)
{
    UBOOT_TRACE("IN\n");

    char *sig_str = env_get(ENV_DEMURA_SIG);
    if (sig_str == NULL)
    {
        UBOOT_DEBUG("Empty Board, should decoding data\n");
        UBOOT_TRACE("OK\n");
        return TRUE;
    }
    else
    {
        MS_U16 lut_checksum_sf;
        MS_U32 lut_checksum_bd;
        MS_U32 sample_crc32, cal_crc32;
        MS_U8  buf[SAMPLE_DAT_LEN];

        lut_checksum_sf = get_lut_checksum();

        UBOOT_DEBUG("sig_str = %s\n", sig_str);
        if(2 == sscanf(sig_str, "0x%x:0x%x", &lut_checksum_bd, &sample_crc32))
        {
            UBOOT_DEBUG("lut_checksum_sf = 0x%x\n", (uint)lut_checksum_sf);
            UBOOT_DEBUG("lut_checksum_bd = 0x%x\n", (uint)lut_checksum_bd);
            UBOOT_DEBUG("sample_crc32  = 0x%x\n",   (uint)sample_crc32);

            if (read_spi_flash(buf, (LUT_START + SAMPLE_DAT_START), SAMPLE_DAT_LEN) == TRUE)
            {
                cal_crc32 = MDrv_CRC32_Cal_DeMura(buf, SAMPLE_DAT_LEN);
                UBOOT_DEBUG("cal_crc32     = 0x%x\n", (uint)cal_crc32);
                if ((sample_crc32 == cal_crc32) && (lut_checksum_sf == lut_checksum_bd))
                {
                    UBOOT_DEBUG("Data Match, No Need to decode again\n");
                    UBOOT_TRACE("OK\n");
                    return FALSE;
                }
            }
        }

        UBOOT_TRACE("OK\n");
        return TRUE;
    }

    UBOOT_TRACE("OK\n");
    return FALSE;
}

static void dump_interface_info(interface_info *pDataInfo)
{
    printf("PLANE_NUM = %d  \n", pDataInfo->reg_dmc_plane_num);
    printf("H_BLOCK = %d, V_BLOCK = %d  \n", pDataInfo->reg_dmc_h_block, pDataInfo->reg_dmc_v_block);
    printf("RGB_MODE = %d   \n", pDataInfo->reg_dmc_rgb_mode);
    printf("PANEL_H_SIZE = %d   \n", pDataInfo->reg_dmc_panel_h_size);
    printf("BLACK_LIMIT = 0x%x, WHITE_LIMIT = 0x%x  \n", pDataInfo->reg_dmc_black_limit, pDataInfo->reg_dmc_white_limit);

    printf("PLANE_LEVEL 1 = 0x%x   \n", pDataInfo->reg_dmc_plane_level1);
    printf("PLANE_LEVEL 2 = 0x%x   \n", pDataInfo->reg_dmc_plane_level2);
    printf("PLANE_LEVEL 3 = 0x%x   \n", pDataInfo->reg_dmc_plane_level3);
    printf("PLANE_LEVEL 4 = 0x%x   \n", pDataInfo->reg_dmc_plane_level4);
    printf("PLANE_LEVEL 5 = 0x%x   \n", pDataInfo->reg_dmc_plane_level5);
    printf("PLANE_LEVEL 6 = 0x%x   \n", pDataInfo->reg_dmc_plane_level6);
    printf("PLANE_LEVEL 7 = 0x%x   \n", pDataInfo->reg_dmc_plane_level7);
    printf("PLANE_LEVEL 8 = 0x%x   \n", pDataInfo->reg_dmc_plane_level8);

    printf("DITHER_4_FRAME = %d, DITHER_RST_NUM = %d, DITHER_EN = %d    \n",
        pDataInfo->reg_dmc_dither_rst_e_4_frame, pDataInfo->reg_dmc_dither_pse_rst_num, pDataInfo->reg_dmc_dither_en);

    printf("ROI_EN = %d, ROI_H_START = %d, ROI_H_END = %d, ROI_V_START = %d, ROI_V_END = %d \n",
        pDataInfo->bROI_en, pDataInfo->iROI_hor_start_offset, pDataInfo->iROI_hor_end_offset,
        pDataInfo->iROI_ver_start_offset, pDataInfo->iROI_ver_end_offset);
}

int Get_INDEX(int *array, MS_U8 array_num)
{
    int i = 0;
    int min = array[0];
    for(i = 0; i < array_num; i++)
    {
        if(array[i] < min)
            min = i;
    }
    return min;
}

static MS_BOOL SDC_Decode_To_Mstar_Format(SDC_Demura_Header *phdr, interface_info *pinfo)
{
    int idx, i, j, k, data = 0;
    int table_addr = 0;
    int nLayer = 0, idx_image_size;
    double Value_1 = 0.0, LUT_data = 0.0;

    // assign LUT 12 bit format
    for(k = (MAX_PLANE_NUM - 1); k >= 0; k--)//test for(k = (pinfo->reg_dmc_plane_num - 1); k >= 0; k--)
    {
        for (i = 0; i < phdr->DEMURA_TBL_V; i++)
        {
            for (j = 0; j < phdr->DEMURA_TBL_H ; j++)
            {
                // Update Value_1
                Value_1 = (1<<phdr->Value_1[k])*(255.0/4096.0);//(phdr->Value_1[k] == 0)?255.0/4096.0:255.0/2048.0;

                // 8 bit LUT
                data = phdr->lut_buffer[table_addr];
                if(data >= 128) // signed bit 7
                    data = data - 256;

                table_addr++;

                if((i == (phdr->DEMURA_TBL_V - 1)) && (j == (phdr->DEMURA_TBL_H - 1))) // skip last dummy 0xFF
                    table_addr++;

                switch(k)
                {
                    case 0:
                        nLayer = pinfo->reg_dmc_plane_level1;
                        break;
                    case 1:
                        nLayer = pinfo->reg_dmc_plane_level2;
                        break;
                    case 2:
                        nLayer = pinfo->reg_dmc_plane_level3;
                        break;
                    case 3:
                        nLayer = pinfo->reg_dmc_plane_level4;
                        break;
                    case 4:
                        nLayer = pinfo->reg_dmc_plane_level5;
                        break;
                    case 5:
                        nLayer = pinfo->reg_dmc_plane_level6;
                        break;
                    case 6:
                        nLayer = pinfo->reg_dmc_plane_level7;
                        break;
                    case 7:
                        nLayer = pinfo->reg_dmc_plane_level8;
                        break;
                    default:
                        break;
                }

                LUT_data = (double)(data*4*Value_1) + (double)(nLayer/4.0);
                idx_image_size = i*phdr->DEMURA_TBL_H+j;

                pinfo->Lut_in[k][idx_image_size].dbr   = (double)LUT_data;
                pinfo->Lut_in[k][idx_image_size].dbg   = (double)LUT_data;
                pinfo->Lut_in[k][idx_image_size].dbb   = (double)LUT_data;
                #if (defined (CONFIG_DEMURA_M7622) || defined (CONFIG_DEMURA_M7632))
                pinfo->Lut_in[k][idx_image_size].dbw   = (double)LUT_data;
                #endif

                //LUT_data = LUT_data>>4; // 14bit -> 10bit
                pinfo->Lut_in[k][idx_image_size].r   = (int)LUT_data;
                pinfo->Lut_in[k][idx_image_size].g   = (int)LUT_data;
                pinfo->Lut_in[k][idx_image_size].b   = (int)LUT_data;
                #if (defined (CONFIG_DEMURA_M7622) || defined (CONFIG_DEMURA_M7632))
                pinfo->Lut_in[k][idx_image_size].w   = (int)LUT_data;
                #endif
            }
        }
    }

    #if(FORCE_TO_4_LAYER)
    int layer_size  = sizeof(strgb_structInfo) * 481 * 271;

    for(k = 0; k < 4; k++)
    {
        //pinfo->Lut_in[k] = pinfo->Lut_in[SDC_Select_Layer[k]-1];
        memcpy(pinfo->Lut_in[k], pinfo->Lut_in[SDC_Select_Layer[k]-1], layer_size);
    }

    #endif

    // Free buffer
    free(phdr->hdr_buffer);
    phdr->hdr_buffer = NULL;

    dfree(phdr->lut_buffer);
    phdr->lut_buffer = NULL;

    return TRUE;
}



MS_BOOL Decode_To_Mstar_Format(void *pdat_info, BinOutputInfo *pbin_info)
{
    MS_BOOL bRet;
    SDC_Demura_Header header;

    #if defined (CONFIG_DEMURA_URSA13)
    interface_info *pDataInfo = (interface_info *)pdat_info;
    #elif (defined (CONFIG_DEMURA_M7622) || defined (CONFIG_DEMURA_M7632))
    interface_info *pDataInfo = (interface_info *)pdat_info;
    #else
    #error "Unkown DEMURA_URSA_TYPE !"
    #endif

    // Parse header information
    memset(&header, 0, sizeof(header));
    if (load_vendor_header(&header) != TRUE)
    {
        printf("load_vendor_header Error\n");
        return FALSE;
    }

    if (parse_vendor_header(&header) != TRUE)
    {
        printf("parse_vendor_header Error\n");
        return FALSE;
    }

    if (load_vendor_lut(&header) != TRUE)
    {
        printf("load_vendor_lut Error\n");
        return FALSE;
    }

    Gen_Sf_Signature(&header);
    // Alloc space for Lut_in
    int n_Hnode = 481;
    int n_Vnode = 271;

    header.DEMURA_TBL_H = n_Hnode;
    header.DEMURA_TBL_V = n_Vnode;

    pDataInfo->reg_dmc_h_block            = 0x3;         //  3 bit
    pDataInfo->reg_dmc_v_block            = 0x3;         //  3 bit

    #if(FORCE_TO_4_LAYER)
    pDataInfo->reg_dmc_plane_num              = 4;//test MAX_PLANE_NUM;         //  4 bit
    #else
    pDataInfo->reg_dmc_plane_num              = MAX_PLANE_NUM;
    #endif
    pDataInfo->reg_dmc_rgb_mode               = 0x0;         //  1 bit
    pDataInfo->reg_dmc_panel_h_size           = 0xF00;       // 13 bit
    pDataInfo->reg_dmc_black_limit            = 0x000;       // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level1           = header.PLANE[0]<<4;       // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level2           = header.PLANE[1]<<4;       // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level3           = header.PLANE[2]<<4;       // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level4           = header.PLANE[3]<<4;       // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level5           = header.PLANE[4]<<4;           // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level6           = header.PLANE[5]<<4;           // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level7           = header.PLANE[6]<<4;           // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level8           = 0;           // 12 bit , format 10.2
    pDataInfo->reg_dmc_white_limit            = 0xFFF;       // 12 bit , format 10.2
    pDataInfo->reg_dmc_dither_en              = 0x1;         //  2 bit , 0 : rounding , 1 : dither , 2~3 : truncate
    pDataInfo->reg_dmc_dither_rst_e_4_frame   = 0x0;         //  1 bit
    pDataInfo->reg_dmc_dither_pse_rst_num     = 0x0;         //  2 bit

    // Init Output message
    pbin_info->HNode          = n_Hnode;
    pbin_info->VNode          = n_Vnode;
    pbin_info->LevelCount     = MAX_PLANE_NUM;//test pDataInfo->reg_dmc_plane_num;
    pbin_info->Blk_h_size     = 1 << (pDataInfo->reg_dmc_h_block);
    pbin_info->Blk_v_size     = 1 << (pDataInfo->reg_dmc_v_block);

    bRet = Alloc_LutIn_Space(pDataInfo, pbin_info);
    if (bRet == FALSE)
    {
        printf("Alloc_LutIn_Space error\n");
        return FALSE;
    }

    // Decode Vendor data
    bRet = SDC_Decode_To_Mstar_Format(&header, (interface_info *)pDataInfo);
    if (bRet == FALSE)
    {
        printf("SDC_Decode_To_Mstar_Format error\n");
        return FALSE;
    }

    #if(FORCE_TO_4_LAYER)
    pDataInfo->reg_dmc_plane_level1           = header.PLANE[SDC_Select_Layer[0]-1]<<4;       // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level2           = header.PLANE[SDC_Select_Layer[1]-1]<<4;       // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level3           = header.PLANE[SDC_Select_Layer[2]-1]<<4;       // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level4           = header.PLANE[SDC_Select_Layer[3]-1]<<4;       // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level5           = 0;           // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level6           = 0;           // 12 bit , format 10.2
    pDataInfo->reg_dmc_plane_level7           = 0;           // 12 bit , format 10.2
    #endif

    #if(CONFIG_DEMURA_URSA_TYPE == 13)
    MS_BOOL demura_enable[3]  = {TRUE, TRUE, TRUE};
    #else
    MS_BOOL demura_enable[4]  = {TRUE, TRUE, TRUE, TRUE};
    #endif

    pbin_info->reg_base_addr  =  0x7700;
    pbin_info->project_id     =  ((MSTAR_CHIP_ID << 16) + (1ULL << 15) + ID_CUS_MSTAR);
    pbin_info->data_type      =  IC_DRAM;
    pbin_info->Gain_type      =  10;
    pbin_info->Sep_type       =  0;
    pbin_info->Build_Date     =  0x19021814;

    memcpy(pbin_info->channel_enable, demura_enable, sizeof(demura_enable));

    return TRUE;
}


