/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein is
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
* the prior written permission of MediaTek inc. and/or its licensors, any
* reproduction, modification, use or disclosure of MediaTek Software, and
* information contained herein, in whole or in part, shall be strictly
* prohibited.
*
* Copyright  (C) [2020]  MediaTek Inc. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek
* Software") have been modified by MediaTek Inc. All revisions are subject to
* any receiver's applicable license agreements with MediaTek Inc.
*/

#include <common.h>
#include <command.h>
#include <dtbo.h>
#include <mtk_dtbo.h>
#include <debug_impl.h>
#include <overlay_setting.h>
#include <dtbo_cfg_sel.h>
#ifdef CONFIG_MULTIPLE_DTB_SELECTION
#include <environment.h>
#include <romtblo_impl.h>
#include <iniparser.h>
#include <fs.h>
#include <utility.h>
#include "secure_boot.h"
#include "secure/crypto_auth.h"
#include "secure/secure_common.h"
#include <image-android-dt.h>
#include <mapmem.h>
#include <dt_table.h>
#include <system_impl.h>
#ifdef CONFIG_DATA_SEPARATION
#include <mtk_dataindex.h>
#include <android_ab.h>
#endif
#if (CONFIG_AB_SIDELOAD == 1)
#include <mtk_ab.h>
#endif
#ifdef CONFIG_MULTICORES_PLATFORM
#include <smp/thread_info.h>
extern smp_spin_lock_t fs_spin_lock;
#endif

#include <linux/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <dm/uclass.h>
#include <dm/uclass-id.h>
#include <dm/device.h>
#include <sony_customer.h>
#include <mtk_dataindex.h>
#include <ecinfo.h>

#define KEY_SEPARATOR ":"
#define UnderLine "_"
static iniparser_handle_t dtbo_mapping = NULL;
static iniparser_handle_t dtbo_selection = NULL;
static iniparser_handle_t dtbo_whitelist = NULL;
static unsigned char *mapping_ini = NULL;
static unsigned char *selection_ini = NULL;
static unsigned char *whitelist_ini = NULL;
static unsigned int mapping_ini_size = 0;
static unsigned int selection_ini_size = 0;
static unsigned int whitelist_ini_size = 0;
static bool panel_auto_deteted = false;
static struct list_head dtbo_idx_list;
static int panel_mismatch = 0;

extern unsigned long long get_dram_size(void);


#if defined(CONFIG_LINUX_REF_PLATFORM)
#ifdef CONFIG_DATA_SEPARATION
#define MMAP_2G_STRING "_2g"
#define MMAP_1POINT5G_STRING "_1point5g"
#define MMAP_1G_STRING "_1g"
#endif
#endif

#ifdef CONFIG_MTK_AEE_SUPPORT
#define MMAP_AEE_TAG_STRING "AEE"
#endif

#define MT5873_PAD_BOND_BANK (0x100A)
#define MT5873_PAD_BOND_ADDR (0x0)
#define MT5873_PAD_HTC_SHIFT (0x4)
#define MT5873_PAD_HTC_MASK (0x1)
#define MT5873_PAD_PKG_SHIFT (0x8)
#define MT5873_PAD_PKG_MASK (0x1)
#define MT5873_PAD_EXT_SHIFT (0x6)
#define MT5873_PAD_EXT_MASK (0x1)
#define MT5873_BOND_NTC (0x0)
#define MT5873_BOND_HTC (0x1)
#define MT5873_PKG_SMALL (0x0)
#define MT5873_PKG_BIG (0x1)
#define MT5873_BOND_EXT (0x1)

#define DTBO_CALLBACK_MAX_NUM (32)
#define DTBO_CALLBACK_NAME_MAX_LEN (64)
typedef int (*dtbo_callback)(char*,int);

static dtbo_callback dtbo_callbacks[DTBO_CALLBACK_MAX_NUM] = {0};
static char dtbo_callback_section_name[DTBO_CALLBACK_MAX_NUM][DTBO_CALLBACK_NAME_MAX_LEN] = {{0}};
static unsigned int cur_dtbo_callback_number = 0;

static const char *_get_default_dtbo_cfg(const char *default_path)
{
	static char cfg_path[COMMAND_BUF_SIZE] = { 0 };
	u32 chipid = romtbl_get_chip_id_info_dec();
	u32 revision = romtbl_get_chip_revision_info();

	UBOOT_TRACE("IN\n");
	if (chipid == 0 || revision == 0) {
		UBOOT_ERROR("Wrong chip id/revision = %d/%d\n", chipid, revision);
		return default_path;
	}
    if (dtbo_cfg_sel_get_pcb(cfg_path, sizeof(cfg_path), chipid, revision))
    {
        UBOOT_TRACE("OUT\n");
        return (const char *)cfg_path;
    }
	UBOOT_TRACE("OUT\n");
    return default_path;
}

static int get_device_and_partition_info(char *partition, unsigned int device, char *device_name, char *storage_info)
{
	int ret;

	UBOOT_TRACE("IN\n");
	ret = sys_get_boot_device(device_name, STORAGE_DEVICE_BUF_SIZE);
	if(ret < 0){
		UBOOT_ERROR("Error: Get booting device name failure, Unknown storage device.\n");
		return -1;
	}

	ret = sys_get_storage_info(device,partition,storage_info);
	if(ret < 0){
		UBOOT_ERROR("Error: sys_get_storage_info failure\n");
		return -1;
	}
	UBOOT_TRACE("OUT\n");
	return 0;
}

static int dtb_cfg_exist_check(char *partition, char *path)
{
	char device_name[STORAGE_DEVICE_BUF_SIZE] = {0};
	unsigned int device = 0;
	char storage_info[STORAGE_INDEX_BUF_SIZE] = {0};
	int ret;
#ifdef CONFIG_MULTICORES_PLATFORM
	unsigned long irq_flag = 0;
#endif

	UBOOT_TRACE("IN\n");
	ret = get_device_and_partition_info(partition, device, device_name, storage_info);
	if(ret < 0){
		UBOOT_ERROR("Error: Get device & partition failure, Unknown storage & partition device.\n");
		return -1;
	}

#if defined(CONFIG_MULTICORES_PLATFORM)
	smp_spin_lock_save(&fs_spin_lock, irq_flag);
#endif
    if (fs_set_blk_dev(device_name, storage_info, FS_TYPE_ANY))
    {
#if defined(CONFIG_MULTICORES_PLATFORM)
        smp_spin_unlock_restore(&fs_spin_lock, irq_flag);
#endif
        UBOOT_ERROR("Error: partition select failure\n");
        return -1;
    }

	if (fs_exists(path) == 0){
#if defined(CONFIG_MULTICORES_PLATFORM)
		smp_spin_unlock_restore(&fs_spin_lock, irq_flag);
#endif
		UBOOT_ERROR("Error: %s/%s file does not exist\n",partition,path);
		return -1;
	}
#if defined(CONFIG_MULTICORES_PLATFORM)
	smp_spin_unlock_restore(&fs_spin_lock, irq_flag);
#endif

	UBOOT_TRACE("OUT\n");
	return 0;
}

#define DTBO_CFG_BUFFER_SIZE 128
static int get_customization_config_element(char *type, char *setting)
{
    struct section *section_entry;
    struct keyval_pair *keyval_entry;
    char *ptr;

    UBOOT_TRACE("IN\n");
    UBOOT_DEBUG("type=%s", type);
    iniparser_for_each_section(dtbo_selection, section_entry)
    {
        UBOOT_DEBUG("classification(%s):", section_entry->section);
        iniparser_for_each_keyval(section_entry, keyval_entry)
        {
            UBOOT_DEBUG("[%s]", keyval_entry->key);
            if (!strcmp(type, keyval_entry->key))
            {
                if (strlen(keyval_entry->value) < DTBO_CFG_BUFFER_SIZE)
                {
                    ptr = strncpy(setting, keyval_entry->value, strlen(keyval_entry->value));
                    setting[strlen(keyval_entry->value)] = '\0';
                    if (ptr == NULL)
                    {
                        UBOOT_ERROR("Error: Copy setting failure.\n");
                        UBOOT_TRACE("OUT\n");
                        return -1;
                    }
                }
                else
                {
                    ptr = strncpy(setting, keyval_entry->value, DTBO_CFG_BUFFER_SIZE - 1);
                    setting[DTBO_CFG_BUFFER_SIZE - 1] = '\0';
                    if (ptr == NULL)
                    {
                        UBOOT_ERROR("Error: Copy setting failure.\n");
                        UBOOT_TRACE("OUT\n");
                        return -1;
                    }
                }
                UBOOT_TRACE("OUT\n");
                return 0;
            }
        }
    }
    UBOOT_TRACE("OUT\n");
    return -1;
}

static int get_dtbo_mapping_table_info(char *partition, const char *path)
{
	int ret;
	loff_t size;
	unsigned char *file_buf;
	UBOOT_TRACE("IN\n");

	if(mapping_ini == NULL){
		file_buf = read_storage_file_to_memory(partition, path, &size);
		if(file_buf == NULL){
			UBOOT_ERROR("Error: %s/%s parse error occur\n",partition, path);
			return -1;
		}
		mapping_ini = (unsigned char *)malloc(size);
		if(mapping_ini != NULL){
			memcpy(mapping_ini, file_buf, (unsigned int)size);
			mapping_ini_size = (unsigned int)size;
		}
	}else{
		file_buf = (unsigned char *)malloc(mapping_ini_size);
		if(file_buf == NULL){
			UBOOT_ERROR("Error: allocate file_buf failure\n");
			return -1;
		}
		memcpy(file_buf, mapping_ini, (unsigned int)mapping_ini_size);
		size = mapping_ini_size;
	}

	if (dtbo_mapping){
		UBOOT_INFO("dtbo_mapping exist, destory and renew.\n");
		iniparser_destroy(dtbo_mapping);
	}

	ret = iniparser_create(file_buf, size, &dtbo_mapping);
	free(file_buf);

	if(ret < 0){
		UBOOT_ERROR("Error: dtbo_mapping_table iniparser_create failure\n");
		return -1;
	}
	UBOOT_TRACE("OUT\n");
	return 0;
}

static int get_dtbo_customization_config_info(char *partition, const char *path)
{
	int ret;
	loff_t size;
	unsigned char *file_buf;

	UBOOT_TRACE("IN\n");
	if(selection_ini == NULL){
		file_buf = read_storage_file_to_memory(partition, path, &size);
		if(file_buf == NULL){
			UBOOT_ERROR("Error: %s/%s parse error occur\n",partition, path);
			return -1;
		}
		selection_ini = (unsigned char *)malloc(size);
		if(selection_ini != NULL){
			memcpy(selection_ini, file_buf, (unsigned int)size);
			selection_ini_size = (unsigned int)size;
		}
	}else{
		file_buf = (unsigned char *)malloc(selection_ini_size);
		if(file_buf == NULL){
			UBOOT_ERROR("Error: allocate file_buf failure\n");
			return -1;
		}
		memcpy(file_buf, selection_ini, (unsigned int)selection_ini_size);
		size = selection_ini_size;
	}

	if (dtbo_selection){
		UBOOT_INFO("dtbo_mapping exist, destory and renew.\n");
		iniparser_destroy(dtbo_selection);
	}

	ret = iniparser_create(file_buf, size, &dtbo_selection);
	free(file_buf);

	if(ret < 0){
		UBOOT_ERROR("Error: dtbo_customization_config iniparser_create failure\n");
		return -1;
	}
	UBOOT_TRACE("OUT\n");
	return 0;
}

