/******************************************************************************
 *
 * Copyright(c) 2019 Realtek Corporation. All rights reserved.
 *
 * 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.
 *
 ******************************************************************************/
#include "efuse.h"

static struct mac_efuse_tbl efuse_tbl;
static struct mac_bank_efuse_info bank_efuse_info;
u16 efuse_ctrl = R_AX_EFUSE_CTRL;
u16 read_efuse_cnt = EFUSE_WAIT_CNT;
bool OTP_test;
enum rtw_dv_sel dv_sel = DDV;

static struct efuse_info_item offset_pcie = {
	0x400, /* mac_addr */
	0, /* pid */
	0x408, /* did */
	0x406, /* vid */
	0x40A, /* svid */
	0x40C, /* smid */
};

static struct efuse_info_item offset_usb_8852a = {
	0x438, /* mac_addr */
	0x432, /* pid */
	0, /* did */
	0x430, /* vid */
	0, /* svid */
	0, /* smid */
};

static struct efuse_info_item offset_usb_8852b = {
	0x488, /* mac_addr */
	0x482, /* pid */
	0, /* did */
	0x480, /* vid */
	0, /* svid */
	0, /* smid */
};

static struct efuse_info_item offset_sdio = {
	0x41A, /* mac_addr */
	0, /* pid */
	0, /* did */
	0, /* vid */
	0, /* svid */
	0, /* smid */
};

static struct efuse_info_item def_val_pcie = {
	0x0, /* mac_addr */
	0, /* pid */
	0x52, /* did */
	0xEC, /* vid */
	0xEC, /* svid */
	0x52, /* smid */
};

static struct efuse_info_item def_val_usb_8852a = {
	0x0, /* mac_addr */
	0x5A, /* pid */
	0, /* did */
	0xDA, /* vid */
	0, /* svid */
	0, /* smid */
};

static struct efuse_info_item def_val_usb_8852b = {
	0x0, /* mac_addr */
	0x5B, /* pid */
	0, /* did */
	0xDA, /* vid */
	0, /* svid */
	0, /* smid */
};

static struct efuse_info_item def_val_sdio = {
	0x0, /* mac_addr */
	0, /* pid */
	0, /* did */
	0, /* vid */
	0, /* svid */
	0, /* smid */
};

static struct efuse_info_item len_pcie = {
	6, /* mac_addr */
	0, /* pid */
	2, /* did */
	2, /* vid */
	2, /* svid */
	2, /* smid */
};

static struct efuse_info_item len_usb = {
	6, /* mac_addr */
	2, /* pid */
	0, /* did */
	2, /* vid */
	0, /* svid */
	0, /* smid */
};

static struct efuse_info_item len_sdio = {
	6, /* mac_addr */
	0, /* pid */
	0, /* did */
	0, /* vid */
	0, /* svid */
	0, /* smid */
};

static struct efuse_info efuse_info_pcie = {
	&offset_pcie, /* offset */
	&def_val_pcie, /* def_val */
	&len_pcie, /* len */
};

static struct efuse_info efuse_info_usb_8852a = {
	&offset_usb_8852a, /* offset */
	&def_val_usb_8852a, /* def_val */
	&len_usb, /* len */
};

static struct efuse_info efuse_info_usb_8852b = {
	&offset_usb_8852b, /* offset */
	&def_val_usb_8852b, /* def_val */
	&len_usb, /* len */
};

static struct efuse_info efuse_info_sdio = {
	&offset_sdio, /* offset */
	&def_val_sdio, /* def_val */
	&len_sdio, /* len */
};

static u32 efuse_map_init(struct mac_ax_adapter *adapter,
			  enum efuse_map_sel map_sel);
static u32 efuse_fwcmd_ck(struct mac_ax_adapter *adapter);
static u32 efuse_proc_ck(struct mac_ax_adapter *adapter);
static u32 cnv_efuse_state(struct mac_ax_adapter *adapter, u8 dest_state);
static u32 switch_efuse_bank(struct mac_ax_adapter *adapter,
			     enum mac_ax_efuse_bank bank);
static u32 proc_dump_efuse(struct mac_ax_adapter *adapter,
			   enum mac_ax_efuse_read_cfg cfg);
static u32 read_hw_efuse(struct mac_ax_adapter *adapter, u32 offset, u32 size,
			 u8 *map);
static u32 write_hw_efuse(struct mac_ax_adapter *adapter, u32 offset, u8 value);
static u32 cmp_hw_efuse(struct mac_ax_adapter *adapter, u32 offset, u16 val);
static u32 eeprom_parser(struct mac_ax_adapter *adapter, u8 *phy_map,
			 u8 *log_map, enum mac_ax_efuse_parser_cfg cfg);
static u32 read_log_efuse_map(struct mac_ax_adapter *adapter, u8 *map,
			      u32 log_efuse_size);
static u32 proc_pg_efuse_by_map(struct mac_ax_adapter *adapter,
				struct mac_ax_pg_efuse_info *info,
				enum mac_ax_efuse_read_cfg cfg);
static u32 dump_efuse_drv(struct mac_ax_adapter *adapter);
static u32 dump_efuse_fw(struct mac_ax_adapter *adapter);
static u32 proc_write_log_efuse(struct mac_ax_adapter *adapter, u32 offset,
				u8 value);
static u32 read_efuse(struct mac_ax_adapter *adapter, u32 offset, u32 size,
		      u8 *map);
static u32 update_eeprom_mask(struct mac_ax_adapter *adapter,
			      struct mac_ax_pg_efuse_info *info,
			      u8 *updated_mask, bool pg_sim);
static u32 check_efuse_enough(struct mac_ax_adapter *adapter,
			      struct mac_ax_pg_efuse_info *info,
			      u8 *updated_mask);
static u32 proc_pg_efuse(struct mac_ax_adapter *adapter,
			 struct mac_ax_pg_efuse_info *info, u8 word_en,
			 u8 pre_word_en, u32 eeprom_offset, bool pg_sim);
static u32 program_efuse(struct mac_ax_adapter *adapter,
			 struct mac_ax_pg_efuse_info *info, u8 *updated_mask,
			 bool pg_sim);
static void mask_eeprom(struct mac_ax_adapter *adapter,
			struct mac_ax_pg_efuse_info *info);
static u32 query_status_map(struct mac_ax_adapter *adapter,
			    enum mac_ax_efuse_feature_id feature_id,
			    u8 *map, bool is_limit);
static u32 adjust_mask(struct mac_ax_adapter *adapter,
		       struct mac_ax_pg_efuse_info *info);
static u32 compare_info_length(struct efuse_info *info,
			       enum rtw_efuse_info id, u32 length);
static u32 set_check_sum_val(struct mac_ax_adapter *adapter,
			     u8 *map, u16 value);
static void cal_check_sum(struct mac_ax_adapter *adapter,
			  u16 *chksum);
static u32 compare_version(struct mac_ax_adapter *adapter,
			   struct mac_ax_pg_efuse_info *info, u32 ver_len);
static void add_dummy_read(struct mac_ax_adapter *adapter);
static void enable_OTP_burst_mode(struct mac_ax_adapter *adapter,
				  bool enable);
static void enable_efuse_sw_pwr_cut(struct mac_ax_adapter *adapter,
				    bool is_write);
static void disable_efuse_sw_pwr_cut(struct mac_ax_adapter *adapter,
				     bool is_write);
static u32 enable_efuse_pwr_cut_dav(struct mac_ax_adapter *adapter,
				    bool is_write);
static u32 disable_efuse_pwr_cut_dav(struct mac_ax_adapter *adapter,
				     bool is_write);
static u32 read_hw_efuse_dav(struct mac_ax_adapter *adapter, u32 offset, u32 size,
			     u8 *map);
static u32 write_hw_efuse_dav(struct mac_ax_adapter *adapter, u32 offset,
			      u8 value);
static void switch_dv(struct mac_ax_adapter *adapter, enum rtw_dv_sel);

u32 mac_dump_efuse_map_wl_plus(struct mac_ax_adapter *adapter,
			       enum mac_ax_efuse_read_cfg cfg, u8 *efuse_map)
{
	u32 ret = 0;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u8 chip_id = hw_info->chip_id;

	switch (chip_id) {
	case MAC_AX_CHIP_ID_8852A:
		ret = mac_dump_efuse_map_wl(adapter, cfg, efuse_map);
		break;
	case MAC_AX_CHIP_ID_8852B:
	case MAC_AX_CHIP_ID_8852C:
	case MAC_AX_CHIP_ID_8192XB:
		ret = mac_dump_efuse_map_wl(adapter, cfg, efuse_map);
		if (ret)
			return ret;
		switch_dv(adapter, DAV);
		ret = mac_dump_efuse_map_wl(adapter, MAC_AX_EFUSE_R_DRV,
					    efuse_map + hw_info->efuse_size);
		switch_dv(adapter, DDV);
		break;
	default:
		break;
	}

	if (ret)
		return ret;

	return MACSUCCESS;
}

u32 mac_dump_efuse_map_wl(struct mac_ax_adapter *adapter,
			  enum mac_ax_efuse_read_cfg cfg, u8 *efuse_map)
{
	u32 ret, stat;

#if 0
	if (cfg == MAC_AX_EFUSE_R_FW ||
	    (cfg == MAC_AX_EFUSE_R_AUTO &&
	     adapter->sm.fwdl == MAC_AX_FWDL_INIT_RDY))
		return MACNOITEM;
#else
	if (cfg == MAC_AX_EFUSE_R_FW &&
	    adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) // no fw file
		return MACNOFW;
#endif

	PLTFM_MSG_TRACE("[TRACE]cfg = %d\n", cfg);

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_PHY);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	if (dv_sel == DAV)
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_DAV);
	else
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_WL);
	if (ret != 0)
		return ret;

	ret = proc_dump_efuse(adapter, cfg);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]dump efuse!!\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	query_status_map(adapter, MAC_AX_DUMP_PHYSICAL_EFUSE, efuse_map, 0);

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_dump_efuse_map_bt(struct mac_ax_adapter *adapter,
			  enum mac_ax_efuse_read_cfg cfg, u8 *efuse_map)
{
	u32 ret, stat;

#if 0
	if (cfg == MAC_AX_EFUSE_R_FW ||
	    (cfg == MAC_AX_EFUSE_R_AUTO &&
	     adapter->sm.fwdl == MAC_AX_FWDL_INIT_RDY))
		return MACNOITEM;
#else
	if (cfg == MAC_AX_EFUSE_R_FW &&
	    adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) // no fw file
		return MACNOFW;
#endif

	PLTFM_MSG_TRACE("[TRACE]cfg = %d\n", cfg);

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_PHY);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_BT);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_BT);
	if (ret != 0)
		return ret;

	ret = proc_dump_efuse(adapter, cfg);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]dump efuse!!\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	query_status_map(adapter, MAC_AX_DUMP_PHYSICAL_EFUSE, efuse_map, 0);

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_write_efuse_plus(struct mac_ax_adapter *adapter, u32 addr, u8 val,
			 enum mac_ax_efuse_bank bank)
{
	u32 ret = 0;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u8 chip_id = hw_info->chip_id;
	u32 efuse_size = hw_info->wl_efuse_size;

	switch (bank) {
	case MAC_AX_EFUSE_BANK_WIFI:
		switch (chip_id) {
		case MAC_AX_CHIP_ID_8852A:
			ret = mac_write_efuse(adapter, addr, val, bank);
			break;
		case MAC_AX_CHIP_ID_8852B:
		case MAC_AX_CHIP_ID_8852C:
		case MAC_AX_CHIP_ID_8192XB:
			if (addr < efuse_size) {
				ret = mac_write_efuse(adapter, addr, val, bank);
			} else {
				switch_dv(adapter, DAV);
				ret = mac_write_efuse(adapter, addr -
						      efuse_size, val, bank);
				switch_dv(adapter, DDV);
			}
			break;
		default:
			break;
		}
		break;
	case MAC_AX_EFUSE_BANK_BT:
		ret = mac_write_efuse(adapter, addr, val, bank);
		break;
	default:
		break;
	}
	if (ret)
		return ret;

	return MACSUCCESS;
}

u32 mac_write_efuse(struct mac_ax_adapter *adapter, u32 addr, u8 val,
		    enum mac_ax_efuse_bank bank)
{
	u32 ret, stat, efuse_size = 0;

	if (bank == MAC_AX_EFUSE_BANK_WIFI) {
		if (OTP_test)
			efuse_size = OTP_PHY_SIZE;
		else
			efuse_size = adapter->hw_info->wl_efuse_size;
	} else if (bank == MAC_AX_EFUSE_BANK_BT) {
		efuse_size = adapter->hw_info->bt_efuse_size;
	} else {
		return MACEFUSEBANK;
	}

	if (addr >= efuse_size) {
		PLTFM_MSG_ERR("[ERR]Offset is too large\n");
		return MACEFUSESIZE;
	}

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_PHY);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, bank);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	enable_efuse_sw_pwr_cut(adapter, 1);
	ret = write_hw_efuse(adapter, addr, val);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]write physical efuse\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}
	disable_efuse_sw_pwr_cut(adapter, 1);

	if (bank == MAC_AX_EFUSE_BANK_BT) {
		ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
		if (ret != 0) {
			PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
			stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
			if (stat != 0)
				return stat;
			return ret;
		}
	}

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return ret;
}

u32 mac_read_efuse_plus(struct mac_ax_adapter *adapter, u32 addr, u32 size,
			u8 *val, enum mac_ax_efuse_bank bank)
{
	u32 ret = 0;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u8 chip_id = hw_info->chip_id;
	u32 efuse_size = hw_info->wl_efuse_size;
	u32 size1, size2;

	switch (bank) {
	case MAC_AX_EFUSE_BANK_WIFI:
		switch (chip_id) {
		case MAC_AX_CHIP_ID_8852A:
			ret =  mac_read_efuse(adapter, addr, size, val, bank);
			break;
		case MAC_AX_CHIP_ID_8852B:
		case MAC_AX_CHIP_ID_8852C:
		case MAC_AX_CHIP_ID_8192XB:
			if (addr < efuse_size && addr + size <= efuse_size) {
				ret = mac_read_efuse(adapter, addr, size,
						     val, bank);
			} else if (addr >= efuse_size) {
				switch_dv(adapter, DAV);
				ret = mac_read_efuse(adapter, addr - efuse_size,
						     size, val, bank);
				switch_dv(adapter, DDV);
			} else if (addr < efuse_size &&
				   addr + size > efuse_size) {
				size1 = efuse_size - addr;
				size2 = addr + size - efuse_size;

				ret = mac_read_efuse(adapter, addr, size1,
						     val, bank);
				if (ret)
					return ret;

				switch_dv(adapter, DAV);
				ret = mac_read_efuse(adapter, 0, size2,
						     val + size1, bank);
				switch_dv(adapter, DDV);
			}
			if (ret)
				return ret;
			break;
		default:
			break;
		}
		break;
	case MAC_AX_EFUSE_BANK_BT:
		ret =  mac_read_efuse(adapter, addr, size, val, bank);
		break;
	default:
		break;
	}
	if (ret)
		return ret;

	return MACSUCCESS;
}

