RTL88x2BU-Linux-Driver/hal/halmac/halmac_88xx/halmac_efuse_88xx.c

1903 lines
49 KiB
C

/******************************************************************************
*
* Copyright(c) 2016 - 2018 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 "halmac_efuse_88xx.h"
#include "halmac_88xx_cfg.h"
#include "halmac_common_88xx.h"
#include "halmac_init_88xx.h"
#if HALMAC_88XX_SUPPORT
#define RSVD_EFUSE_SIZE 16
#define RSVD_CS_EFUSE_SIZE 24
#define PROTECT_EFUSE_SIZE 96
#define FEATURE_DUMP_PHY_EFUSE HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE
#define FEATURE_DUMP_LOG_EFUSE HALMAC_FEATURE_DUMP_LOGICAL_EFUSE
static enum halmac_cmd_construct_state
efuse_cmd_cnstr_state_88xx(struct halmac_adapter *adapter);
static enum halmac_ret_status
proc_dump_efuse_88xx(struct halmac_adapter *adapter,
enum halmac_efuse_read_cfg cfg);
static enum halmac_ret_status
read_hw_efuse_88xx(struct halmac_adapter *adapter, u32 offset, u32 size,
u8 *map);
static enum halmac_ret_status
eeprom_parser_88xx(struct halmac_adapter *adapter, u8 *phy_map, u8 *log_map);
static enum halmac_ret_status
read_log_efuse_map_88xx(struct halmac_adapter *adapter, u8 *map);
static enum halmac_ret_status
proc_pg_efuse_by_map_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info,
enum halmac_efuse_read_cfg cfg);
static enum halmac_ret_status
dump_efuse_fw_88xx(struct halmac_adapter *adapter);
static enum halmac_ret_status
dump_efuse_drv_88xx(struct halmac_adapter *adapter);
static enum halmac_ret_status
proc_write_log_efuse_88xx(struct halmac_adapter *adapter, u32 offset, u8 value);
static enum halmac_ret_status
update_eeprom_mask_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info, u8 *updated_mask);
static enum halmac_ret_status
check_efuse_enough_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info, u8 *updated_mask);
static enum halmac_ret_status
pg_extend_efuse_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info, u8 word_en,
u8 pre_word_en, u32 eeprom_offset);
static enum halmac_ret_status
proc_pg_efuse_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info, u8 word_en,
u8 pre_word_en, u32 eeprom_offset);
static enum halmac_ret_status
program_efuse_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info, u8 *updated_mask);
static void
mask_eeprom_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info);
/**
* dump_efuse_map_88xx() - dump "physical" efuse map
* @adapter : the adapter of halmac
* @cfg : dump efuse method
* Author : Ivan Lin/KaiYuan Chang
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
dump_efuse_map_88xx(struct halmac_adapter *adapter,
enum halmac_efuse_read_cfg cfg)
{
u8 *map = NULL;
u8 *efuse_map;
u32 efuse_size = adapter->hw_cfg_info.efuse_size;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
enum halmac_cmd_process_status *proc_status;
proc_status = &adapter->halmac_state.efuse_state.proc_status;
if (cfg == HALMAC_EFUSE_R_FW &&
halmac_fw_validate(adapter) != HALMAC_RET_SUCCESS)
return HALMAC_RET_NO_DLFW;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
PLTFM_MSG_TRACE("[TRACE]cfg = %d\n", cfg);
if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
PLTFM_MSG_WARN("[WARN]Wait event(efuse)\n");
return HALMAC_RET_BUSY_STATE;
}
if (efuse_cmd_cnstr_state_88xx(adapter) != HALMAC_CMD_CNSTR_IDLE) {
PLTFM_MSG_WARN("[WARN]Not idle(efuse)\n");
return HALMAC_RET_ERROR_STATE;
}
if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF)
PLTFM_MSG_ERR("[ERR]Dump efuse in suspend\n");
*proc_status = HALMAC_CMD_PROCESS_IDLE;
adapter->evnt.phy_efuse_map = 1;
status = switch_efuse_bank_88xx(adapter, HALMAC_EFUSE_BANK_WIFI);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
return status;
}
status = proc_dump_efuse_88xx(adapter, cfg);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]dump efuse!!\n");
return status;
}
if (adapter->efuse_map_valid == _TRUE) {
*proc_status = HALMAC_CMD_PROCESS_DONE;
efuse_map = adapter->efuse_map;
map = (u8 *)PLTFM_MALLOC(efuse_size);
if (!map) {
PLTFM_MSG_ERR("[ERR]malloc!!\n");
return HALMAC_RET_MALLOC_FAIL;
}
PLTFM_MEMSET(map, 0xFF, efuse_size);
PLTFM_MUTEX_LOCK(&adapter->efuse_mutex);
PLTFM_MEMCPY(map, efuse_map, efuse_size - PROTECT_EFUSE_SIZE);
PLTFM_MEMCPY(map + efuse_size - PROTECT_EFUSE_SIZE +
RSVD_CS_EFUSE_SIZE,
efuse_map + efuse_size - PROTECT_EFUSE_SIZE +
RSVD_CS_EFUSE_SIZE,
PROTECT_EFUSE_SIZE - RSVD_EFUSE_SIZE -
RSVD_CS_EFUSE_SIZE);
PLTFM_MUTEX_UNLOCK(&adapter->efuse_mutex);
PLTFM_EVENT_SIG(HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE,
*proc_status, map, efuse_size);
adapter->evnt.phy_efuse_map = 0;
PLTFM_FREE(map, efuse_size);
}
if (cnv_efuse_state_88xx(adapter, HALMAC_CMD_CNSTR_IDLE) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_ERROR_STATE;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* dump_efuse_map_bt_88xx() - dump "BT physical" efuse map
* @adapter : the adapter of halmac
* @bank : bt efuse bank
* @size : bt efuse map size. get from halmac_get_efuse_size API
* @map : bt efuse map
* Author : Soar / Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
dump_efuse_map_bt_88xx(struct halmac_adapter *adapter,
enum halmac_efuse_bank bank, u32 size, u8 *map)
{
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
enum halmac_cmd_process_status *proc_status;
proc_status = &adapter->halmac_state.efuse_state.proc_status;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
if (adapter->hw_cfg_info.bt_efuse_size != size)
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
if (bank >= HALMAC_EFUSE_BANK_MAX || bank == HALMAC_EFUSE_BANK_WIFI) {
PLTFM_MSG_ERR("[ERR]Undefined BT bank\n");
return HALMAC_RET_EFUSE_BANK_INCORRECT;
}
if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
PLTFM_MSG_WARN("[WARN]Wait event(efuse)\n");
return HALMAC_RET_BUSY_STATE;
}
if (efuse_cmd_cnstr_state_88xx(adapter) != HALMAC_CMD_CNSTR_IDLE) {
PLTFM_MSG_WARN("[WARN]Not idle(efuse)\n");
return HALMAC_RET_ERROR_STATE;
}
status = switch_efuse_bank_88xx(adapter, bank);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
return status;
}
status = read_hw_efuse_88xx(adapter, 0, size, map);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]read hw efuse\n");
return status;
}
if (cnv_efuse_state_88xx(adapter, HALMAC_CMD_CNSTR_IDLE) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_ERROR_STATE;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* write_efuse_bt_88xx() - write "BT physical" efuse offset
* @adapter : the adapter of halmac
* @offset : offset
* @value : Write value
* @map : bt efuse map
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
write_efuse_bt_88xx(struct halmac_adapter *adapter, u32 offset, u8 value,
enum halmac_efuse_bank bank)
{
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
enum halmac_cmd_process_status *proc_status;
proc_status = &adapter->halmac_state.efuse_state.proc_status;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
PLTFM_MSG_WARN("[WARN]Wait event(efuse)\n");
return HALMAC_RET_BUSY_STATE;
}
if (efuse_cmd_cnstr_state_88xx(adapter) != HALMAC_CMD_CNSTR_IDLE) {
PLTFM_MSG_WARN("[WARN]Not idle(efuse)\n");
return HALMAC_RET_ERROR_STATE;
}
if (offset >= adapter->hw_cfg_info.efuse_size) {
PLTFM_MSG_ERR("[ERR]Offset is too large\n");
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
}
if (bank > HALMAC_EFUSE_BANK_MAX || bank == HALMAC_EFUSE_BANK_WIFI) {
PLTFM_MSG_ERR("[ERR]Undefined BT bank\n");
return HALMAC_RET_EFUSE_BANK_INCORRECT;
}
status = switch_efuse_bank_88xx(adapter, bank);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]switch efuse bank!!\n");
return status;
}
status = write_hw_efuse_88xx(adapter, offset, value);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]write efuse\n");
return status;
}
if (cnv_efuse_state_88xx(adapter, HALMAC_CMD_CNSTR_IDLE) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_ERROR_STATE;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* read_efuse_bt_88xx() - read "BT physical" efuse offset
* @adapter : the adapter of halmac
* @offset : offset
* @value : 1 byte efuse value
* @bank : efuse bank
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
read_efuse_bt_88xx(struct halmac_adapter *adapter, u32 offset, u8 *value,
enum halmac_efuse_bank bank)
{
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
enum halmac_cmd_process_status *proc_status =
&adapter->halmac_state.efuse_state.proc_status;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
PLTFM_MSG_WARN("[WARN]Wait event(efuse)\n");
return HALMAC_RET_BUSY_STATE;
}
if (efuse_cmd_cnstr_state_88xx(adapter) != HALMAC_CMD_CNSTR_IDLE) {
PLTFM_MSG_WARN("[WARN]Not idle(efuse)\n");
return HALMAC_RET_ERROR_STATE;
}
if (offset >= adapter->hw_cfg_info.efuse_size) {
PLTFM_MSG_ERR("[ERR]Offset is too large\n");
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
}
if (bank > HALMAC_EFUSE_BANK_MAX || bank == HALMAC_EFUSE_BANK_WIFI) {
PLTFM_MSG_ERR("[ERR]Undefined BT bank\n");
return HALMAC_RET_EFUSE_BANK_INCORRECT;
}
status = switch_efuse_bank_88xx(adapter, bank);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
return status;
}
status = read_efuse_88xx(adapter, offset, 1, value);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]read efuse\n");
return status;
}
if (cnv_efuse_state_88xx(adapter, HALMAC_CMD_CNSTR_IDLE) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_ERROR_STATE;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* cfg_efuse_auto_check_88xx() - check efuse after writing it
* @adapter : the adapter of halmac
* @enable : 1, enable efuse auto check. others, disable
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
cfg_efuse_auto_check_88xx(struct halmac_adapter *adapter, u8 enable)
{
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
adapter->efuse_auto_check_en = enable;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* get_efuse_available_size_88xx() - get efuse available size
* @adapter : the adapter of halmac
* @size : physical efuse available size
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
get_efuse_available_size_88xx(struct halmac_adapter *adapter, u32 *size)
{
enum halmac_ret_status status;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
status = dump_log_efuse_map_88xx(adapter, HALMAC_EFUSE_R_DRV);
if (status != HALMAC_RET_SUCCESS)
return status;
*size = adapter->hw_cfg_info.efuse_size - PROTECT_EFUSE_SIZE -
adapter->efuse_end;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* get_efuse_size_88xx() - get "physical" efuse size
* @adapter : the adapter of halmac
* @size : physical efuse size
* Author : Ivan Lin/KaiYuan Chang
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
get_efuse_size_88xx(struct halmac_adapter *adapter, u32 *size)
{
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
*size = adapter->hw_cfg_info.efuse_size;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* get_log_efuse_size_88xx() - get "logical" efuse size
* @adapter : the adapter of halmac
* @size : logical efuse size
* Author : Ivan Lin/KaiYuan Chang
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
get_log_efuse_size_88xx(struct halmac_adapter *adapter, u32 *size)
{
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
*size = adapter->hw_cfg_info.eeprom_size;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* dump_log_efuse_map_88xx() - dump "logical" efuse map
* @adapter : the adapter of halmac
* @cfg : dump efuse method
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
dump_log_efuse_map_88xx(struct halmac_adapter *adapter,
enum halmac_efuse_read_cfg cfg)
{
u8 *map = NULL;
u32 size = adapter->hw_cfg_info.eeprom_size;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
enum halmac_cmd_process_status *proc_status =
&adapter->halmac_state.efuse_state.proc_status;
if (cfg == HALMAC_EFUSE_R_FW &&
halmac_fw_validate(adapter) != HALMAC_RET_SUCCESS)
return HALMAC_RET_NO_DLFW;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
PLTFM_MSG_TRACE("[TRACE]cfg = %d\n", cfg);
if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
PLTFM_MSG_WARN("[WARN]Wait event(efuse)\n");
return HALMAC_RET_BUSY_STATE;
}
if (efuse_cmd_cnstr_state_88xx(adapter) != HALMAC_CMD_CNSTR_IDLE) {
PLTFM_MSG_WARN("[WARN]Not idle(efuse)\n");
return HALMAC_RET_ERROR_STATE;
}
if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF)
PLTFM_MSG_ERR("[ERR]Dump efuse in suspend\n");
*proc_status = HALMAC_CMD_PROCESS_IDLE;
adapter->evnt.log_efuse_map = 1;
status = switch_efuse_bank_88xx(adapter, HALMAC_EFUSE_BANK_WIFI);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
return status;
}
status = proc_dump_efuse_88xx(adapter, cfg);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]dump efuse\n");
return status;
}
if (adapter->efuse_map_valid == _TRUE) {
*proc_status = HALMAC_CMD_PROCESS_DONE;
map = (u8 *)PLTFM_MALLOC(size);
if (!map) {
PLTFM_MSG_ERR("[ERR]malloc map\n");
return HALMAC_RET_MALLOC_FAIL;
}
PLTFM_MEMSET(map, 0xFF, size);
if (eeprom_parser_88xx(adapter, adapter->efuse_map, map) !=
HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, size);
return HALMAC_RET_EEPROM_PARSING_FAIL;
}
PLTFM_EVENT_SIG(HALMAC_FEATURE_DUMP_LOGICAL_EFUSE,
*proc_status, map, size);
adapter->evnt.log_efuse_map = 0;
PLTFM_FREE(map, size);
}
if (cnv_efuse_state_88xx(adapter, HALMAC_CMD_CNSTR_IDLE) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_ERROR_STATE;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* read_logical_efuse_88xx() - read logical efuse map 1 byte
* @adapter : the adapter of halmac
* @offset : offset
* @value : 1 byte efuse value
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
read_logical_efuse_88xx(struct halmac_adapter *adapter, u32 offset, u8 *value)
{
u8 *map = NULL;
u32 size = adapter->hw_cfg_info.eeprom_size;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
enum halmac_cmd_process_status *proc_status;
proc_status = &adapter->halmac_state.efuse_state.proc_status;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
if (offset >= size) {
PLTFM_MSG_ERR("[ERR]Offset is too large\n");
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
}
if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
PLTFM_MSG_WARN("[WARN]Wait event(efuse)\n");
return HALMAC_RET_BUSY_STATE;
}
if (efuse_cmd_cnstr_state_88xx(adapter) != HALMAC_CMD_CNSTR_IDLE) {
PLTFM_MSG_WARN("[WARN]Not idle(efuse)\n");
return HALMAC_RET_ERROR_STATE;
}
status = switch_efuse_bank_88xx(adapter, HALMAC_EFUSE_BANK_WIFI);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
return status;
}
map = (u8 *)PLTFM_MALLOC(size);
if (!map) {
PLTFM_MSG_ERR("[ERR]malloc map\n");
return HALMAC_RET_MALLOC_FAIL;
}
PLTFM_MEMSET(map, 0xFF, size);
status = read_log_efuse_map_88xx(adapter, map);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]read logical efuse\n");
PLTFM_FREE(map, size);
return status;
}
*value = *(map + offset);
if (cnv_efuse_state_88xx(adapter, HALMAC_CMD_CNSTR_IDLE) !=
HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, size);
return HALMAC_RET_ERROR_STATE;
}
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
PLTFM_FREE(map, size);
return HALMAC_RET_SUCCESS;
}
/**
* write_log_efuse_88xx() - write "logical" efuse offset
* @adapter : the adapter of halmac
* @offset : offset
* @value : value
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
write_log_efuse_88xx(struct halmac_adapter *adapter, u32 offset, u8 value)
{
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
enum halmac_cmd_process_status *proc_status;
proc_status = &adapter->halmac_state.efuse_state.proc_status;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
if (offset >= adapter->hw_cfg_info.eeprom_size) {
PLTFM_MSG_ERR("[ERR]Offset is too large\n");
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
}
if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
PLTFM_MSG_WARN("[WARN]Wait event(efuse)\n");
return HALMAC_RET_BUSY_STATE;
}
if (efuse_cmd_cnstr_state_88xx(adapter) != HALMAC_CMD_CNSTR_IDLE) {
PLTFM_MSG_WARN("[WARN]Not idle(efuse)\n");
return HALMAC_RET_ERROR_STATE;
}
status = switch_efuse_bank_88xx(adapter, HALMAC_EFUSE_BANK_WIFI);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
return status;
}
status = proc_write_log_efuse_88xx(adapter, offset, value);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]write logical efuse\n");
return status;
}
if (cnv_efuse_state_88xx(adapter, HALMAC_CMD_CNSTR_IDLE) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_ERROR_STATE;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* pg_efuse_by_map_88xx() - pg logical efuse by map
* @adapter : the adapter of halmac
* @info : efuse map information
* @cfg : dump efuse method
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
pg_efuse_by_map_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info,
enum halmac_efuse_read_cfg cfg)
{
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
enum halmac_cmd_process_status *proc_status;
proc_status = &adapter->halmac_state.efuse_state.proc_status;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
if (info->efuse_map_size != adapter->hw_cfg_info.eeprom_size) {
PLTFM_MSG_ERR("[ERR]map size error\n");
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
}
if ((info->efuse_map_size & 0xF) > 0) {
PLTFM_MSG_ERR("[ERR]not multiple of 16\n");
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
}
if (info->efuse_mask_size != info->efuse_map_size >> 4) {
PLTFM_MSG_ERR("[ERR]mask size error\n");
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
}
if (!info->efuse_map) {
PLTFM_MSG_ERR("[ERR]map is NULL\n");
return HALMAC_RET_NULL_POINTER;
}
if (!info->efuse_mask) {
PLTFM_MSG_ERR("[ERR]mask is NULL\n");
return HALMAC_RET_NULL_POINTER;
}
if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
PLTFM_MSG_WARN("[WARN]Wait event(efuse)\n");
return HALMAC_RET_BUSY_STATE;
}
if (efuse_cmd_cnstr_state_88xx(adapter) != HALMAC_CMD_CNSTR_IDLE) {
PLTFM_MSG_WARN("[WARN]Not idle(efuse)\n");
return HALMAC_RET_ERROR_STATE;
}
status = switch_efuse_bank_88xx(adapter, HALMAC_EFUSE_BANK_WIFI);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]switch efuse bank\n");
return status;
}
status = proc_pg_efuse_by_map_88xx(adapter, info, cfg);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]pg efuse\n");
return status;
}
if (cnv_efuse_state_88xx(adapter, HALMAC_CMD_CNSTR_IDLE) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_ERROR_STATE;
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* mask_log_efuse_88xx() - mask logical efuse
* @adapter : the adapter of halmac
* @info : efuse map information
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
mask_log_efuse_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info)
{
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
if (info->efuse_map_size != adapter->hw_cfg_info.eeprom_size) {
PLTFM_MSG_ERR("[ERR]map size error\n");
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
}
if ((info->efuse_map_size & 0xF) > 0) {
PLTFM_MSG_ERR("[ERR]not multiple of 16\n");
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
}
if (info->efuse_mask_size != info->efuse_map_size >> 4) {
PLTFM_MSG_ERR("[ERR]mask size error\n");
return HALMAC_RET_EFUSE_SIZE_INCORRECT;
}
if (!info->efuse_map) {
PLTFM_MSG_ERR("[ERR]map is NULL\n");
return HALMAC_RET_NULL_POINTER;
}
if (!info->efuse_mask) {
PLTFM_MSG_ERR("[ERR]mask is NULL\n");
return HALMAC_RET_NULL_POINTER;
}
mask_eeprom_88xx(adapter, info);
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
static enum halmac_cmd_construct_state
efuse_cmd_cnstr_state_88xx(struct halmac_adapter *adapter)
{
return adapter->halmac_state.efuse_state.cmd_cnstr_state;
}
enum halmac_ret_status
switch_efuse_bank_88xx(struct halmac_adapter *adapter,
enum halmac_efuse_bank bank)
{
u8 reg_value;
struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
if (cnv_efuse_state_88xx(adapter, HALMAC_CMD_CNSTR_BUSY) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_ERROR_STATE;
reg_value = HALMAC_REG_R8(REG_LDO_EFUSE_CTRL + 1);
if (bank == (reg_value & (BIT(0) | BIT(1))))
return HALMAC_RET_SUCCESS;
reg_value &= ~(BIT(0) | BIT(1));
reg_value |= bank;
HALMAC_REG_W8(REG_LDO_EFUSE_CTRL + 1, reg_value);
reg_value = HALMAC_REG_R8(REG_LDO_EFUSE_CTRL + 1);
if ((reg_value & (BIT(0) | BIT(1))) != bank)
return HALMAC_RET_SWITCH_EFUSE_BANK_FAIL;
return HALMAC_RET_SUCCESS;
}
static enum halmac_ret_status
proc_dump_efuse_88xx(struct halmac_adapter *adapter,
enum halmac_efuse_read_cfg cfg)
{
u32 h2c_init;
struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
enum halmac_cmd_process_status *proc_status;
proc_status = &adapter->halmac_state.efuse_state.proc_status;
*proc_status = HALMAC_CMD_PROCESS_SENDING;
if (cnv_efuse_state_88xx(adapter, HALMAC_CMD_CNSTR_H2C_SENT) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_ERROR_STATE;
if (cfg == HALMAC_EFUSE_R_AUTO) {
h2c_init = HALMAC_REG_R32(REG_H2C_PKT_READADDR);
if (adapter->halmac_state.dlfw_state == HALMAC_DLFW_NONE ||
h2c_init == 0)
status = dump_efuse_drv_88xx(adapter);
else
status = dump_efuse_fw_88xx(adapter);
} else if (cfg == HALMAC_EFUSE_R_FW) {
status = dump_efuse_fw_88xx(adapter);
} else {
status = dump_efuse_drv_88xx(adapter);
}
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]dump efsue drv/fw\n");
return status;
}
return status;
}
enum halmac_ret_status
cnv_efuse_state_88xx(struct halmac_adapter *adapter,
enum halmac_cmd_construct_state dest_state)
{
struct halmac_efuse_state *state = &adapter->halmac_state.efuse_state;
if (state->cmd_cnstr_state != HALMAC_CMD_CNSTR_IDLE &&
state->cmd_cnstr_state != HALMAC_CMD_CNSTR_BUSY &&
state->cmd_cnstr_state != HALMAC_CMD_CNSTR_H2C_SENT)
return HALMAC_RET_ERROR_STATE;
if (state->cmd_cnstr_state == dest_state)
return HALMAC_RET_ERROR_STATE;
if (dest_state == HALMAC_CMD_CNSTR_BUSY) {
if (state->cmd_cnstr_state == HALMAC_CMD_CNSTR_H2C_SENT)
return HALMAC_RET_ERROR_STATE;
} else if (dest_state == HALMAC_CMD_CNSTR_H2C_SENT) {
if (state->cmd_cnstr_state == HALMAC_CMD_CNSTR_IDLE)
return HALMAC_RET_ERROR_STATE;
}
state->cmd_cnstr_state = dest_state;
return HALMAC_RET_SUCCESS;
}
static enum halmac_ret_status
read_hw_efuse_88xx(struct halmac_adapter *adapter, u32 offset, u32 size,
u8 *map)
{
u8 enable;
u32 value32;
u32 addr;
u32 tmp32;
u32 cnt;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
/* Read efuse no need 2.5V LDO */
enable = _FALSE;
status = api->halmac_set_hw_value(adapter, HALMAC_HW_LDO25_EN, &enable);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]dis ldo25\n");
return status;
}
value32 = HALMAC_REG_R32(REG_EFUSE_CTRL);
for (addr = offset; addr < offset + size; addr++) {
value32 &= ~(BIT_MASK_EF_DATA | BITS_EF_ADDR);
value32 |= ((addr & BIT_MASK_EF_ADDR) << BIT_SHIFT_EF_ADDR);
HALMAC_REG_W32(REG_EFUSE_CTRL, value32 & (~BIT_EF_FLAG));
cnt = 1000000;
do {
PLTFM_DELAY_US(1);
tmp32 = HALMAC_REG_R32(REG_EFUSE_CTRL);
cnt--;
if (cnt == 0) {
PLTFM_MSG_ERR("[ERR]read\n");
return HALMAC_RET_EFUSE_R_FAIL;
}
} while ((tmp32 & BIT_EF_FLAG) == 0);
*(map + addr - offset) = (u8)(tmp32 & BIT_MASK_EF_DATA);
}
return HALMAC_RET_SUCCESS;
}
enum halmac_ret_status
write_hw_efuse_88xx(struct halmac_adapter *adapter, u32 offset, u8 value)
{
const u8 unlock_code = 0x69;
u8 value_read = 0, enable;
u32 value32;
u32 tmp32;
u32 cnt;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
PLTFM_MUTEX_LOCK(&adapter->efuse_mutex);
adapter->efuse_map_valid = _FALSE;
PLTFM_MUTEX_UNLOCK(&adapter->efuse_mutex);
HALMAC_REG_W8(REG_PMC_DBG_CTRL2 + 3, unlock_code);
/* Enable 2.5V LDO */
enable = _TRUE;
status = api->halmac_set_hw_value(adapter, HALMAC_HW_LDO25_EN, &enable);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]en ldo25\n");
return status;
}
value32 = HALMAC_REG_R32(REG_EFUSE_CTRL);
value32 &= ~(BIT_MASK_EF_DATA | BITS_EF_ADDR);
value32 = value32 | ((offset & BIT_MASK_EF_ADDR) << BIT_SHIFT_EF_ADDR) |
(value & BIT_MASK_EF_DATA);
HALMAC_REG_W32(REG_EFUSE_CTRL, value32 | BIT_EF_FLAG);
cnt = 1000000;
do {
PLTFM_DELAY_US(1);
tmp32 = HALMAC_REG_R32(REG_EFUSE_CTRL);
cnt--;
if (cnt == 0) {
PLTFM_MSG_ERR("[ERR]write!!\n");
return HALMAC_RET_EFUSE_W_FAIL;
}
} while (BIT_EF_FLAG == (tmp32 & BIT_EF_FLAG));
HALMAC_REG_W8(REG_PMC_DBG_CTRL2 + 3, 0x00);
/* Disable 2.5V LDO */
enable = _FALSE;
status = api->halmac_set_hw_value(adapter, HALMAC_HW_LDO25_EN, &enable);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]dis ldo25\n");
return status;
}
if (adapter->efuse_auto_check_en == 1) {
if (read_hw_efuse_88xx(adapter, offset, 1, &value_read) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_EFUSE_R_FAIL;
if (value_read != value) {
PLTFM_MSG_ERR("[ERR]efuse compare\n");
return HALMAC_RET_EFUSE_W_FAIL;
}
}
return HALMAC_RET_SUCCESS;
}
static enum halmac_ret_status
eeprom_parser_88xx(struct halmac_adapter *adapter, u8 *phy_map, u8 *log_map)
{
u8 i;
u8 value8;
u8 blk_idx;
u8 word_en;
u8 valid;
u8 hdr;
u8 hdr2 = 0;
u32 eeprom_idx;
u32 efuse_idx = 0;
struct halmac_hw_cfg_info *hw_info = &adapter->hw_cfg_info;
PLTFM_MEMSET(log_map, 0xFF, hw_info->eeprom_size);
do {
value8 = *(phy_map + efuse_idx);
hdr = value8;
if ((hdr & 0x1f) == 0x0f) {
efuse_idx++;
value8 = *(phy_map + efuse_idx);
hdr2 = value8;
if (hdr2 == 0xff)
break;
blk_idx = ((hdr2 & 0xF0) >> 1) | ((hdr >> 5) & 0x07);
word_en = hdr2 & 0x0F;
} else {
blk_idx = (hdr & 0xF0) >> 4;
word_en = hdr & 0x0F;
}
if (hdr == 0xff)
break;
efuse_idx++;
if (efuse_idx >= hw_info->efuse_size - PROTECT_EFUSE_SIZE - 1)
return HALMAC_RET_EEPROM_PARSING_FAIL;
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) > hw_info->eeprom_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]rad hdr2:0x%X\n",
hdr2);
return HALMAC_RET_EEPROM_PARSING_FAIL;
}
value8 = *(phy_map + efuse_idx);
*(log_map + eeprom_idx) = value8;
eeprom_idx++;
efuse_idx++;
if (efuse_idx > hw_info->efuse_size -
PROTECT_EFUSE_SIZE - 1)
return HALMAC_RET_EEPROM_PARSING_FAIL;
value8 = *(phy_map + efuse_idx);
*(log_map + eeprom_idx) = value8;
efuse_idx++;
if (efuse_idx > hw_info->efuse_size -
PROTECT_EFUSE_SIZE)
return HALMAC_RET_EEPROM_PARSING_FAIL;
}
}
} while (1);
adapter->efuse_end = efuse_idx;
return HALMAC_RET_SUCCESS;
}
static enum halmac_ret_status
read_log_efuse_map_88xx(struct halmac_adapter *adapter, u8 *map)
{
u8 *local_map = NULL;
u32 efuse_size;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
if (adapter->efuse_map_valid == _FALSE) {
efuse_size = adapter->hw_cfg_info.efuse_size;
local_map = (u8 *)PLTFM_MALLOC(efuse_size);
if (!local_map) {
PLTFM_MSG_ERR("[ERR]local map\n");
return HALMAC_RET_MALLOC_FAIL;
}
status = read_efuse_88xx(adapter, 0, efuse_size, local_map);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]read efuse\n");
PLTFM_FREE(local_map, efuse_size);
return status;
}
if (!adapter->efuse_map) {
adapter->efuse_map = (u8 *)PLTFM_MALLOC(efuse_size);
if (!adapter->efuse_map) {
PLTFM_MSG_ERR("[ERR]malloc adapter map\n");
PLTFM_FREE(local_map, efuse_size);
return HALMAC_RET_MALLOC_FAIL;
}
}
PLTFM_MUTEX_LOCK(&adapter->efuse_mutex);
PLTFM_MEMCPY(adapter->efuse_map, local_map, efuse_size);
adapter->efuse_map_valid = _TRUE;
PLTFM_MUTEX_UNLOCK(&adapter->efuse_mutex);
PLTFM_FREE(local_map, efuse_size);
}
if (eeprom_parser_88xx(adapter, adapter->efuse_map, map) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_EEPROM_PARSING_FAIL;
return status;
}
static enum halmac_ret_status
proc_pg_efuse_by_map_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info,
enum halmac_efuse_read_cfg cfg)
{
u8 *updated_mask = NULL;
u32 mask_size = adapter->hw_cfg_info.eeprom_size >> 4;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
updated_mask = (u8 *)PLTFM_MALLOC(mask_size);
if (!updated_mask) {
PLTFM_MSG_ERR("[ERR]malloc updated mask\n");
return HALMAC_RET_MALLOC_FAIL;
}
PLTFM_MEMSET(updated_mask, 0x00, mask_size);
status = update_eeprom_mask_88xx(adapter, info, updated_mask);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]update eeprom mask\n");
PLTFM_FREE(updated_mask, mask_size);
return status;
}
status = check_efuse_enough_88xx(adapter, info, updated_mask);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]chk efuse enough\n");
PLTFM_FREE(updated_mask, mask_size);
return status;
}
status = program_efuse_88xx(adapter, info, updated_mask);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]pg efuse\n");
PLTFM_FREE(updated_mask, mask_size);
return status;
}
PLTFM_FREE(updated_mask, mask_size);
return HALMAC_RET_SUCCESS;
}
static enum halmac_ret_status
dump_efuse_drv_88xx(struct halmac_adapter *adapter)
{
u8 *map = NULL;
u32 efuse_size = adapter->hw_cfg_info.efuse_size;
if (!adapter->efuse_map) {
adapter->efuse_map = (u8 *)PLTFM_MALLOC(efuse_size);
if (!adapter->efuse_map) {
PLTFM_MSG_ERR("[ERR]malloc adapter map!!\n");
reset_ofld_feature_88xx(adapter,
FEATURE_DUMP_PHY_EFUSE);
return HALMAC_RET_MALLOC_FAIL;
}
}
if (adapter->efuse_map_valid == _FALSE) {
map = (u8 *)PLTFM_MALLOC(efuse_size);
if (!map) {
PLTFM_MSG_ERR("[ERR]malloc map\n");
return HALMAC_RET_MALLOC_FAIL;
}
if (read_hw_efuse_88xx(adapter, 0, efuse_size, map) !=
HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, efuse_size);
return HALMAC_RET_EFUSE_R_FAIL;
}
PLTFM_MUTEX_LOCK(&adapter->efuse_mutex);
PLTFM_MEMCPY(adapter->efuse_map, map, efuse_size);
adapter->efuse_map_valid = _TRUE;
PLTFM_MUTEX_UNLOCK(&adapter->efuse_mutex);
PLTFM_FREE(map, efuse_size);
}
return HALMAC_RET_SUCCESS;
}
static enum halmac_ret_status
dump_efuse_fw_88xx(struct halmac_adapter *adapter)
{
u8 h2c_buf[H2C_PKT_SIZE_88XX] = { 0 };
u16 seq_num = 0;
u32 efuse_size = adapter->hw_cfg_info.efuse_size;
struct halmac_h2c_header_info hdr_info;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
hdr_info.sub_cmd_id = SUB_CMD_ID_DUMP_PHYSICAL_EFUSE;
hdr_info.content_size = 0;
hdr_info.ack = _TRUE;
set_h2c_pkt_hdr_88xx(adapter, h2c_buf, &hdr_info, &seq_num);
adapter->halmac_state.efuse_state.seq_num = seq_num;
if (!adapter->efuse_map) {
adapter->efuse_map = (u8 *)PLTFM_MALLOC(efuse_size);
if (!adapter->efuse_map) {
PLTFM_MSG_ERR("[ERR]malloc adapter map\n");
reset_ofld_feature_88xx(adapter,
FEATURE_DUMP_PHY_EFUSE);
return HALMAC_RET_MALLOC_FAIL;
}
}
if (adapter->efuse_map_valid == _FALSE) {
status = send_h2c_pkt_88xx(adapter, h2c_buf);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]send h2c pkt\n");
reset_ofld_feature_88xx(adapter,
FEATURE_DUMP_PHY_EFUSE);
return status;
}
}
return HALMAC_RET_SUCCESS;
}
static enum halmac_ret_status
proc_write_log_efuse_88xx(struct halmac_adapter *adapter, u32 offset, u8 value)
{
u8 byte1;
u8 byte2;
u8 blk;
u8 blk_idx;
u8 hdr;
u8 hdr2;
u8 *map = NULL;
u32 eeprom_size = adapter->hw_cfg_info.eeprom_size;
u32 end;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
map = (u8 *)PLTFM_MALLOC(eeprom_size);
if (!map) {
PLTFM_MSG_ERR("[ERR]malloc map\n");
return HALMAC_RET_MALLOC_FAIL;
}
PLTFM_MEMSET(map, 0xFF, eeprom_size);
status = read_log_efuse_map_88xx(adapter, map);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]read logical efuse\n");
PLTFM_FREE(map, eeprom_size);
return status;
}
if (*(map + offset) != value) {
end = adapter->efuse_end;
blk = (u8)(offset >> 3);
blk_idx = (u8)((offset & (8 - 1)) >> 1);
if (offset > 0x7f) {
hdr = (((blk & 0x07) << 5) & 0xE0) | 0x0F;
hdr2 = (u8)(((blk & 0x78) << 1) +
((0x1 << blk_idx) ^ 0x0F));
} else {
hdr = (u8)((blk << 4) + ((0x01 << blk_idx) ^ 0x0F));
}
if ((offset & 1) == 0) {
byte1 = value;
byte2 = *(map + offset + 1);
} else {
byte1 = *(map + offset - 1);
byte2 = value;
}
if (offset > 0x7f) {
if (adapter->hw_cfg_info.efuse_size <=
4 + PROTECT_EFUSE_SIZE + end) {
PLTFM_FREE(map, eeprom_size);
return HALMAC_RET_EFUSE_NOT_ENOUGH;
}
status = write_hw_efuse_88xx(adapter, end, hdr);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, eeprom_size);
return status;
}
status = write_hw_efuse_88xx(adapter, end + 1, hdr2);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, eeprom_size);
return status;
}
status = write_hw_efuse_88xx(adapter, end + 2, byte1);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, eeprom_size);
return status;
}
status = write_hw_efuse_88xx(adapter, end + 3, byte2);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, eeprom_size);
return status;
}
} else {
if (adapter->hw_cfg_info.efuse_size <=
3 + PROTECT_EFUSE_SIZE + end) {
PLTFM_FREE(map, eeprom_size);
return HALMAC_RET_EFUSE_NOT_ENOUGH;
}
status = write_hw_efuse_88xx(adapter, end, hdr);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, eeprom_size);
return status;
}
status = write_hw_efuse_88xx(adapter, end + 1, byte1);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, eeprom_size);
return status;
}
status = write_hw_efuse_88xx(adapter, end + 2, byte2);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, eeprom_size);
return status;
}
}
}
PLTFM_FREE(map, eeprom_size);
return HALMAC_RET_SUCCESS;
}
enum halmac_ret_status
read_efuse_88xx(struct halmac_adapter *adapter, u32 offset, u32 size, u8 *map)
{
if (!map) {
PLTFM_MSG_ERR("[ERR]malloc map\n");
return HALMAC_RET_NULL_POINTER;
}
if (adapter->efuse_map_valid == _TRUE) {
PLTFM_MEMCPY(map, adapter->efuse_map + offset, size);
} else {
if (read_hw_efuse_88xx(adapter, offset, size, map) !=
HALMAC_RET_SUCCESS)
return HALMAC_RET_EFUSE_R_FAIL;
}
return HALMAC_RET_SUCCESS;
}
static enum halmac_ret_status
update_eeprom_mask_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info, u8 *updated_mask)
{
u8 *map = NULL;
u8 clr_bit = 0;
u32 eeprom_size = adapter->hw_cfg_info.eeprom_size;
u8 *map_pg;
u8 *efuse_mask;
u16 i;
u16 j;
u16 map_offset;
u16 mask_offset;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
map = (u8 *)PLTFM_MALLOC(eeprom_size);
if (!map) {
PLTFM_MSG_ERR("[ERR]malloc map\n");
return HALMAC_RET_MALLOC_FAIL;
}
PLTFM_MEMSET(map, 0xFF, eeprom_size);
PLTFM_MEMSET(updated_mask, 0x00, info->efuse_mask_size);
status = read_log_efuse_map_88xx(adapter, map);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, eeprom_size);
return status;
}
map_pg = info->efuse_map;
efuse_mask = info->efuse_mask;
for (i = 0; i < info->efuse_mask_size; i++)
*(updated_mask + i) = *(efuse_mask + i);
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)) {
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, eeprom_size);
return status;
}
static enum halmac_ret_status
check_efuse_enough_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info, u8 *updated_mask)
{
u8 pre_word_en;
u16 i;
u16 j;
u32 eeprom_offset;
u32 pg_num = 0;
for (i = 0; i < info->efuse_map_size; i = i + 8) {
eeprom_offset = i;
if ((eeprom_offset & 7) > 0)
pre_word_en = (*(updated_mask + (i >> 4)) & 0x0F);
else
pre_word_en = (*(updated_mask + (i >> 4)) >> 4);
if (pre_word_en > 0) {
if (eeprom_offset > 0x7f) {
pg_num += 2;
for (j = 0; j < 4; j++) {
if (((pre_word_en >> j) & 0x1) > 0)
pg_num += 2;
}
} else {
pg_num++;
for (j = 0; j < 4; j++) {
if (((pre_word_en >> j) & 0x1) > 0)
pg_num += 2;
}
}
}
}
if (adapter->hw_cfg_info.efuse_size <=
(pg_num + PROTECT_EFUSE_SIZE + adapter->efuse_end))
return HALMAC_RET_EFUSE_NOT_ENOUGH;
return HALMAC_RET_SUCCESS;
}
static enum halmac_ret_status
pg_extend_efuse_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info, u8 word_en,
u8 pre_word_en, u32 eeprom_offset)
{
u8 blk;
u8 hdr;
u8 hdr2;
u16 i;
u32 efuse_end;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
efuse_end = adapter->efuse_end;
blk = (u8)(eeprom_offset >> 3);
hdr = (((blk & 0x07) << 5) & 0xE0) | 0x0F;
hdr2 = (u8)(((blk & 0x78) << 1) + word_en);
status = write_hw_efuse_88xx(adapter, efuse_end, hdr);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]write efuse\n");
return status;
}
status = write_hw_efuse_88xx(adapter, efuse_end + 1, hdr2);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]write efuse(+1)\n");
return status;
}
efuse_end = efuse_end + 2;
for (i = 0; i < 4; i++) {
if (((pre_word_en >> i) & 0x1) > 0) {
status = write_hw_efuse_88xx(adapter, efuse_end,
*(info->efuse_map +
eeprom_offset +
(i << 1)));
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]write efuse(<<1)\n");
return status;
}
status = write_hw_efuse_88xx(adapter, efuse_end + 1,
*(info->efuse_map +
eeprom_offset + (i << 1)
+ 1));
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]write efuse(<<1)+1\n");
return status;
}
efuse_end = efuse_end + 2;
}
}
adapter->efuse_end = efuse_end;
return status;
}
static enum halmac_ret_status
proc_pg_efuse_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info, u8 word_en,
u8 pre_word_en, u32 eeprom_offset)
{
u8 blk;
u8 hdr;
u16 i;
u32 efuse_end;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
efuse_end = adapter->efuse_end;
blk = (u8)(eeprom_offset >> 3);
hdr = (u8)((blk << 4) + word_en);
status = write_hw_efuse_88xx(adapter, efuse_end, hdr);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]write efuse\n");
return status;
}
efuse_end = efuse_end + 1;
for (i = 0; i < 4; i++) {
if (((pre_word_en >> i) & 0x1) > 0) {
status = write_hw_efuse_88xx(adapter, efuse_end,
*(info->efuse_map +
eeprom_offset +
(i << 1)));
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]write efuse(<<1)\n");
return status;
}
status = write_hw_efuse_88xx(adapter, efuse_end + 1,
*(info->efuse_map +
eeprom_offset + (i << 1)
+ 1));
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]write efuse(<<1)+1\n");
return status;
}
efuse_end = efuse_end + 2;
}
}
adapter->efuse_end = efuse_end;
return status;
}
static enum halmac_ret_status
program_efuse_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info, u8 *updated_mask)
{
u8 pre_word_en;
u8 word_en;
u16 i;
u32 eeprom_offset;
enum halmac_ret_status status = HALMAC_RET_SUCCESS;
for (i = 0; i < info->efuse_map_size; i = 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) {
if (eeprom_offset > 0x7f) {
status = pg_extend_efuse_88xx(adapter, info,
word_en,
pre_word_en,
eeprom_offset);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]extend efuse\n");
return status;
}
} else {
status = proc_pg_efuse_88xx(adapter, info,
word_en,
pre_word_en,
eeprom_offset);
if (status != HALMAC_RET_SUCCESS) {
PLTFM_MSG_ERR("[ERR]extend efuse");
return status;
}
}
}
}
return status;
}
static void
mask_eeprom_88xx(struct halmac_adapter *adapter,
struct halmac_pg_efuse_info *info)
{
u8 pre_word_en;
u8 *updated_mask;
u8 *efuse_map;
u16 i;
u16 j;
u32 offset;
updated_mask = info->efuse_mask;
efuse_map = info->efuse_map;
for (i = 0; i < info->efuse_map_size; i = 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;
}
}
}
}
enum halmac_ret_status
get_efuse_data_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size)
{
u8 seg_id;
u8 seg_size;
u8 seq_num;
u8 fw_rc;
u8 *map = NULL;
u32 eeprom_size = adapter->hw_cfg_info.eeprom_size;
struct halmac_efuse_state *state = &adapter->halmac_state.efuse_state;
enum halmac_cmd_process_status proc_status;
seq_num = (u8)EFUSE_DATA_GET_H2C_SEQ(buf);
PLTFM_MSG_TRACE("[TRACE]Seq num : h2c->%d c2h->%d\n",
state->seq_num, seq_num);
if (seq_num != state->seq_num) {
PLTFM_MSG_ERR("[ERR]Seq num mismatch : h2c->%d c2h->%d\n",
state->seq_num, seq_num);
return HALMAC_RET_SUCCESS;
}
if (state->proc_status != HALMAC_CMD_PROCESS_SENDING) {
PLTFM_MSG_ERR("[ERR]not cmd sending\n");
return HALMAC_RET_SUCCESS;
}
seg_id = (u8)EFUSE_DATA_GET_SEGMENT_ID(buf);
seg_size = (u8)EFUSE_DATA_GET_SEGMENT_SIZE(buf);
if (seg_id == 0)
adapter->efuse_seg_size = seg_size;
map = (u8 *)PLTFM_MALLOC(eeprom_size);
if (!map) {
PLTFM_MSG_ERR("[ERR]malloc map\n");
return HALMAC_RET_MALLOC_FAIL;
}
PLTFM_MEMSET(map, 0xFF, eeprom_size);
PLTFM_MUTEX_LOCK(&adapter->efuse_mutex);
PLTFM_MEMCPY(adapter->efuse_map + seg_id * adapter->efuse_seg_size,
buf + C2H_DATA_OFFSET_88XX, seg_size);
PLTFM_MUTEX_UNLOCK(&adapter->efuse_mutex);
if (EFUSE_DATA_GET_END_SEGMENT(buf) == _FALSE) {
PLTFM_FREE(map, eeprom_size);
return HALMAC_RET_SUCCESS;
}
fw_rc = state->fw_rc;
if ((enum halmac_h2c_return_code)fw_rc == HALMAC_H2C_RETURN_SUCCESS) {
proc_status = HALMAC_CMD_PROCESS_DONE;
state->proc_status = proc_status;
PLTFM_MUTEX_LOCK(&adapter->efuse_mutex);
adapter->efuse_map_valid = _TRUE;
PLTFM_MUTEX_UNLOCK(&adapter->efuse_mutex);
if (adapter->evnt.phy_efuse_map == 1) {
PLTFM_EVENT_SIG(FEATURE_DUMP_PHY_EFUSE,
proc_status, adapter->efuse_map,
adapter->hw_cfg_info.efuse_size);
adapter->evnt.phy_efuse_map = 0;
}
if (adapter->evnt.log_efuse_map == 1) {
if (eeprom_parser_88xx(adapter, adapter->efuse_map,
map) != HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, eeprom_size);
return HALMAC_RET_EEPROM_PARSING_FAIL;
}
PLTFM_EVENT_SIG(FEATURE_DUMP_LOG_EFUSE, proc_status,
map, eeprom_size);
adapter->evnt.log_efuse_map = 0;
}
} else {
proc_status = HALMAC_CMD_PROCESS_ERROR;
state->proc_status = proc_status;
if (adapter->evnt.phy_efuse_map == 1) {
PLTFM_EVENT_SIG(FEATURE_DUMP_PHY_EFUSE, proc_status,
&state->fw_rc, 1);
adapter->evnt.phy_efuse_map = 0;
}
if (adapter->evnt.log_efuse_map == 1) {
PLTFM_EVENT_SIG(FEATURE_DUMP_LOG_EFUSE, proc_status,
&state->fw_rc, 1);
adapter->evnt.log_efuse_map = 0;
}
}
PLTFM_FREE(map, eeprom_size);
return HALMAC_RET_SUCCESS;
}
enum halmac_ret_status
get_dump_phy_efuse_status_88xx(struct halmac_adapter *adapter,
enum halmac_cmd_process_status *proc_status,
u8 *data, u32 *size)
{
u8 *map = NULL;
u32 efuse_size = adapter->hw_cfg_info.efuse_size;
struct halmac_efuse_state *state = &adapter->halmac_state.efuse_state;
*proc_status = state->proc_status;
if (!data)
return HALMAC_RET_NULL_POINTER;
if (!size)
return HALMAC_RET_NULL_POINTER;
if (*proc_status == HALMAC_CMD_PROCESS_DONE) {
if (*size < efuse_size) {
*size = efuse_size;
return HALMAC_RET_BUFFER_TOO_SMALL;
}
*size = efuse_size;
map = (u8 *)PLTFM_MALLOC(efuse_size);
if (!map) {
PLTFM_MSG_ERR("[ERR]malloc map\n");
return HALMAC_RET_MALLOC_FAIL;
}
PLTFM_MEMSET(map, 0xFF, efuse_size);
PLTFM_MUTEX_LOCK(&adapter->efuse_mutex);
PLTFM_MEMCPY(map, adapter->efuse_map,
efuse_size - PROTECT_EFUSE_SIZE);
PLTFM_MEMCPY(map + efuse_size - PROTECT_EFUSE_SIZE +
RSVD_CS_EFUSE_SIZE,
adapter->efuse_map + efuse_size -
PROTECT_EFUSE_SIZE + RSVD_CS_EFUSE_SIZE,
PROTECT_EFUSE_SIZE - RSVD_EFUSE_SIZE -
RSVD_CS_EFUSE_SIZE);
PLTFM_MUTEX_UNLOCK(&adapter->efuse_mutex);
PLTFM_MEMCPY(data, map, *size);
PLTFM_FREE(map, efuse_size);
}
return HALMAC_RET_SUCCESS;
}
enum halmac_ret_status
get_dump_log_efuse_status_88xx(struct halmac_adapter *adapter,
enum halmac_cmd_process_status *proc_status,
u8 *data, u32 *size)
{
u8 *map = NULL;
u32 eeprom_size = adapter->hw_cfg_info.eeprom_size;
struct halmac_efuse_state *state = &adapter->halmac_state.efuse_state;
*proc_status = state->proc_status;
if (!data)
return HALMAC_RET_NULL_POINTER;
if (!size)
return HALMAC_RET_NULL_POINTER;
if (*proc_status == HALMAC_CMD_PROCESS_DONE) {
if (*size < eeprom_size) {
*size = eeprom_size;
return HALMAC_RET_BUFFER_TOO_SMALL;
}
*size = eeprom_size;
map = (u8 *)PLTFM_MALLOC(eeprom_size);
if (!map) {
PLTFM_MSG_ERR("[ERR]malloc map\n");
return HALMAC_RET_MALLOC_FAIL;
}
PLTFM_MEMSET(map, 0xFF, eeprom_size);
if (eeprom_parser_88xx(adapter, adapter->efuse_map, map) !=
HALMAC_RET_SUCCESS) {
PLTFM_FREE(map, eeprom_size);
return HALMAC_RET_EEPROM_PARSING_FAIL;
}
PLTFM_MEMCPY(data, map, *size);
PLTFM_FREE(map, eeprom_size);
}
return HALMAC_RET_SUCCESS;
}
enum halmac_ret_status
get_h2c_ack_phy_efuse_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size)
{
u8 seq_num = 0;
u8 fw_rc;
struct halmac_efuse_state *state = &adapter->halmac_state.efuse_state;
seq_num = (u8)H2C_ACK_HDR_GET_H2C_SEQ(buf);
PLTFM_MSG_TRACE("[TRACE]Seq num : h2c->%d c2h->%d\n",
state->seq_num, seq_num);
if (seq_num != state->seq_num) {
PLTFM_MSG_ERR("[ERR]Seq num mismatch : h2c->%d c2h->%d\n",
state->seq_num, seq_num);
return HALMAC_RET_SUCCESS;
}
if (state->proc_status != HALMAC_CMD_PROCESS_SENDING) {
PLTFM_MSG_ERR("[ERR]not cmd sending\n");
return HALMAC_RET_SUCCESS;
}
fw_rc = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(buf);
state->fw_rc = fw_rc;
return HALMAC_RET_SUCCESS;
}
u32
get_rsvd_efuse_size_88xx(struct halmac_adapter *adapter)
{
return PROTECT_EFUSE_SIZE;
}
#endif /* HALMAC_88XX_SUPPORT */