static int get_dtbo_whitelist_info(char *partition, const char *path)
{
	int ret;
	loff_t size;
	unsigned char *file_buf;

	UBOOT_TRACE("IN\n");
	if(whitelist_ini == NULL){
		file_buf = read_storage_file_to_memory(partition, path, &size);
		if(file_buf == NULL){
			UBOOT_ERROR("Error: %s/%s parse error occur\n",partition, path);
			return -1;
		}
		whitelist_ini = (unsigned char *)malloc(size);
		if(whitelist_ini != NULL){
			memcpy(whitelist_ini, file_buf, (unsigned int)size);
			whitelist_ini_size = (unsigned int)size;
		}
	}else{
		file_buf = (unsigned char *)malloc(whitelist_ini_size);
		if(file_buf == NULL){
			UBOOT_ERROR("Error: allocate file_buf failure\n");
			return -1;
		}
		memcpy(file_buf, whitelist_ini, (unsigned int)whitelist_ini_size);
		size = whitelist_ini_size;
	}

	if (dtbo_whitelist){
		UBOOT_INFO("dtbo_whitelist exist, destory and renew.\n");
		iniparser_destroy(dtbo_whitelist);
	}

	ret = iniparser_create(file_buf, size, &dtbo_whitelist);
	free(file_buf);

	if(ret < 0){
		UBOOT_ERROR("Error: dtbo_whitelist iniparser_create failure\n");
		return -1;
	}
	UBOOT_TRACE("OUT\n");
	return 0;
}

#ifdef CONFIG_DATA_SEPARATION
static int read_dtbo_ini_info(enum INI_FILE_TYPE type, char *section, char *key, char *part, char *env_name, char *default_ini)
#else
static int read_dtbo_ini_info(enum INI_FILE_TYPE type, char *part, char *env_name, char *default_ini)
#endif
{
	int ret = -1, len = 0;
    unsigned int chip = 0;
#ifdef CONFIG_DATA_SEPARATION
	char filepath[FILE_PATH_SIZE];
#else
	char filepath[STRING_BUFFER_SIZE];
#endif
	const char *ptr = NULL;

#ifdef CONFIG_DATA_SEPARATION
	char partition[STRING_BUFFER_SIZE];
	const char *relpath = NULL;
	memset(partition, 0, sizeof(partition));
	memset(filepath, 0, sizeof(filepath));

        /*
         * For OTA issue, some device might has dtbo_cfg_select setted, thus need to remove dtbo_cfg_select at OTA boot
         */
#if (CONFIG_AB_SIDELOAD == 1)
       if (!ab_get_slot_successful_boot())
       {
                UBOOT_INFO("After OTA done, enter the first time boot state\n");
                env_set(CFG_SEL_ENV_NAME, NULL);
                env_save();
                UBOOT_INFO("Remove debug use dtbo_cfg_sel parameter done\n");
       }
#endif

	/* TODO: remove this dtbo_cfg_sel env rule for one package
	 *       when auto-selection dtbo_cfg_sel for data separation is ready.
	 **/
	if (type == CFG_SELECT) {
		relpath = env_get(env_name);
		if (relpath) {
			if (!strncmp(relpath, DEFAULT_DTB_CFG_LABEL, sizeof(DEFAULT_DTB_CFG_LABEL)))
				relpath = _get_default_dtbo_cfg(relpath);
			strncpy(partition, part, sizeof(partition));
			partition[sizeof(partition)-1] = 0;
			UBOOT_DEBUG("use %s env to get %s\n", env_name, relpath);
                }
                else
                {
                        UBOOT_DEBUG("env is not set\n");
                }
        }

        if (!relpath)
        {
                // First to get path
                dataindex_get_key(filepath, FILE_PATH_SIZE, section, key, NULL);

                /* Check if the path is "default" or specified file path.
                 * Once the path is default then trigger auto select scheme
                 */
                if (!strncmp(filepath, DEFAULT_DTB_CFG_LABEL, sizeof(DEFAULT_DTB_CFG_LABEL)))
                {
                        UBOOT_INFO("[DATA_SEPARATION]Get filepath %s\n", filepath);
                        relpath = _get_default_dtbo_cfg(filepath);
                        strncpy(partition, part, sizeof(partition));
                        partition[sizeof(partition)-1] = 0;
                }
                else
                {
                        if (dataindex_resolve_path(partition, PART_NAME_SIZE, &relpath, filepath) != 0)
                        {
                                UBOOT_ERROR("[DATA_SEPARATION] Get partition, relpath failure base on filepath:%s.\n", filepath);
                                goto DATA_SEPARATION_FAIL;
                        }
                }

                UBOOT_INFO("use dataindex to get %s\n", relpath);
        }

        switch (type)
        {
                case DTB_MAPPING:
                        ret = get_dtbo_mapping_table_info(partition, relpath);
                        break;
                case WHITELIST:
                        ret = get_dtbo_whitelist_info(partition, relpath);
                        break;
                case CFG_SELECT:
                        ret = get_dtbo_customization_config_info(partition, relpath);
                        break;
                default:
                        UBOOT_ERROR("[DATA_SEPARATION] Input INI_FILE_TYPE type is not support.\n");
                        break;
        }

	if(ret < 0){
		UBOOT_ERROR("[DATA_SEPARATION][INI_FILE_TYPE:%d] Parse %s file under %s failure.\n",type,relpath,partition);
		goto DATA_SEPARATION_FAIL;
	}

	return 0;
DATA_SEPARATION_FAIL:
#endif
    chip = romtbl_get_chip_id_info_dec();
    if (chip == MEDIATEK_TV_CHIP_ID_MT5896 || chip == MEDIATEK_TV_CHIP_ID_MT5897)
    {
        memset(filepath, 0, sizeof(filepath));
        ptr = env_get(env_name);
        if (type == CFG_SELECT)
        {
            if (ptr == NULL)
            {
                ptr = _get_default_dtbo_cfg(ptr);
            }
            else if (!strncmp(ptr, DEFAULT_DTB_CFG_LABEL, sizeof(DEFAULT_DTB_CFG_LABEL)))
            {
                ptr = _get_default_dtbo_cfg(ptr);
            }
        }
        if (ptr == NULL)
        {
            UBOOT_DEBUG("%s env is not set, use default %s.\n", env_name, default_ini);
            ptr = default_ini;
        }
        if (sizeof(filepath) <= strlen(ptr))
            len = sizeof(filepath)-1;
        else
            len = strlen(ptr);
        if (len > 0)
        {
            strncpy(filepath, ptr, len);
            filepath[len] = '\0';
        }
        else
        {
            UBOOT_ERROR("filepath string length is not correct.\n");
            return -1;
        }

        if(type == DTB_MAPPING)
            ret = get_dtbo_mapping_table_info(part,filepath);
        else if(type == WHITELIST)
            ret = get_dtbo_whitelist_info(part,filepath);
        else if(type == CFG_SELECT)
            ret = get_dtbo_customization_config_info(part,filepath);
        else
            UBOOT_ERROR("Input INI_FILE_TYPE type is not support.\n");
        if (ret < 0)
        {
            UBOOT_ERROR("[INI_FILE_TYPE:%d] Parse %s file under %s failure.\n", type, filepath, part);
            return -1;
        }
        return 0;
    }
    else
    {
        UBOOT_DEBUG("Not execute dtb overlay for this chip, used offline dtb overlay by default\n");
        return -1;
    }
}

static void add_dtbo_idx_to_bootargs(int kernel_dtb_num)
{
	DTBO_IDX_T *pos, *n;
	char bootargs_dtbo_idx[] = ANDROID_BOOTARGS_DTBO_IDX;
	char key[KEY_BUFFER_SIZE]={0},set_cfg[STRING_BUFFER_SIZE]={0},id_str[DIGIT_NUM];
	char *key_value, *ret;
	int len;

	strncpy(key,bootargs_dtbo_idx,strlen(bootargs_dtbo_idx));
	key[strlen(bootargs_dtbo_idx)] = '\0';
	if(kernel_dtb_num > 0){
		key_value = (char *)malloc(kernel_dtb_num*DIGIT_NUM);
		if(key_value != NULL){
			memset(key_value, 0, kernel_dtb_num*DIGIT_NUM);
			list_for_each_entry_safe(pos, n, &dtbo_idx_list, list){
				memset(id_str, 0, sizeof(id_str));
				len = snprintf(id_str, sizeof(id_str)-1, "%d", pos->dtbo_id);
				if(len > 0){
					ret = strncat(key_value, id_str, strlen(id_str));
					if(ret == NULL)
						UBOOT_DEBUG("Set key_value failure\n");
					UBOOT_DEBUG("Set key_value:%s as %s\n",ANDROID_BOOTARGS_DTBO_IDX,key_value);
					kernel_dtb_num--;
					if(kernel_dtb_num > 0)
						strncat(key_value, ",", 1);
				}
			}
			len = snprintf(set_cfg, sizeof(set_cfg)-1,"%s=%s",key,key_value);
			if (len >= (sizeof(set_cfg)-1))
				UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", (int)(sizeof(set_cfg)-1), set_cfg);
			free(key_value);
		}else{
			UBOOT_ERROR("Heap memory is not enough\n");
			len = snprintf(set_cfg, sizeof(set_cfg)-1,"%s=%d",key,0);
			if (len >= (sizeof(set_cfg)-1))
				UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", (int)(sizeof(set_cfg)-1), set_cfg);
		}
	}else{
		UBOOT_ERROR("kernel_dtb_num is zero, kernel dtb overlay selection failure occur\n");
		len = snprintf(set_cfg, sizeof(set_cfg)-1,"%s=%d",key,0);
			if (len >= (sizeof(set_cfg)-1))
				UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", (int)(sizeof(set_cfg)-1), set_cfg);
	}

	add_bootargs(key,set_cfg,0);
	list_for_each_entry_safe(pos, n, &dtbo_idx_list, list)
		free(pos);
}

int get_dtbo_cfg_selection(char *partition, char *cfg_name, char *type, char *setting)
{
	int ret;
	char *name;

	UBOOT_TRACE("IN\n");
	if(cfg_name == NULL){
		UBOOT_ERROR("cfg_name name is NULL\n");
		return -1;
	}

	ret = get_dtbo_customization_config_info(partition,cfg_name);
	if(ret < 0){
		UBOOT_ERROR("Parse %s file failure\n",cfg_name);
		return -1;
	}

	ret = get_customization_config_element(type, setting);
	if(ret < 0){
		UBOOT_ERROR("Error: Get type and setting error occur\n");
		return -1;
	}

	if (strcmp(type, "panel") == 0)
	{
		name = get_panel_id();
		if (name != NULL)
		{
			strncpy(setting, name, strlen(name));
			setting[strlen(name)] = '\0';
		}
	}

	UBOOT_TRACE("OUT\n");
	return 0;
}