u32 mac_read_efuse(struct mac_ax_adapter *adapter, u32 addr, u32 size, u8 *val,
		   enum mac_ax_efuse_bank bank)
{
	u32 ret, stat, efuse_size = 0;

	if (bank == MAC_AX_EFUSE_BANK_WIFI) {
		if (OTP_test)
			efuse_size = OTP_PHY_SIZE;
		else
			efuse_size = adapter->hw_info->wl_efuse_size;
	} else if (bank == MAC_AX_EFUSE_BANK_BT) {
		efuse_size = adapter->hw_info->bt_efuse_size;
	} else {
		return MACEFUSEBANK;
	}

	if (addr >= efuse_size || addr + size > efuse_size) {
		PLTFM_MSG_ERR("[ERR] Wrong efuse index\n");
		return MACEFUSESIZE;
	}

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_PHY);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, bank);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = read_hw_efuse(adapter, addr, size, val);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]read hw efuse\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	if (bank == MAC_AX_EFUSE_BANK_BT) {
		ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
		if (ret != 0) {
			PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
			stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
			if (stat != 0)
				return stat;
			return ret;
		}
	}

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_get_efuse_avl_size(struct mac_ax_adapter *adapter, u32 *size)
{
	u32 ret;
	u8 *map;
	u32 efuse_size = adapter->hw_info->log_efuse_size;
	struct mac_ax_efuse_param *efuse_param = &adapter->efuse_param;

	map = (u8 *)PLTFM_MALLOC(efuse_size);
	if (!map) {
		PLTFM_MSG_ERR("[ERR]malloc map\n");
		return MACBUFALLOC;
	}

	ret = mac_dump_log_efuse(adapter, MAC_AX_EFUSE_PARSER_MAP,
				 MAC_AX_EFUSE_R_AUTO, map, 0);

	PLTFM_FREE(map, efuse_size);

	if (ret != 0)
		return ret;

	*size = adapter->hw_info->efuse_size - efuse_param->efuse_end;

	return MACSUCCESS;
}

u32 mac_get_efuse_avl_size_bt(struct mac_ax_adapter *adapter, u32 *size)
{
	u32 ret;
	u8 *map;
	u32 efuse_size = adapter->hw_info->bt_log_efuse_size;
	struct mac_ax_efuse_param *efuse_param = &adapter->efuse_param;

	map = (u8 *)PLTFM_MALLOC(efuse_size);
	if (!map) {
		PLTFM_MSG_ERR("[ERR]malloc map\n");
		return MACBUFALLOC;
	}

	ret = mac_dump_log_efuse_bt(adapter, MAC_AX_EFUSE_PARSER_MAP,
				    MAC_AX_EFUSE_R_DRV, map);

	PLTFM_FREE(map, efuse_size);

	if (ret != 0)
		return ret;

	*size = adapter->hw_info->bt_efuse_size - efuse_param->bt_efuse_end;

	return MACSUCCESS;
}

u32 mac_dump_log_efuse_plus(struct mac_ax_adapter *adapter,
			    enum mac_ax_efuse_parser_cfg parser_cfg,
			    enum mac_ax_efuse_read_cfg cfg,
			    u8 *efuse_map, bool is_limit)
{
	u32 ret = 0;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u8 chip_id = hw_info->chip_id;
	enum mac_ax_intf intf = adapter->hw_info->intf;
	u32 map_size = hw_info->log_efuse_size;

	switch (chip_id) {
	case MAC_AX_CHIP_ID_8852A:
		ret = mac_dump_log_efuse(adapter, parser_cfg, cfg,
					 efuse_map, is_limit);
		break;
	case MAC_AX_CHIP_ID_8852B:
	case MAC_AX_CHIP_ID_8852C:
	case MAC_AX_CHIP_ID_8192XB:
		ret = mac_dump_log_efuse(adapter, parser_cfg, cfg,
					 efuse_map, is_limit);
		if (ret)
			return ret;
		switch_dv(adapter, DAV);
		if (is_limit) {
			switch (intf) {
			case MAC_AX_INTF_PCIE:
				map_size = hw_info->limit_efuse_size_pcie;
				break;
			case MAC_AX_INTF_USB:
				map_size = hw_info->limit_efuse_size_usb;
				break;
			case MAC_AX_INTF_SDIO:
				map_size = hw_info->limit_efuse_size_sdio;
				break;
			default:
				break;
			}
		}
		ret = mac_dump_log_efuse(adapter, parser_cfg,
					 MAC_AX_EFUSE_R_DRV, efuse_map +
					 map_size, 0);
		switch_dv(adapter, DDV);
		break;
	default:
		break;
	}

	if (ret)
		return ret;

	return MACSUCCESS;
}

u32 mac_dump_log_efuse(struct mac_ax_adapter *adapter,
		       enum mac_ax_efuse_parser_cfg parser_cfg,
		       enum mac_ax_efuse_read_cfg cfg,
		       u8 *efuse_map, bool is_limit)
{
	u8 *map = NULL;
	u32 ret, stat;
	u32 efuse_size;

#if 0
	if (cfg == MAC_AX_EFUSE_R_FW ||
	    (cfg == MAC_AX_EFUSE_R_AUTO &&
	     adapter->sm.fwdl == MAC_AX_FWDL_INIT_RDY))
		return MACNOITEM;
#else
	if (cfg == MAC_AX_EFUSE_R_FW &&
	    adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY)
		return MACNOFW;
#endif
	PLTFM_MSG_TRACE("[TRACE]cfg = %d\n", cfg);

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_LOG_MAP);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	efuse_size = *bank_efuse_info.log_map_size;

	if (dv_sel == DAV) {
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_DAV);
		if (ret != 0)
			return ret;
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG_DAV);
	} else {
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG);
		if (ret != 0)
			return ret;
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_WL);
	}
	if (ret)
		return ret;

	if (*bank_efuse_info.log_map_valid == 0) {
		ret = proc_dump_efuse(adapter, cfg);
		if (ret != 0) {
			PLTFM_MSG_ERR("[ERR]dump efuse\n");
			stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
			if (stat != 0)
				return stat;
			return ret;
		}

		if (*bank_efuse_info.phy_map_valid == 1) {
			map = (u8 *)PLTFM_MALLOC(efuse_size);
			if (!map) {
				PLTFM_MSG_ERR("[ERR]malloc map\n");
				stat = cnv_efuse_state(adapter,
						       MAC_AX_EFUSE_IDLE);
				if (stat != 0)
					return stat;
				return MACBUFALLOC;
			}

			ret = eeprom_parser(adapter, *bank_efuse_info.phy_map,
					    map, parser_cfg);
			if (ret != 0) {
				PLTFM_FREE(map, efuse_size);
				stat = cnv_efuse_state(adapter,
						       MAC_AX_EFUSE_IDLE);
				if (stat != 0)
					return stat;
				return ret;
			}
			PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
			PLTFM_MEMCPY(*bank_efuse_info.log_map, map,
				     efuse_size);
			*bank_efuse_info.log_map_valid = 1;
			PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);
			PLTFM_FREE(map, efuse_size);
		}
	}

	query_status_map(adapter, MAC_AX_DUMP_LOGICAL_EFUSE,
			 efuse_map, is_limit);

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_read_log_efuse_plus(struct mac_ax_adapter *adapter, u32 addr, u32 size,
			    u8 *val)
{
	u32 ret = 0;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u8 chip_id = hw_info->chip_id;
	u32 efuse_size = hw_info->log_efuse_size;
	u32 size1, size2;

	switch (chip_id) {
	case MAC_AX_CHIP_ID_8852A:
		ret = mac_read_log_efuse(adapter, addr, size, val);
		break;
	case MAC_AX_CHIP_ID_8852B:
	case MAC_AX_CHIP_ID_8852C:
	case MAC_AX_CHIP_ID_8192XB:
		if (addr < efuse_size && addr + size <= efuse_size) {
			ret = mac_read_log_efuse(adapter, addr, size, val);
		} else if (addr >= efuse_size) {
			switch_dv(adapter, DAV);
			ret = mac_read_log_efuse(adapter, addr - efuse_size,
						 size, val);
			switch_dv(adapter, DDV);
		} else if (addr < efuse_size && addr + size > efuse_size) {
			size1 = efuse_size - addr;
			size2 = addr + size - efuse_size;

			ret = mac_read_log_efuse(adapter, addr, size1, val);
			if (ret)
				return ret;

			switch_dv(adapter, DAV);
			ret = mac_read_log_efuse(adapter, 0, size2,
						 val + size1);
			switch_dv(adapter, DDV);
		}
		if (ret)
			return ret;
		break;
	default:
		break;
	}

	if (ret)
		return ret;

	return MACSUCCESS;
}

u32 mac_read_log_efuse(struct mac_ax_adapter *adapter, u32 addr, u32 size,
		       u8 *val)
{
	u8 *map = NULL;
	u32 ret = 0, stat;
	u32 efuse_size;

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_LOG_MAP);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	efuse_size = *bank_efuse_info.log_map_size;

	if (addr >= efuse_size || addr + size > efuse_size) {
		PLTFM_MSG_ERR("[ERR] Wrong efuse index\n");
		return MACEFUSESIZE;
	}

	if (dv_sel == DAV) {
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_DAV);
		if (ret)
			return ret;
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG_DAV);
	} else {
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_WL);
		if (ret)
			return ret;
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG);
	}
	if (ret)
		return ret;

	map = (u8 *)PLTFM_MALLOC(efuse_size);
	if (!map) {
		PLTFM_MSG_ERR("[ERR]malloc map\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return MACBUFALLOC;
	}

	ret = read_log_efuse_map(adapter, map, efuse_size);
	if (ret != 0) {
		PLTFM_FREE(map, efuse_size);
		PLTFM_MSG_ERR("[ERR]read logical efuse\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
	PLTFM_MEMCPY(val, map + addr, size);
	PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);
	PLTFM_FREE(map, efuse_size);

	stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (stat != 0)
		return stat;

	return MACSUCCESS;
}

u32 mac_write_log_efuse_plus(struct mac_ax_adapter *adapter, u32 addr, u8 val)
{
	u32 ret = 0;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u8 chip_id = hw_info->chip_id;
	u32 efuse_size = hw_info->log_efuse_size;

	switch (chip_id) {
	case MAC_AX_CHIP_ID_8852A:
		ret = mac_write_log_efuse(adapter, addr, val);
		break;
	case MAC_AX_CHIP_ID_8852B:
	case MAC_AX_CHIP_ID_8852C:
	case MAC_AX_CHIP_ID_8192XB:
		if (addr < efuse_size) {
			ret = mac_write_log_efuse(adapter, addr, val);
		} else {
			switch_dv(adapter, DAV);
			ret = mac_write_log_efuse(adapter,
						  addr - efuse_size, val);
			switch_dv(adapter, DDV);
		}
		break;
	default:
		break;
	}

	if (ret)
		return ret;

	return MACSUCCESS;
}

u32 mac_write_log_efuse(struct mac_ax_adapter *adapter, u32 addr, u8 val)
{
	u32 ret, stat;

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_LOG_MAP);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	if (addr >= *bank_efuse_info.log_map_size) {
		PLTFM_MSG_ERR("[ERR]addr is too large\n");
		return MACEFUSESIZE;
	}

	if (dv_sel == DAV) {
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_DAV);
		if (ret)
			return ret;
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG_DAV);
	} else {
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_WL);
		if (ret)
			return ret;
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG);
	}
	if (ret)
		return ret;

	ret = proc_write_log_efuse(adapter, addr, val);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]write logical efuse\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_dump_log_efuse_bt(struct mac_ax_adapter *adapter,
			  enum mac_ax_efuse_parser_cfg parser_cfg,
			  enum mac_ax_efuse_read_cfg cfg,
			  u8 *efuse_map)
{
	u8 *map = NULL;
	u32 ret, stat;
	u32 efuse_size = adapter->hw_info->bt_log_efuse_size;
	struct mac_ax_efuse_param *efuse_param = &adapter->efuse_param;

#if 0
	if (cfg == MAC_AX_EFUSE_R_FW ||
	    (cfg == MAC_AX_EFUSE_R_AUTO &&
	     adapter->sm.fwdl == MAC_AX_FWDL_INIT_RDY))
		return MACNOITEM;
#else
	if (cfg == MAC_AX_EFUSE_R_FW &&
	    adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY)
		return MACNOFW;
#endif

	PLTFM_MSG_TRACE("[TRACE]cfg = %d\n", cfg);

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_LOG_MAP);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_BT);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG_BT);
	if (ret != 0)
		return ret;
	ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_BT);
	if (ret != 0)
		return ret;

	if (efuse_param->bt_log_efuse_map_valid == 0) {
		ret = proc_dump_efuse(adapter, cfg);
		if (ret != 0) {
			PLTFM_MSG_ERR("[ERR]dump efuse\n");
			stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
			if (stat != 0)
				return stat;
			return ret;
		}

		if (efuse_param->bt_efuse_map_valid == 1) {
			map = (u8 *)PLTFM_MALLOC(efuse_size);
			if (!map) {
				PLTFM_MSG_ERR("[ERR]malloc map\n");
				stat = cnv_efuse_state(adapter,
						       MAC_AX_EFUSE_IDLE);
				if (stat != 0)
					return stat;
				return MACBUFALLOC;
			}

			ret = eeprom_parser(adapter, efuse_param->bt_efuse_map,
					    map, parser_cfg);
			if (ret != 0) {
				PLTFM_FREE(map, efuse_size);
				stat = cnv_efuse_state(adapter,
						       MAC_AX_EFUSE_IDLE);
				if (stat != 0)
					return stat;
				return ret;
			}
			PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
			PLTFM_MEMCPY(efuse_param->bt_log_efuse_map, map,
				     efuse_size);
			efuse_param->bt_log_efuse_map_valid = 1;
			PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);
			PLTFM_FREE(map, efuse_size);
		}
	}

	query_status_map(adapter, MAC_AX_DUMP_LOGICAL_EFUSE, efuse_map, 0);

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_read_log_efuse_bt(struct mac_ax_adapter *adapter, u32 addr, u32 size,
			  u8 *val)
{
	u8 *map = NULL;
	u32 ret, stat;
	u32 efuse_size = adapter->hw_info->bt_log_efuse_size;

	if (addr >= efuse_size || addr + size > efuse_size) {
		PLTFM_MSG_ERR("[ERR] Wrong efuse index\n");
		return MACEFUSESIZE;
	}

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_LOG_MAP);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_BT);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_BT);
	if (ret)
		return ret;
	ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG_BT);
	if (ret)
		return ret;

	map = (u8 *)PLTFM_MALLOC(efuse_size);
	if (!map) {
		PLTFM_MSG_ERR("[ERR]malloc map\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return MACBUFALLOC;
	}
	PLTFM_MEMSET(map, 0xFF, efuse_size);

	ret = read_log_efuse_map(adapter, map, efuse_size);
	if (ret != 0) {
		PLTFM_FREE(map, efuse_size);
		PLTFM_MSG_ERR("[ERR]read logical efuse\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
	PLTFM_MEMCPY(val, map + addr, size);
	PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);
	PLTFM_FREE(map, efuse_size);

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (stat != 0)
		return stat;

	return MACSUCCESS;
}

u32 mac_write_log_efuse_bt(struct mac_ax_adapter *adapter, u32 addr, u8 val)
{
	u32 ret, stat;

	if (addr >= adapter->hw_info->log_efuse_size) {
		PLTFM_MSG_ERR("[ERR]addr is too large\n");
		return MACEFUSESIZE;
	}

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_LOG_MAP);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_BT);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_BT);
	if (ret)
		return ret;
	ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG_BT);
	if (ret)
		return ret;

	ret = proc_write_log_efuse(adapter, addr, val);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]write logical efuse\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_pg_efuse_by_map_plus(struct mac_ax_adapter *adapter,
			     struct mac_ax_pg_efuse_info *info,
			     enum mac_ax_efuse_read_cfg cfg,
			     bool part, bool is_limit)
{
	u8 chip_id = adapter->hw_info->chip_id;
	u32 ret;
	struct mac_ax_pg_efuse_info info_DAV;
	u32 ver_len = 0;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	enum mac_ax_intf intf = adapter->hw_info->intf;
	u32 map_size = adapter->hw_info->log_efuse_size;
	//u8 *phy_map = NULL;

	ret = mac_get_hw_value(adapter,
			       MAC_AX_HW_GET_EFUSE_VERSION_SIZE, &ver_len);
	if (ret)
		return ret;

	switch (chip_id) {
	case MAC_AX_CHIP_ID_8852A:
		ret = mac_pg_efuse_by_map(adapter, info, cfg, part, is_limit);
		break;
	case MAC_AX_CHIP_ID_8852B:
	case MAC_AX_CHIP_ID_8852C:
	case MAC_AX_CHIP_ID_8192XB:
		/* cut map */
		if (is_limit) {
			switch (intf) {
			case MAC_AX_INTF_PCIE:
				map_size = hw_info->limit_efuse_size_pcie;
				break;
			case MAC_AX_INTF_USB:
				map_size = hw_info->limit_efuse_size_usb;
				break;
			case MAC_AX_INTF_SDIO:
				map_size = hw_info->limit_efuse_size_sdio;
				break;
			default:
				break;
			}
		}

		info_DAV.efuse_map_size = hw_info->dav_log_efuse_size;
		info_DAV.efuse_mask_size = hw_info->dav_log_efuse_size >> 4;

		info_DAV.efuse_map = (u8 *)PLTFM_MALLOC(info_DAV.efuse_map_size + ver_len);
		if (!info_DAV.efuse_map) {
			PLTFM_MSG_ERR("[ERR]malloc map\n");
			return MACBUFALLOC;
		}
		info_DAV.efuse_mask = (u8 *)PLTFM_MALLOC(info_DAV.efuse_mask_size + ver_len);
		if (!info_DAV.efuse_mask) {
			PLTFM_MSG_ERR("[ERR]malloc map\n");
			return MACBUFALLOC;
		}

		PLTFM_MEMCPY(info_DAV.efuse_map, info->efuse_map + map_size,
			     info_DAV.efuse_map_size + ver_len);
		PLTFM_MEMCPY(info_DAV.efuse_mask,
			     info->efuse_mask + (map_size >> 4),
			     info_DAV.efuse_mask_size + ver_len);

		info->efuse_map_size -= info_DAV.efuse_map_size;
		info->efuse_mask_size -= info_DAV.efuse_mask_size;

		PLTFM_MEMCPY(info->efuse_map + map_size, info->efuse_map +
			     map_size + info_DAV.efuse_map_size, ver_len);
		PLTFM_MEMCPY(info->efuse_mask + (map_size >> 4),
			     info->efuse_mask + (map_size >> 4) +
			     info_DAV.efuse_mask_size, ver_len);

		ret = mac_pg_efuse_by_map(adapter, info, cfg, part, is_limit);
		if (ret)
			return ret;
		switch_dv(adapter, DAV);
		ret = mac_pg_efuse_by_map(adapter,
					  &info_DAV, cfg, part, 0);
		//phy_map = (u8 *)PLTFM_MALLOC(hw_info->wl_efuse_size_DAV);
		//if (!phy_map) {
		//	PLTFM_MSG_ERR("[ERR]malloc map\n");
		//	return MACBUFALLOC;
		//}
		//PLTFM_MEMSET(phy_map, 0xFF, hw_info->wl_efuse_size_DAV);
		//ret = mac_pg_simulator(adapter, &info_DAV, phy_map);
		switch_dv(adapter, DDV);
		break;
	default:
		break;
	}
	if (ret)
		return ret;

	return MACSUCCESS;
}

