/******************************************************************************
 *
 * Copyright(c) 2019 Realtek Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 *****************************************************************************/
/*
The purpose of hal_efuse.c

Provide efuse operations.
a. efuse init function
b. efuse shadow map read/write/update
c. efuse information query, map size/used bytes...

*/

#define _HAL_EFUSE_C_
#include "../hal_headers.h"
#include "hal_efuse.h"
#include "hal_efuse_export.h"

#define get_hci_to_a_die_offset(log_size, limit_log_size) (log_size - limit_log_size)
#define get_a_die_start_offset(limit_log_size, a_die_size) (limit_log_size - a_die_size)

/* WIFI EFUSE API */
void efuse_shadow_read_one_byte(struct efuse_t *efuse, u16 offset, u8 *value)
{
	*value = efuse->shadow_map[offset];
}

void efuse_shadow_read_two_byte(struct efuse_t *efuse, u16 offset, u16 *value)
{
	*value = efuse->shadow_map[offset];
	*value |= efuse->shadow_map[offset+1] << 8;
}

void efuse_shadow_read_four_byte(struct efuse_t *efuse, u16 offset, u32 *value)
{
	*value = efuse->shadow_map[offset];
	*value |= efuse->shadow_map[offset+1] << 8;
	*value |= efuse->shadow_map[offset+2] << 16;
	*value |= efuse->shadow_map[offset+3] << 24;
}

void efuse_shadow_write_one_byte(struct efuse_t *efuse, u16 offset, u16 value)
{
	efuse->shadow_map[offset] = (u8)(value&0x00FF);
}

void efuse_shadow_write_two_byte(struct efuse_t *efuse, u16 offset, u16 value)
{
	efuse->shadow_map[offset] = (u8)(value&0x00FF);
	efuse->shadow_map[offset+1] = (u8)((value&0xFF00) >> 8);
}

void efuse_shadow_write_four_byte(struct efuse_t *efuse, u16 offset, u32 value)
{
	efuse->shadow_map[offset] = (u8)(value&0x000000FF);
	efuse->shadow_map[offset+1] = (u8)((value&0x0000FF00) >> 8);
	efuse->shadow_map[offset+2] = (u8)((value&0x00FF0000) >> 16);
	efuse->shadow_map[offset+3] = (u8)((value&0xFF000000) >> 24);
}

u32 efuse_check_autoload(struct efuse_t *efuse)
{
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;

	hal_status = rtw_hal_mac_check_efuse_autoload(efuse->hal_com,
												  &efuse->is_map_valid);
	if (efuse->is_map_valid != true)
		efuse->map_from_status = DEFAULT_MAP;

	return hal_status;
}

u32 efuse_hidden_handle(struct efuse_t *efuse)
{
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;

	hal_status = rtw_hal_mac_read_hidden_rpt(efuse->hal_com);

	return hal_status;
}

enum rtw_hal_status efuse_set_hw_cap(struct efuse_t *efuse)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct rtw_hal_com_t *hal_com = efuse->hal_com;
	u8 pkg_type = 0xFF;
	u8 rfe_type = 0xFF;
	u8 xcap = 0xFF;
	u8 domain = 0xFF;
	u8 domain_6g = 0xFF;
	u8 rf_board_opt = 0xFF;

	status = rtw_efuse_get_info(efuse, EFUSE_INFO_RF_PKG_TYPE, &pkg_type,
				    sizeof(pkg_type));

	if(status != RTW_HAL_STATUS_SUCCESS) {
		PHL_WARN("%s: Get pkg type fail! Status(%x)\n", __FUNCTION__, status);
	}

	status = rtw_efuse_get_info(efuse, EFUSE_INFO_RF_RFE, &rfe_type,
				    sizeof(rfe_type));

	if(status != RTW_HAL_STATUS_SUCCESS) {
		PHL_WARN("%s: Get rfe type fail! Status(%x)\n", __FUNCTION__, status);
	}

	status = rtw_efuse_get_info(efuse, EFUSE_INFO_RF_XTAL, &xcap,
				    sizeof(xcap));

	if(status != RTW_HAL_STATUS_SUCCESS) {
		PHL_WARN("%s: Get xcap fail! Status(%x)\n", __FUNCTION__, status);
	}

	status = rtw_efuse_get_info(efuse, EFUSE_INFO_RF_CHAN_PLAN, &domain,
				    sizeof(domain));

	if(status != RTW_HAL_STATUS_SUCCESS) {
		PHL_WARN("%s: Get domain fail! Status(%x)\n", __FUNCTION__, status);
	}

	status = rtw_efuse_get_info(efuse, EFUSE_INFO_RF_CHAN_PLAN_6GHZ,
					&domain_6g, sizeof(domain_6g));

	if(status != RTW_HAL_STATUS_SUCCESS) {
		PHL_WARN("%s: Get 6ghz domain fail! Status(%x)\n", __FUNCTION__, status);
	}

	status = rtw_efuse_get_info(efuse, EFUSE_INFO_RF_BOARD_OPTION, &rf_board_opt,
				sizeof(rf_board_opt));

	if(status != RTW_HAL_STATUS_SUCCESS) {
		PHL_WARN("%s: Get domain fail! Status(%x)\n", __FUNCTION__, status);
	}

	hal_com->dev_hw_cap.pkg_type = pkg_type;
	hal_com->dev_hw_cap.rfe_type = rfe_type;
	hal_com->dev_hw_cap.xcap = xcap;
	hal_com->dev_hw_cap.domain = domain;
	hal_com->dev_hw_cap.domain_6g = domain_6g;
	hal_com->dev_hw_cap.rf_board_opt = rf_board_opt;

	return status;
}

/*
 * This function is used for backward compatible by calling RF-API.
 * ex:
 *     In 1T2R setting, backward to 1T1R by checking rfe_type
 *     RFE_43(efuse_x02CA=0x2B): 1T2R(Tx diversity + Rx MRC)
 *     RFE_41(efuse_x02CA=0x29): 1T1R(Tx/Rx@pathB)
 *
 */
void efuse_compatible_chk(struct efuse_t *efuse)
{
	rtw_hal_rf_rfe_ant_num_chk(efuse->hal_com);
}

enum rtw_hal_status rtw_efuse_logicmap_buf_load(void *efuse, u8* buf, bool is_limit)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	status = rtw_hal_mac_read_log_efuse_map(efuse_info->hal_com,
						buf,
						is_limit);
	return status;
}