int set_dtbo_cfg_selection(char *partition, char *cfg_name)
{
	UBOOT_TRACE("IN\n");
	if(cfg_name == NULL){
		UBOOT_ERROR("cfg_name name is NULL\n");
		return -1;
	}

	if(dtb_cfg_exist_check(partition, cfg_name) != 0){
		UBOOT_ERROR("Error: User select cfg not exist\n");
		return -1;
	}

	env_set("dtbo_cfg_sel",cfg_name);
	env_save();
	UBOOT_TRACE("OUT\n");
	return 0;
}

int ls_dtbo_cfg(char *partition)
{
	char device_name[STORAGE_DEVICE_BUF_SIZE] = {0};
	unsigned int device = 0;
	char storage_info[STORAGE_INDEX_BUF_SIZE] = {0};
	char folder_path[STORAGE_DEVICE_BUF_SIZE] = {0};
	int ret;
#ifdef CONFIG_MULTICORES_PLATFORM
	unsigned long irq_flag = 0;
#endif

	UBOOT_TRACE("IN\n");
	strncpy(folder_path,"dtb", sizeof(folder_path));
	ret = get_device_and_partition_info(partition, device, device_name, storage_info);
	if(ret < 0){
		UBOOT_ERROR("Error: Get device & partition failure, Unknown storage & partition device.\n");
		return -1;
	}

#if defined(CONFIG_MULTICORES_PLATFORM)
	smp_spin_lock_save(&fs_spin_lock, irq_flag);
#endif
    if (fs_set_blk_dev(device_name, storage_info, FS_TYPE_ANY))
    {
#if defined(CONFIG_MULTICORES_PLATFORM)
        smp_spin_unlock_restore(&fs_spin_lock, irq_flag);
#endif
        UBOOT_ERROR("Error: partition select failure\n");
        return -1;
    }

	if (fs_ls(folder_path)){
#if defined(CONFIG_MULTICORES_PLATFORM)
		smp_spin_unlock_restore(&fs_spin_lock, irq_flag);
#endif
		UBOOT_ERROR("Error: file list failure\n");
		return -1;
	}
#if defined(CONFIG_MULTICORES_PLATFORM)
	smp_spin_unlock_restore(&fs_spin_lock, irq_flag);
#endif
	UBOOT_TRACE("OUT\n");
	return 0;
}

static dtbo_callback dtbo_get_auto_detection_callback(char* section_name)
{
	unsigned int i = 0;

	if (section_name == NULL)
		return NULL;

	for (i = 0; i< cur_dtbo_callback_number; i++){
		if (strncmp(section_name, dtbo_callback_section_name[i], DTBO_CALLBACK_NAME_MAX_LEN) == 0){
			return dtbo_callbacks[i];
		}
	}

	return NULL;
}

int set_panel_mismatch_status(char *status, char *name)
{
	UBOOT_DEBUG("##call status = %s, name = %s.\n", status, PANEL_MISMATCH);
	char command[COMMAND_BUF_SIZE] = {0};
	int ret = 0;
	ret = snprintf(command, COMMAND_BUF_SIZE, "setenv %s %s", PANEL_MISMATCH, status);
	if (ret >= COMMAND_BUF_SIZE)
	{
		UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", COMMAND_BUF_SIZE, command);
		return CMD_RET_FAILURE;
	}
	ret = run_command(command, 0);
	if (ret != CMD_RET_SUCCESS)
	{
		UBOOT_ERROR("Error: setenv %s fail\n", PANEL_MISMATCH);
		return CMD_RET_FAILURE;
	}
	return ret;
}

int set_panel_id(char *name)
{
	char command[COMMAND_BUF_SIZE] = {0};
	int ret;
/*
	ret = snprintf(command, COMMAND_BUF_SIZE, "setenv %s %s", PANEL_MISMATCH, status);
	if (ret >= COMMAND_BUF_SIZE)
	{
		UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", COMMAND_BUF_SIZE, command);
		return CMD_RET_FAILURE;
	}
	ret = run_command(command, 0);
	if (ret != CMD_RET_SUCCESS)
	{
		UBOOT_ERROR("Error: setenv %s fail\n", PANEL_MISMATCH);
		return CMD_RET_FAILURE;
	}

	ret = snprintf(command, COMMAND_BUF_SIZE, "addbootargs %s %s", PANEL_MISMATCH, status);
	if (ret >= COMMAND_BUF_SIZE)
	{
		UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", COMMAND_BUF_SIZE, command);
		return CMD_RET_FAILURE;
	}
	ret = run_command(command, 0);
	if (ret != CMD_RET_SUCCESS)
	{
		UBOOT_ERROR("Error: addbootargs %s fail\n", PANEL_MISMATCH);
		return CMD_RET_FAILURE;
	}
*/
	ret = snprintf(command, COMMAND_BUF_SIZE, "addbootargs %s %s", PANEL_ID, name);
	if (ret >= COMMAND_BUF_SIZE)
	{
		UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", COMMAND_BUF_SIZE, command);
		return CMD_RET_FAILURE;
	}
	ret = run_command(command, 0);
	if (ret != CMD_RET_SUCCESS)
	{
		UBOOT_ERROR("Error: addbootargs %s fail\n", PANEL_ID);
		return CMD_RET_FAILURE;
	}
/*
	ret = snprintf(command, COMMAND_BUF_SIZE, "addbootargs firmware_class.path /vendor/firmware/,/vendor/tvconfig/frc/");
	if (ret >= COMMAND_BUF_SIZE)
	{
		UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", COMMAND_BUF_SIZE, command);
		return CMD_RET_FAILURE;
	}
	ret = run_command(command, 0);
	if (ret != CMD_RET_SUCCESS)
	{
		UBOOT_ERROR("Error: addbootargs firmware_class.path fail\n");
		return CMD_RET_FAILURE;
	}
	printf("Change FRC Path to /vendor/tvconfig/frc/\n");
*/
	return ret;
}

int get_device_id(char *classification, char *static_name)
{
	unsigned long id;
	struct section *section_entry;
	struct keyval_pair *keyval_entry;
	char* name = static_name;
	char detected_name[DTBO_CALLBACK_NAME_MAX_LEN] = {0};
	dtbo_callback callback = NULL;
	unsigned long id_num[128] = {0};
	char *chassis_index_str;
	int chassis_index, chassis_index_min=127;
	char *panel_id_str = static_name;

	UBOOT_TRACE("IN\n");
	UBOOT_DEBUG("[dtbo_class=%s, dtbo_name=%s]\n", classification, static_name);

	callback = dtbo_get_auto_detection_callback(classification);

	if (callback){
		if (callback(detected_name, DTBO_CALLBACK_NAME_MAX_LEN)){
			panel_auto_deteted = false;
			UBOOT_DEBUG("auto_detection failed @ %s \n", classification);
		} else {
			panel_auto_deteted = true;
			name = detected_name;
			UBOOT_INFO("use detected name %s\n", name);
		}
	}

	iniparser_for_each_section(dtbo_mapping, section_entry) {
		if (strncmp(section_entry->section, classification, strlen(classification)) == 0 && strlen(section_entry->section) == strlen(classification)) {
			iniparser_for_each_keyval(section_entry, keyval_entry) {
				UBOOT_INFO("[%s][%s=%s]\n", section_entry->section, keyval_entry->key, keyval_entry->value);
				if (strncmp(keyval_entry->key, name, strlen(name)) == 0 && strlen(keyval_entry->key) == strlen(name)) {
					id = simple_strtoul(keyval_entry->value, NULL, DIGIT_NUM);
					UBOOT_DEBUG("[dtbo_class=%s, dtbo_name=%s][dtbo_id=%lu]\n",
								classification, keyval_entry->key, id);
					if (strncmp("panel", classification, strlen(classification)) == 0)
					{
						if (panel_auto_deteted == true)
						{
							set_panel_id(get_panel_id());
						}else{
							set_panel_id(name);
						}
						panel_mismatch = 0;
						set_panel_mismatch_status("0", PANEL_MISMATCH);
					}
					UBOOT_TRACE("OUT\n");
					return id;
				}
			}
			//panel mismatch handle
			if (strncmp("panel", classification, strlen(classification)) == 0)
			{
				keyval_entry = NULL;
				iniparser_for_each_keyval(section_entry, keyval_entry) {
					UBOOT_INFO("[%s][%s=%s]\n", section_entry->section, keyval_entry->key, keyval_entry->value);
					if (strncmp(keyval_entry->key, get_panel_id(), strlen(get_panel_id())) == 0) {
						chassis_index_str = keyval_entry->key + strlen(get_panel_id()) + 1;
						chassis_index = (int)simple_strtoul(chassis_index_str, NULL, DIGIT_NUM);
						id = simple_strtoul(keyval_entry->value, NULL, DIGIT_NUM);
						id_num[chassis_index] = id;
						if (get_tconless_status() == 0)  //tconless board chassis_index must larger than or equal to 10
						{
							if (chassis_index < 10)
							{
								continue;
							}
						}else{
							if (chassis_index > 9)  //tcon board chassis_index must lower than 10
							{
								continue;
							}
						}
						if(chassis_index < chassis_index_min)
						{
							chassis_index_min = chassis_index;
							strncpy(panel_id_str, keyval_entry->key, strlen(keyval_entry->key));
						}
						UBOOT_INFO("[dtbo_class=%s, dtbo_name=%s][dtbo_id=%lu] panel_id:%s chassis_index_str:%s chassis_index:%d chassis_index_min:%d\n",
									classification, keyval_entry->key, id, get_panel_id(), chassis_index_str, chassis_index, chassis_index_min);
					}
				}

				if (id_num[chassis_index_min] != 0)
				{
					set_panel_id(panel_id_str);
					panel_mismatch = 0;
					UBOOT_TRACE("OUT\n");
					return id_num[chassis_index_min];
				}

				keyval_entry = NULL;
				iniparser_for_each_keyval(section_entry, keyval_entry) {
					UBOOT_INFO("[%s][%s=%s]\n", section_entry->section, keyval_entry->key, keyval_entry->value);
					if (strncmp(keyval_entry->key, static_name, strlen(static_name)) == 0 && strlen(keyval_entry->key) == strlen(static_name)) {
						id = simple_strtoul(keyval_entry->value, NULL, DIGIT_NUM);
						UBOOT_DEBUG("[dtbo_class=%s, dtbo_name=%s][dtbo_id=%lu]\n",
									classification, keyval_entry->key, id);
						set_panel_id(static_name);
						panel_mismatch = 1;
						set_panel_mismatch_status("1", PANEL_MISMATCH);
						UBOOT_TRACE("OUT\n");
						return id;
					}
				}
			}
			UBOOT_ERROR("[dtbo_class=%s, dtbo_name=%s][not found!]\n",
						classification, name);
			UBOOT_TRACE("OUT\n");
			return -1;
		}
	}
	UBOOT_ERROR("[dtbo_class=%s, dtbo_name=%s][not found!]\n",
				classification, name);
	UBOOT_TRACE("OUT\n");
	return -1;
}