u32 mac_pg_efuse_by_map(struct mac_ax_adapter *adapter,
			struct mac_ax_pg_efuse_info *info,
			enum mac_ax_efuse_read_cfg cfg,
			bool part, bool is_limit)
{
	u32 ret, stat;
	enum mac_ax_intf intf = adapter->hw_info->intf;
	u32 map_size = adapter->hw_info->log_efuse_size;
	u32 ver_len = 0;

	if (is_limit) {
		switch (intf) {
		case MAC_AX_INTF_PCIE:
			map_size = adapter->hw_info->limit_efuse_size_pcie;
			break;
		case MAC_AX_INTF_USB:
			map_size = adapter->hw_info->limit_efuse_size_usb;
			break;
		case MAC_AX_INTF_SDIO:
			map_size = adapter->hw_info->limit_efuse_size_sdio;
			break;
		default:
			break;
		}
	}

	if (dv_sel == DAV)
		map_size = adapter->hw_info->dav_log_efuse_size;

	if (info->efuse_map_size != map_size) {
		PLTFM_MSG_ERR("[ERR]map size error\n");
		return MACEFUSESIZE;
	}

	if ((info->efuse_map_size & 0xF) > 0) {
		PLTFM_MSG_ERR("[ERR]not multiple of 16\n");
		return MACEFUSESIZE;
	}

	if (info->efuse_mask_size != info->efuse_map_size >> 4) {
		PLTFM_MSG_ERR("[ERR]mask size error\n");
		return MACEFUSESIZE;
	}

	if (!info->efuse_map) {
		PLTFM_MSG_ERR("[ERR]map is NULL\n");
		return MACNPTR;
	}

	if (!info->efuse_mask) {
		PLTFM_MSG_ERR("[ERR]mask is NULL\n");
		return MACNPTR;
	}

	ret = mac_get_hw_value(adapter,
			       MAC_AX_HW_GET_EFUSE_VERSION_SIZE, &ver_len);
	if (ret)
		return ret;
	ret = compare_version(adapter, info, ver_len);
	if (ret != 0)
		return ret;

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_PHY);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	if (dv_sel == DAV) {
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_DAV);
		if (ret)
			return ret;
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG_DAV);
	} else {
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_WL);
		if (ret)
			return ret;
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG);
	}
	if (ret)
		return ret;

	if (part)
		ret = adjust_mask(adapter, info);
	if (ret != 0) {
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = proc_pg_efuse_by_map(adapter, info, cfg);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]pg efuse\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_pg_efuse_by_map_bt(struct mac_ax_adapter *adapter,
			   struct mac_ax_pg_efuse_info *info,
			   enum mac_ax_efuse_read_cfg cfg)
{
	u32 ret, stat;

	if (info->efuse_map_size != adapter->hw_info->bt_log_efuse_size) {
		PLTFM_MSG_ERR("[ERR]map size error\n");
		return MACEFUSESIZE;
	}

	if ((info->efuse_map_size & 0xF) > 0) {
		PLTFM_MSG_ERR("[ERR]not multiple of 16\n");
		return MACEFUSESIZE;
	}

	if (info->efuse_mask_size != info->efuse_map_size >> 4) {
		PLTFM_MSG_ERR("[ERR]mask size error\n");
		return MACEFUSESIZE;
	}

	if (!info->efuse_map) {
		PLTFM_MSG_ERR("[ERR]map is NULL\n");
		return MACNPTR;
	}

	if (!info->efuse_mask) {
		PLTFM_MSG_ERR("[ERR]mask is NULL\n");
		return MACNPTR;
	}

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_PHY);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_BT);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = proc_pg_efuse_by_map(adapter, info, cfg);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]pg efuse\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_mask_log_efuse(struct mac_ax_adapter *adapter,
		       struct mac_ax_pg_efuse_info *info)
{
	if (info->efuse_map_size != adapter->hw_info->log_efuse_size) {
		PLTFM_MSG_ERR("[ERR]map size error\n");
		return MACEFUSESIZE;
	}

	if ((info->efuse_map_size & 0xF) > 0) {
		PLTFM_MSG_ERR("[ERR]not multiple of 16\n");
		return MACEFUSESIZE;
	}

	if (info->efuse_mask_size != info->efuse_map_size >> 4) {
		PLTFM_MSG_ERR("[ERR]mask size error\n");
		return MACEFUSESIZE;
	}

	if (!info->efuse_map) {
		PLTFM_MSG_ERR("[ERR]map is NULL\n");
		return MACNPTR;
	}

	if (!info->efuse_mask) {
		PLTFM_MSG_ERR("[ERR]mask is NULL\n");
		return MACNPTR;
	}

	mask_eeprom(adapter, info);

	return MACSUCCESS;
}

u32 mac_pg_sec_data_by_map(struct mac_ax_adapter *adapter,
			   struct mac_ax_pg_efuse_info *info)
{
	u32 ret, stat;
	u32 addr, efuse_size, sec_data_size;
	u8 *map_pg;
	u32 mac_addr_size = 6;

	/*Soar TBD add MAC address PG*/

	map_pg = info->efuse_map;
	efuse_size = adapter->hw_info->efuse_size;
	sec_data_size = adapter->hw_info->sec_data_efuse_size;

	if (info->efuse_map_size != adapter->hw_info->sec_data_efuse_size) {
		PLTFM_MSG_ERR("[ERR]map size error\n");
		return MACEFUSESIZE;
	}

	if (!info->efuse_map) {
		PLTFM_MSG_ERR("[ERR]map is NULL\n");
		return MACNPTR;
	}

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_PHY);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	enable_efuse_sw_pwr_cut(adapter, 1);
	for (addr = mac_addr_size; addr < sec_data_size; addr++) {
		ret = write_hw_efuse(adapter, addr + efuse_size,
				     *(map_pg + addr));
		if (ret != 0) {
			PLTFM_MSG_ERR("[ERR]write physical efuse\n");
			stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
			if (stat != 0)
				return stat;
			return ret;
		}
	}
	disable_efuse_sw_pwr_cut(adapter, 1);

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_cmp_sec_data_by_map(struct mac_ax_adapter *adapter,
			    struct mac_ax_pg_efuse_info *info)
{
	u32 ret, stat;
	u32 addr, start_addr, sec_data_size;
	u16 val16;
	u8 *map_pg;

	map_pg = info->efuse_map;
	start_addr = adapter->hw_info->efuse_size;
	sec_data_size = adapter->hw_info->sec_data_efuse_size;

	if (info->efuse_map_size != adapter->hw_info->sec_data_efuse_size) {
		PLTFM_MSG_ERR("[ERR]map size error\n");
		return MACEFUSESIZE;
	}

	if (!info->efuse_map) {
		PLTFM_MSG_ERR("[ERR]map is NULL\n");
		return MACNPTR;
	}

	ret = efuse_proc_ck(adapter);
	if (ret != 0)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_PHY);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != 0)
			return stat;
		return ret;
	}

	for (addr = 0;
	     addr < sec_data_size; addr += 2) {
		val16 = *(map_pg + addr) | (*(map_pg + addr + 1) << 8);
		ret = cmp_hw_efuse(adapter, addr + start_addr, val16);
		if (ret == MACEFUSECMP) {
			*(map_pg + addr) = 0xFF;
			*(map_pg + addr + 1) = 0xFF;
		} else if (ret == MACEFUSEREAD) {
			PLTFM_MSG_ERR("[ERR]compare hw efuse\n");
			stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
			if (stat != 0)
				return stat;
		} else if (ret == 0) {
			*(map_pg + addr) = 0x00;
			*(map_pg + addr + 1) = 0x00;
		}
	}

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != 0)
		return ret;

	return MACSUCCESS;
}

u32 mac_get_efuse_info(struct mac_ax_adapter *adapter, u8 *efuse_map,
		       enum rtw_efuse_info id, void *value, u32 length,
		       u8 *autoload_status)
{
	u32 offset, def_val;
	u32 ret;
	enum mac_ax_intf intf = adapter->hw_info->intf;
	struct efuse_info info;

	switch (intf) {
	case MAC_AX_INTF_USB:
		info = (is_chip_id(adapter, MAC_AX_CHIP_ID_8852A)) ?
		       efuse_info_usb_8852a : efuse_info_usb_8852b;
		break;
	case MAC_AX_INTF_PCIE:
		info = efuse_info_pcie;
		break;
	case MAC_AX_INTF_SDIO:
		info = efuse_info_sdio;
		break;
	default:
		return MACINTF;
	}

	ret = compare_info_length(&info, id, length);
	if (ret != MACSUCCESS)
		return ret;

	switch (id) {
	case EFUSE_INFO_MAC_ADDR:
		offset = info.offset->mac_addr;
		def_val = info.def_val->mac_addr;
		break;
	case EFUSE_INFO_MAC_PID:
		offset = info.offset->pid;
		def_val = info.def_val->pid;
		break;
	case EFUSE_INFO_MAC_DID:
		offset = info.offset->did;
		def_val = info.def_val->did;
		break;
	case EFUSE_INFO_MAC_VID:
		offset = info.offset->vid;
		def_val = info.def_val->vid;
		break;
	case EFUSE_INFO_MAC_SVID:
		offset = info.offset->svid;
		def_val = info.def_val->svid;
		break;
	case EFUSE_INFO_MAC_SMID:
		offset = info.offset->smid;
		def_val = info.def_val->smid;
		break;
	default:
		return MACNOITEM;
	}

	if (*autoload_status == 0)
		PLTFM_MEMCPY(value, &def_val, 1);
	else
		PLTFM_MEMCPY(value, efuse_map + offset, length);

	return MACSUCCESS;
}

