18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 2009-2012 Realtek Corporation.*/ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "wifi.h" 58c2ecf20Sopenharmony_ci#include "efuse.h" 68c2ecf20Sopenharmony_ci#include "pci.h" 78c2ecf20Sopenharmony_ci#include <linux/export.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_cistatic const u8 PGPKT_DATA_SIZE = 8; 108c2ecf20Sopenharmony_cistatic const int EFUSE_MAX_SIZE = 512; 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define START_ADDRESS 0x1000 138c2ecf20Sopenharmony_ci#define REG_MCUFWDL 0x0080 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic const struct rtl_efuse_ops efuse_ops = { 168c2ecf20Sopenharmony_ci .efuse_onebyte_read = efuse_one_byte_read, 178c2ecf20Sopenharmony_ci .efuse_logical_map_read = efuse_shadow_read, 188c2ecf20Sopenharmony_ci}; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, 218c2ecf20Sopenharmony_ci u8 *value); 228c2ecf20Sopenharmony_cistatic void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, 238c2ecf20Sopenharmony_ci u16 *value); 248c2ecf20Sopenharmony_cistatic void efuse_shadow_read_4byte(struct ieee80211_hw *hw, u16 offset, 258c2ecf20Sopenharmony_ci u32 *value); 268c2ecf20Sopenharmony_cistatic void efuse_shadow_write_1byte(struct ieee80211_hw *hw, u16 offset, 278c2ecf20Sopenharmony_ci u8 value); 288c2ecf20Sopenharmony_cistatic void efuse_shadow_write_2byte(struct ieee80211_hw *hw, u16 offset, 298c2ecf20Sopenharmony_ci u16 value); 308c2ecf20Sopenharmony_cistatic void efuse_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset, 318c2ecf20Sopenharmony_ci u32 value); 328c2ecf20Sopenharmony_cistatic int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, 338c2ecf20Sopenharmony_ci u8 data); 348c2ecf20Sopenharmony_cistatic void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse); 358c2ecf20Sopenharmony_cistatic int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, 368c2ecf20Sopenharmony_ci u8 *data); 378c2ecf20Sopenharmony_cistatic int efuse_pg_packet_write(struct ieee80211_hw *hw, u8 offset, 388c2ecf20Sopenharmony_ci u8 word_en, u8 *data); 398c2ecf20Sopenharmony_cistatic void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, 408c2ecf20Sopenharmony_ci u8 *targetdata); 418c2ecf20Sopenharmony_cistatic u8 enable_efuse_data_write(struct ieee80211_hw *hw, 428c2ecf20Sopenharmony_ci u16 efuse_addr, u8 word_en, u8 *data); 438c2ecf20Sopenharmony_cistatic u16 efuse_get_current_size(struct ieee80211_hw *hw); 448c2ecf20Sopenharmony_cistatic u8 efuse_calculate_word_cnts(u8 word_en); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_civoid efuse_initialize(struct ieee80211_hw *hw) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 498c2ecf20Sopenharmony_ci u8 bytetemp; 508c2ecf20Sopenharmony_ci u8 temp; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1); 538c2ecf20Sopenharmony_ci temp = bytetemp | 0x20; 548c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1, temp); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1); 578c2ecf20Sopenharmony_ci temp = bytetemp & 0xFE; 588c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1, temp); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); 618c2ecf20Sopenharmony_ci temp = bytetemp | 0x80; 628c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, temp); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, 0x2F8, 0x3); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ciu8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 738c2ecf20Sopenharmony_ci u8 data; 748c2ecf20Sopenharmony_ci u8 bytetemp; 758c2ecf20Sopenharmony_ci u8 temp; 768c2ecf20Sopenharmony_ci u32 k = 0; 778c2ecf20Sopenharmony_ci const u32 efuse_len = 788c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (address < efuse_len) { 818c2ecf20Sopenharmony_ci temp = address & 0xFF; 828c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, 838c2ecf20Sopenharmony_ci temp); 848c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, 858c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 2); 868c2ecf20Sopenharmony_ci temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC); 878c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, 888c2ecf20Sopenharmony_ci temp); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, 918c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 3); 928c2ecf20Sopenharmony_ci temp = bytetemp & 0x7F; 938c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 948c2ecf20Sopenharmony_ci temp); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, 978c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 3); 988c2ecf20Sopenharmony_ci while (!(bytetemp & 0x80)) { 998c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, 1008c2ecf20Sopenharmony_ci rtlpriv->cfg-> 1018c2ecf20Sopenharmony_ci maps[EFUSE_CTRL] + 3); 1028c2ecf20Sopenharmony_ci k++; 1038c2ecf20Sopenharmony_ci if (k == 1000) 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); 1078c2ecf20Sopenharmony_ci return data; 1088c2ecf20Sopenharmony_ci } else 1098c2ecf20Sopenharmony_ci return 0xFF; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(efuse_read_1byte); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_civoid efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 1178c2ecf20Sopenharmony_ci u8 bytetemp; 1188c2ecf20Sopenharmony_ci u8 temp; 1198c2ecf20Sopenharmony_ci u32 k = 0; 1208c2ecf20Sopenharmony_ci const u32 efuse_len = 1218c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, "Addr=%x Data =%x\n", 1248c2ecf20Sopenharmony_ci address, value); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (address < efuse_len) { 1278c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci temp = address & 0xFF; 1308c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, 1318c2ecf20Sopenharmony_ci temp); 1328c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, 1338c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 2); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC); 1368c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, 1378c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 2, temp); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, 1408c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 3); 1418c2ecf20Sopenharmony_ci temp = bytetemp | 0x80; 1428c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, 1438c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 3, temp); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, 1468c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 3); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci while (bytetemp & 0x80) { 1498c2ecf20Sopenharmony_ci bytetemp = rtl_read_byte(rtlpriv, 1508c2ecf20Sopenharmony_ci rtlpriv->cfg-> 1518c2ecf20Sopenharmony_ci maps[EFUSE_CTRL] + 3); 1528c2ecf20Sopenharmony_ci k++; 1538c2ecf20Sopenharmony_ci if (k == 100) { 1548c2ecf20Sopenharmony_ci k = 0; 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_civoid read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 1658c2ecf20Sopenharmony_ci u32 value32; 1668c2ecf20Sopenharmony_ci u8 readbyte; 1678c2ecf20Sopenharmony_ci u16 retry; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, 1708c2ecf20Sopenharmony_ci (_offset & 0xff)); 1718c2ecf20Sopenharmony_ci readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2); 1728c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, 1738c2ecf20Sopenharmony_ci ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3); 1768c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 1778c2ecf20Sopenharmony_ci (readbyte & 0x7f)); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci retry = 0; 1808c2ecf20Sopenharmony_ci value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); 1818c2ecf20Sopenharmony_ci while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { 1828c2ecf20Sopenharmony_ci value32 = rtl_read_dword(rtlpriv, 1838c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL]); 1848c2ecf20Sopenharmony_ci retry++; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci udelay(50); 1888c2ecf20Sopenharmony_ci value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci *pbuf = (u8) (value32 & 0xff); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(read_efuse_byte); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_civoid read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 1978c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 1988c2ecf20Sopenharmony_ci u8 *efuse_tbl; 1998c2ecf20Sopenharmony_ci u8 rtemp8[1]; 2008c2ecf20Sopenharmony_ci u16 efuse_addr = 0; 2018c2ecf20Sopenharmony_ci u8 offset, wren; 2028c2ecf20Sopenharmony_ci u8 u1temp = 0; 2038c2ecf20Sopenharmony_ci u16 i; 2048c2ecf20Sopenharmony_ci u16 j; 2058c2ecf20Sopenharmony_ci const u16 efuse_max_section = 2068c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; 2078c2ecf20Sopenharmony_ci const u32 efuse_len = 2088c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; 2098c2ecf20Sopenharmony_ci u16 **efuse_word; 2108c2ecf20Sopenharmony_ci u16 efuse_utilized = 0; 2118c2ecf20Sopenharmony_ci u8 efuse_usage; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) { 2148c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, 2158c2ecf20Sopenharmony_ci "%s: Invalid offset(%#x) with read bytes(%#x)!!\n", 2168c2ecf20Sopenharmony_ci __func__, _offset, _size_byte); 2178c2ecf20Sopenharmony_ci return; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* allocate memory for efuse_tbl and efuse_word */ 2218c2ecf20Sopenharmony_ci efuse_tbl = kzalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], 2228c2ecf20Sopenharmony_ci GFP_ATOMIC); 2238c2ecf20Sopenharmony_ci if (!efuse_tbl) 2248c2ecf20Sopenharmony_ci return; 2258c2ecf20Sopenharmony_ci efuse_word = kcalloc(EFUSE_MAX_WORD_UNIT, sizeof(u16 *), GFP_ATOMIC); 2268c2ecf20Sopenharmony_ci if (!efuse_word) 2278c2ecf20Sopenharmony_ci goto out; 2288c2ecf20Sopenharmony_ci for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { 2298c2ecf20Sopenharmony_ci efuse_word[i] = kcalloc(efuse_max_section, sizeof(u16), 2308c2ecf20Sopenharmony_ci GFP_ATOMIC); 2318c2ecf20Sopenharmony_ci if (!efuse_word[i]) 2328c2ecf20Sopenharmony_ci goto done; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci for (i = 0; i < efuse_max_section; i++) 2368c2ecf20Sopenharmony_ci for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) 2378c2ecf20Sopenharmony_ci efuse_word[j][i] = 0xFFFF; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci read_efuse_byte(hw, efuse_addr, rtemp8); 2408c2ecf20Sopenharmony_ci if (*rtemp8 != 0xFF) { 2418c2ecf20Sopenharmony_ci efuse_utilized++; 2428c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, 2438c2ecf20Sopenharmony_ci "Addr=%d\n", efuse_addr); 2448c2ecf20Sopenharmony_ci efuse_addr++; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) { 2488c2ecf20Sopenharmony_ci /* Check PG header for section num. */ 2498c2ecf20Sopenharmony_ci if ((*rtemp8 & 0x1F) == 0x0F) {/* extended header */ 2508c2ecf20Sopenharmony_ci u1temp = ((*rtemp8 & 0xE0) >> 5); 2518c2ecf20Sopenharmony_ci read_efuse_byte(hw, efuse_addr, rtemp8); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if ((*rtemp8 & 0x0F) == 0x0F) { 2548c2ecf20Sopenharmony_ci efuse_addr++; 2558c2ecf20Sopenharmony_ci read_efuse_byte(hw, efuse_addr, rtemp8); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (*rtemp8 != 0xFF && 2588c2ecf20Sopenharmony_ci (efuse_addr < efuse_len)) { 2598c2ecf20Sopenharmony_ci efuse_addr++; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci continue; 2628c2ecf20Sopenharmony_ci } else { 2638c2ecf20Sopenharmony_ci offset = ((*rtemp8 & 0xF0) >> 1) | u1temp; 2648c2ecf20Sopenharmony_ci wren = (*rtemp8 & 0x0F); 2658c2ecf20Sopenharmony_ci efuse_addr++; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci } else { 2688c2ecf20Sopenharmony_ci offset = ((*rtemp8 >> 4) & 0x0f); 2698c2ecf20Sopenharmony_ci wren = (*rtemp8 & 0x0f); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (offset < efuse_max_section) { 2738c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, 2748c2ecf20Sopenharmony_ci "offset-%d Worden=%x\n", offset, wren); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { 2778c2ecf20Sopenharmony_ci if (!(wren & 0x01)) { 2788c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, 2798c2ecf20Sopenharmony_ci EFUSE_READ_ALL, 2808c2ecf20Sopenharmony_ci "Addr=%d\n", efuse_addr); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci read_efuse_byte(hw, efuse_addr, rtemp8); 2838c2ecf20Sopenharmony_ci efuse_addr++; 2848c2ecf20Sopenharmony_ci efuse_utilized++; 2858c2ecf20Sopenharmony_ci efuse_word[i][offset] = 2868c2ecf20Sopenharmony_ci (*rtemp8 & 0xff); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (efuse_addr >= efuse_len) 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, 2928c2ecf20Sopenharmony_ci EFUSE_READ_ALL, 2938c2ecf20Sopenharmony_ci "Addr=%d\n", efuse_addr); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci read_efuse_byte(hw, efuse_addr, rtemp8); 2968c2ecf20Sopenharmony_ci efuse_addr++; 2978c2ecf20Sopenharmony_ci efuse_utilized++; 2988c2ecf20Sopenharmony_ci efuse_word[i][offset] |= 2998c2ecf20Sopenharmony_ci (((u16)*rtemp8 << 8) & 0xff00); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (efuse_addr >= efuse_len) 3028c2ecf20Sopenharmony_ci break; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci wren >>= 1; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, 3108c2ecf20Sopenharmony_ci "Addr=%d\n", efuse_addr); 3118c2ecf20Sopenharmony_ci read_efuse_byte(hw, efuse_addr, rtemp8); 3128c2ecf20Sopenharmony_ci if (*rtemp8 != 0xFF && (efuse_addr < efuse_len)) { 3138c2ecf20Sopenharmony_ci efuse_utilized++; 3148c2ecf20Sopenharmony_ci efuse_addr++; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci for (i = 0; i < efuse_max_section; i++) { 3198c2ecf20Sopenharmony_ci for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { 3208c2ecf20Sopenharmony_ci efuse_tbl[(i * 8) + (j * 2)] = 3218c2ecf20Sopenharmony_ci (efuse_word[j][i] & 0xff); 3228c2ecf20Sopenharmony_ci efuse_tbl[(i * 8) + ((j * 2) + 1)] = 3238c2ecf20Sopenharmony_ci ((efuse_word[j][i] >> 8) & 0xff); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci for (i = 0; i < _size_byte; i++) 3288c2ecf20Sopenharmony_ci pbuf[i] = efuse_tbl[_offset + i]; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci rtlefuse->efuse_usedbytes = efuse_utilized; 3318c2ecf20Sopenharmony_ci efuse_usage = (u8) ((efuse_utilized * 100) / efuse_len); 3328c2ecf20Sopenharmony_ci rtlefuse->efuse_usedpercentage = efuse_usage; 3338c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES, 3348c2ecf20Sopenharmony_ci (u8 *)&efuse_utilized); 3358c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE, 3368c2ecf20Sopenharmony_ci &efuse_usage); 3378c2ecf20Sopenharmony_cidone: 3388c2ecf20Sopenharmony_ci for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) 3398c2ecf20Sopenharmony_ci kfree(efuse_word[i]); 3408c2ecf20Sopenharmony_ci kfree(efuse_word); 3418c2ecf20Sopenharmony_ciout: 3428c2ecf20Sopenharmony_ci kfree(efuse_tbl); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cibool efuse_shadow_update_chk(struct ieee80211_hw *hw) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 3488c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 3498c2ecf20Sopenharmony_ci u8 section_idx, i, base; 3508c2ecf20Sopenharmony_ci u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; 3518c2ecf20Sopenharmony_ci bool wordchanged, result = true; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci for (section_idx = 0; section_idx < 16; section_idx++) { 3548c2ecf20Sopenharmony_ci base = section_idx * 8; 3558c2ecf20Sopenharmony_ci wordchanged = false; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci for (i = 0; i < 8; i = i + 2) { 3588c2ecf20Sopenharmony_ci if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] != 3598c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i] || 3608c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i + 1] != 3618c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i + 3628c2ecf20Sopenharmony_ci 1]) { 3638c2ecf20Sopenharmony_ci words_need++; 3648c2ecf20Sopenharmony_ci wordchanged = true; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (wordchanged) 3698c2ecf20Sopenharmony_ci hdr_num++; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci totalbytes = hdr_num + words_need * 2; 3738c2ecf20Sopenharmony_ci efuse_used = rtlefuse->efuse_usedbytes; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if ((totalbytes + efuse_used) >= 3768c2ecf20Sopenharmony_ci (EFUSE_MAX_SIZE - rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) 3778c2ecf20Sopenharmony_ci result = false; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, 3808c2ecf20Sopenharmony_ci "%s: totalbytes(%#x), hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", 3818c2ecf20Sopenharmony_ci __func__, totalbytes, hdr_num, words_need, efuse_used); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return result; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_civoid efuse_shadow_read(struct ieee80211_hw *hw, u8 type, 3878c2ecf20Sopenharmony_ci u16 offset, u32 *value) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci if (type == 1) 3908c2ecf20Sopenharmony_ci efuse_shadow_read_1byte(hw, offset, (u8 *)value); 3918c2ecf20Sopenharmony_ci else if (type == 2) 3928c2ecf20Sopenharmony_ci efuse_shadow_read_2byte(hw, offset, (u16 *)value); 3938c2ecf20Sopenharmony_ci else if (type == 4) 3948c2ecf20Sopenharmony_ci efuse_shadow_read_4byte(hw, offset, value); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(efuse_shadow_read); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_civoid efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, 4008c2ecf20Sopenharmony_ci u32 value) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci if (type == 1) 4038c2ecf20Sopenharmony_ci efuse_shadow_write_1byte(hw, offset, (u8) value); 4048c2ecf20Sopenharmony_ci else if (type == 2) 4058c2ecf20Sopenharmony_ci efuse_shadow_write_2byte(hw, offset, (u16) value); 4068c2ecf20Sopenharmony_ci else if (type == 4) 4078c2ecf20Sopenharmony_ci efuse_shadow_write_4byte(hw, offset, value); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cibool efuse_shadow_update(struct ieee80211_hw *hw) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 4148c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 4158c2ecf20Sopenharmony_ci u16 i, offset, base; 4168c2ecf20Sopenharmony_ci u8 word_en = 0x0F; 4178c2ecf20Sopenharmony_ci u8 first_pg = false; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, "\n"); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (!efuse_shadow_update_chk(hw)) { 4228c2ecf20Sopenharmony_ci efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); 4238c2ecf20Sopenharmony_ci memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], 4248c2ecf20Sopenharmony_ci &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 4258c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, 4288c2ecf20Sopenharmony_ci "efuse out of capacity!!\n"); 4298c2ecf20Sopenharmony_ci return false; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci efuse_power_switch(hw, true, true); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci for (offset = 0; offset < 16; offset++) { 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci word_en = 0x0F; 4368c2ecf20Sopenharmony_ci base = offset * 8; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 4398c2ecf20Sopenharmony_ci if (first_pg) { 4408c2ecf20Sopenharmony_ci word_en &= ~(BIT(i / 2)); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] = 4438c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]; 4448c2ecf20Sopenharmony_ci } else { 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] != 4478c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]) { 4488c2ecf20Sopenharmony_ci word_en &= ~(BIT(i / 2)); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] = 4518c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (word_en != 0x0F) { 4578c2ecf20Sopenharmony_ci u8 tmpdata[8]; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci memcpy(tmpdata, 4608c2ecf20Sopenharmony_ci &rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base], 4618c2ecf20Sopenharmony_ci 8); 4628c2ecf20Sopenharmony_ci RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, 4638c2ecf20Sopenharmony_ci "U-efuse\n", tmpdata, 8); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (!efuse_pg_packet_write(hw, (u8) offset, word_en, 4668c2ecf20Sopenharmony_ci tmpdata)) { 4678c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING, 4688c2ecf20Sopenharmony_ci "PG section(%#x) fail!!\n", offset); 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci efuse_power_switch(hw, true, false); 4758c2ecf20Sopenharmony_ci efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], 4788c2ecf20Sopenharmony_ci &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 4798c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, "\n"); 4828c2ecf20Sopenharmony_ci return true; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_civoid rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 4888c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (rtlefuse->autoload_failflag) 4918c2ecf20Sopenharmony_ci memset((&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]), 4928c2ecf20Sopenharmony_ci 0xFF, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); 4938c2ecf20Sopenharmony_ci else 4948c2ecf20Sopenharmony_ci efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], 4978c2ecf20Sopenharmony_ci &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 4988c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rtl_efuse_shadow_map_update); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_civoid efuse_force_write_vendor_id(struct ieee80211_hw *hw) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci u8 tmpdata[8] = { 0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF }; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci efuse_power_switch(hw, true, true); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci efuse_pg_packet_write(hw, 1, 0xD, tmpdata); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci efuse_power_switch(hw, true, false); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_civoid efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic void efuse_shadow_read_1byte(struct ieee80211_hw *hw, 5208c2ecf20Sopenharmony_ci u16 offset, u8 *value) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 5238c2ecf20Sopenharmony_ci *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic void efuse_shadow_read_2byte(struct ieee80211_hw *hw, 5278c2ecf20Sopenharmony_ci u16 offset, u16 *value) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; 5328c2ecf20Sopenharmony_ci *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void efuse_shadow_read_4byte(struct ieee80211_hw *hw, 5378c2ecf20Sopenharmony_ci u16 offset, u32 *value) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; 5428c2ecf20Sopenharmony_ci *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8; 5438c2ecf20Sopenharmony_ci *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] << 16; 5448c2ecf20Sopenharmony_ci *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] << 24; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic void efuse_shadow_write_1byte(struct ieee80211_hw *hw, 5488c2ecf20Sopenharmony_ci u16 offset, u8 value) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic void efuse_shadow_write_2byte(struct ieee80211_hw *hw, 5568c2ecf20Sopenharmony_ci u16 offset, u16 value) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value & 0x00FF; 5618c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = value >> 8; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic void efuse_shadow_write_4byte(struct ieee80211_hw *hw, 5668c2ecf20Sopenharmony_ci u16 offset, u32 value) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = 5718c2ecf20Sopenharmony_ci (u8) (value & 0x000000FF); 5728c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = 5738c2ecf20Sopenharmony_ci (u8) ((value >> 8) & 0x0000FF); 5748c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] = 5758c2ecf20Sopenharmony_ci (u8) ((value >> 16) & 0x00FF); 5768c2ecf20Sopenharmony_ci rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] = 5778c2ecf20Sopenharmony_ci (u8) ((value >> 24) & 0xFF); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ciint efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 5848c2ecf20Sopenharmony_ci u8 tmpidx = 0; 5858c2ecf20Sopenharmony_ci int result; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, 5888c2ecf20Sopenharmony_ci (u8) (addr & 0xff)); 5898c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, 5908c2ecf20Sopenharmony_ci ((u8) ((addr >> 8) & 0x03)) | 5918c2ecf20Sopenharmony_ci (rtl_read_byte(rtlpriv, 5928c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 2) & 5938c2ecf20Sopenharmony_ci 0xFC)); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci while (!(0x80 & rtl_read_byte(rtlpriv, 5988c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) 5998c2ecf20Sopenharmony_ci && (tmpidx < 100)) { 6008c2ecf20Sopenharmony_ci tmpidx++; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (tmpidx < 100) { 6048c2ecf20Sopenharmony_ci *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); 6058c2ecf20Sopenharmony_ci result = true; 6068c2ecf20Sopenharmony_ci } else { 6078c2ecf20Sopenharmony_ci *data = 0xff; 6088c2ecf20Sopenharmony_ci result = false; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci return result; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(efuse_one_byte_read); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 6178c2ecf20Sopenharmony_ci u8 tmpidx = 0; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, 6208c2ecf20Sopenharmony_ci "Addr = %x Data=%x\n", addr, data); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, 6238c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8) (addr & 0xff)); 6248c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, 6258c2ecf20Sopenharmony_ci (rtl_read_byte(rtlpriv, 6268c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 6278c2ecf20Sopenharmony_ci 2) & 0xFC) | (u8) ((addr >> 8) & 0x03)); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], data); 6308c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0xF2); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci while ((0x80 & rtl_read_byte(rtlpriv, 6338c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) 6348c2ecf20Sopenharmony_ci && (tmpidx < 100)) { 6358c2ecf20Sopenharmony_ci tmpidx++; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (tmpidx < 100) 6398c2ecf20Sopenharmony_ci return true; 6408c2ecf20Sopenharmony_ci return false; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci efuse_power_switch(hw, false, true); 6488c2ecf20Sopenharmony_ci read_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse); 6498c2ecf20Sopenharmony_ci efuse_power_switch(hw, false, false); 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, 6538c2ecf20Sopenharmony_ci u8 efuse_data, u8 offset, u8 *tmpdata, 6548c2ecf20Sopenharmony_ci u8 *readstate) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci bool dataempty = true; 6578c2ecf20Sopenharmony_ci u8 hoffset; 6588c2ecf20Sopenharmony_ci u8 tmpidx; 6598c2ecf20Sopenharmony_ci u8 hworden; 6608c2ecf20Sopenharmony_ci u8 word_cnts; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci hoffset = (efuse_data >> 4) & 0x0F; 6638c2ecf20Sopenharmony_ci hworden = efuse_data & 0x0F; 6648c2ecf20Sopenharmony_ci word_cnts = efuse_calculate_word_cnts(hworden); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (hoffset == offset) { 6678c2ecf20Sopenharmony_ci for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) { 6688c2ecf20Sopenharmony_ci if (efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx, 6698c2ecf20Sopenharmony_ci &efuse_data)) { 6708c2ecf20Sopenharmony_ci tmpdata[tmpidx] = efuse_data; 6718c2ecf20Sopenharmony_ci if (efuse_data != 0xff) 6728c2ecf20Sopenharmony_ci dataempty = false; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (!dataempty) { 6778c2ecf20Sopenharmony_ci *readstate = PG_STATE_DATA; 6788c2ecf20Sopenharmony_ci } else { 6798c2ecf20Sopenharmony_ci *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; 6808c2ecf20Sopenharmony_ci *readstate = PG_STATE_HEADER; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci } else { 6848c2ecf20Sopenharmony_ci *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; 6858c2ecf20Sopenharmony_ci *readstate = PG_STATE_HEADER; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci u8 readstate = PG_STATE_HEADER; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci bool continual = true; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci u8 efuse_data, word_cnts = 0; 6968c2ecf20Sopenharmony_ci u16 efuse_addr = 0; 6978c2ecf20Sopenharmony_ci u8 tmpdata[8]; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (data == NULL) 7008c2ecf20Sopenharmony_ci return false; 7018c2ecf20Sopenharmony_ci if (offset > 15) 7028c2ecf20Sopenharmony_ci return false; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); 7058c2ecf20Sopenharmony_ci memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci while (continual && (efuse_addr < EFUSE_MAX_SIZE)) { 7088c2ecf20Sopenharmony_ci if (readstate & PG_STATE_HEADER) { 7098c2ecf20Sopenharmony_ci if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) 7108c2ecf20Sopenharmony_ci && (efuse_data != 0xFF)) 7118c2ecf20Sopenharmony_ci efuse_read_data_case1(hw, &efuse_addr, 7128c2ecf20Sopenharmony_ci efuse_data, offset, 7138c2ecf20Sopenharmony_ci tmpdata, &readstate); 7148c2ecf20Sopenharmony_ci else 7158c2ecf20Sopenharmony_ci continual = false; 7168c2ecf20Sopenharmony_ci } else if (readstate & PG_STATE_DATA) { 7178c2ecf20Sopenharmony_ci efuse_word_enable_data_read(0, tmpdata, data); 7188c2ecf20Sopenharmony_ci efuse_addr = efuse_addr + (word_cnts * 2) + 1; 7198c2ecf20Sopenharmony_ci readstate = PG_STATE_HEADER; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if ((data[0] == 0xff) && (data[1] == 0xff) && 7258c2ecf20Sopenharmony_ci (data[2] == 0xff) && (data[3] == 0xff) && 7268c2ecf20Sopenharmony_ci (data[4] == 0xff) && (data[5] == 0xff) && 7278c2ecf20Sopenharmony_ci (data[6] == 0xff) && (data[7] == 0xff)) 7288c2ecf20Sopenharmony_ci return false; 7298c2ecf20Sopenharmony_ci else 7308c2ecf20Sopenharmony_ci return true; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, 7358c2ecf20Sopenharmony_ci u8 efuse_data, u8 offset, 7368c2ecf20Sopenharmony_ci int *continual, u8 *write_state, 7378c2ecf20Sopenharmony_ci struct pgpkt_struct *target_pkt, 7388c2ecf20Sopenharmony_ci int *repeat_times, int *result, u8 word_en) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 7418c2ecf20Sopenharmony_ci struct pgpkt_struct tmp_pkt; 7428c2ecf20Sopenharmony_ci int dataempty = true; 7438c2ecf20Sopenharmony_ci u8 originaldata[8 * sizeof(u8)]; 7448c2ecf20Sopenharmony_ci u8 badworden = 0x0F; 7458c2ecf20Sopenharmony_ci u8 match_word_en, tmp_word_en; 7468c2ecf20Sopenharmony_ci u8 tmpindex; 7478c2ecf20Sopenharmony_ci u8 tmp_header = efuse_data; 7488c2ecf20Sopenharmony_ci u8 tmp_word_cnts; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci tmp_pkt.offset = (tmp_header >> 4) & 0x0F; 7518c2ecf20Sopenharmony_ci tmp_pkt.word_en = tmp_header & 0x0F; 7528c2ecf20Sopenharmony_ci tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (tmp_pkt.offset != target_pkt->offset) { 7558c2ecf20Sopenharmony_ci *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; 7568c2ecf20Sopenharmony_ci *write_state = PG_STATE_HEADER; 7578c2ecf20Sopenharmony_ci } else { 7588c2ecf20Sopenharmony_ci for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) { 7598c2ecf20Sopenharmony_ci if (efuse_one_byte_read(hw, 7608c2ecf20Sopenharmony_ci (*efuse_addr + 1 + tmpindex), 7618c2ecf20Sopenharmony_ci &efuse_data) && 7628c2ecf20Sopenharmony_ci (efuse_data != 0xFF)) 7638c2ecf20Sopenharmony_ci dataempty = false; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (!dataempty) { 7678c2ecf20Sopenharmony_ci *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; 7688c2ecf20Sopenharmony_ci *write_state = PG_STATE_HEADER; 7698c2ecf20Sopenharmony_ci } else { 7708c2ecf20Sopenharmony_ci match_word_en = 0x0F; 7718c2ecf20Sopenharmony_ci if (!((target_pkt->word_en & BIT(0)) | 7728c2ecf20Sopenharmony_ci (tmp_pkt.word_en & BIT(0)))) 7738c2ecf20Sopenharmony_ci match_word_en &= (~BIT(0)); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (!((target_pkt->word_en & BIT(1)) | 7768c2ecf20Sopenharmony_ci (tmp_pkt.word_en & BIT(1)))) 7778c2ecf20Sopenharmony_ci match_word_en &= (~BIT(1)); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if (!((target_pkt->word_en & BIT(2)) | 7808c2ecf20Sopenharmony_ci (tmp_pkt.word_en & BIT(2)))) 7818c2ecf20Sopenharmony_ci match_word_en &= (~BIT(2)); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (!((target_pkt->word_en & BIT(3)) | 7848c2ecf20Sopenharmony_ci (tmp_pkt.word_en & BIT(3)))) 7858c2ecf20Sopenharmony_ci match_word_en &= (~BIT(3)); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if ((match_word_en & 0x0F) != 0x0F) { 7888c2ecf20Sopenharmony_ci badworden = 7898c2ecf20Sopenharmony_ci enable_efuse_data_write(hw, 7908c2ecf20Sopenharmony_ci *efuse_addr + 1, 7918c2ecf20Sopenharmony_ci tmp_pkt.word_en, 7928c2ecf20Sopenharmony_ci target_pkt->data); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (0x0F != (badworden & 0x0F)) { 7958c2ecf20Sopenharmony_ci u8 reorg_offset = offset; 7968c2ecf20Sopenharmony_ci u8 reorg_worden = badworden; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci efuse_pg_packet_write(hw, reorg_offset, 7998c2ecf20Sopenharmony_ci reorg_worden, 8008c2ecf20Sopenharmony_ci originaldata); 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci tmp_word_en = 0x0F; 8048c2ecf20Sopenharmony_ci if ((target_pkt->word_en & BIT(0)) ^ 8058c2ecf20Sopenharmony_ci (match_word_en & BIT(0))) 8068c2ecf20Sopenharmony_ci tmp_word_en &= (~BIT(0)); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if ((target_pkt->word_en & BIT(1)) ^ 8098c2ecf20Sopenharmony_ci (match_word_en & BIT(1))) 8108c2ecf20Sopenharmony_ci tmp_word_en &= (~BIT(1)); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if ((target_pkt->word_en & BIT(2)) ^ 8138c2ecf20Sopenharmony_ci (match_word_en & BIT(2))) 8148c2ecf20Sopenharmony_ci tmp_word_en &= (~BIT(2)); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if ((target_pkt->word_en & BIT(3)) ^ 8178c2ecf20Sopenharmony_ci (match_word_en & BIT(3))) 8188c2ecf20Sopenharmony_ci tmp_word_en &= (~BIT(3)); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if ((tmp_word_en & 0x0F) != 0x0F) { 8218c2ecf20Sopenharmony_ci *efuse_addr = efuse_get_current_size(hw); 8228c2ecf20Sopenharmony_ci target_pkt->offset = offset; 8238c2ecf20Sopenharmony_ci target_pkt->word_en = tmp_word_en; 8248c2ecf20Sopenharmony_ci } else { 8258c2ecf20Sopenharmony_ci *continual = false; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci *write_state = PG_STATE_HEADER; 8288c2ecf20Sopenharmony_ci *repeat_times += 1; 8298c2ecf20Sopenharmony_ci if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { 8308c2ecf20Sopenharmony_ci *continual = false; 8318c2ecf20Sopenharmony_ci *result = false; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci } else { 8348c2ecf20Sopenharmony_ci *efuse_addr += (2 * tmp_word_cnts) + 1; 8358c2ecf20Sopenharmony_ci target_pkt->offset = offset; 8368c2ecf20Sopenharmony_ci target_pkt->word_en = word_en; 8378c2ecf20Sopenharmony_ci *write_state = PG_STATE_HEADER; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse PG_STATE_HEADER-1\n"); 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, 8458c2ecf20Sopenharmony_ci int *continual, u8 *write_state, 8468c2ecf20Sopenharmony_ci struct pgpkt_struct target_pkt, 8478c2ecf20Sopenharmony_ci int *repeat_times, int *result) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 8508c2ecf20Sopenharmony_ci struct pgpkt_struct tmp_pkt; 8518c2ecf20Sopenharmony_ci u8 pg_header; 8528c2ecf20Sopenharmony_ci u8 tmp_header; 8538c2ecf20Sopenharmony_ci u8 originaldata[8 * sizeof(u8)]; 8548c2ecf20Sopenharmony_ci u8 tmp_word_cnts; 8558c2ecf20Sopenharmony_ci u8 badworden = 0x0F; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci pg_header = ((target_pkt.offset << 4) & 0xf0) | target_pkt.word_en; 8588c2ecf20Sopenharmony_ci efuse_one_byte_write(hw, *efuse_addr, pg_header); 8598c2ecf20Sopenharmony_ci efuse_one_byte_read(hw, *efuse_addr, &tmp_header); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (tmp_header == pg_header) { 8628c2ecf20Sopenharmony_ci *write_state = PG_STATE_DATA; 8638c2ecf20Sopenharmony_ci } else if (tmp_header == 0xFF) { 8648c2ecf20Sopenharmony_ci *write_state = PG_STATE_HEADER; 8658c2ecf20Sopenharmony_ci *repeat_times += 1; 8668c2ecf20Sopenharmony_ci if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { 8678c2ecf20Sopenharmony_ci *continual = false; 8688c2ecf20Sopenharmony_ci *result = false; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci } else { 8718c2ecf20Sopenharmony_ci tmp_pkt.offset = (tmp_header >> 4) & 0x0F; 8728c2ecf20Sopenharmony_ci tmp_pkt.word_en = tmp_header & 0x0F; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci memset(originaldata, 0xff, 8 * sizeof(u8)); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) { 8798c2ecf20Sopenharmony_ci badworden = enable_efuse_data_write(hw, 8808c2ecf20Sopenharmony_ci *efuse_addr + 1, 8818c2ecf20Sopenharmony_ci tmp_pkt.word_en, 8828c2ecf20Sopenharmony_ci originaldata); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (0x0F != (badworden & 0x0F)) { 8858c2ecf20Sopenharmony_ci u8 reorg_offset = tmp_pkt.offset; 8868c2ecf20Sopenharmony_ci u8 reorg_worden = badworden; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci efuse_pg_packet_write(hw, reorg_offset, 8898c2ecf20Sopenharmony_ci reorg_worden, 8908c2ecf20Sopenharmony_ci originaldata); 8918c2ecf20Sopenharmony_ci *efuse_addr = efuse_get_current_size(hw); 8928c2ecf20Sopenharmony_ci } else { 8938c2ecf20Sopenharmony_ci *efuse_addr = *efuse_addr + 8948c2ecf20Sopenharmony_ci (tmp_word_cnts * 2) + 1; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci } else { 8978c2ecf20Sopenharmony_ci *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci *write_state = PG_STATE_HEADER; 9018c2ecf20Sopenharmony_ci *repeat_times += 1; 9028c2ecf20Sopenharmony_ci if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { 9038c2ecf20Sopenharmony_ci *continual = false; 9048c2ecf20Sopenharmony_ci *result = false; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, 9088c2ecf20Sopenharmony_ci "efuse PG_STATE_HEADER-2\n"); 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cistatic int efuse_pg_packet_write(struct ieee80211_hw *hw, 9138c2ecf20Sopenharmony_ci u8 offset, u8 word_en, u8 *data) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 9168c2ecf20Sopenharmony_ci struct pgpkt_struct target_pkt; 9178c2ecf20Sopenharmony_ci u8 write_state = PG_STATE_HEADER; 9188c2ecf20Sopenharmony_ci int continual = true, result = true; 9198c2ecf20Sopenharmony_ci u16 efuse_addr = 0; 9208c2ecf20Sopenharmony_ci u8 efuse_data; 9218c2ecf20Sopenharmony_ci u8 target_word_cnts = 0; 9228c2ecf20Sopenharmony_ci u8 badworden = 0x0F; 9238c2ecf20Sopenharmony_ci static int repeat_times; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE - 9268c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) { 9278c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, 9288c2ecf20Sopenharmony_ci "efuse_pg_packet_write error\n"); 9298c2ecf20Sopenharmony_ci return false; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci target_pkt.offset = offset; 9338c2ecf20Sopenharmony_ci target_pkt.word_en = word_en; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci memset(target_pkt.data, 0xFF, 8 * sizeof(u8)); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci efuse_word_enable_data_read(word_en, data, target_pkt.data); 9388c2ecf20Sopenharmony_ci target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse Power ON\n"); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci while (continual && (efuse_addr < (EFUSE_MAX_SIZE - 9438c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) { 9448c2ecf20Sopenharmony_ci if (write_state == PG_STATE_HEADER) { 9458c2ecf20Sopenharmony_ci badworden = 0x0F; 9468c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, 9478c2ecf20Sopenharmony_ci "efuse PG_STATE_HEADER\n"); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) && 9508c2ecf20Sopenharmony_ci (efuse_data != 0xFF)) 9518c2ecf20Sopenharmony_ci efuse_write_data_case1(hw, &efuse_addr, 9528c2ecf20Sopenharmony_ci efuse_data, offset, 9538c2ecf20Sopenharmony_ci &continual, 9548c2ecf20Sopenharmony_ci &write_state, 9558c2ecf20Sopenharmony_ci &target_pkt, 9568c2ecf20Sopenharmony_ci &repeat_times, &result, 9578c2ecf20Sopenharmony_ci word_en); 9588c2ecf20Sopenharmony_ci else 9598c2ecf20Sopenharmony_ci efuse_write_data_case2(hw, &efuse_addr, 9608c2ecf20Sopenharmony_ci &continual, 9618c2ecf20Sopenharmony_ci &write_state, 9628c2ecf20Sopenharmony_ci target_pkt, 9638c2ecf20Sopenharmony_ci &repeat_times, 9648c2ecf20Sopenharmony_ci &result); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci } else if (write_state == PG_STATE_DATA) { 9678c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, 9688c2ecf20Sopenharmony_ci "efuse PG_STATE_DATA\n"); 9698c2ecf20Sopenharmony_ci badworden = 9708c2ecf20Sopenharmony_ci enable_efuse_data_write(hw, efuse_addr + 1, 9718c2ecf20Sopenharmony_ci target_pkt.word_en, 9728c2ecf20Sopenharmony_ci target_pkt.data); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if ((badworden & 0x0F) == 0x0F) { 9758c2ecf20Sopenharmony_ci continual = false; 9768c2ecf20Sopenharmony_ci } else { 9778c2ecf20Sopenharmony_ci efuse_addr = 9788c2ecf20Sopenharmony_ci efuse_addr + (2 * target_word_cnts) + 1; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci target_pkt.offset = offset; 9818c2ecf20Sopenharmony_ci target_pkt.word_en = badworden; 9828c2ecf20Sopenharmony_ci target_word_cnts = 9838c2ecf20Sopenharmony_ci efuse_calculate_word_cnts(target_pkt. 9848c2ecf20Sopenharmony_ci word_en); 9858c2ecf20Sopenharmony_ci write_state = PG_STATE_HEADER; 9868c2ecf20Sopenharmony_ci repeat_times++; 9878c2ecf20Sopenharmony_ci if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { 9888c2ecf20Sopenharmony_ci continual = false; 9898c2ecf20Sopenharmony_ci result = false; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, 9928c2ecf20Sopenharmony_ci "efuse PG_STATE_HEADER-3\n"); 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (efuse_addr >= (EFUSE_MAX_SIZE - 9988c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) { 9998c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, 10008c2ecf20Sopenharmony_ci "efuse_addr(%#x) Out of size!!\n", efuse_addr); 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci return true; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, 10078c2ecf20Sopenharmony_ci u8 *targetdata) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci if (!(word_en & BIT(0))) { 10108c2ecf20Sopenharmony_ci targetdata[0] = sourdata[0]; 10118c2ecf20Sopenharmony_ci targetdata[1] = sourdata[1]; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (!(word_en & BIT(1))) { 10158c2ecf20Sopenharmony_ci targetdata[2] = sourdata[2]; 10168c2ecf20Sopenharmony_ci targetdata[3] = sourdata[3]; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (!(word_en & BIT(2))) { 10208c2ecf20Sopenharmony_ci targetdata[4] = sourdata[4]; 10218c2ecf20Sopenharmony_ci targetdata[5] = sourdata[5]; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (!(word_en & BIT(3))) { 10258c2ecf20Sopenharmony_ci targetdata[6] = sourdata[6]; 10268c2ecf20Sopenharmony_ci targetdata[7] = sourdata[7]; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic u8 enable_efuse_data_write(struct ieee80211_hw *hw, 10318c2ecf20Sopenharmony_ci u16 efuse_addr, u8 word_en, u8 *data) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 10348c2ecf20Sopenharmony_ci u16 tmpaddr; 10358c2ecf20Sopenharmony_ci u16 start_addr = efuse_addr; 10368c2ecf20Sopenharmony_ci u8 badworden = 0x0F; 10378c2ecf20Sopenharmony_ci u8 tmpdata[8]; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci memset(tmpdata, 0xff, PGPKT_DATA_SIZE); 10408c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, 10418c2ecf20Sopenharmony_ci "word_en = %x efuse_addr=%x\n", word_en, efuse_addr); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (!(word_en & BIT(0))) { 10448c2ecf20Sopenharmony_ci tmpaddr = start_addr; 10458c2ecf20Sopenharmony_ci efuse_one_byte_write(hw, start_addr++, data[0]); 10468c2ecf20Sopenharmony_ci efuse_one_byte_write(hw, start_addr++, data[1]); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci efuse_one_byte_read(hw, tmpaddr, &tmpdata[0]); 10498c2ecf20Sopenharmony_ci efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[1]); 10508c2ecf20Sopenharmony_ci if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) 10518c2ecf20Sopenharmony_ci badworden &= (~BIT(0)); 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if (!(word_en & BIT(1))) { 10558c2ecf20Sopenharmony_ci tmpaddr = start_addr; 10568c2ecf20Sopenharmony_ci efuse_one_byte_write(hw, start_addr++, data[2]); 10578c2ecf20Sopenharmony_ci efuse_one_byte_write(hw, start_addr++, data[3]); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci efuse_one_byte_read(hw, tmpaddr, &tmpdata[2]); 10608c2ecf20Sopenharmony_ci efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[3]); 10618c2ecf20Sopenharmony_ci if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) 10628c2ecf20Sopenharmony_ci badworden &= (~BIT(1)); 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (!(word_en & BIT(2))) { 10668c2ecf20Sopenharmony_ci tmpaddr = start_addr; 10678c2ecf20Sopenharmony_ci efuse_one_byte_write(hw, start_addr++, data[4]); 10688c2ecf20Sopenharmony_ci efuse_one_byte_write(hw, start_addr++, data[5]); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci efuse_one_byte_read(hw, tmpaddr, &tmpdata[4]); 10718c2ecf20Sopenharmony_ci efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[5]); 10728c2ecf20Sopenharmony_ci if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) 10738c2ecf20Sopenharmony_ci badworden &= (~BIT(2)); 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (!(word_en & BIT(3))) { 10778c2ecf20Sopenharmony_ci tmpaddr = start_addr; 10788c2ecf20Sopenharmony_ci efuse_one_byte_write(hw, start_addr++, data[6]); 10798c2ecf20Sopenharmony_ci efuse_one_byte_write(hw, start_addr++, data[7]); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci efuse_one_byte_read(hw, tmpaddr, &tmpdata[6]); 10828c2ecf20Sopenharmony_ci efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[7]); 10838c2ecf20Sopenharmony_ci if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) 10848c2ecf20Sopenharmony_ci badworden &= (~BIT(3)); 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci return badworden; 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_civoid efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 10938c2ecf20Sopenharmony_ci struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 10948c2ecf20Sopenharmony_ci u8 tempval; 10958c2ecf20Sopenharmony_ci u16 tmpv16; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (pwrstate && (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)) { 10988c2ecf20Sopenharmony_ci if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE && 10998c2ecf20Sopenharmony_ci rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) { 11008c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, 11018c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_ACCESS], 0x69); 11028c2ecf20Sopenharmony_ci } else { 11038c2ecf20Sopenharmony_ci tmpv16 = 11048c2ecf20Sopenharmony_ci rtl_read_word(rtlpriv, 11058c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[SYS_ISO_CTRL]); 11068c2ecf20Sopenharmony_ci if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { 11078c2ecf20Sopenharmony_ci tmpv16 |= rtlpriv->cfg->maps[EFUSE_PWC_EV12V]; 11088c2ecf20Sopenharmony_ci rtl_write_word(rtlpriv, 11098c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[SYS_ISO_CTRL], 11108c2ecf20Sopenharmony_ci tmpv16); 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci tmpv16 = rtl_read_word(rtlpriv, 11148c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[SYS_FUNC_EN]); 11158c2ecf20Sopenharmony_ci if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_FEN_ELDR])) { 11168c2ecf20Sopenharmony_ci tmpv16 |= rtlpriv->cfg->maps[EFUSE_FEN_ELDR]; 11178c2ecf20Sopenharmony_ci rtl_write_word(rtlpriv, 11188c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[SYS_FUNC_EN], tmpv16); 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci tmpv16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_CLK]); 11228c2ecf20Sopenharmony_ci if ((!(tmpv16 & rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN])) || 11238c2ecf20Sopenharmony_ci (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_ANA8M]))) { 11248c2ecf20Sopenharmony_ci tmpv16 |= (rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN] | 11258c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_ANA8M]); 11268c2ecf20Sopenharmony_ci rtl_write_word(rtlpriv, 11278c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[SYS_CLK], tmpv16); 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (pwrstate) { 11328c2ecf20Sopenharmony_ci if (write) { 11338c2ecf20Sopenharmony_ci tempval = rtl_read_byte(rtlpriv, 11348c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_TEST] + 11358c2ecf20Sopenharmony_ci 3); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { 11388c2ecf20Sopenharmony_ci tempval &= ~(BIT(3) | BIT(4) | BIT(5) | BIT(6)); 11398c2ecf20Sopenharmony_ci tempval |= (VOLTAGE_V25 << 3); 11408c2ecf20Sopenharmony_ci } else if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) { 11418c2ecf20Sopenharmony_ci tempval &= 0x0F; 11428c2ecf20Sopenharmony_ci tempval |= (VOLTAGE_V25 << 4); 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, 11468c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_TEST] + 3, 11478c2ecf20Sopenharmony_ci (tempval | 0x80)); 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { 11518c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], 11528c2ecf20Sopenharmony_ci 0x03); 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci } else { 11558c2ecf20Sopenharmony_ci if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE && 11568c2ecf20Sopenharmony_ci rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) 11578c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, 11588c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_ACCESS], 0); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci if (write) { 11618c2ecf20Sopenharmony_ci tempval = rtl_read_byte(rtlpriv, 11628c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_TEST] + 11638c2ecf20Sopenharmony_ci 3); 11648c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, 11658c2ecf20Sopenharmony_ci rtlpriv->cfg->maps[EFUSE_TEST] + 3, 11668c2ecf20Sopenharmony_ci (tempval & 0x7F)); 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { 11708c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], 11718c2ecf20Sopenharmony_ci 0x02); 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(efuse_power_switch); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic u16 efuse_get_current_size(struct ieee80211_hw *hw) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci int continual = true; 11808c2ecf20Sopenharmony_ci u16 efuse_addr = 0; 11818c2ecf20Sopenharmony_ci u8 hworden; 11828c2ecf20Sopenharmony_ci u8 efuse_data, word_cnts; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) && 11858c2ecf20Sopenharmony_ci (efuse_addr < EFUSE_MAX_SIZE)) { 11868c2ecf20Sopenharmony_ci if (efuse_data != 0xFF) { 11878c2ecf20Sopenharmony_ci hworden = efuse_data & 0x0F; 11888c2ecf20Sopenharmony_ci word_cnts = efuse_calculate_word_cnts(hworden); 11898c2ecf20Sopenharmony_ci efuse_addr = efuse_addr + (word_cnts * 2) + 1; 11908c2ecf20Sopenharmony_ci } else { 11918c2ecf20Sopenharmony_ci continual = false; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci return efuse_addr; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic u8 efuse_calculate_word_cnts(u8 word_en) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci u8 word_cnts = 0; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (!(word_en & BIT(0))) 12038c2ecf20Sopenharmony_ci word_cnts++; 12048c2ecf20Sopenharmony_ci if (!(word_en & BIT(1))) 12058c2ecf20Sopenharmony_ci word_cnts++; 12068c2ecf20Sopenharmony_ci if (!(word_en & BIT(2))) 12078c2ecf20Sopenharmony_ci word_cnts++; 12088c2ecf20Sopenharmony_ci if (!(word_en & BIT(3))) 12098c2ecf20Sopenharmony_ci word_cnts++; 12108c2ecf20Sopenharmony_ci return word_cnts; 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ciint rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv, 12148c2ecf20Sopenharmony_ci int max_size, u8 *hwinfo, int *params) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 12178c2ecf20Sopenharmony_ci struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); 12188c2ecf20Sopenharmony_ci struct device *dev = &rtlpcipriv->dev.pdev->dev; 12198c2ecf20Sopenharmony_ci u16 eeprom_id; 12208c2ecf20Sopenharmony_ci u16 i, usvalue; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci switch (rtlefuse->epromtype) { 12238c2ecf20Sopenharmony_ci case EEPROM_BOOT_EFUSE: 12248c2ecf20Sopenharmony_ci rtl_efuse_shadow_map_update(hw); 12258c2ecf20Sopenharmony_ci break; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci case EEPROM_93C46: 12288c2ecf20Sopenharmony_ci pr_err("RTL8XXX did not boot from eeprom, check it !!\n"); 12298c2ecf20Sopenharmony_ci return 1; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci default: 12328c2ecf20Sopenharmony_ci dev_warn(dev, "no efuse data\n"); 12338c2ecf20Sopenharmony_ci return 1; 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], max_size); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP", 12398c2ecf20Sopenharmony_ci hwinfo, max_size); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci eeprom_id = *((u16 *)&hwinfo[0]); 12428c2ecf20Sopenharmony_ci if (eeprom_id != params[0]) { 12438c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING, 12448c2ecf20Sopenharmony_ci "EEPROM ID(%#x) is invalid!!\n", eeprom_id); 12458c2ecf20Sopenharmony_ci rtlefuse->autoload_failflag = true; 12468c2ecf20Sopenharmony_ci } else { 12478c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); 12488c2ecf20Sopenharmony_ci rtlefuse->autoload_failflag = false; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci if (rtlefuse->autoload_failflag) 12528c2ecf20Sopenharmony_ci return 1; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci rtlefuse->eeprom_vid = *(u16 *)&hwinfo[params[1]]; 12558c2ecf20Sopenharmony_ci rtlefuse->eeprom_did = *(u16 *)&hwinfo[params[2]]; 12568c2ecf20Sopenharmony_ci rtlefuse->eeprom_svid = *(u16 *)&hwinfo[params[3]]; 12578c2ecf20Sopenharmony_ci rtlefuse->eeprom_smid = *(u16 *)&hwinfo[params[4]]; 12588c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 12598c2ecf20Sopenharmony_ci "EEPROMId = 0x%4x\n", eeprom_id); 12608c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 12618c2ecf20Sopenharmony_ci "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); 12628c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 12638c2ecf20Sopenharmony_ci "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); 12648c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 12658c2ecf20Sopenharmony_ci "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); 12668c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 12678c2ecf20Sopenharmony_ci "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci for (i = 0; i < 6; i += 2) { 12708c2ecf20Sopenharmony_ci usvalue = *(u16 *)&hwinfo[params[5] + i]; 12718c2ecf20Sopenharmony_ci *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "%pM\n", rtlefuse->dev_addr); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci rtlefuse->eeprom_channelplan = *&hwinfo[params[6]]; 12768c2ecf20Sopenharmony_ci rtlefuse->eeprom_version = *(u16 *)&hwinfo[params[7]]; 12778c2ecf20Sopenharmony_ci rtlefuse->txpwr_fromeprom = true; 12788c2ecf20Sopenharmony_ci rtlefuse->eeprom_oemid = *&hwinfo[params[8]]; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 12818c2ecf20Sopenharmony_ci "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* set channel plan to world wide 13 */ 12848c2ecf20Sopenharmony_ci rtlefuse->channel_plan = params[9]; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci return 0; 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rtl_get_hwinfo); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_civoid rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 12938c2ecf20Sopenharmony_ci u8 *pu4byteptr = (u8 *)buffer; 12948c2ecf20Sopenharmony_ci u32 i; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) 12978c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, (START_ADDRESS + i), *(pu4byteptr + i)); 12988c2ecf20Sopenharmony_ci} 12998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rtl_fw_block_write); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_civoid rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer, 13028c2ecf20Sopenharmony_ci u32 size) 13038c2ecf20Sopenharmony_ci{ 13048c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 13058c2ecf20Sopenharmony_ci u8 value8; 13068c2ecf20Sopenharmony_ci u8 u8page = (u8)(page & 0x07); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); 13118c2ecf20Sopenharmony_ci rtl_fw_block_write(hw, buffer, size); 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rtl_fw_page_write); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_civoid rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci u32 fwlen = *pfwlen; 13188c2ecf20Sopenharmony_ci u8 remain = (u8)(fwlen % 4); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci remain = (remain == 0) ? 0 : (4 - remain); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci while (remain > 0) { 13238c2ecf20Sopenharmony_ci pfwbuf[fwlen] = 0; 13248c2ecf20Sopenharmony_ci fwlen++; 13258c2ecf20Sopenharmony_ci remain--; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci *pfwlen = fwlen; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rtl_fill_dummy); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_civoid rtl_efuse_ops_init(struct ieee80211_hw *hw) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci rtlpriv->efuse.efuse_ops = &efuse_ops; 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rtl_efuse_ops_init); 1339