enum rtw_hal_status rtw_efuse_shadow_load(void *efuse, bool is_limit)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	status = rtw_hal_mac_read_log_efuse_map(efuse_info->hal_com,
											efuse_info->shadow_map,
											is_limit);

	if (efuse_info->is_map_valid == true && status == RTW_HAL_STATUS_SUCCESS)
		efuse_info->map_from_status = HW_LOG_MAP;

	return status;
}

enum rtw_hal_status rtw_efuse_shadow_file_load(void *efuse, char *ic_name, bool is_limit)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS;

#ifdef CONFIG_EFUSE_CONFIG_FILE
	struct efuse_t *efuse_info = efuse;

	if (efuse_info->is_map_valid != true ||
		rtw_hal_rf_check_efuse_data(efuse_info->hal_com, HW_PHY_0) != true) {

		if (rtw_hal_efuse_shadow_file_load(efuse_info->hal_com ,
						ic_name, is_limit) == RTW_HAL_STATUS_SUCCESS) {

			if (rtw_hal_rf_check_efuse_data(efuse_info->hal_com, HW_PHY_0) == true) {
				efuse_info->is_map_valid = true;
				PHL_INFO(" %s() hal_rf check file efuse is_map_valid.\n", __FUNCTION__);
			} else {
				status = RTW_HAL_STATUS_FAILURE;
				PHL_WARN(" %s() efuse Power invalid !\n", __FUNCTION__);
			}
		} else {
			PHL_WARN("%s: efuse shadow_file_load fail!\n", __FUNCTION__);
			status = RTW_HAL_STATUS_FAILURE;
		}
	}
#endif
	return status;
}

enum rtw_hal_status rtw_efuse_shadow_update(void *efuse, bool is_limit)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_EFUSE_PG_FAIL;
	enum rtw_hal_status reload_status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	u32 map_size = 0, mask_size = 0;

	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS) == false) {
		PHL_WARN("%s: efuse map not load yet!\n", __FUNCTION__);
		status = RTW_HAL_STATUS_EFUSE_UNINIT;
		goto exit;
	}

	/* Load efuse mask file before PG */
	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_MASK_FILE_LOADED) == false) {
		PHL_WARN("%s: efuse mask not load yet!\n", __FUNCTION__);
		status = RTW_HAL_STATUS_EFUSE_PG_FAIL;
		goto exit;
	}

	/*
	 * If driver does not load external map file,
	 * assign the map version with the mask version for the version check.
	 */
	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_MAP_FILE_LOADED) == false) {
		_os_mem_cpy(efuse_info->hal_com->drv_priv, efuse_info->map_version,
					efuse_info->mask_version, efuse_info->version_len);
	}

	if(is_limit) {
		map_size = efuse_info->limit_efuse_size;
		mask_size = efuse_info->limit_mask_size;
	}
	else {
		map_size = efuse_info->log_efuse_size;
		mask_size = efuse_info->mask_size;
	}

	status = rtw_hal_mac_write_log_efuse_map(efuse_info->hal_com,
							efuse_info->shadow_map,
							map_size,
							efuse_info->mask,
							mask_size,
							efuse_info->map_version,
							efuse_info->mask_version,
							efuse_info->version_len,
							0,
							is_limit,
							efuse_info->efuse_a_die_size,
							efuse_info->hci_to_a_die_offset,
							efuse_info->a_die_start_offset);

	if(status != RTW_HAL_STATUS_SUCCESS)
		PHL_WARN("%s: PG Fail!\n", __FUNCTION__);

	/* Reload shadow map after PG */
	reload_status = rtw_hal_mac_read_log_efuse_map(efuse_info->hal_com,
								efuse_info->shadow_map,
								is_limit);
	if(reload_status != RTW_HAL_STATUS_SUCCESS)
		PHL_WARN("%s: Reload shadow map Fail!\n", __FUNCTION__);

	/*
	 * Clear the load external map file flag and map version
	 * after reloading the map.
	 */
	if(TEST_STATUS_FLAG(efuse_info->status,
						EFUSE_STATUS_MAP_FILE_LOADED) == true) {
		CLEAR_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_MAP_FILE_LOADED);
	}

	_os_mem_set(efuse_info->hal_com->drv_priv,
				efuse_info->map_version,
				0,
				efuse_info->version_len);
exit:
	return status;
}

enum rtw_hal_status
rtw_efuse_shadow_read(void *efuse, u8 byte_count, u16 offset, u32 *value,
					  bool is_limit)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	u32	efuse_size = 0;

	if(is_limit)
		efuse_size = efuse_info->limit_efuse_size;
	else
		efuse_size = efuse_info->log_efuse_size;

	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS) == false) {
		PHL_WARN("%s: efuse map not load yet!\n", __FUNCTION__);
		status = RTW_HAL_STATUS_EFUSE_UNINIT;
		goto exit;
	}

	if((u32)(offset+byte_count) > efuse_size) {
		PHL_WARN("%s: Invalid offset!\n", __FUNCTION__);
		status = RTW_HAL_STATUS_EFUSE_IVALID_OFFSET;
		goto exit;
	}

	if (efuse_info->efuse_a_die_size != 0 &&
		offset >= efuse_info->a_die_start_offset &&
		is_limit)
		offset += (u16)efuse_info->hci_to_a_die_offset;

	if (byte_count == 1)
		efuse_shadow_read_one_byte(efuse_info, offset, (u8 *)value);
	else if (byte_count == 2)
		efuse_shadow_read_two_byte(efuse_info, offset, (u16 *)value);
	else if (byte_count == 4)
		efuse_shadow_read_four_byte(efuse_info, offset, (u32 *)value);

	status = RTW_HAL_STATUS_SUCCESS;
exit:
	return status;
}

enum rtw_hal_status
rtw_efuse_shadow_write(void *efuse, u8 byte_count, u16 offset, u32 value,
					   bool is_limit)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	u32	efuse_size = 0;

	if(is_limit)
		efuse_size = efuse_info->limit_efuse_size;
	else
		efuse_size = efuse_info->log_efuse_size;

	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS) == false) {
		PHL_WARN("%s: efuse map not load yet!\n", __FUNCTION__);
		status = RTW_HAL_STATUS_EFUSE_UNINIT;
		goto exit;
	}

	if((u32)(offset+byte_count) > efuse_size) {
		PHL_WARN("%s: Invalid offset!\n", __FUNCTION__);
		status = RTW_HAL_STATUS_EFUSE_IVALID_OFFSET;
		goto exit;
	}

	if (efuse_info->efuse_a_die_size != 0 &&
		offset >= efuse_info->a_die_start_offset &&
		is_limit)
		offset += (u16)efuse_info->hci_to_a_die_offset;

	if (byte_count == 1)
		efuse_shadow_write_one_byte(efuse_info, offset, (u8)value);
	else if (byte_count == 2)
		efuse_shadow_write_two_byte(efuse_info, offset, (u16)value);
	else if (byte_count == 4)
		efuse_shadow_write_four_byte(efuse_info, offset, (u32)value);

	status = RTW_HAL_STATUS_SUCCESS;