u32 mac_set_efuse_info(struct mac_ax_adapter *adapter, u8 *efuse_map,
		       enum rtw_efuse_info id, void *value, u32 length)
{
	u32 offset;
	u32 ret;
	enum mac_ax_intf intf = adapter->hw_info->intf;
	struct efuse_info info;

	switch (intf) {
	case MAC_AX_INTF_USB:
		info = (is_chip_id(adapter, MAC_AX_CHIP_ID_8852A)) ?
		       efuse_info_usb_8852a : efuse_info_usb_8852b;
		break;
	case MAC_AX_INTF_PCIE:
		info = efuse_info_pcie;
		break;
	case MAC_AX_INTF_SDIO:
		info = efuse_info_sdio;
		break;
	default:
		return MACINTF;
	}

	ret = compare_info_length(&info, id, length);
	if (ret != MACSUCCESS)
		return ret;

	switch (id) {
	case EFUSE_INFO_MAC_ADDR:
		offset = info.offset->mac_addr;
		break;
	case EFUSE_INFO_MAC_PID:
		offset = info.offset->pid;
		break;
	case EFUSE_INFO_MAC_DID:
		offset = info.offset->did;
		break;
	case EFUSE_INFO_MAC_VID:
		offset = info.offset->vid;
		break;
	case EFUSE_INFO_MAC_SVID:
		offset = info.offset->svid;
		break;
	case EFUSE_INFO_MAC_SMID:
		offset = info.offset->smid;
		break;
	default:
		return MACNOITEM;
	}

	PLTFM_MEMCPY(efuse_map + offset, value, length);

	return MACSUCCESS;
}

u32 mac_read_hidden_rpt(struct mac_ax_adapter *adapter,
			struct mac_defeature_value *rpt)
{
#if 0
	return MACNOITEM;
#else
	u32 ret, stat;
	struct mac_ax_h2creg_info h2c;
	struct mac_ax_c2hreg_poll c2h;
	struct fwcmd_c2hreg *c2h_content;

	ret = efuse_proc_ck(adapter);
	if (ret != MACSUCCESS)
		return ret;

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_PHY);
	if (ret != MACSUCCESS)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat != MACSUCCESS)
			return stat;
		return ret;
	}

	ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_WL);
	if (ret != MACSUCCESS)
		return ret;

	h2c.id = FWCMD_H2CREG_FUNC_HIDDEN_GET;
	h2c.content_len = sizeof(struct mac_efuse_hidden_h2creg);

	c2h.polling_id = FWCMD_C2HREG_FUNC_EFUSE_HIDDEN;
	c2h.retry_cnt = EFUSE_C2HREG_WAIT_CNT;
	c2h.retry_wait_us = EFUSE_C2HREG_RETRY_WAIT_US;

	ret = proc_msg_reg(adapter, &h2c, &c2h);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]read hidden rpt proc msg reg %d\n", ret);
		stat = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
		if (stat)
			return stat;
		return ret;
	}

	c2h_content = &c2h.c2hreg_cont.c2h_content;
	rpt->rx_spatial_stream =
	GET_FIELD(c2h_content->dword0, FWCMD_C2HREG_EFUSE_HIDDEN_RX_NSS);
	rpt->bandwidth =
	GET_FIELD(c2h_content->dword0, FWCMD_C2HREG_EFUSE_HIDDEN_BW);
	rpt->tx_spatial_stream =
	GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_EFUSE_HIDDEN_TX_NSS);
	rpt->protocol_80211 =
	GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_EFUSE_HIDDEN_PROT80211);
	rpt->NIC_router =
	GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_EFUSE_HIDDEN_NIC_ROUTER);
	rpt->wl_func_support =
	GET_FIELD(c2h_content->dword1,
		  FWCMD_C2HREG_EFUSE_HIDDEN_WL_FUNC_SUPPORT);
	rpt->hw_special_type =
	GET_FIELD(c2h_content->dword2,
		  FWCMD_C2HREG_EFUSE_HIDDEN_HW_SPECIAL_TYPE);
	rpt->uuid =
	GET_FIELD(c2h_content->dword3,
		  FWCMD_C2HREG_EFUSE_HIDDEN_UUID_BYTE_3) << 24 |
	GET_FIELD(c2h_content->dword2,
		  FWCMD_C2HREG_EFUSE_HIDDEN_UUID_BYTE_2) << 16 |
	GET_FIELD(c2h_content->dword2,
		  FWCMD_C2HREG_EFUSE_HIDDEN_UUID_BYTE_1) << 8 |
	GET_FIELD(c2h_content->dword2,
		  FWCMD_C2HREG_EFUSE_HIDDEN_UUID_BYTE_0);

	ret = cnv_efuse_state(adapter, MAC_AX_EFUSE_IDLE);
	if (ret != MACSUCCESS)
		return ret;

	return MACSUCCESS;
#endif
}

u32 mac_check_efuse_autoload(struct mac_ax_adapter *adapter,
			     u8 *autoload_status)
{
#define AUTOLOAD_SUS 1
#define AUTOLOAD_FAIL 0

	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);

	if (MAC_REG_R16(R_AX_SYS_EEPROM_CTRL) & B_AX_AUTOLOAD_SUS)
		*autoload_status = AUTOLOAD_SUS;
	else
		*autoload_status = AUTOLOAD_FAIL;

	return MACSUCCESS;

#undef AUTOLOAD_SUS
#undef AUTOLOAD_FAIL
}

u32 mac_pg_simulator_plus(struct mac_ax_adapter *adapter,
			  struct mac_ax_pg_efuse_info *info, u8 *phy_map)
{
	u8 chip_id = adapter->hw_info->chip_id;
	u32 ret;
	struct mac_ax_pg_efuse_info info_dav;
	u32 ver_len = 0;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u32 map_size = hw_info->log_efuse_size;

	ret = mac_get_hw_value(adapter,
			       MAC_AX_HW_GET_EFUSE_VERSION_SIZE, &ver_len);
	if (ret)
		return ret;

	switch (chip_id) {
	case MAC_AX_CHIP_ID_8852A:
		ret = mac_pg_simulator(adapter, info, phy_map);
		break;
	case MAC_AX_CHIP_ID_8852B:
	case MAC_AX_CHIP_ID_8852C:
	case MAC_AX_CHIP_ID_8192XB:
		/* cut log map */
		info_dav.efuse_map_size = hw_info->dav_log_efuse_size;
		info_dav.efuse_mask_size = hw_info->dav_log_efuse_size >> 4;

		info_dav.efuse_map =
			(u8 *)PLTFM_MALLOC(info_dav.efuse_map_size + ver_len);
		if (!info_dav.efuse_map) {
			PLTFM_MSG_ERR("[ERR]malloc map\n");
			return MACBUFALLOC;
		}
		info_dav.efuse_mask =
			(u8 *)PLTFM_MALLOC(info_dav.efuse_mask_size +
					   ver_len);
		if (!info_dav.efuse_mask) {
			PLTFM_MSG_ERR("[ERR]malloc map\n");
			return MACBUFALLOC;
		}

		PLTFM_MEMCPY(info_dav.efuse_map, info->efuse_map + map_size,
			     info_dav.efuse_map_size + ver_len);
		PLTFM_MEMCPY(info_dav.efuse_mask,
			     info->efuse_mask + (map_size >> 4),
			     info_dav.efuse_mask_size + ver_len);

		info->efuse_map_size -= info_dav.efuse_map_size;
		info->efuse_mask_size -= info_dav.efuse_mask_size;

		PLTFM_MEMCPY(info->efuse_map + map_size, info->efuse_map +
			     map_size + info_dav.efuse_map_size, ver_len);
		PLTFM_MEMCPY(info->efuse_mask + (map_size >> 4),
			     info->efuse_mask + (map_size >> 4) +
			     info_dav.efuse_mask_size, ver_len);

		ret = mac_pg_simulator(adapter, info, phy_map);
		if (ret)
			return ret;
		switch_dv(adapter, DAV);
		ret = mac_pg_simulator(adapter, &info_dav,
				       phy_map + hw_info->wl_efuse_size);
		switch_dv(adapter, DDV);
		PLTFM_MEMCPY(info->efuse_map + map_size, info_dav.efuse_map,
			     info_dav.efuse_map_size + ver_len);
		break;
	default:
		break;
	}
	if (ret)
		return ret;

	return MACSUCCESS;
}

u32 mac_pg_simulator(struct mac_ax_adapter *adapter,
		     struct mac_ax_pg_efuse_info *info, u8 *phy_map)
{
	u8 *updated_mask;
	u32 ret;
	u32 mask_size;
	u8 *log_efuse_map = NULL;
	enum mac_ax_intf intf = adapter->hw_info->intf;
	u32 map_size = adapter->hw_info->log_efuse_size;
	u32 ver_len = 0;

	if (info->efuse_map_size != adapter->hw_info->log_efuse_size) {
		switch (intf) {
		case MAC_AX_INTF_PCIE:
			map_size = adapter->hw_info->limit_efuse_size_pcie;
			break;
		case MAC_AX_INTF_USB:
			map_size = adapter->hw_info->limit_efuse_size_usb;
			break;
		case MAC_AX_INTF_SDIO:
			map_size = adapter->hw_info->limit_efuse_size_sdio;
			break;
		default:
			break;
		}
	}

	if (dv_sel == DAV)
		map_size = adapter->hw_info->dav_log_efuse_size;

	if (info->efuse_map_size != map_size) {
		PLTFM_MSG_ERR("[ERR]map size error\n");
		return MACEFUSESIZE;
	}

	mask_size = map_size >> 4;

	ret = mac_get_hw_value(adapter,
			       MAC_AX_HW_GET_EFUSE_VERSION_SIZE, &ver_len);
	if (ret)
		return ret;

	ret = compare_version(adapter, info, ver_len);
	if (ret != 0)
		return ret;

	ret = switch_efuse_bank(adapter, MAC_AX_EFUSE_BANK_WIFI);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
		return ret;
	}

	if (dv_sel == DAV) {
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_DAV);
		if (ret)
			return ret;
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG_DAV);
	} else {
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_PHY_WL);
		if (ret)
			return ret;
		ret = efuse_map_init(adapter, EFUSE_MAP_SEL_LOG);
	}
	if (ret)
		return ret;

	ret = eeprom_parser(adapter, phy_map, *bank_efuse_info.log_map,
			    MAC_AX_EFUSE_PARSER_MAP);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]logical map parser\n");
		return ret;
	}
	PLTFM_MEMCPY(*bank_efuse_info.phy_map, phy_map,
		     *bank_efuse_info.phy_map_size);

	updated_mask = (u8 *)PLTFM_MALLOC(mask_size);
	if (!updated_mask) {
		PLTFM_MSG_ERR("[ERR]malloc updated mask\n");
		return MACBUFALLOC;
	}
	PLTFM_MEMSET(updated_mask, 0x00, mask_size);

	ret = update_eeprom_mask(adapter, info, updated_mask, 1);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]update eeprom mask\n");
		goto error;
	}

	ret = check_efuse_enough(adapter, info, updated_mask);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]chk efuse enough\n");
		goto error;
	}

	ret = program_efuse(adapter, info, updated_mask, 1);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]pg efuse\n");
		goto error;
	}

	PLTFM_FREE(updated_mask, mask_size);

	PLTFM_MEMCPY(phy_map, *bank_efuse_info.phy_map,
		     *bank_efuse_info.phy_map_size);
	ret = eeprom_parser(adapter, phy_map, info->efuse_map,
			    MAC_AX_EFUSE_PARSER_MAP);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]parser error\n");
		PLTFM_FREE(log_efuse_map, map_size);
		return ret;
	}

	/* For subsequent dump */
	*bank_efuse_info.log_map_valid = 0;
	*bank_efuse_info.phy_map_valid = 0;

	return MACSUCCESS;

error:
	PLTFM_FREE(updated_mask, mask_size);
	return ret;
}

u32 mac_checksum_update(struct mac_ax_adapter *adapter)
{
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u32 log_efuse_size = hw_info->log_efuse_size;
	u8 *map;
	u16 chksum;
	u32 ret;

	map = (u8 *)PLTFM_MALLOC(log_efuse_size);
	if (!map) {
		PLTFM_MSG_ERR("[ERR]malloc map\n");
		return MACBUFALLOC;
	}
	PLTFM_MEMSET(map, 0xFF, log_efuse_size);

	ret = mac_dump_log_efuse(adapter, MAC_AX_EFUSE_PARSER_MAP,
				 MAC_AX_EFUSE_R_AUTO, map, 0);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]Dump log map\n");
		goto error;
	}

	cal_check_sum(adapter, &chksum);

	ret = set_check_sum_val(adapter, map, chksum);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]write check sum\n");
		goto error;
	}

	PLTFM_FREE(map, log_efuse_size);
	return MACSUCCESS;
error:
	PLTFM_FREE(map, log_efuse_size);
	return ret;
}

u32 mac_checksum_rpt(struct mac_ax_adapter *adapter, u16 *chksum)
{
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u32 log_efuse_size = hw_info->log_efuse_size;
	u8 *tmp;
	u32 ret;
	u16 real_chksum = 0;

	/* Read chksum val */
	tmp = (u8 *)PLTFM_MALLOC(sizeof(real_chksum));
	if (!tmp) {
		PLTFM_MSG_ERR("[ERR]malloc tmp\n");
		return MACBUFALLOC;
	}
	ret = mac_read_log_efuse(adapter, chksum_offset_1, sizeof(real_chksum),
				 tmp);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]read log efuse\n");
		PLTFM_FREE(tmp, sizeof(real_chksum));
		return ret;
	}

	real_chksum = *(u16 *)tmp;
	PLTFM_FREE(tmp, sizeof(real_chksum));

	if (real_chksum == 0xFFFF)
		return MACCHKSUMEMPTY;

	/* Read log map*/
	tmp = (u8 *)PLTFM_MALLOC(log_efuse_size);
	if (!tmp) {
		PLTFM_MSG_ERR("[ERR]malloc map\n");
		return MACBUFALLOC;
	}
	PLTFM_MEMSET(tmp, 0xFF, log_efuse_size);

	ret = mac_read_log_efuse(adapter, 0, log_efuse_size, tmp);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]read log efuse\n");
		PLTFM_FREE(tmp, log_efuse_size);
		return ret;
	}
	PLTFM_FREE(tmp, log_efuse_size);

	cal_check_sum(adapter, chksum);
	if (*chksum != real_chksum)
		return MACCHKSUMFAIL;

	return MACSUCCESS;
}