#if defined(CONFIG_LINUX_REF_PLATFORM)
static int mmap_auto_detection_callback_linux_ref(char* detected_name, int size)
{
#ifdef CONFIG_DATA_SEPARATION
    //Linux platform
    static unsigned long long dram_size = 1;
    char mmap_size_string[STRING_BUFFER_SIZE];
    char mmap_auto_detect[STRING_BUFFER_SIZE];
    char mmap_auto_detect_prefix[STRING_BUFFER_SIZE];
    char mmap_auto_detect_postfix[STRING_BUFFER_SIZE];
    UBOOT_DEBUG("MMAP auto detection - Linux-Ref\n");
    {
        dram_size = get_dram_size();
        memset(detected_name, 0, size);
        memset(mmap_size_string, 0, STRING_BUFFER_SIZE);
        memset(mmap_auto_detect, 0, STRING_BUFFER_SIZE);
        memset(mmap_auto_detect_prefix, 0, STRING_BUFFER_SIZE);
        memset(mmap_auto_detect_postfix, 0, STRING_BUFFER_SIZE);

        if (dataindex_get_key(mmap_auto_detect, STRING_BUFFER_SIZE, DTB_OVERLAY_SECTION, MMAP_AUTO_DETECT_KEY, NULL) != 0)
        {
            UBOOT_DEBUG("Can't get %s. Disable MMAP auto detect.\n", MMAP_AUTO_DETECT_KEY);
            return 1;
        }

        if(strncmp(mmap_auto_detect, MMAP_AUTO_DETECT_VALUE_ENABLE, strlen(MMAP_AUTO_DETECT_VALUE_ENABLE)) != 0 ||
                strlen(mmap_auto_detect) != strlen(MMAP_AUTO_DETECT_VALUE_ENABLE))
        {
            UBOOT_DEBUG("%s is %s. Disable MMAP auto detect.\n", MMAP_AUTO_DETECT_VALUE_ENABLE, mmap_auto_detect);
            return 1;
        }

        if (dataindex_get_key(mmap_auto_detect_prefix, STRING_BUFFER_SIZE, DTB_OVERLAY_SECTION, MMAP_AUTO_DETECT_PREFIX_KEY, NULL) != 0)
        {
            UBOOT_DEBUG("Can't get %s.\n", MMAP_AUTO_DETECT_PREFIX_KEY);
        }

        if (dataindex_get_key(mmap_auto_detect_postfix, STRING_BUFFER_SIZE, DTB_OVERLAY_SECTION, MMAP_AUTO_DETECT_POSTFIX_KEY, NULL) != 0)
        {
            UBOOT_DEBUG("Can't get %s.\n", MMAP_AUTO_DETECT_POSTFIX_KEY);
        }

        UBOOT_DEBUG("MMAP prefix=\"%s\" postfix=\"%s\"\n", mmap_auto_detect_prefix, mmap_auto_detect_postfix);
        if (MT5873 == romtbl_get_chip_id_info())
        {
            if (dram_size == SIZE_2G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 2GB\n");
                strncpy(mmap_size_string, MMAP_2G_STRING, strlen(MMAP_2G_STRING));
            }
            else if (dram_size == SIZE_1p5G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 1.5GB\n");
                strncpy(mmap_size_string, MMAP_1POINT5G_STRING, strlen(MMAP_1POINT5G_STRING));

                // Add for ASYM alloc w/ VMSPLIT_2_5G
                add_bootargs("vmalloc", "vmalloc=648M", 0);
                add_bootargs("movablecore", "movablecore=568M", 0);
            }
            else if (dram_size == SIZE_1G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 1GB\n");
                strncpy(mmap_size_string, MMAP_1G_STRING, strlen(MMAP_1G_STRING));
            }
            else
            {
                UBOOT_DEBUG("WARNING: DRAM auto detection failed! Un-supported DRAM size = 0x%llx\n", dram_size);
                return 1;
            }

            strncpy(detected_name, "mmap_mt5873", size-1);
            if (strlen(mmap_auto_detect_prefix) > 0)
            {
                strncat(detected_name, "_", 1);
                strncat(detected_name, mmap_auto_detect_prefix, strlen(mmap_auto_detect_prefix));
            }
            strncat(detected_name, mmap_size_string, strlen(mmap_size_string));
            if (strlen(mmap_auto_detect_postfix) > 0)
            {
                strncat(detected_name, "_", 1);
                strncat(detected_name, mmap_auto_detect_postfix, strlen(mmap_auto_detect_postfix));
            }
            UBOOT_DEBUG("detected_name:%s\n",detected_name);
            return 0;
        }
        else
        {
            UBOOT_DEBUG("WARNING: DRAM auto detection failed! Un-supported chip ID = %d\n", romtbl_get_chip_id_info());
            return 1;
        }
    }
#else
    UBOOT_DEBUG("CONFIG_DATA_SEPARATION is disable. Not support MMAP auto detect.\n");
    return 1;
#endif
}
#endif

/*
 return 0: success
 return otherwise: fail
*/
static int mmap_auto_detection_callback(char* detected_name, int size)
{
#if defined(CONFIG_ANDROID_CN_PLATFORM) || defined(CONFIG_ANDROID_WW_PLATFORM)
    static unsigned long long dram_size = 1;
    UBOOT_DEBUG("MMAP auto detection - AOSP\n");
    {
        dram_size = get_dram_size();
        memset(detected_name, 0, size);

        if (MT5879 == romtbl_get_chip_id_info())
        {
#ifdef AOSP_ONE_IMAGE_SUPPORT
            if (dram_size == SIZE_4G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 4GB\n");
#ifdef COMMERCIAL_DISPLAY_SUPPORT
                strncpy(detected_name, "mmap_mt5879_h1v1_aosp_4g_iommu_cd", size-1);
#else
                strncpy(detected_name, "mmap_mt5879_h1v1_aosp_4g_iommu", size-1);
#endif
                return 0;
            }
            else if (dram_size == SIZE_3G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 3GB\n");
#ifdef COMMERCIAL_DISPLAY_SUPPORT
                strncpy(detected_name, "mmap_mt5879_h1v1_aosp_3g_iommu_cd", size-1);
#else
                strncpy(detected_name, "mmap_mt5879_h1v1_aosp_3g_iommu", size-1);
#endif
                return 0;
            }
            else if (dram_size == SIZE_6G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 6GB\n");
                strncpy(detected_name, "mmap_mt5879_h1v1_aosp_6g_iommu", size-1);
                return 0;
            }
            else if (dram_size == SIZE_8G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 8GB\n");
                strncpy(detected_name, "mmap_mt5879_h1v1_aosp_8g_iommu", size-1);
                return 0;
            }
#else
            UBOOT_DEBUG("AOSP_ONE_IMAGE_SUPPORT is not supported\n");
#endif

#ifdef AOW_ONE_IMAGE_SUPPORT
            if (dram_size == SIZE_4G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 4GB\n");
#ifdef EDLA_SUPPORT
                strncpy(detected_name, "mmap_mt5879_h1v1_aosp_4g_iommu_cd", size-1);
#else
                strncpy(detected_name, "mmap_mt5879_h1v1_aow_4g_iommu", size-1);
#endif
                return 0;
            }
            else if (dram_size == SIZE_3G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 3GB\n");
                strncpy(detected_name, "mmap_mt5879_h1v1_aow_3g_iommu", size-1);
                return 0;
            }
            else if (dram_size == SIZE_8G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 8GB\n");
#ifdef EDLA_SUPPORT
                strncpy(detected_name, "mmap_mt5879_h1v1_aosp_8g_iommu_cd", size-1);
#endif
                return 0;
            }
#else
            UBOOT_DEBUG("AOW_ONE_IMAGE_SUPPORT is not supported\n");
#endif

        }
        else if (MT5873 == romtbl_get_chip_id_info())
        {
#if defined(AOSP_ONE_IMAGE_SUPPORT) || defined(AOW_ONE_IMAGE_SUPPORT)
            if (dram_size == SIZE_2G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 2GB\n");
#ifdef COMMERCIAL_DISPLAY_SUPPORT
                strncpy(detected_name, "mmap_mt5873_h1v1_an_2g_iommu_cd", size-1);
#else
                strncpy(detected_name, "mmap_mt5873_h1v1_an_2g_iommu", size-1);
#endif
#ifdef CONFIG_MTK_AEE_SUPPORT
                strncat(detected_name, "_", 1);
                strncat(detected_name, MMAP_AEE_TAG_STRING, strlen(MMAP_AEE_TAG_STRING));
#endif
                return 0;
            }
            else if (dram_size == SIZE_1p5G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 1.5GB\n");
                strncpy(detected_name, "mmap_mt5873_h1v1_an_1point5g_iommu", size-1);
                return 0;
            }
            else if (dram_size == SIZE_1G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 1GB\n");
                strncpy(detected_name, "mmap_mt5873_h1v1_an_1g_iommu", size-1);
                return 0;
            }
            else if (dram_size == SIZE_4G)
            {
#ifdef COMMERCIAL_DISPLAY_SUPPORT
                strncpy(detected_name, "mmap_mt5873_h1v1_an_4g_iommu_cd", size-1);
#else
                strncpy(detected_name, "mmap_mt5873_h1v1_an_4g_iommu", size-1);
#endif
#ifdef CONFIG_MTK_AEE_SUPPORT
                strncat(detected_name, "_", 1);
                strncat(detected_name, MMAP_AEE_TAG_STRING, strlen(MMAP_AEE_TAG_STRING));
#endif
                return 0;
            }
            else if (dram_size == SIZE_3G)
            {
#ifdef COMMERCIAL_DISPLAY_SUPPORT
                strncpy(detected_name, "mmap_mt5873_h1v1_an_3g_iommu_cd", size-1);
#else
                strncpy(detected_name, "mmap_mt5873_h1v1_an_3g_iommu", size-1);
#endif
#ifdef CONFIG_MTK_AEE_SUPPORT
                strncat(detected_name, "_", 1);
                strncat(detected_name, MMAP_AEE_TAG_STRING, strlen(MMAP_AEE_TAG_STRING));
#endif
                return 0;
            }
            else
                UBOOT_DEBUG("AOSP_ONE_IMAGE_SUPPORT is failed\n");
#else
            UBOOT_DEBUG("AOSP_ONE_IMAGE_SUPPORT is not supported\n");
#endif
        }
        else
        {
            if (dram_size == SIZE_6G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 6GB\n");
                strncpy(detected_name, "mmap_mt5896_h1v1_an_6g", size-1);
                return 0;
            }
            else if (dram_size == SIZE_8G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 8GB\n");
                strncpy(detected_name, "mmap_mt5896_h1v1_an_8g", size-1);

                /* Add for ASYM alloc */
                add_bootargs("movablecore", "movablecore=2G", 0);
                return 0;
            }
        }

        UBOOT_DEBUG("WARNING: DRAM auto detection failed! Un-supported DRAM size = 0x%llx\n", dram_size);
        return 1;
    }
#elif defined(CONFIG_LINUX_REF_PLATFORM)
    if (mmap_auto_detection_callback_linux_ref(detected_name, size) == 0)
    {
        UBOOT_DEBUG("Linux-Ref MMAP detect %s\n", detected_name);
        return 0;
    }
    else
    {
        UBOOT_DEBUG("Linux-Ref MMAP detect failed\n");
        return 1;
    }
#else
    UBOOT_DEBUG("MMAP auto detection\n");
    UBOOT_DEBUG("To be implemented\n");
    return 1;
#endif
}