exit:
	return status;
}


/*
 * This API is used for original mp dll command.
 * usage = used percentage(1 Byte) + used bytes(2 Bytes)
 */
enum rtw_hal_status rtw_efuse_get_usage(void *efuse, u32 *usage)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	u32 avl_size = 0;
	u16 used_byte = 0;
	u32 total_size = 0;
	u8 used_percentage = 0;

	status = rtw_hal_mac_get_efuse_avl(efuse_info->hal_com, &avl_size);
	status = rtw_hal_mac_get_efuse_size(efuse_info->hal_com, &total_size);

	if(total_size != 0){
		used_byte = (u16)(total_size - avl_size);
		used_percentage = (u8)(used_byte*100/total_size);
		*usage = (used_percentage<<16)|(used_byte);
	}

	return status;
}

enum rtw_hal_status rtw_efuse_shadow2buf(void *efuse, u8 *destbuf, u16 buflen)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS;
	struct efuse_t *efuse_info = efuse;

	_os_mem_cpy(efuse_info->hal_com->drv_priv, (void *)destbuf,
				(void *)efuse_info->shadow_map , buflen);

	return status;
}

enum rtw_hal_status
efuse_map_buf2shadow(struct efuse_t *efuse, u8 *srcbuf, u16 buflen)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS;

	_os_mem_cpy(efuse->hal_com->drv_priv, (void *)efuse->shadow_map,
				(void *)srcbuf, buflen);
	SET_STATUS_FLAG(efuse->status, EFUSE_STATUS_MAP_FILE_LOADED);

	return status;
}

enum rtw_hal_status
efuse_file_map2version(struct efuse_t *efuse, u8 *srcbuf, u16 buflen)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS;

	_os_mem_cpy(efuse->hal_com->drv_priv, (void *)efuse->map_version,
				(void *)srcbuf, buflen);
	debug_dump_data(efuse->map_version, efuse->version_len,
					"[HAL EFUSE] map version =");

	return status;
}

enum rtw_hal_status
efuse_file_mask2buf(struct efuse_t *efuse, u8 *srcbuf, u16 buflen)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;

	_os_mem_cpy(efuse->hal_com->drv_priv, (void *)efuse->mask, (void *)srcbuf,
				buflen);
	SET_STATUS_FLAG(efuse->status, EFUSE_STATUS_MASK_FILE_LOADED);
	status = RTW_HAL_STATUS_SUCCESS;

	debug_dump_data(efuse->mask, efuse->mask_size, "[HAL EFUSE] mask data =");

	return status;
}

enum rtw_hal_status
efuse_file_mask2version(struct efuse_t *efuse, u8 *srcbuf, u16 buflen)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;

	if (buflen <= efuse->version_len) {
		_os_mem_cpy(efuse->hal_com->drv_priv, (void *)efuse->mask_version,
					(void *)srcbuf, buflen);
		debug_dump_data(efuse->mask_version, efuse->version_len,
						"[HAL EFUSE] mask ver =");
		status = RTW_HAL_STATUS_SUCCESS;
	}

	return status;
}

static u16 efuse_file_open(void *d, char *filepath, u8 *buf, u32 buflen)
{
	char *ptmpbuf = NULL, *ptr;
	u32 bufsize = 5120;
	u8 val8 = 0;
	u32 file_size = 0, i = 0, j= 0, tmp = 0;
	int err = 0;

	ptmpbuf = _os_mem_alloc(d, bufsize);
	if (ptmpbuf == NULL) {
		PHL_INFO("%s, alloc buf FAIL!!\n", __FUNCTION__);
		return 0;
	}

	file_size = _os_read_file(filepath, (u8*)ptmpbuf, bufsize);
	if (file_size > 0) {
		if (file_size <= 90) {
			_os_mem_free(d, (void*)ptmpbuf, bufsize);
			PHL_INFO("%s, filepatch %s, size=%d not over 90, FAIL!!\n",
								__FUNCTION__, filepath, file_size);
			return 0;
		}
		i = 0;
		j = 0;
		ptr = ptmpbuf;
		while ((j < buflen) && (i < file_size)) {
			if (ptmpbuf[i] == '\0')
				break;
			ptr = _os_strpbrk((char *)&ptmpbuf[i], " \t\n\r");
			if (ptr) {
				if (ptr == &ptmpbuf[i]) {
					i++;
					continue;
				}
				/* Add string terminating null */
				*ptr = 0;
			} else {
				ptr = &ptmpbuf[file_size-1];
			}

			err = _os_sscanf((char *)&ptmpbuf[i], "%x", &tmp);

			if (err != 1) {
				PHL_INFO("Something wrong to parse efuse file, string=%s\n", &ptmpbuf[i]);
			} else {
				val8 = (u8)tmp;
				buf[j] = val8;
				PHL_INFO("i=%d, j=%d, 0x%02x\n", i, j, buf[j]);
				j++;
			}
			i = (u32)(ptr - ptmpbuf + 1);
		}
	}
	if (ptmpbuf)
		_os_mem_free(d, (void*)ptmpbuf, bufsize);
	PHL_INFO("%s, filepatch %s, size=%d, done\n", __FUNCTION__, filepath, file_size);
	return (u16)j;
}