u32 mac_disable_rf(struct mac_ax_adapter *adapter,
		   enum mac_ax_disable_rf_func func, enum mac_ax_net_type type)
{
	u32 ret;
#if MAC_AX_PHL_H2C
	struct rtw_h2c_pkt *h2cb;
#else
	struct h2c_buf *h2cb;
#endif
	u8 *buf;
	struct fwcmd_disable_rf *write_ptr;

	/* H2C */
	if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY)
		return MACNOFW;

	h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD);
	if (!h2cb)
		return MACNPTR;

	buf = h2cb_put(h2cb, sizeof(struct mac_ax_pkt_ofld_hdr));
	if (!buf) {
		h2cb_free(adapter, h2cb);
		return MACNOBUF;
	}

	write_ptr = (struct fwcmd_disable_rf *)buf;
	write_ptr->dword0 =
	cpu_to_le32(SET_WORD(func, FWCMD_H2C_DISABLE_RF_FUNC) |
		    SET_WORD(type, FWCMD_H2C_DISABLE_RF_NET_TYPE)
	);

	ret = h2c_pkt_set_hdr(adapter, h2cb,
			      FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC,
			      FWCMD_H2C_CL_FW_OFLD, FWCMD_H2C_FUNC_DISABLE_RF,
			      0, 0);
	if (ret) {
		h2cb_free(adapter, h2cb);
		return ret;
	}

	ret = h2c_pkt_build_txd(adapter, h2cb);
	if (ret) {
		h2cb_free(adapter, h2cb);
		return ret;
	}

#if MAC_AX_PHL_H2C
	ret = PLTFM_TX(h2cb);
#else
	ret = PLTFM_TX(h2cb->data, h2cb->len);
#endif
	if (ret) {
		PLTFM_MSG_ERR("[ERR]platform tx\n");
		h2cb_free(adapter, h2cb);
		return ret;
	}

	h2cb_free(adapter, h2cb);

	return MACSUCCESS;
}

u32 mac_check_OTP(struct mac_ax_adapter *adapter, u8 is_start)
{
#define is_read 0
#define secure 1
	u8 val8;

	if (is_start == 1) {
		enable_efuse_sw_pwr_cut(adapter, is_read);

		mac_set_efuse_ctrl(adapter, secure);
		read_efuse_cnt = CHK_OTP_WAIT_CNT;

		mac_read_efuse_plus(adapter, CHK_OTP_ADDR, 1, &val8,
				    MAC_AX_EFUSE_BANK_WIFI);

		disable_efuse_sw_pwr_cut(adapter, is_read);

		mac_set_efuse_ctrl(adapter, !secure);
		read_efuse_cnt = EFUSE_WAIT_CNT;
	}

	return MACSUCCESS;
}

void mac_set_efuse_ctrl(struct mac_ax_adapter *adapter, u8 is_secure)
{
	efuse_ctrl = is_secure ? R_AX_EFUSE_CTRL_S : R_AX_EFUSE_CTRL;
}

u32 mac_otp_test(struct mac_ax_adapter *adapter, bool is_OTP_test)
{
	if (is_OTP_test)
		OTP_test = 1;
	else
		OTP_test = 0;

	return MACSUCCESS;
}

void cfg_efuse_auto_ck(struct mac_ax_adapter *adapter, u8 enable)
{
	/*Soar TBD* move to set hw value */

#ifdef NEVER
	PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
	adapter->efuse_param.auto_ck_en = enable;
	PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
#endif /* NEVER */
}

u32 efuse_tbl_init(struct mac_ax_adapter *adapter)
{
	PLTFM_MUTEX_INIT(&efuse_tbl.lock);

	return MACSUCCESS;
}

u32 efuse_tbl_exit(struct mac_ax_adapter *adapter)
{
	PLTFM_MUTEX_DEINIT(&efuse_tbl.lock);

	return MACSUCCESS;
}

static u32 efuse_map_init(struct mac_ax_adapter *adapter,
			  enum efuse_map_sel map_sel)
{
	u32 size;
	struct mac_ax_efuse_param *efuse_param = &adapter->efuse_param;

	switch (map_sel) {
	case EFUSE_MAP_SEL_PHY_WL:
		size = adapter->hw_info->efuse_size;
		if (!efuse_param->efuse_map) {
			efuse_param->efuse_map = (u8 *)PLTFM_MALLOC(size);
			if (!efuse_param->efuse_map) {
				PLTFM_MSG_ERR("[ERR]malloc map\n");
				return MACBUFALLOC;
			}
		}
		break;
	case EFUSE_MAP_SEL_PHY_BT:
		size = adapter->hw_info->bt_efuse_size;
		if (!efuse_param->bt_efuse_map) {
			efuse_param->bt_efuse_map = (u8 *)PLTFM_MALLOC(size);
			if (!efuse_param->bt_efuse_map) {
				PLTFM_MSG_ERR("[ERR]malloc map\n");
				return MACBUFALLOC;
			}
		}
		break;
	case EFUSE_MAP_SEL_LOG:
		size = adapter->hw_info->log_efuse_size;
		if (!efuse_param->log_efuse_map) {
			efuse_param->log_efuse_map = (u8 *)PLTFM_MALLOC(size);
			if (!efuse_param->log_efuse_map) {
				PLTFM_MSG_ERR("[ERR]malloc map\n");
				return MACBUFALLOC;
			}
		}
		break;
	case EFUSE_MAP_SEL_LOG_BT:
		size = adapter->hw_info->bt_log_efuse_size;
		if (!efuse_param->bt_log_efuse_map) {
			efuse_param->bt_log_efuse_map =
				(u8 *)PLTFM_MALLOC(size);
			if (!efuse_param->bt_log_efuse_map) {
				PLTFM_MSG_ERR("[ERR]malloc map\n");
				return MACBUFALLOC;
			}
		}
		break;
	case EFUSE_MAP_SEL_PHY_DAV:
		size = adapter->hw_info->dav_efuse_size;
		if (!efuse_param->dav_efuse_map) {
			efuse_param->dav_efuse_map = (u8 *)PLTFM_MALLOC(size);
			if (!efuse_param->dav_efuse_map) {
				PLTFM_MSG_ERR("[ERR]malloc map\n");
				return MACBUFALLOC;
			}
		}
		break;
	case EFUSE_MAP_SEL_LOG_DAV:
		size = adapter->hw_info->dav_log_efuse_size;
		if (!efuse_param->dav_log_efuse_map) {
			efuse_param->dav_log_efuse_map =
				(u8 *)PLTFM_MALLOC(size);
			if (!efuse_param->dav_log_efuse_map) {
				PLTFM_MSG_ERR("[ERR]malloc map\n");
				return MACBUFALLOC;
			}
		}
		break;
	default:
		break;
	}

	return MACSUCCESS;
}

static u32 efuse_fwcmd_ck(struct mac_ax_adapter *adapter)
{
/*Soar TBD*/
#ifdef NEVER
	u32 ret;

	ret = fwcmd_wq_idle(adapter,
			    SET_FWCMD_ID(FWCMD_TYPE_H2C,
					 FWCMD_H2C_CAT_MAC,
					 TBD,
					 TBD));
	if (ret != 0) {
		PLTFM_MSG_WARN("[WARN]H2C not idle(efuse)\n");
		return ret;
	}
#endif /* NEVER */
	return MACSUCCESS;
}

static u32 efuse_proc_ck(struct mac_ax_adapter *adapter)
{
/*Soar TBD*/
#ifdef NEVER
	u32 ret;

	ret = efuse_fwcmd_ck(adapter);
	if (ret != 0)
		return ret;
#endif /* NEVER */
	if (adapter->sm.efuse != MAC_AX_EFUSE_IDLE) {
		PLTFM_MSG_WARN("[WARN]Proc not idle(efuse)\n");
		return MACPROCBUSY;
	}

	if (adapter->sm.pwr != MAC_AX_PWR_ON)
		PLTFM_MSG_ERR("[ERR]Access efuse in suspend\n");

	return MACSUCCESS;
}

static u32 cnv_efuse_state(struct mac_ax_adapter *adapter, u8 dest_state)
{
	if (adapter->sm.efuse >= MAC_AX_EFUSE_MAX)
		return MACPROCERR;

	if (adapter->sm.efuse == dest_state)
		return MACPROCERR;

	if (dest_state != MAC_AX_EFUSE_IDLE) {
		if (adapter->sm.efuse != MAC_AX_EFUSE_IDLE)
			return MACPROCERR;
	}

	adapter->sm.efuse = dest_state;

	return MACSUCCESS;
}

static u32 switch_efuse_bank(struct mac_ax_adapter *adapter,
			     enum mac_ax_efuse_bank bank)
{
	u8 reg_value;
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	struct mac_ax_efuse_param *efuse_param = &adapter->efuse_param;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u8 chip_id = adapter->hw_info->chip_id;

	switch (chip_id) {
	case MAC_AX_CHIP_ID_8852A:
		if (bank == MAC_AX_EFUSE_BANK_BT) {
			/* check bt state */
			MAC_REG_W8(R_AX_SYSON_FSM_MON + 3, 0x05);
			reg_value = MAC_REG_R8(R_AX_SYSON_FSM_MON);
			if (reg_value != 0x04)
				return MACEFUSEBANK;
		}

		reg_value = MAC_REG_R8(R_AX_EFUSE_CTRL_1 + 1);
		if (bank == (reg_value & B_AX_EF_CELL_SEL_MSK))
			goto set_val;

		reg_value &= ~B_AX_EF_CELL_SEL_MSK;
		reg_value |= bank;
		MAC_REG_W8(R_AX_EFUSE_CTRL_1 + 1, reg_value);

		reg_value = MAC_REG_R8(R_AX_EFUSE_CTRL_1 + 1);
		if ((reg_value & B_AX_EF_CELL_SEL_MSK) == bank)
			goto set_val;
		else
			return MACEFUSEBANK;
		break;
	case MAC_AX_CHIP_ID_8852B:
	case MAC_AX_CHIP_ID_8852C:
	case MAC_AX_CHIP_ID_8192XB:
		goto set_val;
	default:
		break;
	}

set_val:
	switch (bank) {
	case MAC_AX_EFUSE_BANK_WIFI:
		if (dv_sel == DAV) {
			bank_efuse_info.phy_map = &efuse_param->dav_efuse_map;
			bank_efuse_info.log_map =
				&efuse_param->dav_log_efuse_map;
			bank_efuse_info.phy_map_valid =
				&efuse_param->dav_efuse_map_valid;
			bank_efuse_info.log_map_valid =
				&efuse_param->dav_log_efuse_map_valid;
			bank_efuse_info.efuse_end =
				&efuse_param->dav_efuse_end;
			bank_efuse_info.phy_map_size =
				&hw_info->dav_efuse_size;
			bank_efuse_info.log_map_size =
				&hw_info->dav_log_efuse_size;
			bank_efuse_info.efuse_start =
				&hw_info->dav_efuse_start_addr;
			break;
		}

		bank_efuse_info.phy_map = &efuse_param->efuse_map;
		bank_efuse_info.log_map = &efuse_param->log_efuse_map;
		bank_efuse_info.phy_map_valid = &efuse_param->efuse_map_valid;
		bank_efuse_info.log_map_valid =
			&efuse_param->log_efuse_map_valid;
		bank_efuse_info.efuse_end = &efuse_param->efuse_end;
		bank_efuse_info.phy_map_size = &hw_info->efuse_size;
		bank_efuse_info.log_map_size = &hw_info->log_efuse_size;
		bank_efuse_info.efuse_start = &hw_info->wl_efuse_start_addr;
		break;
	case MAC_AX_EFUSE_BANK_BT:
		bank_efuse_info.phy_map = &efuse_param->bt_efuse_map;
		bank_efuse_info.log_map = &efuse_param->bt_log_efuse_map;
		bank_efuse_info.phy_map_valid =
			&efuse_param->bt_efuse_map_valid;
		bank_efuse_info.log_map_valid =
			&efuse_param->bt_log_efuse_map_valid;
		bank_efuse_info.efuse_end = &efuse_param->bt_efuse_end;
		bank_efuse_info.phy_map_size = &hw_info->bt_efuse_size;
		bank_efuse_info.log_map_size = &hw_info->bt_log_efuse_size;
		bank_efuse_info.efuse_start = &hw_info->bt_efuse_start_addr;
		break;
	default:
		return MACEFUSEBANK;
	}

	return MACSUCCESS;
}

static u32 proc_dump_efuse(struct mac_ax_adapter *adapter,
			   enum mac_ax_efuse_read_cfg cfg)
{
	u32 ret;

	if (cfg == MAC_AX_EFUSE_R_AUTO) {
		if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY)
			ret = dump_efuse_drv(adapter);
		else
			ret = dump_efuse_fw(adapter);
	} else if (cfg == MAC_AX_EFUSE_R_FW) {
		ret = dump_efuse_fw(adapter);
	} else {
		ret = dump_efuse_drv(adapter);
	}

	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]dump efsue drv/fw\n");
		return ret;
	}

	return MACSUCCESS;
}

static u32 read_hw_efuse(struct mac_ax_adapter *adapter, u32 offset, u32 size,
			 u8 *map)
{
	u32 addr;
	u32 tmp32 = 0;
	u32 cnt;
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 efuse_start = *bank_efuse_info.efuse_start;

	offset += efuse_start;

	if (dv_sel == DDV) {
		enable_efuse_sw_pwr_cut(adapter, 0);

		for (addr = offset; addr < offset + size; addr++) {
			MAC_REG_W32(efuse_ctrl,
				    ((addr & B_AX_EF_ADDR_MSK) << B_AX_EF_ADDR_SH)
				    & ~B_AX_EF_RDY);

			cnt = read_efuse_cnt;
			if ((is_chip_id(adapter, MAC_AX_CHIP_ID_8852B) ||
			     is_chip_id(adapter, MAC_AX_CHIP_ID_8852C)) &&
			    efuse_ctrl == R_AX_EFUSE_CTRL)
				cnt = EFUSE_WAIT_CNT_PLUS;

			while (--cnt) {
				tmp32 = MAC_REG_R32(efuse_ctrl);
				if (tmp32 & B_AX_EF_RDY)
					break;
				PLTFM_DELAY_US(1);
			}

			if (!cnt) {
				PLTFM_MSG_ERR("[ERR]read efuse\n");
				return MACEFUSEREAD;
			}

			*(map + addr - offset) = (u8)(tmp32 & 0xFF);
		}

		disable_efuse_sw_pwr_cut(adapter, 0);
	} else {
		read_hw_efuse_dav(adapter, offset, size, map);
	}

	return MACSUCCESS;
}