#if defined(CONFIG_LINUX_REF_PLATFORM)
static int reserved_memory_auto_detection_linux_ref(char* detected_name, int size)
{
#ifdef CONFIG_DATA_SEPARATION
    //Linux platform
    static unsigned long long dram_size = 1;
    char mmap_size_string[STRING_BUFFER_SIZE];
    char mmap_auto_detect[STRING_BUFFER_SIZE];
    char mmap_auto_detect_prefix[STRING_BUFFER_SIZE];
    char mmap_auto_detect_postfix[STRING_BUFFER_SIZE];
    UBOOT_DEBUG("resv_mem auto detection - Linux-Ref\n");
    {
        dram_size = get_dram_size();
        memset(detected_name, 0, size);
        memset(mmap_size_string, 0, STRING_BUFFER_SIZE);
        memset(mmap_auto_detect, 0, STRING_BUFFER_SIZE);
        memset(mmap_auto_detect_prefix, 0, STRING_BUFFER_SIZE);
        memset(mmap_auto_detect_postfix, 0, STRING_BUFFER_SIZE);

        if (dataindex_get_key(mmap_auto_detect, STRING_BUFFER_SIZE, DTB_OVERLAY_SECTION, MMAP_AUTO_DETECT_KEY, NULL) != 0)
        {
            UBOOT_DEBUG("Can't get %s. Disable resv_mem auto detect.\n", MMAP_AUTO_DETECT_KEY);
            return 1;
        }

        if(strncmp(mmap_auto_detect, MMAP_AUTO_DETECT_VALUE_ENABLE, strlen(MMAP_AUTO_DETECT_VALUE_ENABLE)) != 0 ||
                strlen(mmap_auto_detect) != strlen(MMAP_AUTO_DETECT_VALUE_ENABLE))
        {
            UBOOT_DEBUG("%s is %s. Disable resv_mem auto detect.\n", MMAP_AUTO_DETECT_VALUE_ENABLE, mmap_auto_detect);
            return 1;
        }

        if (dataindex_get_key(mmap_auto_detect_prefix, STRING_BUFFER_SIZE, DTB_OVERLAY_SECTION, MMAP_AUTO_DETECT_PREFIX_KEY, NULL) != 0)
        {
            UBOOT_DEBUG("Can't get %s.\n", MMAP_AUTO_DETECT_PREFIX_KEY);
        }

        if (dataindex_get_key(mmap_auto_detect_postfix, STRING_BUFFER_SIZE, DTB_OVERLAY_SECTION, MMAP_AUTO_DETECT_POSTFIX_KEY, NULL) != 0)
        {
            UBOOT_DEBUG("Can't get %s.\n", MMAP_AUTO_DETECT_POSTFIX_KEY);
        }

        UBOOT_DEBUG("resv_mem prefix=\"%s\" postfix=\"%s\"\n", mmap_auto_detect_prefix, mmap_auto_detect_postfix);

        if (MT5873 == romtbl_get_chip_id_info())
        {
            if (dram_size == SIZE_2G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 2GB\n");
                strncpy(mmap_size_string, MMAP_2G_STRING, strlen(MMAP_2G_STRING));
            }
            else if (dram_size == SIZE_1p5G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 1.5GB\n");
                strncpy(mmap_size_string, MMAP_1POINT5G_STRING, strlen(MMAP_1POINT5G_STRING));
            }
            else if (dram_size == SIZE_1G)
            {
                UBOOT_DEBUG("WARNING: DRAM size is 1GB\n");
                strncpy(mmap_size_string, MMAP_1G_STRING, strlen(MMAP_1G_STRING));
            }
            else
            {
                UBOOT_DEBUG("WARNING: DRAM auto detection (resv_mem) failed! Un-supported DRAM size = 0x%llx\n", dram_size);
                return 1;
            }

            strncpy(detected_name, "resv_mem_mt5873", size-1);
            if (strlen(mmap_auto_detect_prefix) > 0)
            {
                strncat(detected_name, "_", 1);
                strncat(detected_name, mmap_auto_detect_prefix, strlen(mmap_auto_detect_prefix));
            }
            strncat(detected_name, mmap_size_string, strlen(mmap_size_string));
            if (strlen(mmap_auto_detect_postfix) > 0)
            {
                strncat(detected_name, "_", 1);
                strncat(detected_name, mmap_auto_detect_postfix, strlen(mmap_auto_detect_postfix));
            }
            UBOOT_DEBUG("detected_name:%s\n",detected_name);
            return 0;
        }
        else
        {
            UBOOT_DEBUG("WARNING: DRAM auto detection (resv_mem) failed! Un-supported chip ID = %d\n", romtbl_get_chip_id_info());
            return 1;
        }
    }
#else
    UBOOT_DEBUG("CONFIG_DATA_SEPARATION is disable. Not support DRAM auto detection (resv_mem).\n");
    return 1;
#endif
}
#endif

/*
 return 0: success
 return otherwise: fail
*/
static int reserved_memory_auto_detection_callback\
(char* detected_name, int size)
{
#if defined(CONFIG_ANDROID_CN_PLATFORM) || defined(CONFIG_ANDROID_WW_PLATFORM)
	static unsigned long long dram_size = 1;
	UBOOT_DEBUG("resv_mem auto detection - AOSP\n");
	{
		dram_size = get_dram_size();
		memset(detected_name, 0, size);

		if (MT5879 == romtbl_get_chip_id_info())
		{
#ifdef AOSP_ONE_IMAGE_SUPPORT
			if (dram_size == SIZE_4G)
			{
				UBOOT_DEBUG("WARNING: DRAM size is 4GB\n");
#ifdef EDLA_SUPPORT
                                strlcpy(detected_name, "resv_mem_mt5879_h1v1_aosp_4g_iommu_cd", size-1);
#else
                                strlcpy(detected_name, "resv_mem_mt5879_h1v1_aosp_4g_iommu", size-1);
#endif
				return 0;
			}
			else if (dram_size == SIZE_3G)
			{
				UBOOT_DEBUG("WARNING: DRAM size is 3GB\n");
				strlcpy(detected_name, "resv_mem_mt5879_h1v1_aosp_3g_iommu", size-1);
				return 0;
			}
			else if (dram_size == SIZE_6G)
			{
				UBOOT_DEBUG("WARNING: DRAM size is 6GB\n");
				strlcpy(detected_name, "resv_mem_mt5879_h1v1_aosp_6g_iommu", size-1);
				return 0;
			}
                        else if (dram_size == SIZE_8G)
                        {
                                 UBOOT_DEBUG("WARNING: DRAM size is 8GB\n");
#ifdef EDLA_SUPPORT
                                 strlcpy(detected_name, "resv_mem_mt5879_h1v1_aosp_8g_iommu_cd", size-1);
#else
                                 strlcpy(detected_name, "resv_mem_mt5879_h1v1_aosp_8g_iommu", size-1);
#endif
                                 return 0;
                        }
#else
			UBOOT_DEBUG("AOSP_ONE_IMAGE_SUPPORT is not supported\n");
#endif

#ifdef AOW_ONE_IMAGE_SUPPORT
                        if (dram_size == SIZE_4G)
                        {
                                UBOOT_DEBUG("WARNING: DRAM size is 4GB\n");
#ifdef EDLA_SUPPORT
                                strlcpy(detected_name, "resv_mem_mt5879_h1v1_aosp_4g_iommu_cd", size-1);
#else
                                strlcpy(detected_name, "resv_mem_mt5879_h1v1_aow_4g_iommu", size-1);
#endif
                                return 0;
                        }
                        else if (dram_size == SIZE_3G)
                        {
                                UBOOT_DEBUG("WARNING: DRAM size is 3GB\n");
                                strlcpy(detected_name, "resv_mem_mt5879_h1v1_aow_3g_iommu", size-1);
                                return 0;
                        }
                        else if (dram_size == SIZE_8G)
                        {
#ifdef EDLA_SUPPORT
                                UBOOT_DEBUG("WARNING: DRAM size is 8GB\n");
                                strlcpy(detected_name, "resv_mem_mt5879_h1v1_aosp_8g_iommu_cd", size-1);
#endif
                                return 0;
                        }
#else
                        UBOOT_DEBUG("AOW_ONE_IMAGE_SUPPORT is not supported\n");
#endif
		}
        else if (MT5873 == romtbl_get_chip_id_info())
        {
#if defined(AOSP_ONE_IMAGE_SUPPORT) || defined(AOW_ONE_IMAGE_SUPPORT)
            switch (dram_size)
            {
                case SIZE_2G:
                    UBOOT_DEBUG("WARNING: DRAM size is 2GB\n");
#ifdef COMMERCIAL_DISPLAY_SUPPORT
                    strlcpy(detected_name, "resv_mem_mt5873_h1v1_an_2g_iommu_cd", size-1);
#else
                    strlcpy(detected_name, "resv_mem_mt5873_h1v1_an_2g_iommu", size-1);
#endif
#ifdef CONFIG_MTK_AEE_SUPPORT
                    strncat(detected_name, "_", 1);
                    strncat(detected_name, MMAP_AEE_TAG_STRING, strlen(MMAP_AEE_TAG_STRING));
#endif
                    return 0;
                case SIZE_1p5G:
                    UBOOT_DEBUG("WARNING: DRAM size is 1.5GB\n");
                    strlcpy(detected_name, "resv_mem_mt5873_h1v1_an_1point5g_iommu", size-1);
                    return 0;
                case SIZE_1G:
                    UBOOT_DEBUG("WARNING: DRAM size is 1GB\n");
                    strlcpy(detected_name, "resv_mem_mt5873_h1v1_an_1g_iommu", size-1);
                    return 0;
                case SIZE_4G:
                    UBOOT_DEBUG("WARNING: DRAM size is 4GB\n");
#ifdef COMMERCIAL_DISPLAY_SUPPORT
                    strlcpy(detected_name, "resv_mem_mt5873_h1v1_an_4g_iommu_cd", size-1);
#else
                    strlcpy(detected_name, "resv_mem_mt5873_h1v1_an_4g_iommu", size-1);
#endif
#ifdef CONFIG_MTK_AEE_SUPPORT
                    strncat(detected_name, "_", 1);
                    strncat(detected_name, MMAP_AEE_TAG_STRING, strlen(MMAP_AEE_TAG_STRING));
#endif
                    return 0;
                case SIZE_3G:
                    UBOOT_DEBUG("WARNING: DRAM size is 3GB\n");
#ifdef COMMERCIAL_DISPLAY_SUPPORT
                    strlcpy(detected_name, "resv_mem_mt5873_h1v1_an_3g_iommu_cd", size-1);
#else
                    strlcpy(detected_name, "resv_mem_mt5873_h1v1_an_3g_iommu", size-1);
#endif
#ifdef CONFIG_MTK_AEE_SUPPORT
                    strncat(detected_name, "_", 1);
                    strncat(detected_name, MMAP_AEE_TAG_STRING, strlen(MMAP_AEE_TAG_STRING));
#endif
                    return 0;
                default:
                    UBOOT_DEBUG("AOSP_ONE_IMAGE_SUPPORT is failed\n");
                    break;
            }
#else
            UBOOT_DEBUG("AOSP_ONE_IMAGE_SUPPORT is not supported\n");
#endif
        }
		else if (MT5896 == romtbl_get_chip_id_info())
		{
			if (dram_size == SIZE_6G)
			{
				UBOOT_DEBUG("WARNING: DRAM size is 6GB\n");
				strlcpy(detected_name, "resv_mem_mt5896_h1v1_an_6g", size-1);
				return 0;
			}
			else if (dram_size == SIZE_8G)
			{
				UBOOT_DEBUG("WARNING: DRAM size is 8GB\n");
				strlcpy(detected_name, "resv_mem_mt5896_h1v1_an_8g", size-1);
				return 0;
			}
		}

		UBOOT_DEBUG("WARNING: DRAM auto detection (resv_mem) failed! Un-supported DRAM size = 0x%llx\n", dram_size);
		return 1;
	}
#elif defined(CONFIG_LINUX_REF_PLATFORM)
    if (reserved_memory_auto_detection_linux_ref(detected_name, size) == 0)
    {
        UBOOT_DEBUG("Linux-Ref reserved memory detect %s\n", detected_name);
        return 0;
    }
    else
    {
        UBOOT_DEBUG("Linux-Ref reserved memory detect failed\n");
        return 1;
    }
#else
	/* non-aosp project, no need to select resv_mem */
	return 1;
#endif
}