enum rtw_hal_status
rtw_efuse_file_map_load(void *efuse, char *file_path, u8 is_limit)
{
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	void *d = efuse_info->hal_com->drv_priv;
	u8 *mapbuf = NULL;
	u16 data_len = 0;
	u32 map_sz = 0, full_map_sz = 0;
	u32 offset;

	if (is_limit)
		map_sz = efuse_info->limit_efuse_size;
	else
		map_sz = efuse_info->log_efuse_size;

	if (map_sz == 0) {
		map_sz = MAX_EFUSE_MAP_LEN;
		full_map_sz = MAX_EFUSE_MAP_LEN + MAX_EFUSE_FILE_VERSION_LENGTH;
	} else
		full_map_sz = map_sz + efuse_info->version_len;

	if (file_path && full_map_sz != 0) {
		mapbuf= _os_mem_alloc(d, full_map_sz);
		if (mapbuf == NULL) {
			PHL_INFO("%s, alloc buf FAIL!!\n", __FUNCTION__);
			goto exit;
		}
		_os_mem_set(d, mapbuf, 0xFF, full_map_sz);

		data_len = efuse_file_open(d, file_path, mapbuf, full_map_sz);

		if ((data_len > map_sz) && (data_len <= full_map_sz)) {
			efuse_file_map2version(efuse_info, mapbuf + map_sz,
								   efuse_info->version_len);

			if (data_len > map_sz)
				data_len -= efuse_info->version_len;

			PHL_INFO("%s , File eFuse map to shadow len %d\n", __FUNCTION__, data_len);
			hal_status = efuse_map_buf2shadow(efuse_info, mapbuf, data_len);

			if (efuse_info->efuse_a_die_size != 0 && is_limit) {
				for (offset = efuse_info->a_die_start_offset;
					offset < (efuse_info->a_die_start_offset + (u32)efuse_info->efuse_a_die_size);
					offset++)
					efuse_info->shadow_map[offset + efuse_info->hci_to_a_die_offset] =
						mapbuf[offset];
			}

			efuse_info->map_from_status = FILE_MAP;
		} else {
			PHL_INFO("Error No Map Version !, File Map Data Len %d not over 1536.\n", data_len);
			goto exit;
		}
	}
exit:
	if (mapbuf)
		_os_mem_free(d, (void*)mapbuf, full_map_sz);

	return hal_status;
}

enum rtw_hal_status
rtw_efuse_file_mask_load(void *efuse, char *file_path, u8 is_limit)
{
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	void *d = efuse_info->hal_com->drv_priv;
	u8 *maskbuf = NULL;
	u16 data_len = 0;
	u32 mask_sz = 0, full_mask_sz = 0;

	if (is_limit)
		mask_sz = efuse_info->limit_mask_size;
	else
		mask_sz = efuse_info->mask_size;

	if (mask_sz == 0) {
		mask_sz = EFUSE_MASK_FILE_LEN;
		full_mask_sz = EFUSE_MASK_FILE_LEN + MAX_EFUSE_FILE_VERSION_LENGTH;
	} else
		full_mask_sz = mask_sz + efuse_info->version_len;

	if (file_path) {
		maskbuf= _os_mem_alloc(d, full_mask_sz);
		if (maskbuf == NULL) {
			PHL_INFO("%s, alloc buf FAIL!!\n", __FUNCTION__);
			goto exit;
		}
		_os_mem_set(d, maskbuf, 0xFF, full_mask_sz);

		data_len = efuse_file_open(d, file_path, maskbuf, full_mask_sz);

		if ((data_len > mask_sz) && (data_len <= full_mask_sz)) {
			efuse_file_mask2version(efuse_info, maskbuf + mask_sz,
									efuse_info->version_len);

			if (data_len > mask_sz)
				data_len -= efuse_info->version_len;

			PHL_INFO("Mask File data 2 buf len %d\n", data_len);
			hal_status = efuse_file_mask2buf(efuse_info, maskbuf, data_len);

		} else {
			PHL_INFO("Error No Map Version !, File Map Data Len %d not over 102.\n", data_len);
			goto exit;
		}
	}
exit:
	if (maskbuf)
		_os_mem_free(d, (void*)maskbuf, full_mask_sz);

	return hal_status;
}

enum rtw_hal_status rtw_efuse_get_logical_size(void *efuse, u32 *size,
											   bool is_limited)
{
	struct efuse_t *efuse_info = efuse;

	if(is_limited == true)
		*size = efuse_info->limit_efuse_size;
	else
		*size = efuse_info->log_efuse_size;

	PHL_INFO("%s: size = %d\n", __FUNCTION__, *size);
	return RTW_HAL_STATUS_SUCCESS;
}

enum rtw_hal_status rtw_efuse_get_size(void *efuse, u32 *size)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	status = rtw_hal_mac_get_efuse_size(efuse_info->hal_com, size);

	PHL_INFO("%s: size = %d\n", __FUNCTION__, *size);
	return status;
}

enum rtw_hal_status rtw_efuse_get_avl(void *efuse, u32 *size)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	status = rtw_hal_mac_get_efuse_avl(efuse_info->hal_com, size);

	/* [TEMP] Set avl size for testing */
	/* size = 512; */
	PHL_INFO("%s: size = %d\n", __FUNCTION__, *size);
	return status;
}

enum rtw_hal_status rtw_efuse_get_offset_mask(void *efuse, u16 offset, u8 *mask)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS;
	struct efuse_t *efuse_info = efuse;

	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS) == false)
		return RTW_HAL_STATUS_EFUSE_UNINIT;

	if(offset >= efuse_info->limit_mask_size)
		return RTW_HAL_STATUS_EFUSE_IVALID_OFFSET;

	*mask = efuse_info->mask[offset];
	PHL_INFO("%s: offset = %x mask = %x\n", __FUNCTION__, offset, *mask);
	return status;
}

enum rtw_hal_status rtw_efuse_get_mask_buf(void *efuse, u8 *destbuf, u32 *buflen)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	if (efuse_info->mask_size > 0) {
		_os_mem_cpy(efuse_info->hal_com->drv_priv, (void *)destbuf,
				(void *)efuse_info->mask , efuse_info->mask_size);
		*buflen = efuse_info->mask_size;

		PHL_INFO("%s: size = %d\n", __FUNCTION__, efuse_info->mask_size);
		status = RTW_HAL_STATUS_SUCCESS;
	}

	return status;
}

enum rtw_hal_status rtw_efuse_get_shadowmap_from(void *efuse, u8 *val)
{
	struct efuse_t *efuse_info = efuse;

	*val = efuse_info->map_from_status;

	PHL_INFO("%s:get efuse %s\n", __FUNCTION__, SHADOWMAP_FROM2STR(*val));
	return RTW_HAL_STATUS_SUCCESS;
}

char* rtw_efuse_get_shadowmap_from_to_str(void *efuse)
{
	struct efuse_t *efuse_info = efuse;

	return SHADOWMAP_FROM2STR(efuse_info->map_from_status);
}