static u32 write_hw_efuse(struct mac_ax_adapter *adapter, u32 offset, u8 value)
{
	//const u8 unlock_code = 0x69;
	u8 value_read = 0;
	u32 value32;
	u32 cnt;
	u32 ret;
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	struct mac_ax_efuse_param *efuse_param = &adapter->efuse_param;
	u32 efuse_start = *bank_efuse_info.efuse_start;

	PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
	*bank_efuse_info.phy_map_valid = 0;
	*bank_efuse_info.log_map_valid = 0;
	PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);

	offset += efuse_start;

	if (dv_sel == DDV) {
		//MAC_REG_W8(R_AX_PMC_DBG_CTRL2 + 3, unlock_code);

		value32 = value |
			  ((offset & B_AX_EF_ADDR_MSK) << B_AX_EF_ADDR_SH);
		value32 &= ~B_AX_EF_RDY;
		MAC_REG_W32(efuse_ctrl,
			    value32 | (MODE_WRITE << B_AX_EF_MODE_SEL_SH));

		cnt = EFUSE_WAIT_CNT;
		while (--cnt) {
			if (MAC_REG_R32(efuse_ctrl) & B_AX_EF_RDY)
				break;
			PLTFM_DELAY_US(1);
		}

		if (!cnt) {
			PLTFM_MSG_ERR("[ERR]write efuse\n");
			return MACEFUSEWRITE;
		}

		//MAC_REG_W8(R_AX_PMC_DBG_CTRL2 + 3, 0x00);
	} else {
		write_hw_efuse_dav(adapter, offset, value);
	}

	if (efuse_param->auto_ck_en == 1) {
		ret = read_hw_efuse(adapter, offset, 1, &value_read);
		if (ret != 0)
			return ret;

		if (value_read != value) {
			PLTFM_MSG_ERR("[ERR]efuse compare\n");
			return MACEFUSEWRITE;
		}
	}

	return MACSUCCESS;
}

static u32 cmp_hw_efuse(struct mac_ax_adapter *adapter, u32 offset, u16 val)
{
	u32 val32;
	u32 tmp32 = 0;
	u32 cnt;
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);

	val32 = val | ((offset & B_AX_EF_ADDR_MSK) << B_AX_EF_ADDR_SH);
	MAC_REG_W32(efuse_ctrl, val32 | (MODE_CMP << B_AX_EF_MODE_SEL_SH));

	cnt = EFUSE_WAIT_CNT;
	while (--cnt) {
		tmp32 = MAC_REG_R32(efuse_ctrl);
		if (tmp32 & B_AX_EF_RDY)
			break;
		PLTFM_DELAY_US(1);
	}

	if (!cnt) {
		PLTFM_MSG_ERR("[ERR]compare efuse\n");
		return MACEFUSEREAD;
	}

	if (0 == (tmp32 & B_AX_EF_COMP_RESULT))
		return MACEFUSECMP;

	return MACSUCCESS;
}

static u32 eeprom_parser(struct mac_ax_adapter *adapter, u8 *phy_map,
			 u8 *log_map, enum mac_ax_efuse_parser_cfg cfg)
{
	u8 i;
	u8 value8;
	u8 blk_idx;
	u8 word_en;
	u8 valid;
	u8 hdr = 0;
	u8 hdr2 = 0;
	u32 eeprom_idx;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	u32 sec_ctrl_size = hw_info->sec_ctrl_efuse_size;
	u32 efuse_idx;
	u32 efuse_size = *bank_efuse_info.phy_map_size;
	bool is_bt = 0;
	u32 log_efuse_size = *bank_efuse_info.log_map_size;

	PLTFM_MEMSET(log_map, 0xFF, log_efuse_size);

	if (log_efuse_size == hw_info->bt_log_efuse_size) {
		sec_ctrl_size = 0;
		is_bt = 1;
	}
	efuse_idx = sec_ctrl_size;

	do {
		if (efuse_idx >= efuse_size) // secure zone
			break;

		value8 = *(phy_map + efuse_idx);
		hdr = value8;
		if (hdr == 0xff)
			break;
		efuse_idx++;

		if (is_bt) {
			if ((hdr & 0xF) != 0xF) {// 1byte entry
				blk_idx = (hdr & 0xF0) >> 4;
				word_en = hdr & 0x0F;
			} else {// 2byte entry
				value8 = *(phy_map + efuse_idx);
				hdr2 = value8;
				if (hdr2 == 0xff)
					break;

				blk_idx = (((hdr2 & 0xF0) >> 4) << 3) +
					  (((hdr & 0xF0) >> 4) >> 1); // offset
				word_en = hdr2 & 0x0F;

				efuse_idx++;
			}
		} else { // WLAN
			value8 = *(phy_map + efuse_idx);
			hdr2 = value8;
			if (hdr2 == 0xff)
				break;

			blk_idx = ((hdr2 & 0xF0) >> 4) | ((hdr & 0x0F) << 4);
			word_en = hdr2 & 0x0F;

			efuse_idx++;
		}

		if (efuse_idx >= efuse_size - 1)
			return MACEFUSEPARSE;

		for (i = 0; i < 4; i++) {
			valid = (u8)((~(word_en >> i)) & BIT(0));
			if (valid == 1) {
				eeprom_idx = (blk_idx << 3) + (i << 1);

				if ((eeprom_idx + 1) >
				    *bank_efuse_info.log_map_size) {
					PLTFM_MSG_ERR("[ERR]efuse idx:0x%X\n",
						      efuse_idx - 1);
					PLTFM_MSG_ERR("[ERR]read hdr:0x%X\n",
						      hdr);
					PLTFM_MSG_ERR("[ERR]read hdr2:0x%X\n",
						      hdr2);
					return MACEFUSEPARSE;
				}

				if (cfg == MAC_AX_EFUSE_PARSER_MAP) {
					value8 = *(phy_map + efuse_idx);
					*(log_map + eeprom_idx) = value8;
				} else if (cfg == MAC_AX_EFUSE_PARSER_MASK) {
					*(log_map + eeprom_idx) = 0x00;
				}

				eeprom_idx++;// 1 byte
				efuse_idx++;

				if (efuse_idx > efuse_size - 1)
					return MACEFUSEPARSE;

				if (cfg == MAC_AX_EFUSE_PARSER_MAP) {
					value8 = *(phy_map + efuse_idx);
					*(log_map + eeprom_idx) = value8;
				} else if (cfg == MAC_AX_EFUSE_PARSER_MASK) {
					*(log_map + eeprom_idx) = 0x00;
				}

				efuse_idx++;

				if (efuse_idx > efuse_size)
					return MACEFUSEPARSE;
			}
		}
	} while (1);

	*bank_efuse_info.efuse_end = efuse_idx;

	return MACSUCCESS;
}

static u32 read_log_efuse_map(struct mac_ax_adapter *adapter, u8 *map,
			      u32 log_efuse_size)
{
	u8 *local_map = NULL;
	u32 efuse_size = *bank_efuse_info.phy_map_size;
	u32 ret;

	if (*bank_efuse_info.log_map_valid == 0) {
		if (*bank_efuse_info.phy_map_valid == 0) {
			local_map = (u8 *)PLTFM_MALLOC(efuse_size);
			if (!local_map) {
				PLTFM_MSG_ERR("[ERR]malloc map\n");
				return MACBUFALLOC;
			}

			ret = read_efuse(adapter, 0, efuse_size, local_map);
			if (ret != 0) {
				PLTFM_MSG_ERR("[ERR]read efuse\n");
				goto error;
			}

			PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
			PLTFM_MEMCPY(*bank_efuse_info.phy_map, local_map,
				     efuse_size);
			*bank_efuse_info.phy_map_valid = 1;
			PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);

			PLTFM_FREE(local_map, efuse_size);
		}

		ret = eeprom_parser(adapter, *bank_efuse_info.phy_map, map,
				    MAC_AX_EFUSE_PARSER_MAP);
		if (ret != 0)
			return ret;

		PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
		PLTFM_MEMCPY(*bank_efuse_info.log_map, map, log_efuse_size);
		*bank_efuse_info.log_map_valid = 1;
		PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);
	} else {
		PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
		PLTFM_MEMCPY(map, *bank_efuse_info.log_map, log_efuse_size);
		PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);
	}

	return MACSUCCESS;
error:
	PLTFM_FREE(local_map, efuse_size);
	return ret;
}

static u32 proc_pg_efuse_by_map(struct mac_ax_adapter *adapter,
				struct mac_ax_pg_efuse_info *info,
				enum mac_ax_efuse_read_cfg cfg)
{
	u8 *updated_mask = NULL;
	u32 ret;
	u32 log_efuse_size = *bank_efuse_info.log_map_size;
	u32 mask_size = log_efuse_size >> 4;

	updated_mask = (u8 *)PLTFM_MALLOC(mask_size);
	if (!updated_mask) {
		PLTFM_MSG_ERR("[ERR]malloc updated mask\n");
		return MACBUFALLOC;
	}
	PLTFM_MEMSET(updated_mask, 0x00, mask_size);

	ret = update_eeprom_mask(adapter, info, updated_mask, 0);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]update eeprom mask\n");
		goto error;
	}

	ret = check_efuse_enough(adapter, info, updated_mask);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]chk efuse enough\n");
		goto error;
	}

	ret = program_efuse(adapter, info, updated_mask, 0);
	if (ret != 0) {
		PLTFM_MSG_ERR("[ERR]pg efuse\n");
		goto error;
	}

	PLTFM_FREE(updated_mask, mask_size);
	return MACSUCCESS;
error:
	PLTFM_FREE(updated_mask, mask_size);
	return ret;
}

static u32 dump_efuse_drv(struct mac_ax_adapter *adapter)
{
	u8 *map = NULL;
	u32 efuse_size = *bank_efuse_info.phy_map_size;
	u32 ret;

	if (*bank_efuse_info.phy_map_valid == 0) {
		map = (u8 *)PLTFM_MALLOC(efuse_size);
		if (!map) {
			PLTFM_MSG_ERR("[ERR]malloc map\n");
			return MACBUFALLOC;
		}

		ret = read_hw_efuse(adapter, 0, efuse_size, map);
		if (ret != 0) {
			PLTFM_FREE(map, efuse_size);
			return ret;
		}

		PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
		PLTFM_MEMCPY(*bank_efuse_info.phy_map, map, efuse_size);
		*bank_efuse_info.phy_map_valid = 1;
		PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);
		PLTFM_FREE(map, efuse_size);
	}

	return MACSUCCESS;
}

static u32 dump_efuse_fw(struct mac_ax_adapter *adapter)
{
	u32 ret, cnt;
	struct mac_ax_ops *ops = adapter->ops;
	u8 *map = NULL;
	u32 efuse_size = *bank_efuse_info.phy_map_size;

	if (*bank_efuse_info.phy_map_valid == 0) {
		/* H2C */
		ret = ops->dump_efuse_ofld(adapter, efuse_size, 0);
		if (ret)
			return ret;

		/* Wait for C2H */
		cnt = EFUSE_FW_DUMP_WAIT_CNT;
		while (--cnt) {
			if (adapter->sm.efuse_ofld == MAC_AX_OFLD_H2C_DONE)
				break;
			PLTFM_DELAY_US(1);
		}
		if (!cnt) {
			PLTFM_MSG_ERR("[ERR]efuse C2H\n");
			adapter->sm.efuse_ofld = MAC_AX_OFLD_H2C_IDLE;
			return MACPROCERR;
		}

		/* cpy map */
		map = (u8 *)PLTFM_MALLOC(efuse_size);
		if (!map) {
			PLTFM_MSG_ERR("[ERR]malloc map\n");
			return MACBUFALLOC;
		}
		PLTFM_MEMSET(map, 0xFF, efuse_size);

		ret = ops->efuse_ofld_map(adapter, map, efuse_size);
		if (ret) {
			PLTFM_FREE(map, efuse_size);
			return ret;
		}

		PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
		PLTFM_MEMCPY(*bank_efuse_info.phy_map, map, efuse_size);
		*bank_efuse_info.phy_map_valid = 1;
		PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);
		PLTFM_FREE(map, efuse_size);
	}

	return MACSUCCESS;
}

static u32 proc_write_log_efuse(struct mac_ax_adapter *adapter, u32 offset,
				u8 value)
{
	u8 byte1;
	u8 byte2;
	u8 blk;
	u8 blk_idx;
	u8 hdr;
	u8 hdr2 = 0;
	u8 *map = NULL;
	u32 log_efuse_size = *bank_efuse_info.log_map_size;
	u32 end, ret;
	bool is_bt = 0;

	map = (u8 *)PLTFM_MALLOC(log_efuse_size);
	if (!map) {
		PLTFM_MSG_ERR("[ERR]malloc map\n");
		return MACBUFALLOC;
	}

	if (*bank_efuse_info.log_map_valid == 0) {
		ret = read_log_efuse_map(adapter, map, log_efuse_size);
		if (ret != 0) {
			PLTFM_MSG_ERR("[ERR]read logical efuse\n");
			PLTFM_FREE(map, log_efuse_size);
			return ret;
		}
	} else {
		PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
		PLTFM_MEMCPY(map, *bank_efuse_info.log_map, log_efuse_size);
		PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);
	}

	if (log_efuse_size == adapter->hw_info->bt_log_efuse_size)
		is_bt = 1;

	if (*(map + offset) != value) {
		end = *bank_efuse_info.efuse_end;

		if (is_bt) {
			if (offset < BT_1B_ENTRY_SIZE) { // 1 byte entry
				blk = (u8)(offset >> 3);
				blk_idx = (u8)((offset & (8 - 1)) >> 1);//mod8

				hdr = (u8)((blk << 4) +
					   ((0x1 << blk_idx) ^ 0x0F));
			} else { // 2 byte entry
				blk = (u8)(offset >> 3 >> 3); // large section
				blk_idx = (u8)(((offset >> 3) & (8 - 1)) << 1);
				hdr = (u8)((blk_idx << 4) + 0xF);

				blk_idx = (u8)((offset & (8 - 1)) >> 1);
				hdr2 = (u8)((blk << 4) +
					    ((0x1 << blk_idx) ^ 0x0F));
			}
		} else {
			blk = (u8)(offset >> 3);// offset
			blk_idx = (u8)((offset & (8 - 1)) >> 1); // mod8 0 1 2 3

			hdr = ((blk & 0xF0) >> 4) | 0x30;
			hdr2 = (u8)(((blk & 0x0F) << 4) +
				    ((0x1 << blk_idx) ^ 0x0F));
		}

		if ((offset & 1) == 0) {
			byte1 = value;
			byte2 = *(map + offset + 1);
		} else {
			byte1 = *(map + offset - 1);
			byte2 = value;
		}

		if (*bank_efuse_info.phy_map_size <= 4 + end) { // write 4 bytes
			PLTFM_FREE(map, log_efuse_size);
			return MACEFUSESIZE;
		}

		enable_efuse_sw_pwr_cut(adapter, 1);

		ret = write_hw_efuse(adapter, end, hdr);
		if (ret != 0)
			goto error;

		if (!is_bt || offset >= BT_1B_ENTRY_SIZE) {
			ret = write_hw_efuse(adapter, end + 1, hdr2);
			if (ret != 0)
				goto error;
			end++;
		}

		ret = write_hw_efuse(adapter, end + 1, byte1);
		if (ret != 0)
			goto error;

		ret = write_hw_efuse(adapter, end + 2, byte2);
		if (ret != 0)
			goto error;

		disable_efuse_sw_pwr_cut(adapter, 1);
	}

	PLTFM_FREE(map, log_efuse_size);
	return MACSUCCESS;
