/****************************************************************************** * * 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 */