/*
 return 0: success
 return otherwise: fail
*/
static int iommu_cust_auto_detection_callback(char* detected_name, int size)
{
#if defined(CONFIG_ANDROID_CN_PLATFORM) || defined(CONFIG_ANDROID_WW_PLATFORM) || defined(CONFIG_LINUX_REF_PLATFORM)
    static unsigned long long dram_size = 1;
    int chip_id = -1;
    int chip_number;
    int len = 0;
    UBOOT_DEBUG("iommu_cust auto detection\n");

#if defined(CONFIG_LINUX_REF_PLATFORM)
    char mmap_auto_detect[STRING_BUFFER_SIZE];

    if (dataindex_get_key(mmap_auto_detect, STRING_BUFFER_SIZE, DTB_OVERLAY_SECTION, MMAP_AUTO_DETECT_KEY, NULL) != 0)
    {
        UBOOT_DEBUG("Can't get %s. Disable iommu_cust auto detect.\n", MMAP_AUTO_DETECT_KEY);
        return 1;
    }

    if (strncmp(mmap_auto_detect, MMAP_AUTO_DETECT_VALUE_ENABLE, strlen(MMAP_AUTO_DETECT_VALUE_ENABLE)) != 0 ||
        strlen(mmap_auto_detect) != strlen(MMAP_AUTO_DETECT_VALUE_ENABLE))
    {
        UBOOT_DEBUG("%s is %s. Disable iommu_cust auto detect.\n", MMAP_AUTO_DETECT_VALUE_ENABLE, mmap_auto_detect);
        return 1;
    }
#endif

    dram_size = get_dram_size();
    memset(detected_name, 0, size);

    chip_id = romtbl_get_chip_id_info();
    switch (chip_id)
    {
        case MT5896:
            chip_number = MEDIATEK_TV_CHIP_ID_MT5896;
            break;
        case MT5897:
            chip_number = MEDIATEK_TV_CHIP_ID_MT5897;
            break;
        case MT5876:
            chip_number = MEDIATEK_TV_CHIP_ID_MT5876;
            break;
        case MT5879:
            chip_number = MEDIATEK_TV_CHIP_ID_MT5879;
            break;
        case MT5873:
            chip_number = MEDIATEK_TV_CHIP_ID_MT5873;
            break;
        default:
            UBOOT_DEBUG("Chip id %d is not support\n", chip_id);
            return 1;
    }

    switch (dram_size)
    {
        case SIZE_8G:
            len = snprintf(detected_name, size - 1, "mt%d_%s", chip_number, "8g");
            break;
        case SIZE_6G:
            len = snprintf(detected_name, size - 1, "mt%d_%s", chip_number, "6g");
            break;
        case SIZE_4G:
            len = snprintf(detected_name, size - 1, "mt%d_%s", chip_number, "4g");
            break;
        case SIZE_3G:
            len = snprintf(detected_name, size - 1, "mt%d_%s", chip_number, "3g");
            break;
        case SIZE_2G:
            len = snprintf(detected_name, size - 1, "mt%d_%s", chip_number, "2g");
            break;
        case SIZE_1p5G:
            len = snprintf(detected_name, size - 1, "mt%d_%s", chip_number, "1point5g");
            break;
        case SIZE_1G:
            len = snprintf(detected_name, size - 1, "mt%d_%s", chip_number, "1g");
            break;
        default:
            UBOOT_DEBUG("ERROR: DRAM auto detection (iommu_cust) failed! Un-supported DRAM size = 0x%llx\n", dram_size);
            return 1;
    }

    if (len >= size - 1)
    {
        UBOOT_DEBUG("ERROR: DRAM auto detection (iommu_cust) over sized, len: %d\n", len);
        return 1;
    }

    UBOOT_DEBUG("DEBUG: iommu_cust select name: %s.dtso\n", detected_name);
    return 0;
#else
    UBOOT_DEBUG("iommu_cust auto detection\n");
    UBOOT_DEBUG("To be implemented\n");
    return 1;
#endif
}

/*
 return 0: success
 return otherwise: fail
*/
static int thermal_auto_detection_callback(char* detected_name, int size)
{
    int chip_id = -1;
    unsigned short bond = 0;
    int pkg = 0, htc = 0, ext = 0;

    memset(detected_name, 0, size);

    chip_id = romtbl_get_chip_id_info();
    switch (chip_id)
    {
        case MT5873:
            bond = CPU_REGISTER_ACCESS(MT5873_PAD_BOND_BANK, MT5873_PAD_BOND_ADDR);
            htc = ((bond >> MT5873_PAD_HTC_SHIFT) & MT5873_PAD_HTC_MASK);
            pkg = ((bond >> MT5873_PAD_PKG_SHIFT) & MT5873_PAD_PKG_MASK);
            ext = ((bond >> MT5873_PAD_EXT_SHIFT) & MT5873_PAD_EXT_MASK);

            if (htc == MT5873_BOND_NTC && pkg == MT5873_PKG_BIG)
            {
                strncpy(detected_name, "thermal_mt5873_ntc", size-1);
            }
            if (htc == MT5873_BOND_NTC && pkg == MT5873_PKG_SMALL)
            {
                strncpy(detected_name, "thermal_mt5873_ntc_small", size-1);
            }
            if (htc == MT5873_BOND_HTC && pkg == MT5873_PKG_BIG)
            {
                strncpy(detected_name, "thermal_mt5873_htc", size-1);
            }
            if (ext == MT5873_BOND_EXT)
            {
                strncpy(detected_name, "thermal_mt5873_ext", size-1);
            }
            break;
        default:
            UBOOT_DEBUG("thermal Chip id %d is not support thermal\n", chip_id);
            return 1;
    }

    UBOOT_DEBUG("DEBUG: bound: %d, thermal select name: %s.dtso\n", bond, detected_name);
    return 0;
}

static int panel_auto_detection_callback(char* detected_name, int size)
{
    char *name = NULL;
/*    int ret;
    char chassisIndex[INI_INFO_SIZE];
    char * ec_chassis_key = "panel_chassis_config";
    char * ec_chassis_value = (char *) malloc(MAX_VALUE_LENGTH);
    char * force_tcon = NULL;

    UBOOT_DEBUG("PANEL auto detection\n");
    {
        memset(detected_name, 0, size);
        ret = get_ec_value(ec_chassis_key, ec_chassis_value, MAX_VALUE_LENGTH);
        if (ret < 0)
        {
            UBOOT_ERROR("Error: get ec value [%s] failure\n", "panel_chassis_config");
            strcpy(chassisIndex, "00");
            chassisIndex[2] = '\0';
        }else{
            strncpy(chassisIndex, ec_chassis_value, strlen(ec_chassis_value) + 1);
        }
        if (get_tconless_status() == 0)
        {
            chassisIndex[0] = '1';
        }else{
            chassisIndex[0] = '0';
        }
        //force to set tconless
        force_tcon = env_get("force_tcon");
        if (force_tcon != NULL)
        {
		    if (strcmp(force_tcon, "1") == 0)
            {
                chassisIndex[0] = '0';
            }else if (strcmp(force_tcon, "0") == 0){
                chassisIndex[0] = '1';
            }
        }
*/
        name = get_panel_id();
        if(name != NULL)
        {
            strncpy(detected_name, name, strlen(name));
            //strncat(detected_name, "_", 1);
            //strncat(detected_name, chassisIndex, strlen(chassisIndex));
            UBOOT_INFO("auto detected panel ID:%s\n", detected_name);
        }else{
            UBOOT_INFO("WARNING: PANEL auto detection dont get panel name!\n");
            return 1;
        }
//    }
    return 0;
}

static int uart_auto_detection_callback(char* detected_name, int size)
{
	int ret;
	char * ec_rs232_key = "enable_rs232c";
	char * ec_rs232_value = (char *) malloc(MAX_VALUE_LENGTH);

	UBOOT_DEBUG("UART auto detection\n");
	{
		memset(detected_name, 0, size);
		ret = get_ec_value(ec_rs232_key, ec_rs232_value, MAX_VALUE_LENGTH);
		if (ret < 0)
		{
			UBOOT_INFO("Error: get ec value [%s] failure ret:%d\n", ec_rs232_key, ret);
			free(ec_rs232_value);
			return ret;
		}else{
			UBOOT_DEBUG(" get ec value %s[%s]\n", ec_rs232_key, ec_rs232_value);
			if (strcmp("true", ec_rs232_value) == 0)
			{
				UBOOT_INFO("RS232 status is okay\n");
				strncpy(detected_name, "cus_uart_enable", size-1);
			}else{
				UBOOT_INFO("RS232 status is disable\n");
				strncpy(detected_name, "cus_uart_disable", size-1);
			}
		}
	}
	free(ec_rs232_value);
    return 0;
}