error:
	PLTFM_FREE(map, log_efuse_size);
	return ret;
}

static u32 read_efuse(struct mac_ax_adapter *adapter, u32 offset, u32 size,
		      u8 *map)
{
	u32 ret;

	if (!map) {
		PLTFM_MSG_ERR("[ERR]malloc map\n");
		return MACBUFALLOC;
	}

	if (*bank_efuse_info.phy_map_valid == 1) {
		PLTFM_MEMCPY(map, *bank_efuse_info.phy_map + offset, size);
	} else {
		ret = read_hw_efuse(adapter, offset, size, map);
		if (ret != 0)
			return ret;
	}

	return MACSUCCESS;
}

static u32 update_eeprom_mask(struct mac_ax_adapter *adapter,
			      struct mac_ax_pg_efuse_info *info,
			      u8 *updated_mask, bool pg_sim)
{
	u8 *map = NULL;
	u8 *mask_map = NULL;
	u8 clr_bit = 0;
	u8 *map_pg;
	u8 *efuse_mask;
	u32 i;
	u16 j;
	u16 map_offset;
	u16 mask_offset;
	u32 ret;
	u32 log_efuse_size = *bank_efuse_info.log_map_size;

	map = (u8 *)PLTFM_MALLOC(log_efuse_size);
	if (!map) {
		PLTFM_MSG_ERR("[ERR]malloc map\n");
		return MACBUFALLOC;
	}
	PLTFM_MEMSET(map, 0xFF, log_efuse_size); // default: 0xFF

	if (pg_sim) { //WL
		PLTFM_MEMCPY(map, *bank_efuse_info.log_map, log_efuse_size);
	} else {
		ret = read_log_efuse_map(adapter, map, log_efuse_size);
		if (ret != 0)
			goto error;
	}

	/*log mask*/
	mask_map = (u8 *)PLTFM_MALLOC(log_efuse_size);
	if (!mask_map) {
		PLTFM_MSG_ERR("[ERR]malloc mask map\n");
		PLTFM_FREE(map, log_efuse_size);
		return MACBUFALLOC;
	}
	PLTFM_MEMSET(mask_map, 0xFF, log_efuse_size);// default: 0xFF

	ret = eeprom_parser(adapter, *bank_efuse_info.phy_map,
			    mask_map, MAC_AX_EFUSE_PARSER_MASK);
	if (ret != 0) {
		PLTFM_FREE(mask_map, log_efuse_size);
		goto error;
	}

	map_pg = info->efuse_map;
	efuse_mask = info->efuse_mask;

	PLTFM_MEMCPY(updated_mask, efuse_mask, info->efuse_mask_size);

	for (i = 0; i < info->efuse_map_size; i += 16) {
		for (j = 0; j < 16; j += 2) {
			map_offset = i + j;
			mask_offset = i >> 4;
			if (*(u16 *)(map_pg + map_offset) ==
			    *(u16 *)(map + map_offset) &&
			    *(mask_map + map_offset) == 0x00) {
				switch (j) {
				case 0:
					clr_bit = BIT(4);
					break;
				case 2:
					clr_bit = BIT(5);
					break;
				case 4:
					clr_bit = BIT(6);
					break;
				case 6:
					clr_bit = BIT(7);
					break;
				case 8:
					clr_bit = BIT(0);
					break;
				case 10:
					clr_bit = BIT(1);
					break;
				case 12:
					clr_bit = BIT(2);
					break;
				case 14:
					clr_bit = BIT(3);
					break;
				default:
					break;
				}
				*(updated_mask + mask_offset) &= ~clr_bit;
			}
		}
	}

	PLTFM_FREE(map, log_efuse_size);
	PLTFM_FREE(mask_map, log_efuse_size);
	return MACSUCCESS;
error:
	PLTFM_FREE(map, log_efuse_size);
	return ret;
}

static u32 check_efuse_enough(struct mac_ax_adapter *adapter,
			      struct mac_ax_pg_efuse_info *info,
			      u8 *updated_mask)
{
	u8 pre_word_en;
	u32 i;
	u16 j;
	u32 eeprom_offset;
	u32 pg_num = 0;

	for (i = 0; i < info->efuse_map_size; i += 8) {
		eeprom_offset = i;

		if ((eeprom_offset & 0xF) > 0)
			pre_word_en = (*(updated_mask + (i >> 4)) & 0x0F);
		else
			pre_word_en = (*(updated_mask + (i >> 4)) >> 4);

		if (pre_word_en > 0) { // msk ==1 -> write
			pg_num += 2;
			for (j = 0; j < 4; j++) {
				if (((pre_word_en >> j) & 0x1) > 0)
					pg_num += 2;
			}
		}
	}

	if (*bank_efuse_info.phy_map_size
		< (pg_num + *bank_efuse_info.efuse_end))
		return MACEFUSESIZE;

	return MACSUCCESS;
}

static u32 proc_pg_efuse(struct mac_ax_adapter *adapter,
			 struct mac_ax_pg_efuse_info *info, u8 word_en,
			 u8 pre_word_en, u32 eeprom_offset, bool pg_sim)
{
	u8 blk, blk_idx;
	u8 hdr;
	u8 hdr2 = 0xFF;
	u8 i;
	u32 efuse_end, ret;
	u8 *efuse_map = *bank_efuse_info.phy_map;
	bool is_bt = 0;

	if (info->efuse_map_size == adapter->hw_info->bt_log_efuse_size)
		is_bt = 1;

	efuse_end = *bank_efuse_info.efuse_end;

	if (is_bt) {
		if (eeprom_offset < BT_1B_ENTRY_SIZE) {
			blk = (u8)(eeprom_offset >> 3);
			hdr = (u8)((blk << 4) + word_en);
		} else {
			blk = (u8)(eeprom_offset >> 3 >> 3);
			blk_idx = (u8)(((eeprom_offset >> 3) & (8 - 1)) << 1);
			hdr = (u8)((blk_idx << 4) | 0xF);
			hdr2 = (u8)((blk << 4) + word_en);
		}
	} else {
		blk = (u8)(eeprom_offset >> 3);
		hdr = ((blk & 0xF0) >> 4) | 0x30;
		hdr2 = (u8)(((blk & 0x0F) << 4) + word_en);
	}

	if (pg_sim) { //WL
		*(efuse_map + efuse_end) = hdr;
		*(efuse_map + efuse_end + 1) = hdr2;

		efuse_end += 2;

		for (i = 0; i < 4; i++) {
			if (((pre_word_en >> i) & 0x1) > 0) {
				*(efuse_map + efuse_end) = *(info->efuse_map +
					eeprom_offset + (i << 1));
				efuse_end++;

				*(efuse_map + efuse_end) = *(info->efuse_map +
					eeprom_offset + (i << 1) + 1);
				efuse_end++;
			}
		}
	} else {
		ret = write_hw_efuse(adapter, efuse_end, hdr);
		if (ret != 0) {
			PLTFM_MSG_ERR("[ERR]write efuse\n");
			return ret;
		}

		if (is_bt == 0 || eeprom_offset >= BT_1B_ENTRY_SIZE) {
			ret = write_hw_efuse(adapter, efuse_end + 1, hdr2);
			if (ret != 0) {
				PLTFM_MSG_ERR("[ERR]write efuse(+1)\n");
				return ret;
			}
			efuse_end++;
		}

		efuse_end++;
		for (i = 0; i < 4; i++) {
			if (((pre_word_en >> i) & 0x1) > 0) {
				ret = write_hw_efuse(adapter, efuse_end,
						     *(info->efuse_map +
						     eeprom_offset + (i << 1)));
				if (ret != 0) {
					PLTFM_MSG_ERR("[ERR]write efuse\n");
					return ret;
				}

				ret = write_hw_efuse(adapter, efuse_end + 1,
						     *(info->efuse_map +
						     eeprom_offset +
						     (i << 1) + 1));
				if (ret != 0) {
					PLTFM_MSG_ERR("[ERR]write efuse+1\n");
					return ret;
				}
				efuse_end = efuse_end + 2;
			}
		}
	}
	*bank_efuse_info.efuse_end = efuse_end;
	return MACSUCCESS;
}

static u32 program_efuse(struct mac_ax_adapter *adapter,
			 struct mac_ax_pg_efuse_info *info, u8 *updated_mask,
			 bool pg_sim)
{
	u8 pre_word_en;
	u8 word_en;
	u32 i;
	u32 eeprom_offset, ret;

	enable_efuse_sw_pwr_cut(adapter, 1);

	for (i = 0; i < info->efuse_map_size; i += 8) {
		eeprom_offset = i;

		if (((eeprom_offset >> 3) & 1) > 0) {
			pre_word_en = (*(updated_mask + (i >> 4)) & 0x0F);
			word_en = pre_word_en ^ 0x0F;
		} else {
			pre_word_en = (*(updated_mask + (i >> 4)) >> 4);
			word_en = pre_word_en ^ 0x0F;
		}

		if (pre_word_en > 0) {
			ret = proc_pg_efuse(adapter, info, word_en, pre_word_en,
					    eeprom_offset, pg_sim);
			if (ret != 0) {
				PLTFM_MSG_ERR("[ERR]pg efuse");
				return ret;
			}
		}
	}

	disable_efuse_sw_pwr_cut(adapter, 1);

	return MACSUCCESS;
}

static void mask_eeprom(struct mac_ax_adapter *adapter,
			struct mac_ax_pg_efuse_info *info)
{
	u8 pre_word_en;
	u8 *updated_mask;
	u8 *efuse_map;
	u32 i;
	u16 j;
	u32 offset;

	updated_mask = info->efuse_mask;
	efuse_map = info->efuse_map;

	for (i = 0; i < info->efuse_map_size; i += 8) {
		offset = i;

		if (((offset >> 3) & 1) > 0)
			pre_word_en = (*(updated_mask + (i >> 4)) & 0x0F);
		else
			pre_word_en = (*(updated_mask + (i >> 4)) >> 4);

		for (j = 0; j < 4; j++) {
			if (((pre_word_en >> j) & 0x1) == 0) {
				*(efuse_map + offset + (j << 1)) = 0xFF;
				*(efuse_map + offset + (j << 1) + 1) = 0xFF;
			}
		}
	}
}

static u32 query_status_map(struct mac_ax_adapter *adapter,
			    enum mac_ax_efuse_feature_id feature_id,
			    u8 *map, bool is_limit)
{
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	enum mac_ax_intf intf = adapter->hw_info->intf;
	u32 map_size = 0;

	PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
	switch (feature_id) {
	case MAC_AX_DUMP_PHYSICAL_EFUSE:
		map_size = *bank_efuse_info.phy_map_size;
		PLTFM_MEMCPY(map, *bank_efuse_info.phy_map, map_size);
		break;
	case MAC_AX_DUMP_LOGICAL_EFUSE:
		if (!is_limit) {
			map_size = *bank_efuse_info.log_map_size;
		} else {// WL
			switch (intf) {
			case MAC_AX_INTF_PCIE:
				map_size = hw_info->limit_efuse_size_pcie;
				break;
			case MAC_AX_INTF_USB:
				map_size = hw_info->limit_efuse_size_usb;
				break;
			case MAC_AX_INTF_SDIO:
				map_size = hw_info->limit_efuse_size_sdio;
				break;
			default:
				break;
			}
		}
		PLTFM_MEMCPY(map, *bank_efuse_info.log_map, map_size);
		break;
	default:
		return MACFUNCINPUT;
	}
	PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);

	return MACSUCCESS;
}

static u32 adjust_mask(struct mac_ax_adapter *adapter,
		       struct mac_ax_pg_efuse_info *info)
{
	u8 *efuse_mask = info->efuse_mask;
	u8 *efuse_map = info->efuse_map;
	u32 i = 0;
	u16 j = 0;
	u16 map_offset;
	u16 mask_offset;
	u8 adj_bit = 0;

	PLTFM_MEMSET(efuse_mask, 0xFF, info->efuse_mask_size);

	for (i = 0; i < info->efuse_map_size; i += 16) {
		for (j = 0; j < 16; j += 2) {
			map_offset = i + j;
			mask_offset = i >> 4;

			if (*(u16 *)(efuse_map + map_offset) == 0xFFFF) {
				switch (j) {
				case 0:
					adj_bit = BIT(4);
					break;
				case 2:
					adj_bit = BIT(5);
					break;
				case 4:
					adj_bit = BIT(6);
					break;
				case 6:
					adj_bit = BIT(7);
					break;
				case 8:
					adj_bit = BIT(0);
					break;
				case 10:
					adj_bit = BIT(1);
					break;
				case 12:
					adj_bit = BIT(2);
					break;
				case 14:
					adj_bit = BIT(3);
					break;
				}
				*(efuse_mask + mask_offset) &= ~adj_bit;
			}
		}
	}

	return MACSUCCESS;
}

static u32 compare_info_length(struct efuse_info *info,
			       enum rtw_efuse_info id, u32 length)
{
	u32 idle_len;

	switch (id) {
	case EFUSE_INFO_MAC_ADDR:
		idle_len = info->len->mac_addr;
		break;
	case EFUSE_INFO_MAC_PID:
		idle_len = info->len->pid;
		break;
	case EFUSE_INFO_MAC_DID:
		idle_len = info->len->did;
		break;
	case EFUSE_INFO_MAC_VID:
		idle_len = info->len->vid;
		break;
	case EFUSE_INFO_MAC_SVID:
		idle_len = info->len->svid;
		break;
	case EFUSE_INFO_MAC_SMID:
		idle_len = info->len->smid;
		break;
	default:
		return MACNOITEM;
	}