enum rtw_hal_status rtw_efuse_get_info(void *efuse,
									   enum rtw_efuse_info info_type,
									   void *value,
									   u8 size)
{
	struct efuse_t *efuse_info = efuse;
	struct rtw_hal_com_t *hal_com = efuse_info->hal_com;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;

	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS) == false)
		return RTW_HAL_STATUS_EFUSE_UNINIT;

	if(info_type <= EFUSE_INFO_MAC_MAX)
		hal_status = rtw_hal_mac_get_efuse_info(hal_com,
												efuse_info->shadow_map,
												info_type,
												value,
												size,
												efuse_info->is_map_valid);
	else if (info_type <= EFUSE_INFO_BB_MAX)
		hal_status = rtw_hal_bb_get_efuse_info(hal_com,
											   efuse_info->shadow_map,
											   info_type,
											   value,
											   size,
											   efuse_info->is_map_valid);
	else if (info_type <= EFUSE_INFO_RF_MAX)
		hal_status = rtw_hal_rf_get_efuse_info(hal_com,
											   efuse_info->shadow_map,
											   info_type,
											   value,
											   size,
											   efuse_info->is_map_valid);
	else
		hal_status = rtw_hal_btc_get_efuse_info(hal_com,
												efuse_info->shadow_map,
												info_type,
												value,
												size,
												efuse_info->is_map_valid);

	return hal_status;
}

void rtw_efuse_process(void *efuse, char *ic_name)
{
	struct efuse_t *efuse_info = (struct efuse_t *)efuse;

	if(efuse_info == NULL) {
		PHL_ERR("%s efuse_info is NULL\n",__FUNCTION__);
		return;
	}

	efuse_check_autoload(efuse_info);
	/* Load wifi full map to shadow map */
	rtw_efuse_shadow_load(efuse_info, false);

	SET_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS);

	rtw_efuse_shadow_file_load(efuse_info, ic_name, true);

	debug_dump_data(efuse_info->shadow_map, efuse_info->log_efuse_size,
					"Logical EFUSE MAP:");
	efuse_hidden_handle(efuse_info);

	/*
	 * We can set the hw cap after we got the shadow map.
	 * The efuse get info API will check the efuse is processed or not.
	 */
	efuse_set_hw_cap(efuse_info);

	efuse_compatible_chk(efuse_info);

	if (RTW_DRV_MODE_EQC == efuse_info->phl_com->drv_mode) {
		rtw_hal_rf_get_default_rfe_type(efuse_info->hal_com);
		rtw_hal_rf_get_default_xtal(efuse_info->hal_com);
		PHL_WARN("%s: Use default RFE type(0x%x) / XTAL(0x%x) configuration for EQC mode\n",
			 __FUNCTION__,
			 efuse_info->hal_com->dev_hw_cap.rfe_type,
			 efuse_info->hal_com->dev_hw_cap.xcap);
	}
}

bool rtw_efuse_is_processed(void *efuse)
{
	struct efuse_t *efuse_info = (struct efuse_t *)efuse;

	if (TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS) == true)
		return true;
	else
		return false;
}

u32 rtw_efuse_init(struct rtw_phl_com_t *phl_com,
				   struct rtw_hal_com_t *hal_com, void **efuse)
{
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = NULL;

	efuse_info = _os_mem_alloc(hal_com->drv_priv, sizeof(struct efuse_t));

	if(efuse_info == NULL) {
		hal_status = RTW_HAL_STATUS_RESOURCE;
		return hal_status;
	}

	/* Allocate shadow map memory */
	hal_status = rtw_hal_mac_get_log_efuse_size(hal_com,
						    &(efuse_info->log_efuse_size),
						    false);

	if(hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("%s Get full logical efuse map size fail!\n",__FUNCTION__);
		goto error_efuse_shadow_init;
	}

	efuse_info->shadow_map = _os_mem_alloc(hal_com->drv_priv,
					       efuse_info->log_efuse_size);

	if(efuse_info->shadow_map == NULL) {
		hal_status = RTW_HAL_STATUS_RESOURCE;
		PHL_ERR("%s Allocate shadow efuse map fail!\n", __FUNCTION__);
		goto error_efuse_shadow_init;
	}

	hal_status = rtw_hal_mac_get_log_efuse_size(hal_com,
						    &(efuse_info->limit_efuse_size),
						    true);

	if(hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("%s Get limited logical efuse map size fail!\n", __FUNCTION__);
		goto error_efuse_shadow_init;
	}

	hal_status = rtw_hal_mac_get_efuse_a_die_size(hal_com,
						    &(efuse_info->efuse_a_die_size));

	if(hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("%s Get efuse a die size fail!\n", __FUNCTION__);
		goto error_efuse_shadow_init;
	}

	efuse_info->hci_to_a_die_offset = get_hci_to_a_die_offset(efuse_info->log_efuse_size,
										efuse_info->limit_efuse_size);

	efuse_info->a_die_start_offset = get_a_die_start_offset(efuse_info->limit_efuse_size,
										efuse_info->efuse_a_die_size);

	/* Allocate mask memory */
	hal_status = rtw_hal_mac_get_efuse_mask_size(hal_com,
						     &(efuse_info->mask_size),
						     false);

	if(hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("%s Get full efuse mask size fail!\n", __FUNCTION__);
		goto error_efuse_mask_init;
	}

	efuse_info->mask = _os_mem_alloc(hal_com->drv_priv,
					 efuse_info->mask_size);

	if(efuse_info->mask == NULL) {
		hal_status = RTW_HAL_STATUS_RESOURCE;
		PHL_ERR("%s Allocate efuse mask fail!\n", __FUNCTION__);
		goto error_efuse_mask_init;
	}

	hal_status = rtw_hal_mac_get_efuse_mask_size(hal_com,
						     &(efuse_info->limit_mask_size),
						     true);

	if(hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("%s Get limited efuse mask size fail!\n", __FUNCTION__);
		goto error_efuse_mask_init;
	}

	efuse_info->version_len = rtw_hal_mac_get_efuse_ver_len(hal_com);

	efuse_info->map_version = _os_mem_alloc(hal_com->drv_priv,
						efuse_info->version_len);

	if(efuse_info->map_version == NULL) {
		hal_status = RTW_HAL_STATUS_RESOURCE;
		goto error_map_version_init;
	}

	efuse_info->mask_version = _os_mem_alloc(hal_com->drv_priv,
						 efuse_info->version_len);
	if(efuse_info->mask_version == NULL) {
		hal_status = RTW_HAL_STATUS_RESOURCE;
		goto error_mask_version_init;
	}

	/* Allocate bt shadow map memory */
	hal_status = rtw_hal_mac_get_log_efuse_bt_size(hal_com,
						&(efuse_info->bt_log_efuse_size));

	if(hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("%s Get full logical efuse map size fail!\n",__FUNCTION__);
		goto error_efuse_bt_shadow_init;
	}

	efuse_info->bt_shadow_map = _os_mem_alloc(hal_com->drv_priv,
					       efuse_info->bt_log_efuse_size);

