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 "../pci.h" 68c2ecf20Sopenharmony_ci#include "../base.h" 78c2ecf20Sopenharmony_ci#include "reg.h" 88c2ecf20Sopenharmony_ci#include "def.h" 98c2ecf20Sopenharmony_ci#include "fw.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw) 128c2ecf20Sopenharmony_ci{ 138c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci rtl_write_dword(rtlpriv, RQPN, 0xffffffff); 168c2ecf20Sopenharmony_ci rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff); 178c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, RQPN + 8, 0xff); 188c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80); 198c2ecf20Sopenharmony_ci} 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 248c2ecf20Sopenharmony_ci u32 ichecktime = 200; 258c2ecf20Sopenharmony_ci u16 tmpu2b; 268c2ecf20Sopenharmony_ci u8 tmpu1b, cpustatus = 0; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci _rtl92s_fw_set_rqpn(hw); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci /* Enable CPU. */ 318c2ecf20Sopenharmony_ci tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR); 328c2ecf20Sopenharmony_ci /* AFE source */ 338c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL)); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); 368c2ecf20Sopenharmony_ci rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN)); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* Polling IMEM Ready after CPU has refilled. */ 398c2ecf20Sopenharmony_ci do { 408c2ecf20Sopenharmony_ci cpustatus = rtl_read_byte(rtlpriv, TCR); 418c2ecf20Sopenharmony_ci if (cpustatus & IMEM_RDY) { 428c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 438c2ecf20Sopenharmony_ci "IMEM Ready after CPU has refilled\n"); 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci udelay(100); 488c2ecf20Sopenharmony_ci } while (ichecktime--); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (!(cpustatus & IMEM_RDY)) 518c2ecf20Sopenharmony_ci return false; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return true; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic enum fw_status _rtl92s_firmware_get_nextstatus( 578c2ecf20Sopenharmony_ci enum fw_status fw_currentstatus) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci enum fw_status next_fwstatus = 0; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci switch (fw_currentstatus) { 628c2ecf20Sopenharmony_ci case FW_STATUS_INIT: 638c2ecf20Sopenharmony_ci next_fwstatus = FW_STATUS_LOAD_IMEM; 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci case FW_STATUS_LOAD_IMEM: 668c2ecf20Sopenharmony_ci next_fwstatus = FW_STATUS_LOAD_EMEM; 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case FW_STATUS_LOAD_EMEM: 698c2ecf20Sopenharmony_ci next_fwstatus = FW_STATUS_LOAD_DMEM; 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci case FW_STATUS_LOAD_DMEM: 728c2ecf20Sopenharmony_ci next_fwstatus = FW_STATUS_READY; 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci default: 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return next_fwstatus; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 848c2ecf20Sopenharmony_ci struct rtl_phy *rtlphy = &(rtlpriv->phy); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci switch (rtlphy->rf_type) { 878c2ecf20Sopenharmony_ci case RF_1T1R: 888c2ecf20Sopenharmony_ci return 0x11; 898c2ecf20Sopenharmony_ci case RF_1T2R: 908c2ecf20Sopenharmony_ci return 0x12; 918c2ecf20Sopenharmony_ci case RF_2T2R: 928c2ecf20Sopenharmony_ci return 0x22; 938c2ecf20Sopenharmony_ci default: 948c2ecf20Sopenharmony_ci pr_err("Unknown RF type(%x)\n", rtlphy->rf_type); 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci return 0x22; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw, 1018c2ecf20Sopenharmony_ci struct fw_priv *pfw_priv) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci /* Update RF types for RATR settings. */ 1048c2ecf20Sopenharmony_ci pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw, 1108c2ecf20Sopenharmony_ci struct sk_buff *skb, u8 last) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 1138c2ecf20Sopenharmony_ci struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); 1148c2ecf20Sopenharmony_ci struct rtl8192_tx_ring *ring; 1158c2ecf20Sopenharmony_ci struct rtl_tx_desc *pdesc; 1168c2ecf20Sopenharmony_ci unsigned long flags; 1178c2ecf20Sopenharmony_ci u8 idx = 0; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci ring = &rtlpci->tx_ring[TXCMD_QUEUE]; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; 1248c2ecf20Sopenharmony_ci pdesc = &ring->desc[idx]; 1258c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb); 1268c2ecf20Sopenharmony_ci __skb_queue_tail(&ring->queue, skb); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return true; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw, 1348c2ecf20Sopenharmony_ci u8 *code_virtual_address, u32 buffer_len) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 1378c2ecf20Sopenharmony_ci struct sk_buff *skb; 1388c2ecf20Sopenharmony_ci struct rtl_tcb_desc *tcb_desc; 1398c2ecf20Sopenharmony_ci u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE; 1408c2ecf20Sopenharmony_ci u16 frag_length, frag_offset = 0; 1418c2ecf20Sopenharmony_ci u16 extra_descoffset = 0; 1428c2ecf20Sopenharmony_ci u8 last_inipkt = 0; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci _rtl92s_fw_set_rqpn(hw); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) { 1478c2ecf20Sopenharmony_ci pr_err("Size over FIRMWARE_CODE_SIZE!\n"); 1488c2ecf20Sopenharmony_ci return false; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci extra_descoffset = 0; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci do { 1548c2ecf20Sopenharmony_ci if ((buffer_len - frag_offset) > frag_threshold) { 1558c2ecf20Sopenharmony_ci frag_length = frag_threshold + extra_descoffset; 1568c2ecf20Sopenharmony_ci } else { 1578c2ecf20Sopenharmony_ci frag_length = (u16)(buffer_len - frag_offset + 1588c2ecf20Sopenharmony_ci extra_descoffset); 1598c2ecf20Sopenharmony_ci last_inipkt = 1; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Allocate skb buffer to contain firmware */ 1638c2ecf20Sopenharmony_ci /* info and tx descriptor info. */ 1648c2ecf20Sopenharmony_ci skb = dev_alloc_skb(frag_length); 1658c2ecf20Sopenharmony_ci if (!skb) 1668c2ecf20Sopenharmony_ci return false; 1678c2ecf20Sopenharmony_ci skb_reserve(skb, extra_descoffset); 1688c2ecf20Sopenharmony_ci skb_put_data(skb, code_virtual_address + frag_offset, 1698c2ecf20Sopenharmony_ci (u32)(frag_length - extra_descoffset)); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci tcb_desc = (struct rtl_tcb_desc *)(skb->cb); 1728c2ecf20Sopenharmony_ci tcb_desc->queue_index = TXCMD_QUEUE; 1738c2ecf20Sopenharmony_ci tcb_desc->cmd_or_init = DESC_PACKET_TYPE_INIT; 1748c2ecf20Sopenharmony_ci tcb_desc->last_inipkt = last_inipkt; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci _rtl92s_cmd_send_packet(hw, skb, last_inipkt); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci frag_offset += (frag_length - extra_descoffset); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci } while (frag_offset < buffer_len); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return true ; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw, 1888c2ecf20Sopenharmony_ci u8 loadfw_status) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 1918c2ecf20Sopenharmony_ci struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 1928c2ecf20Sopenharmony_ci struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware; 1938c2ecf20Sopenharmony_ci u32 tmpu4b; 1948c2ecf20Sopenharmony_ci u8 cpustatus = 0; 1958c2ecf20Sopenharmony_ci short pollingcnt = 1000; 1968c2ecf20Sopenharmony_ci bool rtstatus = true; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 1998c2ecf20Sopenharmony_ci "LoadStaus(%d)\n", loadfw_status); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci firmware->fwstatus = (enum fw_status)loadfw_status; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci switch (loadfw_status) { 2048c2ecf20Sopenharmony_ci case FW_STATUS_LOAD_IMEM: 2058c2ecf20Sopenharmony_ci /* Polling IMEM code done. */ 2068c2ecf20Sopenharmony_ci do { 2078c2ecf20Sopenharmony_ci cpustatus = rtl_read_byte(rtlpriv, TCR); 2088c2ecf20Sopenharmony_ci if (cpustatus & IMEM_CODE_DONE) 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci udelay(5); 2118c2ecf20Sopenharmony_ci } while (pollingcnt--); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) { 2148c2ecf20Sopenharmony_ci pr_err("FW_STATUS_LOAD_IMEM FAIL CPU, Status=%x\n", 2158c2ecf20Sopenharmony_ci cpustatus); 2168c2ecf20Sopenharmony_ci goto status_check_fail; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci case FW_STATUS_LOAD_EMEM: 2218c2ecf20Sopenharmony_ci /* Check Put Code OK and Turn On CPU */ 2228c2ecf20Sopenharmony_ci /* Polling EMEM code done. */ 2238c2ecf20Sopenharmony_ci do { 2248c2ecf20Sopenharmony_ci cpustatus = rtl_read_byte(rtlpriv, TCR); 2258c2ecf20Sopenharmony_ci if (cpustatus & EMEM_CODE_DONE) 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci udelay(5); 2288c2ecf20Sopenharmony_ci } while (pollingcnt--); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) { 2318c2ecf20Sopenharmony_ci pr_err("FW_STATUS_LOAD_EMEM FAIL CPU, Status=%x\n", 2328c2ecf20Sopenharmony_ci cpustatus); 2338c2ecf20Sopenharmony_ci goto status_check_fail; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Turn On CPU */ 2378c2ecf20Sopenharmony_ci rtstatus = _rtl92s_firmware_enable_cpu(hw); 2388c2ecf20Sopenharmony_ci if (!rtstatus) { 2398c2ecf20Sopenharmony_ci pr_err("Enable CPU fail!\n"); 2408c2ecf20Sopenharmony_ci goto status_check_fail; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci case FW_STATUS_LOAD_DMEM: 2458c2ecf20Sopenharmony_ci /* Polling DMEM code done */ 2468c2ecf20Sopenharmony_ci do { 2478c2ecf20Sopenharmony_ci cpustatus = rtl_read_byte(rtlpriv, TCR); 2488c2ecf20Sopenharmony_ci if (cpustatus & DMEM_CODE_DONE) 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci udelay(5); 2518c2ecf20Sopenharmony_ci } while (pollingcnt--); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) { 2548c2ecf20Sopenharmony_ci pr_err("Polling DMEM code done fail ! cpustatus(%#x)\n", 2558c2ecf20Sopenharmony_ci cpustatus); 2568c2ecf20Sopenharmony_ci goto status_check_fail; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 2608c2ecf20Sopenharmony_ci "DMEM code download success, cpustatus(%#x)\n", 2618c2ecf20Sopenharmony_ci cpustatus); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Prevent Delay too much and being scheduled out */ 2648c2ecf20Sopenharmony_ci /* Polling Load Firmware ready */ 2658c2ecf20Sopenharmony_ci pollingcnt = 2000; 2668c2ecf20Sopenharmony_ci do { 2678c2ecf20Sopenharmony_ci cpustatus = rtl_read_byte(rtlpriv, TCR); 2688c2ecf20Sopenharmony_ci if (cpustatus & FWRDY) 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci udelay(40); 2718c2ecf20Sopenharmony_ci } while (pollingcnt--); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 2748c2ecf20Sopenharmony_ci "Polling Load Firmware ready, cpustatus(%x)\n", 2758c2ecf20Sopenharmony_ci cpustatus); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) || 2788c2ecf20Sopenharmony_ci (pollingcnt <= 0)) { 2798c2ecf20Sopenharmony_ci pr_err("Polling Load Firmware ready fail ! cpustatus(%x)\n", 2808c2ecf20Sopenharmony_ci cpustatus); 2818c2ecf20Sopenharmony_ci goto status_check_fail; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* If right here, we can set TCR/RCR to desired value */ 2858c2ecf20Sopenharmony_ci /* and config MAC lookback mode to normal mode */ 2868c2ecf20Sopenharmony_ci tmpu4b = rtl_read_dword(rtlpriv, TCR); 2878c2ecf20Sopenharmony_ci rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV))); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci tmpu4b = rtl_read_dword(rtlpriv, RCR); 2908c2ecf20Sopenharmony_ci rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS | 2918c2ecf20Sopenharmony_ci RCR_APP_ICV | RCR_APP_MIC)); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 2948c2ecf20Sopenharmony_ci "Current RCR settings(%#x)\n", tmpu4b); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Set to normal mode. */ 2978c2ecf20Sopenharmony_ci rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL); 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci default: 3018c2ecf20Sopenharmony_ci pr_err("Unknown status check!\n"); 3028c2ecf20Sopenharmony_ci rtstatus = false; 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatus_check_fail: 3078c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 3088c2ecf20Sopenharmony_ci "loadfw_status(%d), rtstatus(%x)\n", 3098c2ecf20Sopenharmony_ci loadfw_status, rtstatus); 3108c2ecf20Sopenharmony_ci return rtstatus; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ciint rtl92s_download_fw(struct ieee80211_hw *hw) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 3168c2ecf20Sopenharmony_ci struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 3178c2ecf20Sopenharmony_ci struct rt_firmware *firmware = NULL; 3188c2ecf20Sopenharmony_ci struct fw_hdr *pfwheader; 3198c2ecf20Sopenharmony_ci struct fw_priv *pfw_priv = NULL; 3208c2ecf20Sopenharmony_ci u8 *puc_mappedfile = NULL; 3218c2ecf20Sopenharmony_ci u32 ul_filelength = 0; 3228c2ecf20Sopenharmony_ci u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE; 3238c2ecf20Sopenharmony_ci u8 fwstatus = FW_STATUS_INIT; 3248c2ecf20Sopenharmony_ci bool rtstatus = true; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware) 3278c2ecf20Sopenharmony_ci return 1; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci firmware = (struct rt_firmware *)rtlhal->pfirmware; 3308c2ecf20Sopenharmony_ci firmware->fwstatus = FW_STATUS_INIT; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci puc_mappedfile = firmware->sz_fw_tmpbuffer; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* 1. Retrieve FW header. */ 3358c2ecf20Sopenharmony_ci firmware->pfwheader = (struct fw_hdr *) puc_mappedfile; 3368c2ecf20Sopenharmony_ci pfwheader = firmware->pfwheader; 3378c2ecf20Sopenharmony_ci firmware->firmwareversion = byte(pfwheader->version, 0); 3388c2ecf20Sopenharmony_ci firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */ 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, 3418c2ecf20Sopenharmony_ci "signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", 3428c2ecf20Sopenharmony_ci pfwheader->signature, 3438c2ecf20Sopenharmony_ci pfwheader->version, pfwheader->dmem_size, 3448c2ecf20Sopenharmony_ci pfwheader->img_imem_size, pfwheader->img_sram_size); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* 2. Retrieve IMEM image. */ 3478c2ecf20Sopenharmony_ci if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size > 3488c2ecf20Sopenharmony_ci sizeof(firmware->fw_imem))) { 3498c2ecf20Sopenharmony_ci pr_err("memory for data image is less than IMEM required\n"); 3508c2ecf20Sopenharmony_ci goto fail; 3518c2ecf20Sopenharmony_ci } else { 3528c2ecf20Sopenharmony_ci puc_mappedfile += fwhdr_size; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci memcpy(firmware->fw_imem, puc_mappedfile, 3558c2ecf20Sopenharmony_ci pfwheader->img_imem_size); 3568c2ecf20Sopenharmony_ci firmware->fw_imem_len = pfwheader->img_imem_size; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* 3. Retriecve EMEM image. */ 3608c2ecf20Sopenharmony_ci if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) { 3618c2ecf20Sopenharmony_ci pr_err("memory for data image is less than EMEM required\n"); 3628c2ecf20Sopenharmony_ci goto fail; 3638c2ecf20Sopenharmony_ci } else { 3648c2ecf20Sopenharmony_ci puc_mappedfile += firmware->fw_imem_len; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci memcpy(firmware->fw_emem, puc_mappedfile, 3678c2ecf20Sopenharmony_ci pfwheader->img_sram_size); 3688c2ecf20Sopenharmony_ci firmware->fw_emem_len = pfwheader->img_sram_size; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* 4. download fw now */ 3728c2ecf20Sopenharmony_ci fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus); 3738c2ecf20Sopenharmony_ci while (fwstatus != FW_STATUS_READY) { 3748c2ecf20Sopenharmony_ci /* Image buffer redirection. */ 3758c2ecf20Sopenharmony_ci switch (fwstatus) { 3768c2ecf20Sopenharmony_ci case FW_STATUS_LOAD_IMEM: 3778c2ecf20Sopenharmony_ci puc_mappedfile = firmware->fw_imem; 3788c2ecf20Sopenharmony_ci ul_filelength = firmware->fw_imem_len; 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci case FW_STATUS_LOAD_EMEM: 3818c2ecf20Sopenharmony_ci puc_mappedfile = firmware->fw_emem; 3828c2ecf20Sopenharmony_ci ul_filelength = firmware->fw_emem_len; 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci case FW_STATUS_LOAD_DMEM: 3858c2ecf20Sopenharmony_ci /* Partial update the content of header private. */ 3868c2ecf20Sopenharmony_ci pfwheader = firmware->pfwheader; 3878c2ecf20Sopenharmony_ci pfw_priv = &pfwheader->fwpriv; 3888c2ecf20Sopenharmony_ci _rtl92s_firmwareheader_priveupdate(hw, pfw_priv); 3898c2ecf20Sopenharmony_ci puc_mappedfile = (u8 *)(firmware->pfwheader) + 3908c2ecf20Sopenharmony_ci RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; 3918c2ecf20Sopenharmony_ci ul_filelength = fwhdr_size - 3928c2ecf20Sopenharmony_ci RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci default: 3958c2ecf20Sopenharmony_ci pr_err("Unexpected Download step!!\n"); 3968c2ecf20Sopenharmony_ci goto fail; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* <2> Download image file */ 4008c2ecf20Sopenharmony_ci rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile, 4018c2ecf20Sopenharmony_ci ul_filelength); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (!rtstatus) { 4048c2ecf20Sopenharmony_ci pr_err("fail!\n"); 4058c2ecf20Sopenharmony_ci goto fail; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* <3> Check whether load FW process is ready */ 4098c2ecf20Sopenharmony_ci rtstatus = _rtl92s_firmware_checkready(hw, fwstatus); 4108c2ecf20Sopenharmony_ci if (!rtstatus) { 4118c2ecf20Sopenharmony_ci pr_err("rtl8192se: firmware fail!\n"); 4128c2ecf20Sopenharmony_ci goto fail; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return rtstatus; 4198c2ecf20Sopenharmony_cifail: 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, 4248c2ecf20Sopenharmony_ci u32 cmd_num, u32 *pelement_id, u32 *pcmd_len, 4258c2ecf20Sopenharmony_ci u8 **pcmb_buffer, u8 *cmd_start_seq) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci u32 totallen = 0, len = 0, tx_desclen = 0; 4288c2ecf20Sopenharmony_ci u32 pre_continueoffset = 0; 4298c2ecf20Sopenharmony_ci u8 *ph2c_buffer; 4308c2ecf20Sopenharmony_ci u8 i = 0; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci do { 4338c2ecf20Sopenharmony_ci /* 8 - Byte alignment */ 4348c2ecf20Sopenharmony_ci len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Buffer length is not enough */ 4378c2ecf20Sopenharmony_ci if (h2cbufferlen < totallen + len + tx_desclen) 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Clear content */ 4418c2ecf20Sopenharmony_ci ph2c_buffer = skb_put(skb, (u32)len); 4428c2ecf20Sopenharmony_ci memset((ph2c_buffer + totallen + tx_desclen), 0, len); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* CMD len */ 4458c2ecf20Sopenharmony_ci le32p_replace_bits((__le32 *)(ph2c_buffer + totallen + 4468c2ecf20Sopenharmony_ci tx_desclen), pcmd_len[i], 4478c2ecf20Sopenharmony_ci GENMASK(15, 0)); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* CMD ID */ 4508c2ecf20Sopenharmony_ci le32p_replace_bits((__le32 *)(ph2c_buffer + totallen + 4518c2ecf20Sopenharmony_ci tx_desclen), pelement_id[i], 4528c2ecf20Sopenharmony_ci GENMASK(23, 16)); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* CMD Sequence */ 4558c2ecf20Sopenharmony_ci *cmd_start_seq = *cmd_start_seq % 0x80; 4568c2ecf20Sopenharmony_ci le32p_replace_bits((__le32 *)(ph2c_buffer + totallen + 4578c2ecf20Sopenharmony_ci tx_desclen), *cmd_start_seq, 4588c2ecf20Sopenharmony_ci GENMASK(30, 24)); 4598c2ecf20Sopenharmony_ci ++*cmd_start_seq; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Copy memory */ 4628c2ecf20Sopenharmony_ci memcpy((ph2c_buffer + totallen + tx_desclen + 4638c2ecf20Sopenharmony_ci H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* CMD continue */ 4668c2ecf20Sopenharmony_ci /* set the continue in prevoius cmd. */ 4678c2ecf20Sopenharmony_ci if (i < cmd_num - 1) 4688c2ecf20Sopenharmony_ci le32p_replace_bits((__le32 *)(ph2c_buffer + 4698c2ecf20Sopenharmony_ci pre_continueoffset), 4708c2ecf20Sopenharmony_ci 1, BIT(31)); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci pre_continueoffset = totallen; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci totallen += len; 4758c2ecf20Sopenharmony_ci } while (++i < cmd_num); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci return totallen; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci u32 totallen = 0, len = 0, tx_desclen = 0; 4838c2ecf20Sopenharmony_ci u8 i = 0; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci do { 4868c2ecf20Sopenharmony_ci /* 8 - Byte alignment */ 4878c2ecf20Sopenharmony_ci len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* Buffer length is not enough */ 4908c2ecf20Sopenharmony_ci if (h2cbufferlen < totallen + len + tx_desclen) 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci totallen += len; 4948c2ecf20Sopenharmony_ci } while (++i < cmd_num); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci return totallen + tx_desclen; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd, 5008c2ecf20Sopenharmony_ci u8 *pcmd_buffer) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 5038c2ecf20Sopenharmony_ci struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 5048c2ecf20Sopenharmony_ci struct rtl_tcb_desc *cb_desc; 5058c2ecf20Sopenharmony_ci struct sk_buff *skb; 5068c2ecf20Sopenharmony_ci u32 element_id = 0; 5078c2ecf20Sopenharmony_ci u32 cmd_len = 0; 5088c2ecf20Sopenharmony_ci u32 len; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci switch (h2c_cmd) { 5118c2ecf20Sopenharmony_ci case FW_H2C_SETPWRMODE: 5128c2ecf20Sopenharmony_ci element_id = H2C_SETPWRMODE_CMD ; 5138c2ecf20Sopenharmony_ci cmd_len = sizeof(struct h2c_set_pwrmode_parm); 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci case FW_H2C_JOINBSSRPT: 5168c2ecf20Sopenharmony_ci element_id = H2C_JOINBSSRPT_CMD; 5178c2ecf20Sopenharmony_ci cmd_len = sizeof(struct h2c_joinbss_rpt_parm); 5188c2ecf20Sopenharmony_ci break; 5198c2ecf20Sopenharmony_ci case FW_H2C_WOWLAN_UPDATE_GTK: 5208c2ecf20Sopenharmony_ci element_id = H2C_WOWLAN_UPDATE_GTK_CMD; 5218c2ecf20Sopenharmony_ci cmd_len = sizeof(struct h2c_wpa_two_way_parm); 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci case FW_H2C_WOWLAN_UPDATE_IV: 5248c2ecf20Sopenharmony_ci element_id = H2C_WOWLAN_UPDATE_IV_CMD; 5258c2ecf20Sopenharmony_ci cmd_len = sizeof(unsigned long long); 5268c2ecf20Sopenharmony_ci break; 5278c2ecf20Sopenharmony_ci case FW_H2C_WOWLAN_OFFLOAD: 5288c2ecf20Sopenharmony_ci element_id = H2C_WOWLAN_FW_OFFLOAD; 5298c2ecf20Sopenharmony_ci cmd_len = sizeof(u8); 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci default: 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len); 5368c2ecf20Sopenharmony_ci skb = dev_alloc_skb(len); 5378c2ecf20Sopenharmony_ci if (!skb) 5388c2ecf20Sopenharmony_ci return false; 5398c2ecf20Sopenharmony_ci cb_desc = (struct rtl_tcb_desc *)(skb->cb); 5408c2ecf20Sopenharmony_ci cb_desc->queue_index = TXCMD_QUEUE; 5418c2ecf20Sopenharmony_ci cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL; 5428c2ecf20Sopenharmony_ci cb_desc->last_inipkt = false; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci _rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id, 5458c2ecf20Sopenharmony_ci &cmd_len, &pcmd_buffer, &rtlhal->h2c_txcmd_seq); 5468c2ecf20Sopenharmony_ci _rtl92s_cmd_send_packet(hw, skb, false); 5478c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return true; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_civoid rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 5558c2ecf20Sopenharmony_ci struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 5568c2ecf20Sopenharmony_ci struct h2c_set_pwrmode_parm pwrmode; 5578c2ecf20Sopenharmony_ci u16 max_wakeup_period = 0; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci pwrmode.mode = mode; 5608c2ecf20Sopenharmony_ci pwrmode.flag_low_traffic_en = 0; 5618c2ecf20Sopenharmony_ci pwrmode.flag_lpnav_en = 0; 5628c2ecf20Sopenharmony_ci pwrmode.flag_rf_low_snr_en = 0; 5638c2ecf20Sopenharmony_ci pwrmode.flag_dps_en = 0; 5648c2ecf20Sopenharmony_ci pwrmode.bcn_rx_en = 0; 5658c2ecf20Sopenharmony_ci pwrmode.bcn_to = 0; 5668c2ecf20Sopenharmony_ci le16p_replace_bits((__le16 *)(((u8 *)(&pwrmode) + 8)), 5678c2ecf20Sopenharmony_ci mac->vif->bss_conf.beacon_int, GENMASK(15, 0)); 5688c2ecf20Sopenharmony_ci pwrmode.app_itv = 0; 5698c2ecf20Sopenharmony_ci pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl; 5708c2ecf20Sopenharmony_ci pwrmode.smart_ps = 1; 5718c2ecf20Sopenharmony_ci pwrmode.bcn_pass_period = 10; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* Set beacon pass count */ 5748c2ecf20Sopenharmony_ci if (pwrmode.mode == FW_PS_MIN_MODE) 5758c2ecf20Sopenharmony_ci max_wakeup_period = mac->vif->bss_conf.beacon_int; 5768c2ecf20Sopenharmony_ci else if (pwrmode.mode == FW_PS_MAX_MODE) 5778c2ecf20Sopenharmony_ci max_wakeup_period = mac->vif->bss_conf.beacon_int * 5788c2ecf20Sopenharmony_ci mac->vif->bss_conf.dtim_period; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (max_wakeup_period >= 500) 5818c2ecf20Sopenharmony_ci pwrmode.bcn_pass_cnt = 1; 5828c2ecf20Sopenharmony_ci else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500)) 5838c2ecf20Sopenharmony_ci pwrmode.bcn_pass_cnt = 2; 5848c2ecf20Sopenharmony_ci else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300)) 5858c2ecf20Sopenharmony_ci pwrmode.bcn_pass_cnt = 3; 5868c2ecf20Sopenharmony_ci else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200)) 5878c2ecf20Sopenharmony_ci pwrmode.bcn_pass_cnt = 5; 5888c2ecf20Sopenharmony_ci else 5898c2ecf20Sopenharmony_ci pwrmode.bcn_pass_cnt = 1; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_civoid rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, 5968c2ecf20Sopenharmony_ci u8 mstatus, u8 ps_qosinfo) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 5998c2ecf20Sopenharmony_ci struct h2c_joinbss_rpt_parm joinbss_rpt; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci joinbss_rpt.opmode = mstatus; 6028c2ecf20Sopenharmony_ci joinbss_rpt.ps_qos_info = ps_qosinfo; 6038c2ecf20Sopenharmony_ci joinbss_rpt.bssid[0] = mac->bssid[0]; 6048c2ecf20Sopenharmony_ci joinbss_rpt.bssid[1] = mac->bssid[1]; 6058c2ecf20Sopenharmony_ci joinbss_rpt.bssid[2] = mac->bssid[2]; 6068c2ecf20Sopenharmony_ci joinbss_rpt.bssid[3] = mac->bssid[3]; 6078c2ecf20Sopenharmony_ci joinbss_rpt.bssid[4] = mac->bssid[4]; 6088c2ecf20Sopenharmony_ci joinbss_rpt.bssid[5] = mac->bssid[5]; 6098c2ecf20Sopenharmony_ci le16p_replace_bits((__le16 *)(((u8 *)(&joinbss_rpt) + 8)), 6108c2ecf20Sopenharmony_ci mac->vif->bss_conf.beacon_int, GENMASK(15, 0)); 6118c2ecf20Sopenharmony_ci le16p_replace_bits((__le16 *)(((u8 *)(&joinbss_rpt) + 10)), 6128c2ecf20Sopenharmony_ci mac->assoc_id, GENMASK(15, 0)); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 617