static int emmc_ds_config_auto_detection_callback(char* detected_name, int size)
{
	int ret;
	char * ec_emmc_dtbo_key = "emmc_ds_config_dtbo";
	char * ec_emmc_dtbo_value = (char *) malloc(MAX_VALUE_LENGTH);

	UBOOT_DEBUG("emmc_ds_config auto detection\n");
	{
		memset(detected_name, 0, size);
		ret = get_ec_value(ec_emmc_dtbo_key, ec_emmc_dtbo_value, MAX_VALUE_LENGTH);
		if (ret < 0)
		{
			UBOOT_INFO("Error: get ec value [%s] failure ret:%d\n", ec_emmc_dtbo_key, ret);
			free(ec_emmc_dtbo_value);
			return ret;
		}else{
			UBOOT_DEBUG("get ec value %s[%s]\n", ec_emmc_dtbo_key, ec_emmc_dtbo_value);
			strcpy(detected_name, ec_emmc_dtbo_value);
		}
	}
	free(ec_emmc_dtbo_value);
    return 0;
}

static int enable_builtin_mic_auto_detection_callback(char* detected_name, int size)
{
	int ret;
	char * ec_builtin_mic_dtbo_key = "enable_builtin_mic";
	char * ec_builtin_mic_dtbo_value = (char *) malloc(MAX_VALUE_LENGTH);

	UBOOT_DEBUG("builtin_mic auto detection\n");
	{
		memset(detected_name, 0, size);
		ret = get_ec_value(ec_builtin_mic_dtbo_key, ec_builtin_mic_dtbo_value, MAX_VALUE_LENGTH);
		if (ret < 0)
		{
			UBOOT_INFO("Error: get ec value [%s] failure ret:%d\n", ec_builtin_mic_dtbo_key, ret);
			free(ec_builtin_mic_dtbo_value);
			return ret;
		}else{
			UBOOT_DEBUG("get ec value %s[%s]\n", ec_builtin_mic_dtbo_key, ec_builtin_mic_dtbo_value);
			if(strcmp(ec_builtin_mic_dtbo_value,"true") == 0){
				strcpy(detected_name, "voc_pcb_enable");
			}else if(strcmp(ec_builtin_mic_dtbo_value,"false") == 0){
				strcpy(detected_name, "voc_pcb_disable");
			}
		}
	}
	free(ec_builtin_mic_dtbo_value);
    return 0;
}

static int ld_variation_auto_detection_callback(char* detected_name, int size)
{
	int ret;
	char SOPQ_LDM_CONST_KEY[MAX_VALUE_LENGTH] = "PQ_LD_";
	char * ec_ld_variation_key = "ld_variation";
	char * ec_ld_variation_value = (char *) malloc(MAX_VALUE_LENGTH);
	char * SubECValue = (char *) malloc(MAX_VALUE_LENGTH);
	char * buf = (char *) malloc(MAX_VALUE_LENGTH + 1);

	UBOOT_DEBUG("ld_variation auto detection\n");
	{
		memset(detected_name, 0, size);
		ret = get_ec_value(ec_ld_variation_key, ec_ld_variation_value, MAX_VALUE_LENGTH);
		if (ret < 0)
		{
			UBOOT_INFO("Error: get ec value [%s] failure ret:%d\n", ec_ld_variation_key, ret);
			free(ec_ld_variation_value);
			free(SubECValue);
			free(buf);
			return ret;
		}else{
			strcat(SOPQ_LDM_CONST_KEY, ec_ld_variation_value); //PQ_LD_var009
			strcat(SOPQ_LDM_CONST_KEY, UnderLine); //PQ_LD_var009_
			strcat(SOPQ_LDM_CONST_KEY, get_panel_index_buf()); //PQ_LD_var009_0045
			UBOOT_INFO("SOPQ_LDM_CONST_KEY:[%s]\n", SOPQ_LDM_CONST_KEY);
			if (ExGetJsonValue("SOPQ_LDM", SOPQ_LDM_CONST_KEY, SubECValue, 0) < 0) {
				UBOOT_INFO("cannot find %s from subec SOPQ_LDM, \"%s\" return\n", "ld_variation", SOPQ_LDM_CONST_KEY);
				UBOOT_INFO("Turn to use default value AAA_0043_AAA_0043_AAA_0043_AAA_0043\n");
				strcpy(SubECValue, "AAA_0043_AAA_0043_AAA_0043_AAA_0043");
			}
			if (snprintf(buf, MAX_VALUE_LENGTH, "%s%s", "ldm", SubECValue+26) < 0){ //ldm_AAA_0043
				UBOOT_INFO("ld_variation_auto_detection_callback cannot generate\n");
				strcpy(detected_name, "ldm_AAA_0043");
			}else{
				strcpy(detected_name, buf);
			}
			UBOOT_INFO("ld_variation_auto_detection_callback detected_name :%s\n", detected_name);
		}
	}
	free(ec_ld_variation_value);
	free(SubECValue);
	free(buf);
    return 0;
}

static int pcmcia_acas_auto_detection_callback(char* detected_name, int size)
{
	int ret;
	char * ec_tuner_pin_config_key = "tuner_pin_config";
	char * ec_tuner_pin_config_value = (char *) malloc(MAX_VALUE_LENGTH);

	UBOOT_DEBUG("pcmcia_acas auto detection\n");
	{
		memset(detected_name, 0, size);
		ret = get_ec_value(ec_tuner_pin_config_key, ec_tuner_pin_config_value, MAX_VALUE_LENGTH);
		if (ret < 0)
		{
			UBOOT_INFO("Error: get ec value [%s] failure ret:%d\n", ec_tuner_pin_config_key, ret);
			free(ec_tuner_pin_config_value);
			return ret;
		}else{
			UBOOT_INFO("get ec value %s[%s]\n", ec_tuner_pin_config_key, ec_tuner_pin_config_value);
			if (strcmp(ec_tuner_pin_config_value, "var_t2s2") == 0)
			{
				strcpy(detected_name, "enable_pcmcia");
			}else{
				strcpy(detected_name, "enable_acas");
			}
		}
	}
	free(ec_tuner_pin_config_value);
	return 0;
}

static int panel_mismatch_dtbo_auto_detection_callback(char* detected_name, int size)
{
	UBOOT_DEBUG("#panel_mismatch = %d\n", panel_mismatch);
	if (panel_mismatch)
	{
		strcpy(detected_name, "mismatch");
	}else{
		strcpy(detected_name, "match");
	}
	return 0;
}

static int key_response_dtbo_auto_detection_callback(char* detected_name, int size)
{
	if (get_key_response())
	{
		strcpy(detected_name, "response");
	}else{
		strcpy(detected_name, "not_response");
	}
	return 0;
}
static int dtbo_register_auto_detection_callback(char* section_name, dtbo_callback cb)
{
	if (cur_dtbo_callback_number >= DTBO_CALLBACK_MAX_NUM){
		UBOOT_ERROR("dtbo_register_auto_detection_callback failed: no empty slot\n");
		return 1;
	}

	if (section_name == NULL){
		UBOOT_ERROR("dtbo_register_auto_detection_callback failed: invalid section name\n");
		return 1;
	}

	if (strnlen(section_name, DTBO_CALLBACK_NAME_MAX_LEN) == DTBO_CALLBACK_NAME_MAX_LEN){
		UBOOT_ERROR("dtbo_register_auto_detection_callback failed: section name too long\n");
		return 1;
	}

	//here we don't check conflict section names
	//for callbacks with conflict names, the first registered callback will be called

	dtbo_callbacks[cur_dtbo_callback_number] = cb;
	memset(dtbo_callback_section_name[cur_dtbo_callback_number], 0, DTBO_CALLBACK_NAME_MAX_LEN);
	strncpy(dtbo_callback_section_name[cur_dtbo_callback_number], section_name, DTBO_CALLBACK_NAME_MAX_LEN-1);
	cur_dtbo_callback_number++;

	return 0;
}

static int dtbo_init_auto_detection_callbacks(void)
{
	static int inited = 0;

	if (inited)
		return 0;

	inited = 1;

	if (dtbo_register_auto_detection_callback("mmap", mmap_auto_detection_callback))
		UBOOT_INFO("Warning: mmap register failed\n");

	if (dtbo_register_auto_detection_callback("resv_mem", reserved_memory_auto_detection_callback))
		UBOOT_INFO("Warning: resv_mem register failed\n");

	if (dtbo_register_auto_detection_callback("iommu_cust", iommu_cust_auto_detection_callback))
		UBOOT_INFO("Warning: iommu_cust register failed\n");

        if (dtbo_register_auto_detection_callback("thermal", thermal_auto_detection_callback))
        {
            UBOOT_INFO("Warning: thermal register failed\n");
        }
		
	if (dtbo_register_auto_detection_callback("panel", panel_auto_detection_callback))
		UBOOT_INFO("Warning: panel register failed\n");

	if (dtbo_register_auto_detection_callback("uart", uart_auto_detection_callback))
		UBOOT_INFO("Warning: uart register failed\n");

	if (dtbo_register_auto_detection_callback("emmc_ds_config", emmc_ds_config_auto_detection_callback))
		UBOOT_INFO("Warning: emmc_ds register failed\n");

	if (dtbo_register_auto_detection_callback("enable_builtin_mic", enable_builtin_mic_auto_detection_callback))
		UBOOT_INFO("Warning: enable_builtin_mic register failed\n");

	if (dtbo_register_auto_detection_callback("ld_variation", ld_variation_auto_detection_callback))
		UBOOT_INFO("Warning: ld_variation register failed\n");

	if (dtbo_register_auto_detection_callback("pcmcia_acas", pcmcia_acas_auto_detection_callback))
		UBOOT_INFO("Warning: pcmcia_acas register failed\n");

	if (dtbo_register_auto_detection_callback("panel_mismatch_dtbo", panel_mismatch_dtbo_auto_detection_callback))
		UBOOT_INFO("Warning: panel_mismatch_dtbo register failed\n");

	if (dtbo_register_auto_detection_callback("key_response_dtbo", key_response_dtbo_auto_detection_callback))
		UBOOT_INFO("Warning: key_response_dtbo register failed\n");

	return 0;
}

#else
int is_device_id_valid(int device_id)
{
	UBOOT_TRACE("IN\n");
	if(device_id < 0)
	{
		return -1;
	}
	UBOOT_TRACE("OUT\n");
	return 0;
}

int get_device_id(int device_type)
{
	int device_id;
	UBOOT_TRACE("IN\n");
	switch(device_type)
	{
		case DEVICE_BOARD:
			device_id = 0;
			break;
		default:
			device_id = -1;
			break;
	}
	UBOOT_TRACE("OUT\n");
	return device_id;
}
#endif