	if(efuse_info->bt_shadow_map == NULL) {
		hal_status = RTW_HAL_STATUS_RESOURCE;
		PHL_ERR("%s Allocate shadow efuse map fail!\n", __FUNCTION__);
		goto error_efuse_bt_shadow_init;
	}

	/* Allocate mask memory */
	hal_status = rtw_hal_mac_get_efuse_bt_mask_size(hal_com,
						     &(efuse_info->bt_mask_size));

	if(hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("%s Get full efuse mask size fail!\n", __FUNCTION__);
		goto error_efuse_bt_mask_init;
	}

	efuse_info->bt_mask = _os_mem_alloc(hal_com->drv_priv,
					 efuse_info->bt_mask_size);

	if(efuse_info->bt_mask == NULL) {
		hal_status = RTW_HAL_STATUS_RESOURCE;
		PHL_ERR("%s Allocate efuse mask fail!\n", __FUNCTION__);
		goto error_efuse_bt_mask_init;
	}


	efuse_info->phl_com = phl_com;
	efuse_info->hal_com = hal_com;

	*efuse = efuse_info;

	hal_status = RTW_HAL_STATUS_SUCCESS;
	return hal_status;

error_efuse_bt_mask_init:
	_os_mem_free(hal_com->drv_priv, efuse_info->bt_shadow_map,
		     efuse_info->bt_log_efuse_size);

error_efuse_bt_shadow_init:
	_os_mem_free(hal_com->drv_priv, efuse_info->mask_version,
		efuse_info->version_len);

error_mask_version_init:
	_os_mem_free(hal_com->drv_priv, efuse_info->map_version,
		     efuse_info->version_len);

error_map_version_init:
	_os_mem_free(hal_com->drv_priv, efuse_info->mask,
		     efuse_info->mask_size);

error_efuse_mask_init:
	_os_mem_free(hal_com->drv_priv, efuse_info->shadow_map,
		     efuse_info->log_efuse_size);

error_efuse_shadow_init:
	_os_mem_free(hal_com->drv_priv, efuse_info, sizeof(struct efuse_t));

	return hal_status;
}

void rtw_efuse_deinit(struct rtw_hal_com_t *hal_com, void *efuse)
{
	struct efuse_t *efuse_info = efuse;

	if(efuse_info->bt_mask) {
		_os_mem_free(hal_com->drv_priv, efuse_info->bt_mask,
					 efuse_info->bt_mask_size);
		efuse_info->bt_mask = NULL;
	}

	if(efuse_info->bt_shadow_map) {
		_os_mem_free(hal_com->drv_priv, efuse_info->bt_shadow_map,
					 efuse_info->bt_log_efuse_size);
		efuse_info->bt_shadow_map = NULL;
	}

	if(efuse_info->mask) {
		_os_mem_free(hal_com->drv_priv, efuse_info->mask,
					 efuse_info->mask_size);
		efuse_info->mask = NULL;
	}
	if(efuse_info->map_version) {
		_os_mem_free(hal_com->drv_priv, efuse_info->map_version,
					 efuse_info->version_len);
		efuse_info->map_version = NULL;
	}
	if(efuse_info->mask_version) {
		 _os_mem_free(hal_com->drv_priv, efuse_info->mask_version,
		 				efuse_info->version_len);
		 efuse_info->mask_version = NULL;
	}
	if(efuse_info->shadow_map) {
		_os_mem_free(hal_com->drv_priv, efuse_info->shadow_map,
					 efuse_info->log_efuse_size);
		efuse_info->shadow_map = NULL;
	}

	_os_mem_free(hal_com->drv_priv, efuse_info, sizeof(struct efuse_t));
	efuse_info = NULL;
}

/* BT EFUSE API */
void efuse_bt_shadow_read_one_byte(struct efuse_t *efuse, u16 offset, u8 *value)
{
   *value = efuse->bt_shadow_map[offset];
}

void efuse_bt_shadow_read_two_byte(struct efuse_t *efuse, u16 offset, u16 *value)
{
   *value = efuse->bt_shadow_map[offset];
   *value |= efuse->bt_shadow_map[offset+1] << 8;
}

void efuse_bt_shadow_read_four_byte(struct efuse_t *efuse, u16 offset, u32 *value)
{
   *value = efuse->bt_shadow_map[offset];
   *value |= efuse->bt_shadow_map[offset+1] << 8;
   *value |= efuse->bt_shadow_map[offset+2] << 16;
   *value |= efuse->bt_shadow_map[offset+3] << 24;
}

void efuse_bt_shadow_write_one_byte(struct efuse_t *efuse, u16 offset, u16 value)
{
   efuse->bt_shadow_map[offset] = (u8)(value&0x00FF);
}

void efuse_bt_shadow_write_two_byte(struct efuse_t *efuse, u16 offset, u16 value)
{
   efuse->bt_shadow_map[offset] = (u8)(value&0x00FF);
   efuse->bt_shadow_map[offset+1] = (u8)((value&0xFF00) >> 8);
}

void efuse_bt_shadow_write_four_byte(struct efuse_t *efuse, u16 offset, u32 value)
{
   efuse->bt_shadow_map[offset] = (u8)(value&0x000000FF);
   efuse->bt_shadow_map[offset+1] = (u8)((value&0x0000FF00) >> 8);
   efuse->bt_shadow_map[offset+2] = (u8)((value&0x00FF0000) >> 16);
   efuse->bt_shadow_map[offset+3] = (u8)((value&0xFF000000) >> 24);
}

enum rtw_hal_status rtw_efuse_bt_shadow_load(void *efuse)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	status = rtw_hal_mac_read_log_efuse_bt_map(efuse_info->hal_com,
											efuse_info->bt_shadow_map);

	return status;
}