	if (length != idle_len || idle_len == 0)
		return MACLENCMP;

	return MACSUCCESS;
}

static u32 set_check_sum_val(struct mac_ax_adapter *adapter,
			     u8 *map, u16 value)
{
	u8 byte1;
	u8 byte2;
	u8 blk;
	u8 blk_idx;
	u8 hdr;
	u8 hdr2;
	u32 end = *bank_efuse_info.efuse_end, ret;
	u32 offset = chksum_offset_1;
	u8 i = 0;
	u8 value8 = (u8)(value & 0xFF);

	enable_efuse_sw_pwr_cut(adapter, 1);

	for (i = 0; i < 2; i++) {
		blk = (u8)(offset >> 3);
		blk_idx = (u8)((offset & (8 - 1)) >> 1);

		hdr = ((blk & 0xF0) >> 4) | 0x30;
		hdr2 = (u8)(((blk & 0x0F) << 4) + ((0x1 << blk_idx) ^ 0x0F));

		if ((offset & 1) == 0) {
			byte1 = value8;
			byte2 = *(map + offset + 1);
		} else {
			byte1 = (u8)(value & 0xFF);
			byte2 = value8;
		}

		if (*bank_efuse_info.phy_map_size <= 4 + end)
			return MACEFUSESIZE;

		ret = write_hw_efuse(adapter, end, hdr);
		if (ret != 0)
			return ret;

		ret = write_hw_efuse(adapter, end + 1, hdr2);
		if (ret != 0)
			return ret;

		ret = write_hw_efuse(adapter, end + 2, byte1);
		if (ret != 0)
			return ret;

		ret = write_hw_efuse(adapter, end + 3, byte2);
		if (ret != 0)
			return ret;

		offset = chksum_offset_2;
		value8 = (u8)((value & 0xFF00) >> 8);
		end += 4;
	}

	disable_efuse_sw_pwr_cut(adapter, 1);

	return MACSUCCESS;
}

static void cal_check_sum(struct mac_ax_adapter *adapter, u16 *chksum)
{
	u32 i = 0;
	struct mac_ax_hw_info *hw_info = adapter->hw_info;
	struct mac_ax_efuse_param *efuse_param = &adapter->efuse_param;
	u8 *map = efuse_param->log_efuse_map;
	u16 *data;

	data = (u16 *)map;

	*chksum = 0x0000;
	for (i = 0; i < hw_info->log_efuse_size >> 2; i++) {
		if (i == chksum_offset_1 >> 2)
			*chksum ^= 0x0000 ^ *(data + (2 * i + 1));
		else
			*chksum ^= *(data + 2 * i) ^ *(data + (2 * i + 1));
	}
}

static u32 compare_version(struct mac_ax_adapter *adapter,
			   struct mac_ax_pg_efuse_info *info, u32 ver_len)
{
	u8 *map = info->efuse_map;
	u8 *mask = info->efuse_mask;
	u32 map_size = info->efuse_map_size;
	u32 i = 0;

	for (i = 0; i < ver_len; i++) {
		if (*(map + map_size + i) != *(mask + (map_size >> 4) + i))
			return MACVERERR;
	}
	return MACSUCCESS;
}

static void add_dummy_read(struct mac_ax_adapter *adapter)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);

	MAC_REG_W32(R_AX_EFUSE_CTRL_S,
		    SET_WORD(CHK_OTP_ADDR, B_AX_EF_ADDR) & ~B_AX_EF_RDY);
	PLTFM_DELAY_US(DUMMY_READ_DELAY);
	MAC_REG_W32(R_AX_EFUSE_CTRL,
		    SET_WORD(CHK_OTP_ADDR, B_AX_EF_ADDR) & ~B_AX_EF_RDY);
	PLTFM_DELAY_US(DUMMY_READ_DELAY);
}

static void enable_OTP_burst_mode(struct mac_ax_adapter *adapter,
				  bool enable)
{
	u32 val32;
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);

	val32 = MAC_REG_R32(R_AX_EFUSE_CTRL_1_V1);

	if (enable)
		MAC_REG_W32(R_AX_EFUSE_CTRL_1_V1, val32 | B_AX_EF_BURST);
	else
		MAC_REG_W32(R_AX_EFUSE_CTRL_1_V1, val32 & ~B_AX_EF_BURST);
}

static void enable_efuse_sw_pwr_cut(struct mac_ax_adapter *adapter,
				    bool is_write)
{
	u16 val16;
	u8 val8;
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u8 chip_id = adapter->hw_info->chip_id;

	if (dv_sel == DDV) {
		if (chip_id == MAC_AX_CHIP_ID_8852A && !(is_write))
			return;

		if (is_write)
			MAC_REG_W8(R_AX_PMC_DBG_CTRL2 + 3, UNLOCK_CODE);

		val8 = MAC_REG_R8(R_AX_PMC_DBG_CTRL2);
		MAC_REG_W8(R_AX_PMC_DBG_CTRL2, val8 | B_AX_SYSON_DIS_PMCR_AX_WRMSK);

		val16 = MAC_REG_R16(R_AX_SYS_ISO_CTRL);
		MAC_REG_W16(R_AX_SYS_ISO_CTRL, val16 | BIT(B_AX_PWC_EV2EF_SH));

		PLTFM_DELAY_US(1000);

		val16 = MAC_REG_R16(R_AX_SYS_ISO_CTRL);
		MAC_REG_W16(R_AX_SYS_ISO_CTRL,
			    val16 | BIT(B_AX_PWC_EV2EF_SH + 1));

		if (chip_id == MAC_AX_CHIP_ID_8852A) {
			return;
		} else if (chip_id == MAC_AX_CHIP_ID_8852B) {
			val16 = MAC_REG_R16(R_AX_SYS_ISO_CTRL);
			MAC_REG_W16(R_AX_SYS_ISO_CTRL,
				    val16 & ~(B_AX_ISO_EB2CORE));
			if (is_cv(adapter, CAV))
				enable_OTP_burst_mode(adapter, 1);
		} else {
			val16 = MAC_REG_R16(R_AX_SYS_ISO_CTRL);
			MAC_REG_W16(R_AX_SYS_ISO_CTRL,
				    val16 & ~(B_AX_ISO_EB2CORE));
		}
	} else {
		enable_efuse_pwr_cut_dav(adapter, is_write);
	}
}

static void disable_efuse_sw_pwr_cut(struct mac_ax_adapter *adapter,
				     bool is_write)
{
	u16 value16;
	u8 value8;
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u8 chip_id = adapter->hw_info->chip_id;

	if (dv_sel == DDV) {
		if (chip_id == MAC_AX_CHIP_ID_8852A) {
			if (!(is_write))
				return;
		} else if (chip_id == MAC_AX_CHIP_ID_8852B) {
			if (is_cv(adapter, CAV))
				enable_OTP_burst_mode(adapter, 0);
			value16 = MAC_REG_R16(R_AX_SYS_ISO_CTRL);
			MAC_REG_W16(R_AX_SYS_ISO_CTRL,
				    value16 | B_AX_ISO_EB2CORE);
		} else {
			value16 = MAC_REG_R16(R_AX_SYS_ISO_CTRL);
			MAC_REG_W16(R_AX_SYS_ISO_CTRL,
				    value16 | B_AX_ISO_EB2CORE);
		}

		value16 = MAC_REG_R16(R_AX_SYS_ISO_CTRL);
		MAC_REG_W16(R_AX_SYS_ISO_CTRL,
			    value16 & ~(BIT(B_AX_PWC_EV2EF_SH + 1)));// [15]=0

		PLTFM_DELAY_US(1000);

		value16 = MAC_REG_R16(R_AX_SYS_ISO_CTRL);
		MAC_REG_W16(R_AX_SYS_ISO_CTRL,
			    value16 & ~(BIT(B_AX_PWC_EV2EF_SH)));// [14]=0,

		if (is_write)
			MAC_REG_W8(R_AX_PMC_DBG_CTRL2 + 3, 0x00);

		value8 = MAC_REG_R8(R_AX_PMC_DBG_CTRL2);
		MAC_REG_W8(R_AX_PMC_DBG_CTRL2, value8 & ~B_AX_SYSON_DIS_PMCR_AX_WRMSK);
	} else {
		disable_efuse_pwr_cut_dav(adapter, is_write);
	}
}

static u32 enable_efuse_pwr_cut_dav(struct mac_ax_adapter *adapter,
				    bool is_write)
{
	u32 ret;
	u8 chip_id = adapter->hw_info->chip_id;

	if (!(is_write))
		return MACSUCCESS;

	if (chip_id == MAC_AX_CHIP_ID_8852A) {
		return MACSUCCESS;
	} else {
		ret = mac_write_xtal_si(adapter, XTAL_SI_PWR_CUT,
					XTAL_SI_SMALL_PWR_CUT,
					XTAL_SI_SMALL_PWR_CUT);
		if (ret)
			return ret;

		ret = mac_write_xtal_si(adapter, XTAL_SI_PWR_CUT,
					XTAL_SI_BIG_PWR_CUT,
					XTAL_SI_BIG_PWR_CUT);
		if (ret)
			return ret;
	}

	return MACSUCCESS;
}

static u32 disable_efuse_pwr_cut_dav(struct mac_ax_adapter *adapter,
				     bool is_write)
{
	u32 ret;
	u8 chip_id = adapter->hw_info->chip_id;

	if (!(is_write))
		return MACSUCCESS;

	if (chip_id == MAC_AX_CHIP_ID_8852A) {
		return MACSUCCESS;
	} else {
		ret = mac_write_xtal_si(adapter, XTAL_SI_PWR_CUT, 0,
					XTAL_SI_BIG_PWR_CUT);
		if (ret)
			return ret;

		ret = mac_write_xtal_si(adapter, XTAL_SI_PWR_CUT, 0,
					XTAL_SI_SMALL_PWR_CUT);
		if (ret)
			return ret;
	}

	return MACSUCCESS;
}

static u32 read_hw_efuse_dav(struct mac_ax_adapter *adapter, u32 offset, u32 size,
			     u8 *map)
{
	u32 addr;
	u8 tmp8;
	u32 cnt;
	u32 ret;

	ret = enable_efuse_pwr_cut_dav(adapter, 0);
	if (ret)
		return ret;

	for (addr = offset; addr < offset + size; addr++) {
		/* clear ready bit*/
		ret = mac_write_xtal_si(adapter, XTAL_SI_CTRL, 0x40, FULL_BIT_MASK);
		if (ret)
			return ret;
		/* set addr */
		ret = mac_write_xtal_si(adapter, XTAL_SI_LOW_ADDR,
					(addr & 0xff) << XTAL_SI_LOW_ADDR_SH,
					XTAL_SI_LOW_ADDR_MSK);
		if (ret)
			return ret;
		ret = mac_write_xtal_si(adapter, XTAL_SI_CTRL, (addr >> 8)
					<< XTAL_SI_HIGH_ADDR_SH,
					XTAL_SI_HIGH_ADDR_MSK
					<< XTAL_SI_HIGH_ADDR_SH);
		if (ret)
			return ret;
		/* set ctrl mode sel */
		ret = mac_write_xtal_si(adapter, XTAL_SI_CTRL, 0,
					XTAL_SI_MODE_SEL_MSK
					<< XTAL_SI_MODE_SEL_SH);
		if (ret)
			return ret;

		/* polling */
		cnt = EFUSE_WAIT_CNT;
		while (--cnt) {
			ret = mac_read_xtal_si(adapter, XTAL_SI_CTRL, &tmp8);
			if (ret)
				return ret;
			if (tmp8 & XTAL_SI_RDY)
				break;
			PLTFM_DELAY_US(1);
		}
		if (!cnt) {
			PLTFM_MSG_ERR("[ERR]read efuse\n");
			return MACEFUSEREAD;
		}

		ret = mac_read_xtal_si(adapter, XTAL_SI_READ_VAL, &tmp8);
		if (ret)
			return ret;
		*(map + addr - offset) = tmp8;
	}

	ret = disable_efuse_pwr_cut_dav(adapter, 0);
	if (ret)
		return ret;

	return MACSUCCESS;
}

static u32 write_hw_efuse_dav(struct mac_ax_adapter *adapter, u32 offset,
			      u8 value)
{
	u32 cnt;
	u32 ret;
	u8 tmp8;

	PLTFM_MUTEX_LOCK(&efuse_tbl.lock);
	*bank_efuse_info.phy_map_valid = 0;
	*bank_efuse_info.log_map_valid = 0;
	PLTFM_MUTEX_UNLOCK(&efuse_tbl.lock);

	/* clear ready bit*/
	ret = mac_write_xtal_si(adapter, XTAL_SI_CTRL, 0x40, FULL_BIT_MASK);
	if (ret)
		return ret;
	/* set val */
	ret = mac_write_xtal_si(adapter, XTAL_SI_WRITE_VAL, value <<
				XTAL_SI_WRITE_DATA_SH, XTAL_SI_WRITE_DATA_MSK <<
				XTAL_SI_WRITE_DATA_SH);
	if (ret)
		return ret;
	/* set addr */
	ret = mac_write_xtal_si(adapter, XTAL_SI_LOW_ADDR, (offset & 0xff)
				<< XTAL_SI_LOW_ADDR_SH,
				XTAL_SI_LOW_ADDR_MSK << XTAL_SI_LOW_ADDR_SH);
	if (ret)
		return ret;
	ret = mac_write_xtal_si(adapter, XTAL_SI_CTRL, (offset >> 8)
				<< XTAL_SI_HIGH_ADDR_SH,
				XTAL_SI_HIGH_ADDR_MSK << XTAL_SI_HIGH_ADDR_SH);
	if (ret)
		return ret;
	/* set ctrl mode sel */
	ret = mac_write_xtal_si(adapter, XTAL_SI_CTRL, 0x2
				<< XTAL_SI_MODE_SEL_SH,
				XTAL_SI_MODE_SEL_MSK <<	XTAL_SI_MODE_SEL_SH);
	if (ret)
		return ret;

	/* polling */
	cnt = EFUSE_WAIT_CNT;
	while (--cnt) {
		ret = mac_read_xtal_si(adapter, XTAL_SI_CTRL, &tmp8);
		if (ret)
			return ret;
		if (tmp8 & XTAL_SI_RDY)
			break;
		PLTFM_DELAY_US(1);
	}
	if (!cnt) {
		PLTFM_MSG_ERR("[ERR]write efuse\n");
		return MACEFUSEREAD;
	}

	return MACSUCCESS;
}

static void switch_dv(struct mac_ax_adapter *adapter, enum rtw_dv_sel sel)
{
	dv_sel = sel;
}