int dtbo_selection_and_overlay(void)
{
	int ret = -1;
	int id;
	UBOOT_TRACE("IN\n");
#ifdef CONFIG_MULTIPLE_DTB_SELECTION
	const char *ptr;
	char partition[STRING_BUFFER_SIZE];
	struct section *section_entry, *section_entry_wl;
	struct keyval_pair *keyval_entry, *keyval_entry_wl;
	int len, kernel_dtb_num = 0;
	bool uboot_dtbo = false;
	DTBO_IDX_T *dtbo_idx = NULL;
/*
        if(ec_dtbo_overlay_pre() == -1)
            UBOOT_ERROR("ec_dtbo_overlay_pre failed\n");
*/
	if (dtbo_init_auto_detection_callbacks())
		UBOOT_ERROR("Warning: dtbo_init_auto_detection_callbacks failed\n");

	memset(partition, 0, sizeof(partition));
	ptr = env_get(DTBO_DEF_ENV_NAME);
	if(ptr == NULL){
		UBOOT_DEBUG("Partition not select, use default %s\n",DTBO_DEF_PART);
		strncpy(partition, DTBO_DEF_PART, strlen(DTBO_DEF_PART));
	}else{
#if (CONFIG_AB_SIDELOAD == 1)
		if(sizeof(partition) <= (strlen(ptr) + strlen(PART_SUFFIX_A)))
			len = sizeof(partition)- strlen(PART_SUFFIX_A) - 1;
#else
		if(sizeof(partition) <= strlen(ptr))
			len = sizeof(partition)-1;
#endif
		else
			len = strlen(ptr);
		strncpy(partition, ptr, len);
	}

#ifdef CONFIG_DATA_SEPARATION
	ret = read_dtbo_ini_info(DTB_MAPPING, DTB_OVERLAY_SECTION, MAPPING_CFG_KEY, partition, MAPPING_CFG_ENV_NAME, MAPPING_CFG_DEF_PATH);
#else
	ret = read_dtbo_ini_info(DTB_MAPPING, partition, MAPPING_CFG_ENV_NAME, MAPPING_CFG_DEF_PATH);
#endif
	if(ret < 0){
		UBOOT_ERROR("DTB_MAPPING ini read failure.\n");
		return -1;
	}

#ifdef CONFIG_DATA_SEPARATION
	ret = read_dtbo_ini_info(WHITELIST, DTB_OVERLAY_SECTION, WHITELIST_KEY, partition, WHITELIST_ENV_NAME, WHITELIST_DEF_PATH);
#else
	ret = read_dtbo_ini_info(WHITELIST, partition, WHITELIST_ENV_NAME, WHITELIST_DEF_PATH);
#endif
	if(ret < 0){
		UBOOT_ERROR("WHITELIST ini read failure.\n");
		return -1;
	}

#ifdef CONFIG_DATA_SEPARATION
	ret = read_dtbo_ini_info(CFG_SELECT, DTB_OVERLAY_SECTION, CFG_SEL_KEY, partition, CFG_SEL_ENV_NAME, CFG_SEL_DEF_PATH);
#else
	ret = read_dtbo_ini_info(CFG_SELECT, partition, CFG_SEL_ENV_NAME, CFG_SEL_DEF_PATH);
#endif
	if(ret < 0){
		UBOOT_ERROR("CFG_SELECT ini read failure.\n");
		return -1;
	}

	uboot_dtbo = is_uboot_dtb();
	if(uboot_dtbo == false)
		INIT_LIST_HEAD(&dtbo_idx_list);
	UBOOT_DEBUG("%s\n", uboot_dtbo?"Doing u-boot dtb overlay":"Doing kernel dtb overlay");
	iniparser_for_each_section(dtbo_selection, section_entry) {
		iniparser_for_each_keyval(section_entry, keyval_entry) {
			UBOOT_DEBUG("[%s=%s]\n", keyval_entry->key, keyval_entry->value);
			iniparser_for_each_section(dtbo_whitelist, section_entry_wl) {
				iniparser_for_each_keyval(section_entry_wl, keyval_entry_wl) {
					UBOOT_DEBUG("[%s=%s]\n", keyval_entry_wl->key, keyval_entry_wl->value);
					if(strncmp(keyval_entry_wl->key, keyval_entry->key, strlen((keyval_entry->key))) == 0 && strlen(keyval_entry_wl->key) == strlen(keyval_entry->key)){
						if((uboot_dtbo == true && (strncmp(keyval_entry_wl->value, "U", 1) == 0 || strncmp(keyval_entry_wl->value, "*", 1) == 0))
						|| (uboot_dtbo == false && (strncmp(keyval_entry_wl->value, "K", 1) == 0 || strncmp(keyval_entry_wl->value, "*", 1) == 0))){
							UBOOT_DEBUG("[%s=%s]\n", keyval_entry_wl->key, keyval_entry_wl->value);
							id = get_device_id(keyval_entry->key, keyval_entry->value);
							if(id < 0){
								UBOOT_ERROR("dtb_overlay id:%d is invaild\n",id);
								return -1;
							}

							ret = dtb_overlay(id);
							if(ret != 0){
								UBOOT_ERROR("dtb_overlay execute failure with %d\n",id);
								return -1;
							}
							if(uboot_dtbo == false){
								dtbo_idx = (DTBO_IDX_T *)malloc(sizeof(DTBO_IDX_T));
								if(dtbo_idx != NULL){
									kernel_dtb_num++;
									dtbo_idx->dtbo_id = id;
									UBOOT_DEBUG("[%d] add dtbo_id:%d\n", kernel_dtb_num, dtbo_idx->dtbo_id);
									list_add_tail(&dtbo_idx->list,&dtbo_idx_list);
								}
							}
						}else{
							UBOOT_DEBUG("%s value %s not match\n", keyval_entry_wl->key, keyval_entry_wl->value);
						}
                        break;
					}else{
						UBOOT_DEBUG("Target:%s Source:%s\n", keyval_entry->key, keyval_entry_wl->key);
					}
				}
			}
		}
	}
	if(uboot_dtbo == false)
		add_dtbo_idx_to_bootargs(kernel_dtb_num);

	iniparser_destroy(dtbo_selection);
	iniparser_destroy(dtbo_whitelist);
	iniparser_destroy(dtbo_mapping);
	dtbo_selection = NULL;
	dtbo_whitelist = NULL;
	dtbo_mapping = NULL;
	if(uboot_dtbo == false){
		if(mapping_ini != NULL)
			free(mapping_ini);
		if(selection_ini != NULL)
			free(selection_ini);
		if(whitelist_ini != NULL)
			free(whitelist_ini);
	}
#else
	int i;
	for (i=0;i<DEVICE_MAX;i++){
		id = get_device_id(i);
		ret = is_device_id_valid(id);
		if(ret == 0){
			ret = dtb_overlay(id);
			if(ret != 0){
				printf("dtb_overlay execute failure with %d\n",id);
				return -1;
			}
		} else {
			printf("DEVICE_TYPE %X is invalid\n",i);
			return -1;
		}
	}
#endif

	UBOOT_TRACE("OUT\n");
	return 0;
}

#if defined(CONFIG_DTB_OVERLAY_FOR_UBOOT_DTB) || defined(CONFIG_DTB_OVERLAY_FOR_KERNEL_DTB)
int get_dtbo_img_size(unsigned long dtbo_img_addr, unsigned long *dtbo_img_size)
{
	int ret = 0;
	const struct dt_table_header *hdr;
	u32 image_size;

	ret = android_dt_check_header(dtbo_img_addr);
	if(ret == false)
	{
		UBOOT_ERROR("Check device tree binary image header magic number failure, please check dtbo.img or storage cmd.\n");
		return -EINVAL;
	}

	hdr = map_sysmem(dtbo_img_addr, sizeof(*hdr));
	image_size = fdt32_to_cpu(hdr->total_size);
	unmap_sysmem(hdr);
	*dtbo_img_size = image_size;

	return 0;
}

static int get_public_key_n(EN_SECURE_KEY_TYPE en_key, unsigned char *buffer, unsigned int len)
{
	int ret;
	st_secure_key secure_key = {};

	if (!buffer) {
		UBOOT_ERROR("The input parameter 'buffer' is a null pointer\n");
		return -EINVAL;
	}

	if (len < RSA_PUBLIC_KEY_N_LEN) {
		UBOOT_ERROR("The len is smaller than the lenght of public-N (%d bytes).\n", RSA_PUBLIC_KEY_N_LEN);
		return -EINVAL;
	}

	ret = secure_get_key(en_key, &secure_key);
	if (ret == -1) {
		UBOOT_ERROR("Wrong EN_SECURE_KEY_TYPE Index !!\n");
		return ret;
	}
	memcpy(buffer, secure_key.data, len);
	flush_cache((unsigned long)buffer, len);

	return 0;
}

static int get_public_key_e(EN_SECURE_KEY_TYPE en_key, unsigned char *buffer, unsigned int len)
{
	int ret;
	st_secure_key secure_key = {};

	if (!buffer) {
		UBOOT_ERROR("The input parameter 'buffer' is a null pointer\n");
		return -EINVAL;
	}

	if (len < RSA_PUBLIC_KEY_E_LEN) {
		UBOOT_ERROR("The len is smaller than the lenght of public-E (%d bytes).\n", RSA_PUBLIC_KEY_E_LEN);
		return -EINVAL;
	}

	ret = secure_get_key(en_key, &secure_key);
	if (ret == -1) {
		UBOOT_ERROR("Wrong EN_SECURE_KEY_TYPE Index !!\n");
		return ret;
	}
	memcpy(buffer, secure_key.data + RSA_PUBLIC_KEY_N_LEN, len);
	flush_cache((unsigned long)buffer, len);

	return 0;
}

int verify_dtbo_img(unsigned char *auth_data, unsigned char *sign_data, unsigned long auth_size)
{
	int ret = 0;
	uint8_t rsa_public_key_N[RSA_PUBLIC_KEY_N_LEN] = {0};
	uint8_t rsa_public_key_E[RSA_PUBLIC_KEY_E_LEN] = {0};

	ret = get_public_key_n(KEY_TYPE_CKB_A_RI_KEY, rsa_public_key_N, RSA_PUBLIC_KEY_N_LEN);

	if(ret){
		UBOOT_ERROR("Fail to get public N from CKB_A_RI_KEY.\n");
		return CMD_RET_FAILURE;
	}

	ret = get_public_key_e(KEY_TYPE_CKB_A_RI_KEY, rsa_public_key_E, RSA_PUBLIC_KEY_E_LEN);

	if(ret){
		UBOOT_ERROR("Fail to get public E from CKB_A_RI_KEY.\n");
		return CMD_RET_FAILURE;
	}

	if ((ret = secure_do_authentication(rsa_public_key_N, rsa_public_key_E, sign_data, auth_data, auth_size)) != 0) {
		UBOOT_ERROR("secure_do_authentication fail.\n");
		UBOOT_DEBUG("RSA_PUBLIC_KEY_N_LEN:\n");
		UBOOT_DUMP((void *)rsa_public_key_N, RSA_PUBLIC_KEY_N_LEN);
		UBOOT_DEBUG("RSA_PUBLIC_KEY_E_LEN:\n");
		UBOOT_DUMP((void *)rsa_public_key_E, RSA_PUBLIC_KEY_E_LEN);
		UBOOT_DEBUG("signature:\n");
		UBOOT_DUMP((void *)sign_data, SIGNATURE_LEN);
		UBOOT_DEBUG("image :\n");
		UBOOT_DUMP((void *)auth_data, SIGNATURE_LEN);
		return CMD_RET_FAILURE;
	}
	return CMD_RET_SUCCESS;
}
#endif