enum rtw_hal_status rtw_efuse_bt_shadow_update(void *efuse)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_EFUSE_PG_FAIL;
	enum rtw_hal_status reload_status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	u32 map_size = 0, mask_size = 0;

	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS) == false) {
		PHL_WARN("%s: efuse map not load yet!\n", __FUNCTION__);
		status = RTW_HAL_STATUS_EFUSE_UNINIT;
		goto exit;
	}

	/* Load efuse mask file before PG */
	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_BT_MASK_FILE_LOADED) == false) {
		PHL_WARN("%s: efuse mask not load yet!\n", __FUNCTION__);
		status = RTW_HAL_STATUS_EFUSE_PG_FAIL;
		goto exit;
	}

	map_size = efuse_info->bt_log_efuse_size;
	mask_size = efuse_info->bt_mask_size;

	status = rtw_hal_mac_write_log_efuse_bt_map(efuse_info->hal_com,
							efuse_info->bt_shadow_map,
							map_size,
							efuse_info->bt_mask,
							mask_size);

	if(status != RTW_HAL_STATUS_SUCCESS)
		PHL_WARN("%s: BT PG Fail!\n", __FUNCTION__);

	/* Reload shadow map after PG */
	reload_status = rtw_hal_mac_read_log_efuse_bt_map(efuse_info->hal_com,
								efuse_info->bt_shadow_map);
	if(reload_status != RTW_HAL_STATUS_SUCCESS)
		PHL_WARN("%s: Reload bt shadow map Fail!\n", __FUNCTION__);

	/*
	 * Clear the load external map file flag and map version
	 * after reloading the map.
	 */
	if(TEST_STATUS_FLAG(efuse_info->status,
				EFUSE_STATUS_BT_MAP_FILE_LOADED) == true) {
		CLEAR_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_BT_MAP_FILE_LOADED);
	}

exit:
	return status;
}

enum rtw_hal_status
rtw_efuse_bt_shadow_read(void *efuse, u8 byte_count, u16 offset, u32 *value)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	u32	efuse_bt_size = 0;

	efuse_bt_size = efuse_info->bt_log_efuse_size;

	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS) == false) {
		PHL_WARN("%s: efuse map not load yet!\n", __FUNCTION__);
		status = RTW_HAL_STATUS_EFUSE_UNINIT;
		goto exit;
	}

	if((u32)(offset+byte_count) > efuse_bt_size) {
		PHL_WARN("%s: Invalid offset!\n", __FUNCTION__);
		status = RTW_HAL_STATUS_EFUSE_IVALID_OFFSET;
		goto exit;
	}

	if (byte_count == 1)
		efuse_bt_shadow_read_one_byte(efuse_info, offset, (u8 *)value);
	else if (byte_count == 2)
		efuse_bt_shadow_read_two_byte(efuse_info, offset, (u16 *)value);
	else if (byte_count == 4)
		efuse_bt_shadow_read_four_byte(efuse_info, offset, (u32 *)value);

	status = RTW_HAL_STATUS_SUCCESS;
exit:
	return status;
}

enum rtw_hal_status
rtw_efuse_bt_shadow_write(void *efuse, u8 byte_count, u16 offset, u32 value)
{
  enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
  struct efuse_t *efuse_info = efuse;
  u32 efuse_bt_size = 0;

  efuse_bt_size = efuse_info->bt_log_efuse_size;

  if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS) == false) {
	  PHL_WARN("%s: efuse map not load yet!\n", __FUNCTION__);
	  status = RTW_HAL_STATUS_EFUSE_UNINIT;
	  goto exit;
  }

  if((u32)(offset+byte_count) > efuse_bt_size) {
	  PHL_WARN("%s: Invalid offset!\n", __FUNCTION__);
	  status = RTW_HAL_STATUS_EFUSE_IVALID_OFFSET;
	  goto exit;
  }

  if (byte_count == 1)
	  efuse_bt_shadow_write_one_byte(efuse_info, offset, (u8)value);
  else if (byte_count == 2)
	  efuse_bt_shadow_write_two_byte(efuse_info, offset, (u16)value);
  else if (byte_count == 4)
	  efuse_bt_shadow_write_four_byte(efuse_info, offset, (u32)value);

  status = RTW_HAL_STATUS_SUCCESS;
exit:
  return status;
}

/*
 * This API is used for original mp dll command.
 * usage = used percentage(1 Byte) + used bytes(2 Bytes)
 */
enum rtw_hal_status rtw_efuse_bt_get_usage(void *efuse, u32 *usage)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	u32 avl_size = 0;
	u16 used_byte = 0;
	u32 total_size = 0;
	u8 used_percentage = 0;

	status = rtw_hal_mac_get_efuse_bt_avl(efuse_info->hal_com, &avl_size);
	status = rtw_hal_mac_get_efuse_bt_size(efuse_info->hal_com, &total_size);

	if(total_size != 0){
		used_byte = (u16)(total_size - avl_size);
		used_percentage = (u8)(used_byte*100/total_size);
		*usage = (used_percentage<<16)|(used_byte);
	}

	return status;
}

enum rtw_hal_status rtw_efuse_bt_shadow2buf(void *efuse, u8 *destbuf, u16 buflen)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS;
	struct efuse_t *efuse_info = efuse;

	_os_mem_cpy(efuse_info->hal_com->drv_priv, (void *)destbuf,
				(void *)efuse_info->bt_shadow_map , buflen);

	return status;
}

enum rtw_hal_status
efuse_bt_map_buf2shadow(struct efuse_t *efuse, u8 *srcbuf, u16 buflen)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;

	_os_mem_cpy(efuse->hal_com->drv_priv, (void *)efuse->bt_shadow_map,
				(void *)srcbuf, buflen);
	SET_STATUS_FLAG(efuse->status, EFUSE_STATUS_BT_MAP_FILE_LOADED);
	status = RTW_HAL_STATUS_SUCCESS;

	return status;
}

enum rtw_hal_status
efuse_bt_file_mask2buf(struct efuse_t *efuse, u8 *srcbuf, u16 buflen)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;

	_os_mem_cpy(efuse->hal_com->drv_priv, (void *)efuse->bt_mask, (void *)srcbuf,
				buflen);
	SET_STATUS_FLAG(efuse->status, EFUSE_STATUS_BT_MASK_FILE_LOADED);
	status = RTW_HAL_STATUS_SUCCESS;

	debug_dump_data(efuse->bt_mask, efuse->bt_mask_size, "[HAL EFUSE] bt mask data =");

	return status;
}

enum rtw_hal_status
rtw_efuse_bt_file_map_load(void *efuse, char *file_path)
{
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	void *d = efuse_info->hal_com->drv_priv;
	u8 *mapbuf = NULL;
	u16 data_len = 0;
	u32 bt_map_sz = 0;

	bt_map_sz = efuse_info->bt_log_efuse_size;

	if (bt_map_sz == 0)
		bt_map_sz = MAX_EFUSE_MAP_LEN;

	if (file_path) {
		mapbuf= _os_mem_alloc(d, bt_map_sz);
		if (mapbuf == NULL) {
			PHL_INFO("%s, alloc buf FAIL!!\n", __FUNCTION__);
			goto exit;
		}
		_os_mem_set(d, mapbuf, 0xFF, bt_map_sz);

		data_len = efuse_file_open(d, file_path, mapbuf, bt_map_sz);

		if (data_len <= bt_map_sz && data_len > 0) {
			PHL_INFO("%s , File eFuse bt map to shadow len %d\n", __FUNCTION__, data_len);
			hal_status = efuse_bt_map_buf2shadow(efuse_info, mapbuf, data_len);

		} else {
			PHL_INFO("Error No bt Map Version !, File Map Data Len %d not over 1024.\n", data_len);
			goto exit;
		}
	}
exit:
	if (mapbuf)
		_os_mem_free(d, (void*)mapbuf, bt_map_sz);

	return hal_status;
}


enum rtw_hal_status
rtw_efuse_bt_file_mask_load(void *efuse, char *file_path)
{
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;
	void *d = efuse_info->hal_com->drv_priv;
	u8 *maskbuf = NULL;
	u16 data_len = 0;
	u32 bt_mask_sz = 0;

	bt_mask_sz = efuse_info->bt_mask_size;

	if (bt_mask_sz == 0)
		goto exit;

	if (file_path) {
		maskbuf= _os_mem_alloc(d, bt_mask_sz);
		if (maskbuf == NULL) {
			PHL_INFO("%s, alloc buf FAIL!!\n", __FUNCTION__);
			goto exit;
		}
		_os_mem_set(d, maskbuf, 0xFF, bt_mask_sz);

		data_len = efuse_file_open(d, file_path, maskbuf, bt_mask_sz);

		if (data_len <= bt_mask_sz && data_len > 0) {
			PHL_INFO("Mask File data 2 buf len %d\n", data_len);
			hal_status = efuse_bt_file_mask2buf(efuse_info, maskbuf, data_len);

		} else {
			PHL_INFO("Error No Map Version !, File Map Data Len %d not over 96.\n", data_len);
			goto exit;
		}
	}
exit:
	if (maskbuf)
		_os_mem_free(d, (void*)maskbuf, bt_mask_sz);

	return hal_status;
}

enum rtw_hal_status rtw_efuse_bt_get_logical_size(void *efuse, u32 *size)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	status = rtw_hal_mac_get_log_efuse_bt_size(efuse_info->hal_com, size);

	PHL_INFO("%s: size = %d\n", __FUNCTION__, *size);
	return status;
}

enum rtw_hal_status rtw_efuse_bt_get_size(void *efuse, u32 *size)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	status = rtw_hal_mac_get_efuse_bt_size(efuse_info->hal_com, size);

	PHL_INFO("%s: size = %d\n", __FUNCTION__, *size);
	return status;
}

enum rtw_hal_status rtw_efuse_bt_get_avl(void *efuse, u32 *size)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	status = rtw_hal_mac_get_efuse_bt_avl(efuse_info->hal_com, size);

	PHL_INFO("%s: size = %d\n", __FUNCTION__, *size);
	return status;
}

enum rtw_hal_status rtw_efuse_bt_get_offset_mask(void *efuse, u16 offset, u8 *mask)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	if(TEST_STATUS_FLAG(efuse_info->status, EFUSE_STATUS_PROCESS) == false)
		return RTW_HAL_STATUS_EFUSE_UNINIT;

	if(offset >= efuse_info->bt_mask_size)
		return RTW_HAL_STATUS_EFUSE_IVALID_OFFSET;

	*mask = efuse_info->bt_mask[offset];
	PHL_INFO("%s: bt offset = %x mask = %x\n", __FUNCTION__, offset, *mask);
	return status;
}

enum rtw_hal_status rtw_efuse_bt_get_mask_buf(void *efuse, u8 *destbuf, u32 *buflen)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	if (efuse_info->bt_mask_size > 0) {
		_os_mem_cpy(efuse_info->hal_com->drv_priv, (void *)destbuf,
				(void *)efuse_info->bt_mask , efuse_info->bt_mask_size);
		*buflen = efuse_info->bt_mask_size;

		PHL_INFO("%s: size = %d\n", __FUNCTION__, efuse_info->bt_mask_size);
		status = RTW_HAL_STATUS_SUCCESS;
	}
	return status;
}

enum rtw_hal_status rtw_efuse_bt_read_hidden(void *efuse, u32 addr, u32 size, u8 *val)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	status = rtw_hal_mac_read_efuse_bt_hidden(efuse_info->hal_com, addr, size, val);

	if(status == RTW_HAL_STATUS_SUCCESS)
	{
		PHL_INFO("%s: bt hidden read ok!\n", __FUNCTION__);
	}else{
		PHL_INFO("%s: bt hidden read fail!\n", __FUNCTION__);
	}

	return status;
}

enum rtw_hal_status rtw_efuse_bt_write_hidden(void *efuse, u32 addr, u8 val)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	status = rtw_hal_mac_write_efuse_bt_hidden(efuse_info->hal_com, addr, val);

	if(status == RTW_HAL_STATUS_SUCCESS)
	{
		PHL_INFO("%s: bt hidden PG ok!\n", __FUNCTION__);
	}else{
		PHL_INFO("%s: bt hidden PG fail!\n", __FUNCTION__);
	}

	return status;
}

enum rtw_hal_status rtw_efuse_read_phy_wifi(void *efuse, u32 addr, u32 size, u8 *data, u8 type)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
	struct efuse_t *efuse_info = efuse;

	if(type == HAL_MP_EFUSE_WIFI)
		status = rtw_hal_mac_read_phy_efuse(efuse_info->hal_com, addr, size, data);
	else if(type == HAL_MP_EFUSE_BT)
		status = rtw_hal_mac_read_bt_phy_efuse(efuse_info->hal_com, addr, size, data);

	if(status == RTW_HAL_STATUS_SUCCESS)
	{
		PHL_INFO("%s: real raw read ok!\n", __FUNCTION__);
	}else{
		PHL_INFO("%s: real raw read fail!\n", __FUNCTION__);
	}

	return status;
}

enum rtw_hal_status rtw_efuse_renew(void *efuse, u8 type)
{
	enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS;
	struct efuse_t *efuse_info = efuse;

	if (type == HAL_MP_EFUSE_WIFI) {
		rtw_hal_bb_get_efuse_init(efuse_info->hal_com);
		rtw_hal_rf_get_efuse_ex(efuse_info->hal_com, HW_PHY_0);
		PHL_INFO("%s: hal efuse renew done\n", __FUNCTION__);

	} else if (type == HAL_MP_EFUSE_BT) {
		PHL_INFO("%s: Not ready\n", __FUNCTION__);
	}

	return status;
}
