18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2014 Redpine Signals Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 118c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 148c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/firmware.h> 188c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 198c2ecf20Sopenharmony_ci#include "rsi_mgmt.h" 208c2ecf20Sopenharmony_ci#include "rsi_hal.h" 218c2ecf20Sopenharmony_ci#include "rsi_sdio.h" 228c2ecf20Sopenharmony_ci#include "rsi_common.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* FLASH Firmware */ 258c2ecf20Sopenharmony_cistatic struct ta_metadata metadata_flash_content[] = { 268c2ecf20Sopenharmony_ci {"flash_content", 0x00010000}, 278c2ecf20Sopenharmony_ci {"rsi/rs9113_wlan_qspi.rps", 0x00010000}, 288c2ecf20Sopenharmony_ci {"rsi/rs9113_wlan_bt_dual_mode.rps", 0x00010000}, 298c2ecf20Sopenharmony_ci {"flash_content", 0x00010000}, 308c2ecf20Sopenharmony_ci {"rsi/rs9113_ap_bt_dual_mode.rps", 0x00010000}, 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic struct ta_metadata metadata[] = {{"pmemdata_dummy", 0x00000000}, 358c2ecf20Sopenharmony_ci {"rsi/rs9116_wlan.rps", 0x00000000}, 368c2ecf20Sopenharmony_ci {"rsi/rs9116_wlan_bt_classic.rps", 0x00000000}, 378c2ecf20Sopenharmony_ci {"rsi/pmemdata_dummy", 0x00000000}, 388c2ecf20Sopenharmony_ci {"rsi/rs9116_wlan_bt_classic.rps", 0x00000000} 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciint rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct rsi_hw *adapter = common->priv; 448c2ecf20Sopenharmony_ci int status; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (common->coex_mode > 1) 478c2ecf20Sopenharmony_ci mutex_lock(&common->tx_bus_mutex); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci status = adapter->host_intf_ops->write_pkt(common->priv, 508c2ecf20Sopenharmony_ci skb->data, skb->len); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (common->coex_mode > 1) 538c2ecf20Sopenharmony_ci mutex_unlock(&common->tx_bus_mutex); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return status; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciint rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct rsi_hw *adapter = common->priv; 618c2ecf20Sopenharmony_ci struct ieee80211_hdr *wh = NULL; 628c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 638c2ecf20Sopenharmony_ci struct ieee80211_conf *conf = &adapter->hw->conf; 648c2ecf20Sopenharmony_ci struct ieee80211_vif *vif; 658c2ecf20Sopenharmony_ci struct rsi_mgmt_desc *mgmt_desc; 668c2ecf20Sopenharmony_ci struct skb_info *tx_params; 678c2ecf20Sopenharmony_ci struct rsi_xtended_desc *xtend_desc = NULL; 688c2ecf20Sopenharmony_ci u8 header_size; 698c2ecf20Sopenharmony_ci u32 dword_align_bytes = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (skb->len > MAX_MGMT_PKT_SIZE) { 728c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__); 738c2ecf20Sopenharmony_ci return -EINVAL; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 778c2ecf20Sopenharmony_ci tx_params = (struct skb_info *)info->driver_data; 788c2ecf20Sopenharmony_ci vif = tx_params->vif; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* Update header size */ 818c2ecf20Sopenharmony_ci header_size = FRAME_DESC_SZ + sizeof(struct rsi_xtended_desc); 828c2ecf20Sopenharmony_ci if (header_size > skb_headroom(skb)) { 838c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 848c2ecf20Sopenharmony_ci "%s: Failed to add extended descriptor\n", 858c2ecf20Sopenharmony_ci __func__); 868c2ecf20Sopenharmony_ci return -ENOSPC; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci skb_push(skb, header_size); 898c2ecf20Sopenharmony_ci dword_align_bytes = ((unsigned long)skb->data & 0x3f); 908c2ecf20Sopenharmony_ci if (dword_align_bytes > skb_headroom(skb)) { 918c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 928c2ecf20Sopenharmony_ci "%s: Failed to add dword align\n", __func__); 938c2ecf20Sopenharmony_ci return -ENOSPC; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci skb_push(skb, dword_align_bytes); 968c2ecf20Sopenharmony_ci header_size += dword_align_bytes; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci tx_params->internal_hdr_size = header_size; 998c2ecf20Sopenharmony_ci memset(&skb->data[0], 0, header_size); 1008c2ecf20Sopenharmony_ci wh = (struct ieee80211_hdr *)&skb->data[header_size]; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci mgmt_desc = (struct rsi_mgmt_desc *)skb->data; 1038c2ecf20Sopenharmony_ci xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ]; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci rsi_set_len_qno(&mgmt_desc->len_qno, (skb->len - FRAME_DESC_SZ), 1068c2ecf20Sopenharmony_ci RSI_WIFI_MGMT_Q); 1078c2ecf20Sopenharmony_ci mgmt_desc->frame_type = TX_DOT11_MGMT; 1088c2ecf20Sopenharmony_ci mgmt_desc->header_len = MIN_802_11_HDR_LEN; 1098c2ecf20Sopenharmony_ci mgmt_desc->xtend_desc_size = header_size - FRAME_DESC_SZ; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (ieee80211_is_probe_req(wh->frame_control)) 1128c2ecf20Sopenharmony_ci mgmt_desc->frame_info = cpu_to_le16(RSI_INSERT_SEQ_IN_FW); 1138c2ecf20Sopenharmony_ci mgmt_desc->frame_info |= cpu_to_le16(RATE_INFO_ENABLE); 1148c2ecf20Sopenharmony_ci if (is_broadcast_ether_addr(wh->addr1)) 1158c2ecf20Sopenharmony_ci mgmt_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci mgmt_desc->seq_ctrl = 1188c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl))); 1198c2ecf20Sopenharmony_ci if ((common->band == NL80211_BAND_2GHZ) && !common->p2p_enabled) 1208c2ecf20Sopenharmony_ci mgmt_desc->rate_info = cpu_to_le16(RSI_RATE_1); 1218c2ecf20Sopenharmony_ci else 1228c2ecf20Sopenharmony_ci mgmt_desc->rate_info = cpu_to_le16(RSI_RATE_6); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (conf_is_ht40(conf)) 1258c2ecf20Sopenharmony_ci mgmt_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (ieee80211_is_probe_resp(wh->frame_control)) { 1288c2ecf20Sopenharmony_ci mgmt_desc->misc_flags |= (RSI_ADD_DELTA_TSF_VAP_ID | 1298c2ecf20Sopenharmony_ci RSI_FETCH_RETRY_CNT_FRM_HST); 1308c2ecf20Sopenharmony_ci#define PROBE_RESP_RETRY_CNT 3 1318c2ecf20Sopenharmony_ci xtend_desc->retry_cnt = PROBE_RESP_RETRY_CNT; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (((vif->type == NL80211_IFTYPE_AP) || 1358c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) && 1368c2ecf20Sopenharmony_ci (ieee80211_is_action(wh->frame_control))) { 1378c2ecf20Sopenharmony_ci struct rsi_sta *rsta = rsi_find_sta(common, wh->addr1); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (rsta) 1408c2ecf20Sopenharmony_ci mgmt_desc->sta_id = tx_params->sta_id; 1418c2ecf20Sopenharmony_ci else 1428c2ecf20Sopenharmony_ci return -EINVAL; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci mgmt_desc->rate_info |= 1458c2ecf20Sopenharmony_ci cpu_to_le16((tx_params->vap_id << RSI_DESC_VAP_ID_OFST) & 1468c2ecf20Sopenharmony_ci RSI_DESC_VAP_ID_MASK); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* This function prepares descriptor for given data packet */ 1528c2ecf20Sopenharmony_ciint rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct rsi_hw *adapter = common->priv; 1558c2ecf20Sopenharmony_ci struct ieee80211_vif *vif; 1568c2ecf20Sopenharmony_ci struct ieee80211_hdr *wh = NULL; 1578c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 1588c2ecf20Sopenharmony_ci struct skb_info *tx_params; 1598c2ecf20Sopenharmony_ci struct rsi_data_desc *data_desc; 1608c2ecf20Sopenharmony_ci struct rsi_xtended_desc *xtend_desc; 1618c2ecf20Sopenharmony_ci u8 ieee80211_size = MIN_802_11_HDR_LEN; 1628c2ecf20Sopenharmony_ci u8 header_size; 1638c2ecf20Sopenharmony_ci u8 vap_id = 0; 1648c2ecf20Sopenharmony_ci u8 dword_align_bytes; 1658c2ecf20Sopenharmony_ci bool tx_eapol; 1668c2ecf20Sopenharmony_ci u16 seq_num; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 1698c2ecf20Sopenharmony_ci vif = info->control.vif; 1708c2ecf20Sopenharmony_ci tx_params = (struct skb_info *)info->driver_data; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci tx_eapol = IEEE80211_SKB_CB(skb)->control.flags & 1738c2ecf20Sopenharmony_ci IEEE80211_TX_CTRL_PORT_CTRL_PROTO; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci header_size = FRAME_DESC_SZ + sizeof(struct rsi_xtended_desc); 1768c2ecf20Sopenharmony_ci if (header_size > skb_headroom(skb)) { 1778c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); 1788c2ecf20Sopenharmony_ci return -ENOSPC; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci skb_push(skb, header_size); 1818c2ecf20Sopenharmony_ci dword_align_bytes = ((unsigned long)skb->data & 0x3f); 1828c2ecf20Sopenharmony_ci if (header_size > skb_headroom(skb)) { 1838c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__); 1848c2ecf20Sopenharmony_ci return -ENOSPC; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci skb_push(skb, dword_align_bytes); 1878c2ecf20Sopenharmony_ci header_size += dword_align_bytes; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci tx_params->internal_hdr_size = header_size; 1908c2ecf20Sopenharmony_ci data_desc = (struct rsi_data_desc *)skb->data; 1918c2ecf20Sopenharmony_ci memset(data_desc, 0, header_size); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ]; 1948c2ecf20Sopenharmony_ci wh = (struct ieee80211_hdr *)&skb->data[header_size]; 1958c2ecf20Sopenharmony_ci seq_num = IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl)); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci data_desc->xtend_desc_size = header_size - FRAME_DESC_SZ; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(wh->frame_control)) { 2008c2ecf20Sopenharmony_ci ieee80211_size += 2; 2018c2ecf20Sopenharmony_ci data_desc->mac_flags |= cpu_to_le16(RSI_QOS_ENABLE); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (((vif->type == NL80211_IFTYPE_STATION) || 2058c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && 2068c2ecf20Sopenharmony_ci (adapter->ps_state == PS_ENABLED)) 2078c2ecf20Sopenharmony_ci wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) && 2108c2ecf20Sopenharmony_ci tx_params->have_key) { 2118c2ecf20Sopenharmony_ci if (rsi_is_cipher_wep(common)) 2128c2ecf20Sopenharmony_ci ieee80211_size += 4; 2138c2ecf20Sopenharmony_ci else 2148c2ecf20Sopenharmony_ci ieee80211_size += 8; 2158c2ecf20Sopenharmony_ci data_desc->mac_flags |= cpu_to_le16(RSI_ENCRYPT_PKT); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci rsi_set_len_qno(&data_desc->len_qno, (skb->len - FRAME_DESC_SZ), 2188c2ecf20Sopenharmony_ci RSI_WIFI_DATA_Q); 2198c2ecf20Sopenharmony_ci data_desc->header_len = ieee80211_size; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (common->rate_config[common->band].fixed_enabled) { 2228c2ecf20Sopenharmony_ci /* Send fixed rate */ 2238c2ecf20Sopenharmony_ci u16 fixed_rate = common->rate_config[common->band].fixed_hw_rate; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE); 2268c2ecf20Sopenharmony_ci data_desc->rate_info = cpu_to_le16(fixed_rate); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (conf_is_ht40(&common->priv->hw->conf)) 2298c2ecf20Sopenharmony_ci data_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (common->vif_info[0].sgi && (fixed_rate & 0x100)) { 2328c2ecf20Sopenharmony_ci /* Only MCS rates */ 2338c2ecf20Sopenharmony_ci data_desc->rate_info |= 2348c2ecf20Sopenharmony_ci cpu_to_le16(ENABLE_SHORTGI_RATE); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (tx_eapol) { 2398c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "*** Tx EAPOL ***\n"); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE); 2428c2ecf20Sopenharmony_ci if (common->band == NL80211_BAND_5GHZ) 2438c2ecf20Sopenharmony_ci data_desc->rate_info = cpu_to_le16(RSI_RATE_6); 2448c2ecf20Sopenharmony_ci else 2458c2ecf20Sopenharmony_ci data_desc->rate_info = cpu_to_le16(RSI_RATE_1); 2468c2ecf20Sopenharmony_ci data_desc->mac_flags |= cpu_to_le16(RSI_REKEY_PURPOSE); 2478c2ecf20Sopenharmony_ci data_desc->misc_flags |= RSI_FETCH_RETRY_CNT_FRM_HST; 2488c2ecf20Sopenharmony_ci#define EAPOL_RETRY_CNT 15 2498c2ecf20Sopenharmony_ci xtend_desc->retry_cnt = EAPOL_RETRY_CNT; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (common->eapol4_confirm) 2528c2ecf20Sopenharmony_ci skb->priority = VO_Q; 2538c2ecf20Sopenharmony_ci else 2548c2ecf20Sopenharmony_ci rsi_set_len_qno(&data_desc->len_qno, 2558c2ecf20Sopenharmony_ci (skb->len - FRAME_DESC_SZ), 2568c2ecf20Sopenharmony_ci RSI_WIFI_MGMT_Q); 2578c2ecf20Sopenharmony_ci if (((skb->len - header_size) == EAPOL4_PACKET_LEN) || 2588c2ecf20Sopenharmony_ci ((skb->len - header_size) == EAPOL4_PACKET_LEN - 2)) { 2598c2ecf20Sopenharmony_ci data_desc->misc_flags |= 2608c2ecf20Sopenharmony_ci RSI_DESC_REQUIRE_CFM_TO_HOST; 2618c2ecf20Sopenharmony_ci xtend_desc->confirm_frame_type = EAPOL4_CONFIRM; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci data_desc->mac_flags |= cpu_to_le16(seq_num & 0xfff); 2668c2ecf20Sopenharmony_ci data_desc->qid_tid = ((skb->priority & 0xf) | 2678c2ecf20Sopenharmony_ci ((tx_params->tid & 0xf) << 4)); 2688c2ecf20Sopenharmony_ci data_desc->sta_id = tx_params->sta_id; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if ((is_broadcast_ether_addr(wh->addr1)) || 2718c2ecf20Sopenharmony_ci (is_multicast_ether_addr(wh->addr1))) { 2728c2ecf20Sopenharmony_ci data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE); 2738c2ecf20Sopenharmony_ci data_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT); 2748c2ecf20Sopenharmony_ci data_desc->sta_id = vap_id; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 2778c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 2788c2ecf20Sopenharmony_ci if (common->band == NL80211_BAND_5GHZ) 2798c2ecf20Sopenharmony_ci data_desc->rate_info = cpu_to_le16(RSI_RATE_6); 2808c2ecf20Sopenharmony_ci else 2818c2ecf20Sopenharmony_ci data_desc->rate_info = cpu_to_le16(RSI_RATE_1); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci if (((vif->type == NL80211_IFTYPE_AP) || 2858c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) && 2868c2ecf20Sopenharmony_ci (ieee80211_has_moredata(wh->frame_control))) 2878c2ecf20Sopenharmony_ci data_desc->frame_info |= cpu_to_le16(MORE_DATA_PRESENT); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci data_desc->rate_info |= 2908c2ecf20Sopenharmony_ci cpu_to_le16((tx_params->vap_id << RSI_DESC_VAP_ID_OFST) & 2918c2ecf20Sopenharmony_ci RSI_DESC_VAP_ID_MASK); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return 0; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/* This function sends received data packet from driver to device */ 2978c2ecf20Sopenharmony_ciint rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct rsi_hw *adapter = common->priv; 3008c2ecf20Sopenharmony_ci struct ieee80211_vif *vif; 3018c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 3028c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss; 3038c2ecf20Sopenharmony_ci int status = -EINVAL; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (!skb) 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci if (common->iface_down) 3088c2ecf20Sopenharmony_ci goto err; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 3118c2ecf20Sopenharmony_ci if (!info->control.vif) 3128c2ecf20Sopenharmony_ci goto err; 3138c2ecf20Sopenharmony_ci vif = info->control.vif; 3148c2ecf20Sopenharmony_ci bss = &vif->bss_conf; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (((vif->type == NL80211_IFTYPE_STATION) || 3178c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && 3188c2ecf20Sopenharmony_ci (!bss->assoc)) 3198c2ecf20Sopenharmony_ci goto err; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci status = rsi_send_pkt_to_bus(common, skb); 3228c2ecf20Sopenharmony_ci if (status) 3238c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cierr: 3268c2ecf20Sopenharmony_ci ++common->tx_stats.total_tx_pkt_freed[skb->priority]; 3278c2ecf20Sopenharmony_ci rsi_indicate_tx_status(adapter, skb, status); 3288c2ecf20Sopenharmony_ci return status; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/** 3328c2ecf20Sopenharmony_ci * rsi_send_mgmt_pkt() - This functions sends the received management packet 3338c2ecf20Sopenharmony_ci * from driver to device. 3348c2ecf20Sopenharmony_ci * @common: Pointer to the driver private structure. 3358c2ecf20Sopenharmony_ci * @skb: Pointer to the socket buffer structure. 3368c2ecf20Sopenharmony_ci * 3378c2ecf20Sopenharmony_ci * Return: status: 0 on success, -1 on failure. 3388c2ecf20Sopenharmony_ci */ 3398c2ecf20Sopenharmony_ciint rsi_send_mgmt_pkt(struct rsi_common *common, 3408c2ecf20Sopenharmony_ci struct sk_buff *skb) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct rsi_hw *adapter = common->priv; 3438c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss; 3448c2ecf20Sopenharmony_ci struct ieee80211_hdr *wh; 3458c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 3468c2ecf20Sopenharmony_ci struct skb_info *tx_params; 3478c2ecf20Sopenharmony_ci struct rsi_mgmt_desc *mgmt_desc; 3488c2ecf20Sopenharmony_ci struct rsi_xtended_desc *xtend_desc; 3498c2ecf20Sopenharmony_ci int status = -E2BIG; 3508c2ecf20Sopenharmony_ci u8 header_size; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 3538c2ecf20Sopenharmony_ci tx_params = (struct skb_info *)info->driver_data; 3548c2ecf20Sopenharmony_ci header_size = tx_params->internal_hdr_size; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (tx_params->flags & INTERNAL_MGMT_PKT) { 3578c2ecf20Sopenharmony_ci status = adapter->host_intf_ops->write_pkt(common->priv, 3588c2ecf20Sopenharmony_ci (u8 *)skb->data, 3598c2ecf20Sopenharmony_ci skb->len); 3608c2ecf20Sopenharmony_ci if (status) { 3618c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 3628c2ecf20Sopenharmony_ci "%s: Failed to write the packet\n", __func__); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 3658c2ecf20Sopenharmony_ci return status; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci bss = &info->control.vif->bss_conf; 3698c2ecf20Sopenharmony_ci wh = (struct ieee80211_hdr *)&skb->data[header_size]; 3708c2ecf20Sopenharmony_ci mgmt_desc = (struct rsi_mgmt_desc *)skb->data; 3718c2ecf20Sopenharmony_ci xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ]; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* Indicate to firmware to give cfm for probe */ 3748c2ecf20Sopenharmony_ci if (ieee80211_is_probe_req(wh->frame_control) && !bss->assoc) { 3758c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 3768c2ecf20Sopenharmony_ci "%s: blocking mgmt queue\n", __func__); 3778c2ecf20Sopenharmony_ci mgmt_desc->misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST; 3788c2ecf20Sopenharmony_ci xtend_desc->confirm_frame_type = PROBEREQ_CONFIRM; 3798c2ecf20Sopenharmony_ci common->mgmt_q_block = true; 3808c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Mgmt queue blocked\n"); 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci status = rsi_send_pkt_to_bus(common, skb); 3848c2ecf20Sopenharmony_ci if (status) 3858c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci rsi_indicate_tx_status(common->priv, skb, status); 3888c2ecf20Sopenharmony_ci return status; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ciint rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci int status = -EINVAL; 3948c2ecf20Sopenharmony_ci u8 header_size = 0; 3958c2ecf20Sopenharmony_ci struct rsi_bt_desc *bt_desc; 3968c2ecf20Sopenharmony_ci u8 queueno = ((skb->data[1] >> 4) & 0xf); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (queueno == RSI_BT_MGMT_Q) { 3998c2ecf20Sopenharmony_ci status = rsi_send_pkt_to_bus(common, skb); 4008c2ecf20Sopenharmony_ci if (status) 4018c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Failed to write bt mgmt pkt\n", 4028c2ecf20Sopenharmony_ci __func__); 4038c2ecf20Sopenharmony_ci goto out; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci header_size = FRAME_DESC_SZ; 4068c2ecf20Sopenharmony_ci if (header_size > skb_headroom(skb)) { 4078c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__); 4088c2ecf20Sopenharmony_ci status = -ENOSPC; 4098c2ecf20Sopenharmony_ci goto out; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci skb_push(skb, header_size); 4128c2ecf20Sopenharmony_ci memset(skb->data, 0, header_size); 4138c2ecf20Sopenharmony_ci bt_desc = (struct rsi_bt_desc *)skb->data; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci rsi_set_len_qno(&bt_desc->len_qno, (skb->len - FRAME_DESC_SZ), 4168c2ecf20Sopenharmony_ci RSI_BT_DATA_Q); 4178c2ecf20Sopenharmony_ci bt_desc->bt_pkt_type = cpu_to_le16(bt_cb(skb)->pkt_type); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci status = rsi_send_pkt_to_bus(common, skb); 4208c2ecf20Sopenharmony_ci if (status) 4218c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Failed to write bt pkt\n", __func__); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ciout: 4248c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 4258c2ecf20Sopenharmony_ci return status; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ciint rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci struct rsi_hw *adapter = (struct rsi_hw *)common->priv; 4318c2ecf20Sopenharmony_ci struct rsi_data_desc *bcn_frm; 4328c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = common->priv->hw; 4338c2ecf20Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 4348c2ecf20Sopenharmony_ci struct ieee80211_vif *vif; 4358c2ecf20Sopenharmony_ci struct sk_buff *mac_bcn; 4368c2ecf20Sopenharmony_ci u8 vap_id = 0, i; 4378c2ecf20Sopenharmony_ci u16 tim_offset = 0; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 4408c2ecf20Sopenharmony_ci vif = adapter->vifs[i]; 4418c2ecf20Sopenharmony_ci if (!vif) 4428c2ecf20Sopenharmony_ci continue; 4438c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 4448c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) 4458c2ecf20Sopenharmony_ci break; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci if (!vif) 4488c2ecf20Sopenharmony_ci return -EINVAL; 4498c2ecf20Sopenharmony_ci mac_bcn = ieee80211_beacon_get_tim(adapter->hw, 4508c2ecf20Sopenharmony_ci vif, 4518c2ecf20Sopenharmony_ci &tim_offset, NULL); 4528c2ecf20Sopenharmony_ci if (!mac_bcn) { 4538c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Failed to get beacon from mac80211\n"); 4548c2ecf20Sopenharmony_ci return -EINVAL; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci common->beacon_cnt++; 4588c2ecf20Sopenharmony_ci bcn_frm = (struct rsi_data_desc *)skb->data; 4598c2ecf20Sopenharmony_ci rsi_set_len_qno(&bcn_frm->len_qno, mac_bcn->len, RSI_WIFI_DATA_Q); 4608c2ecf20Sopenharmony_ci bcn_frm->header_len = MIN_802_11_HDR_LEN; 4618c2ecf20Sopenharmony_ci bcn_frm->frame_info = cpu_to_le16(RSI_DATA_DESC_MAC_BBP_INFO | 4628c2ecf20Sopenharmony_ci RSI_DATA_DESC_NO_ACK_IND | 4638c2ecf20Sopenharmony_ci RSI_DATA_DESC_BEACON_FRAME | 4648c2ecf20Sopenharmony_ci RSI_DATA_DESC_INSERT_TSF | 4658c2ecf20Sopenharmony_ci RSI_DATA_DESC_INSERT_SEQ_NO | 4668c2ecf20Sopenharmony_ci RATE_INFO_ENABLE); 4678c2ecf20Sopenharmony_ci bcn_frm->rate_info = cpu_to_le16(vap_id << 14); 4688c2ecf20Sopenharmony_ci bcn_frm->qid_tid = BEACON_HW_Q; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (conf_is_ht40_plus(conf)) { 4718c2ecf20Sopenharmony_ci bcn_frm->bbp_info = cpu_to_le16(LOWER_20_ENABLE); 4728c2ecf20Sopenharmony_ci bcn_frm->bbp_info |= cpu_to_le16(LOWER_20_ENABLE >> 12); 4738c2ecf20Sopenharmony_ci } else if (conf_is_ht40_minus(conf)) { 4748c2ecf20Sopenharmony_ci bcn_frm->bbp_info = cpu_to_le16(UPPER_20_ENABLE); 4758c2ecf20Sopenharmony_ci bcn_frm->bbp_info |= cpu_to_le16(UPPER_20_ENABLE >> 12); 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (common->band == NL80211_BAND_2GHZ) 4798c2ecf20Sopenharmony_ci bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_1); 4808c2ecf20Sopenharmony_ci else 4818c2ecf20Sopenharmony_ci bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_6); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (mac_bcn->data[tim_offset + 2] == 0) 4848c2ecf20Sopenharmony_ci bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci memcpy(&skb->data[FRAME_DESC_SZ], mac_bcn->data, mac_bcn->len); 4878c2ecf20Sopenharmony_ci skb_put(skb, mac_bcn->len + FRAME_DESC_SZ); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci dev_kfree_skb(mac_bcn); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic void bl_cmd_timeout(struct timer_list *t) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct rsi_hw *adapter = from_timer(adapter, t, bl_cmd_timer); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci adapter->blcmd_timer_expired = true; 4998c2ecf20Sopenharmony_ci del_timer(&adapter->bl_cmd_timer); 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic int bl_start_cmd_timer(struct rsi_hw *adapter, u32 timeout) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci timer_setup(&adapter->bl_cmd_timer, bl_cmd_timeout, 0); 5058c2ecf20Sopenharmony_ci adapter->bl_cmd_timer.expires = (msecs_to_jiffies(timeout) + jiffies); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci adapter->blcmd_timer_expired = false; 5088c2ecf20Sopenharmony_ci add_timer(&adapter->bl_cmd_timer); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci return 0; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int bl_stop_cmd_timer(struct rsi_hw *adapter) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci adapter->blcmd_timer_expired = false; 5168c2ecf20Sopenharmony_ci if (timer_pending(&adapter->bl_cmd_timer)) 5178c2ecf20Sopenharmony_ci del_timer(&adapter->bl_cmd_timer); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic int bl_write_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, 5238c2ecf20Sopenharmony_ci u16 *cmd_resp) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; 5268c2ecf20Sopenharmony_ci u32 regin_val = 0, regout_val = 0; 5278c2ecf20Sopenharmony_ci u32 regin_input = 0; 5288c2ecf20Sopenharmony_ci u8 output = 0; 5298c2ecf20Sopenharmony_ci int status; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci regin_input = (REGIN_INPUT | adapter->priv->coex_mode); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci while (!adapter->blcmd_timer_expired) { 5348c2ecf20Sopenharmony_ci regin_val = 0; 5358c2ecf20Sopenharmony_ci status = hif_ops->master_reg_read(adapter, SWBL_REGIN, 5368c2ecf20Sopenharmony_ci ®in_val, 2); 5378c2ecf20Sopenharmony_ci if (status < 0) { 5388c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 5398c2ecf20Sopenharmony_ci "%s: Command %0x REGIN reading failed..\n", 5408c2ecf20Sopenharmony_ci __func__, cmd); 5418c2ecf20Sopenharmony_ci return status; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci mdelay(1); 5448c2ecf20Sopenharmony_ci if ((regin_val >> 12) != REGIN_VALID) 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci if (adapter->blcmd_timer_expired) { 5488c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 5498c2ecf20Sopenharmony_ci "%s: Command %0x REGIN reading timed out..\n", 5508c2ecf20Sopenharmony_ci __func__, cmd); 5518c2ecf20Sopenharmony_ci return -ETIMEDOUT; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 5558c2ecf20Sopenharmony_ci "Issuing write to Regin val:%0x sending cmd:%0x\n", 5568c2ecf20Sopenharmony_ci regin_val, (cmd | regin_input << 8)); 5578c2ecf20Sopenharmony_ci status = hif_ops->master_reg_write(adapter, SWBL_REGIN, 5588c2ecf20Sopenharmony_ci (cmd | regin_input << 8), 2); 5598c2ecf20Sopenharmony_ci if (status < 0) 5608c2ecf20Sopenharmony_ci return status; 5618c2ecf20Sopenharmony_ci mdelay(1); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (cmd == LOAD_HOSTED_FW || cmd == JUMP_TO_ZERO_PC) { 5648c2ecf20Sopenharmony_ci /* JUMP_TO_ZERO_PC doesn't expect 5658c2ecf20Sopenharmony_ci * any response. So return from here 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci while (!adapter->blcmd_timer_expired) { 5718c2ecf20Sopenharmony_ci regout_val = 0; 5728c2ecf20Sopenharmony_ci status = hif_ops->master_reg_read(adapter, SWBL_REGOUT, 5738c2ecf20Sopenharmony_ci ®out_val, 2); 5748c2ecf20Sopenharmony_ci if (status < 0) { 5758c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 5768c2ecf20Sopenharmony_ci "%s: Command %0x REGOUT reading failed..\n", 5778c2ecf20Sopenharmony_ci __func__, cmd); 5788c2ecf20Sopenharmony_ci return status; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci mdelay(1); 5818c2ecf20Sopenharmony_ci if ((regout_val >> 8) == REGOUT_VALID) 5828c2ecf20Sopenharmony_ci break; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci if (adapter->blcmd_timer_expired) { 5858c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 5868c2ecf20Sopenharmony_ci "%s: Command %0x REGOUT reading timed out..\n", 5878c2ecf20Sopenharmony_ci __func__, cmd); 5888c2ecf20Sopenharmony_ci return status; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci *cmd_resp = ((u16 *)®out_val)[0] & 0xffff; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci output = ((u8 *)®out_val)[0] & 0xff; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci status = hif_ops->master_reg_write(adapter, SWBL_REGOUT, 5968c2ecf20Sopenharmony_ci (cmd | REGOUT_INVALID << 8), 2); 5978c2ecf20Sopenharmony_ci if (status < 0) { 5988c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 5998c2ecf20Sopenharmony_ci "%s: Command %0x REGOUT writing failed..\n", 6008c2ecf20Sopenharmony_ci __func__, cmd); 6018c2ecf20Sopenharmony_ci return status; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci mdelay(1); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (output != exp_resp) { 6068c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 6078c2ecf20Sopenharmony_ci "%s: Recvd resp %x for cmd %0x\n", 6088c2ecf20Sopenharmony_ci __func__, output, cmd); 6098c2ecf20Sopenharmony_ci return -EINVAL; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 6128c2ecf20Sopenharmony_ci "%s: Recvd Expected resp %x for cmd %0x\n", 6138c2ecf20Sopenharmony_ci __func__, output, cmd); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int bl_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, char *str) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci u16 regout_val = 0; 6218c2ecf20Sopenharmony_ci u32 timeout; 6228c2ecf20Sopenharmony_ci int status; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if ((cmd == EOF_REACHED) || (cmd == PING_VALID) || (cmd == PONG_VALID)) 6258c2ecf20Sopenharmony_ci timeout = BL_BURN_TIMEOUT; 6268c2ecf20Sopenharmony_ci else 6278c2ecf20Sopenharmony_ci timeout = BL_CMD_TIMEOUT; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci bl_start_cmd_timer(adapter, timeout); 6308c2ecf20Sopenharmony_ci status = bl_write_cmd(adapter, cmd, exp_resp, ®out_val); 6318c2ecf20Sopenharmony_ci if (status < 0) { 6328c2ecf20Sopenharmony_ci bl_stop_cmd_timer(adapter); 6338c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 6348c2ecf20Sopenharmony_ci "%s: Command %s (%0x) writing failed..\n", 6358c2ecf20Sopenharmony_ci __func__, str, cmd); 6368c2ecf20Sopenharmony_ci return status; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci bl_stop_cmd_timer(adapter); 6398c2ecf20Sopenharmony_ci return 0; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci#define CHECK_SUM_OFFSET 20 6438c2ecf20Sopenharmony_ci#define LEN_OFFSET 8 6448c2ecf20Sopenharmony_ci#define ADDR_OFFSET 16 6458c2ecf20Sopenharmony_cistatic int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, 6468c2ecf20Sopenharmony_ci u32 content_size) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; 6498c2ecf20Sopenharmony_ci struct bl_header *bl_hdr; 6508c2ecf20Sopenharmony_ci u32 write_addr, write_len; 6518c2ecf20Sopenharmony_ci int status; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci bl_hdr = kzalloc(sizeof(*bl_hdr), GFP_KERNEL); 6548c2ecf20Sopenharmony_ci if (!bl_hdr) 6558c2ecf20Sopenharmony_ci return -ENOMEM; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci bl_hdr->flags = 0; 6588c2ecf20Sopenharmony_ci bl_hdr->image_no = cpu_to_le32(adapter->priv->coex_mode); 6598c2ecf20Sopenharmony_ci bl_hdr->check_sum = 6608c2ecf20Sopenharmony_ci cpu_to_le32(*(u32 *)&flash_content[CHECK_SUM_OFFSET]); 6618c2ecf20Sopenharmony_ci bl_hdr->flash_start_address = 6628c2ecf20Sopenharmony_ci cpu_to_le32(*(u32 *)&flash_content[ADDR_OFFSET]); 6638c2ecf20Sopenharmony_ci bl_hdr->flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]); 6648c2ecf20Sopenharmony_ci write_len = sizeof(struct bl_header); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) { 6678c2ecf20Sopenharmony_ci write_addr = PING_BUFFER_ADDRESS; 6688c2ecf20Sopenharmony_ci status = hif_ops->write_reg_multiple(adapter, write_addr, 6698c2ecf20Sopenharmony_ci (u8 *)bl_hdr, write_len); 6708c2ecf20Sopenharmony_ci if (status < 0) { 6718c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 6728c2ecf20Sopenharmony_ci "%s: Failed to load Version/CRC structure\n", 6738c2ecf20Sopenharmony_ci __func__); 6748c2ecf20Sopenharmony_ci goto fail; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci } else { 6778c2ecf20Sopenharmony_ci write_addr = PING_BUFFER_ADDRESS >> 16; 6788c2ecf20Sopenharmony_ci status = hif_ops->master_access_msword(adapter, write_addr); 6798c2ecf20Sopenharmony_ci if (status < 0) { 6808c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 6818c2ecf20Sopenharmony_ci "%s: Unable to set ms word to common reg\n", 6828c2ecf20Sopenharmony_ci __func__); 6838c2ecf20Sopenharmony_ci goto fail; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci write_addr = RSI_SD_REQUEST_MASTER | 6868c2ecf20Sopenharmony_ci (PING_BUFFER_ADDRESS & 0xFFFF); 6878c2ecf20Sopenharmony_ci status = hif_ops->write_reg_multiple(adapter, write_addr, 6888c2ecf20Sopenharmony_ci (u8 *)bl_hdr, write_len); 6898c2ecf20Sopenharmony_ci if (status < 0) { 6908c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 6918c2ecf20Sopenharmony_ci "%s: Failed to load Version/CRC structure\n", 6928c2ecf20Sopenharmony_ci __func__); 6938c2ecf20Sopenharmony_ci goto fail; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci status = 0; 6978c2ecf20Sopenharmony_cifail: 6988c2ecf20Sopenharmony_ci kfree(bl_hdr); 6998c2ecf20Sopenharmony_ci return status; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic u32 read_flash_capacity(struct rsi_hw *adapter) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci u32 flash_sz = 0; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if ((adapter->host_intf_ops->master_reg_read(adapter, FLASH_SIZE_ADDR, 7078c2ecf20Sopenharmony_ci &flash_sz, 2)) < 0) { 7088c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 7098c2ecf20Sopenharmony_ci "%s: Flash size reading failed..\n", 7108c2ecf20Sopenharmony_ci __func__); 7118c2ecf20Sopenharmony_ci return 0; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci rsi_dbg(INIT_ZONE, "Flash capacity: %d KiloBytes\n", flash_sz); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return (flash_sz * 1024); /* Return size in kbytes */ 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic int ping_pong_write(struct rsi_hw *adapter, u8 cmd, u8 *addr, u32 size) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; 7218c2ecf20Sopenharmony_ci u32 block_size = adapter->block_size; 7228c2ecf20Sopenharmony_ci u32 cmd_addr; 7238c2ecf20Sopenharmony_ci u16 cmd_resp, cmd_req; 7248c2ecf20Sopenharmony_ci u8 *str; 7258c2ecf20Sopenharmony_ci int status; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (cmd == PING_WRITE) { 7288c2ecf20Sopenharmony_ci cmd_addr = PING_BUFFER_ADDRESS; 7298c2ecf20Sopenharmony_ci cmd_resp = PONG_AVAIL; 7308c2ecf20Sopenharmony_ci cmd_req = PING_VALID; 7318c2ecf20Sopenharmony_ci str = "PING_VALID"; 7328c2ecf20Sopenharmony_ci } else { 7338c2ecf20Sopenharmony_ci cmd_addr = PONG_BUFFER_ADDRESS; 7348c2ecf20Sopenharmony_ci cmd_resp = PING_AVAIL; 7358c2ecf20Sopenharmony_ci cmd_req = PONG_VALID; 7368c2ecf20Sopenharmony_ci str = "PONG_VALID"; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci status = hif_ops->load_data_master_write(adapter, cmd_addr, size, 7408c2ecf20Sopenharmony_ci block_size, addr); 7418c2ecf20Sopenharmony_ci if (status) { 7428c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Unable to write blk at addr %0x\n", 7438c2ecf20Sopenharmony_ci __func__, *addr); 7448c2ecf20Sopenharmony_ci return status; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci status = bl_cmd(adapter, cmd_req, cmd_resp, str); 7488c2ecf20Sopenharmony_ci if (status) 7498c2ecf20Sopenharmony_ci return status; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return 0; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic int auto_fw_upgrade(struct rsi_hw *adapter, u8 *flash_content, 7558c2ecf20Sopenharmony_ci u32 content_size) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci u8 cmd; 7588c2ecf20Sopenharmony_ci u32 temp_content_size, num_flash, index; 7598c2ecf20Sopenharmony_ci u32 flash_start_address; 7608c2ecf20Sopenharmony_ci int status; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (content_size > MAX_FLASH_FILE_SIZE) { 7638c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 7648c2ecf20Sopenharmony_ci "%s: Flash Content size is more than 400K %u\n", 7658c2ecf20Sopenharmony_ci __func__, MAX_FLASH_FILE_SIZE); 7668c2ecf20Sopenharmony_ci return -EINVAL; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci flash_start_address = *(u32 *)&flash_content[FLASH_START_ADDRESS]; 7708c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "flash start address: %08x\n", flash_start_address); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (flash_start_address < FW_IMAGE_MIN_ADDRESS) { 7738c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 7748c2ecf20Sopenharmony_ci "%s: Fw image Flash Start Address is less than 64K\n", 7758c2ecf20Sopenharmony_ci __func__); 7768c2ecf20Sopenharmony_ci return -EINVAL; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if (flash_start_address % FLASH_SECTOR_SIZE) { 7808c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 7818c2ecf20Sopenharmony_ci "%s: Flash Start Address is not multiple of 4K\n", 7828c2ecf20Sopenharmony_ci __func__); 7838c2ecf20Sopenharmony_ci return -EINVAL; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if ((flash_start_address + content_size) > adapter->flash_capacity) { 7878c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 7888c2ecf20Sopenharmony_ci "%s: Flash Content will cross max flash size\n", 7898c2ecf20Sopenharmony_ci __func__); 7908c2ecf20Sopenharmony_ci return -EINVAL; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci temp_content_size = content_size; 7948c2ecf20Sopenharmony_ci num_flash = content_size / FLASH_WRITE_CHUNK_SIZE; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "content_size: %d, num_flash: %d\n", 7978c2ecf20Sopenharmony_ci content_size, num_flash); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci for (index = 0; index <= num_flash; index++) { 8008c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "flash index: %d\n", index); 8018c2ecf20Sopenharmony_ci if (index != num_flash) { 8028c2ecf20Sopenharmony_ci content_size = FLASH_WRITE_CHUNK_SIZE; 8038c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "QSPI content_size:%d\n", 8048c2ecf20Sopenharmony_ci content_size); 8058c2ecf20Sopenharmony_ci } else { 8068c2ecf20Sopenharmony_ci content_size = 8078c2ecf20Sopenharmony_ci temp_content_size % FLASH_WRITE_CHUNK_SIZE; 8088c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 8098c2ecf20Sopenharmony_ci "Writing last sector content_size:%d\n", 8108c2ecf20Sopenharmony_ci content_size); 8118c2ecf20Sopenharmony_ci if (!content_size) { 8128c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "instruction size zero\n"); 8138c2ecf20Sopenharmony_ci break; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (index % 2) 8188c2ecf20Sopenharmony_ci cmd = PING_WRITE; 8198c2ecf20Sopenharmony_ci else 8208c2ecf20Sopenharmony_ci cmd = PONG_WRITE; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci status = ping_pong_write(adapter, cmd, flash_content, 8238c2ecf20Sopenharmony_ci content_size); 8248c2ecf20Sopenharmony_ci if (status) { 8258c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Unable to load %d block\n", 8268c2ecf20Sopenharmony_ci __func__, index); 8278c2ecf20Sopenharmony_ci return status; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 8318c2ecf20Sopenharmony_ci "%s: Successfully loaded %d instructions\n", 8328c2ecf20Sopenharmony_ci __func__, index); 8338c2ecf20Sopenharmony_ci flash_content += content_size; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci status = bl_cmd(adapter, EOF_REACHED, FW_LOADING_SUCCESSFUL, 8378c2ecf20Sopenharmony_ci "EOF_REACHED"); 8388c2ecf20Sopenharmony_ci if (status) 8398c2ecf20Sopenharmony_ci return status; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "FW loading is done and FW is running..\n"); 8428c2ecf20Sopenharmony_ci return 0; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic int rsi_hal_prepare_fwload(struct rsi_hw *adapter) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; 8488c2ecf20Sopenharmony_ci u32 regout_val = 0; 8498c2ecf20Sopenharmony_ci int status; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci while (!adapter->blcmd_timer_expired) { 8548c2ecf20Sopenharmony_ci status = hif_ops->master_reg_read(adapter, SWBL_REGOUT, 8558c2ecf20Sopenharmony_ci ®out_val, 8568c2ecf20Sopenharmony_ci RSI_COMMON_REG_SIZE); 8578c2ecf20Sopenharmony_ci if (status < 0) { 8588c2ecf20Sopenharmony_ci bl_stop_cmd_timer(adapter); 8598c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 8608c2ecf20Sopenharmony_ci "%s: REGOUT read failed\n", __func__); 8618c2ecf20Sopenharmony_ci return status; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci mdelay(1); 8648c2ecf20Sopenharmony_ci if ((regout_val >> 8) == REGOUT_VALID) 8658c2ecf20Sopenharmony_ci break; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci if (adapter->blcmd_timer_expired) { 8688c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: REGOUT read timedout\n", __func__); 8698c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 8708c2ecf20Sopenharmony_ci "%s: Soft boot loader not present\n", __func__); 8718c2ecf20Sopenharmony_ci return -ETIMEDOUT; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci bl_stop_cmd_timer(adapter); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Received Board Version Number: %x\n", 8768c2ecf20Sopenharmony_ci (regout_val & 0xff)); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci status = hif_ops->master_reg_write(adapter, SWBL_REGOUT, 8798c2ecf20Sopenharmony_ci (REGOUT_INVALID | 8808c2ecf20Sopenharmony_ci REGOUT_INVALID << 8), 8818c2ecf20Sopenharmony_ci RSI_COMMON_REG_SIZE); 8828c2ecf20Sopenharmony_ci if (status < 0) 8838c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: REGOUT writing failed..\n", __func__); 8848c2ecf20Sopenharmony_ci else 8858c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 8868c2ecf20Sopenharmony_ci "===> Device is ready to load firmware <===\n"); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci return status; 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic int rsi_load_9113_firmware(struct rsi_hw *adapter) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 8948c2ecf20Sopenharmony_ci const struct firmware *fw_entry = NULL; 8958c2ecf20Sopenharmony_ci u32 content_size; 8968c2ecf20Sopenharmony_ci u16 tmp_regout_val = 0; 8978c2ecf20Sopenharmony_ci struct ta_metadata *metadata_p; 8988c2ecf20Sopenharmony_ci int status; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS, 9018c2ecf20Sopenharmony_ci "AUTO_READ_CMD"); 9028c2ecf20Sopenharmony_ci if (status < 0) 9038c2ecf20Sopenharmony_ci return status; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci adapter->flash_capacity = read_flash_capacity(adapter); 9068c2ecf20Sopenharmony_ci if (adapter->flash_capacity <= 0) { 9078c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 9088c2ecf20Sopenharmony_ci "%s: Unable to read flash size from EEPROM\n", 9098c2ecf20Sopenharmony_ci __func__); 9108c2ecf20Sopenharmony_ci return -EINVAL; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci metadata_p = &metadata_flash_content[adapter->priv->coex_mode]; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci rsi_dbg(INIT_ZONE, "%s: Loading file %s\n", __func__, metadata_p->name); 9168c2ecf20Sopenharmony_ci adapter->fw_file_name = metadata_p->name; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci status = request_firmware(&fw_entry, metadata_p->name, adapter->device); 9198c2ecf20Sopenharmony_ci if (status < 0) { 9208c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n", 9218c2ecf20Sopenharmony_ci __func__, metadata_p->name); 9228c2ecf20Sopenharmony_ci return status; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci content_size = fw_entry->size; 9258c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", content_size); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci /* Get the firmware version */ 9288c2ecf20Sopenharmony_ci common->lmac_ver.ver.info.fw_ver[0] = 9298c2ecf20Sopenharmony_ci fw_entry->data[LMAC_VER_OFFSET_9113] & 0xFF; 9308c2ecf20Sopenharmony_ci common->lmac_ver.ver.info.fw_ver[1] = 9318c2ecf20Sopenharmony_ci fw_entry->data[LMAC_VER_OFFSET_9113 + 1] & 0xFF; 9328c2ecf20Sopenharmony_ci common->lmac_ver.major = 9338c2ecf20Sopenharmony_ci fw_entry->data[LMAC_VER_OFFSET_9113 + 2] & 0xFF; 9348c2ecf20Sopenharmony_ci common->lmac_ver.release_num = 9358c2ecf20Sopenharmony_ci fw_entry->data[LMAC_VER_OFFSET_9113 + 3] & 0xFF; 9368c2ecf20Sopenharmony_ci common->lmac_ver.minor = 9378c2ecf20Sopenharmony_ci fw_entry->data[LMAC_VER_OFFSET_9113 + 4] & 0xFF; 9388c2ecf20Sopenharmony_ci common->lmac_ver.patch_num = 0; 9398c2ecf20Sopenharmony_ci rsi_print_version(common); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci status = bl_write_header(adapter, (u8 *)fw_entry->data, content_size); 9428c2ecf20Sopenharmony_ci if (status) { 9438c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 9448c2ecf20Sopenharmony_ci "%s: RPS Image header loading failed\n", 9458c2ecf20Sopenharmony_ci __func__); 9468c2ecf20Sopenharmony_ci goto fail; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT); 9508c2ecf20Sopenharmony_ci status = bl_write_cmd(adapter, CHECK_CRC, CMD_PASS, &tmp_regout_val); 9518c2ecf20Sopenharmony_ci if (status) { 9528c2ecf20Sopenharmony_ci bl_stop_cmd_timer(adapter); 9538c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 9548c2ecf20Sopenharmony_ci "%s: CHECK_CRC Command writing failed..\n", 9558c2ecf20Sopenharmony_ci __func__); 9568c2ecf20Sopenharmony_ci if ((tmp_regout_val & 0xff) == CMD_FAIL) { 9578c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 9588c2ecf20Sopenharmony_ci "CRC Fail.. Proceeding to Upgrade mode\n"); 9598c2ecf20Sopenharmony_ci goto fw_upgrade; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci bl_stop_cmd_timer(adapter); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci status = bl_cmd(adapter, POLLING_MODE, CMD_PASS, "POLLING_MODE"); 9658c2ecf20Sopenharmony_ci if (status) 9668c2ecf20Sopenharmony_ci goto fail; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ciload_image_cmd: 9698c2ecf20Sopenharmony_ci status = bl_cmd(adapter, LOAD_HOSTED_FW, LOADING_INITIATED, 9708c2ecf20Sopenharmony_ci "LOAD_HOSTED_FW"); 9718c2ecf20Sopenharmony_ci if (status) 9728c2ecf20Sopenharmony_ci goto fail; 9738c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Load Image command passed..\n"); 9748c2ecf20Sopenharmony_ci goto success; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cifw_upgrade: 9778c2ecf20Sopenharmony_ci status = bl_cmd(adapter, BURN_HOSTED_FW, SEND_RPS_FILE, "FW_UPGRADE"); 9788c2ecf20Sopenharmony_ci if (status) 9798c2ecf20Sopenharmony_ci goto fail; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Burn Command Pass.. Upgrading the firmware\n"); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci status = auto_fw_upgrade(adapter, (u8 *)fw_entry->data, content_size); 9848c2ecf20Sopenharmony_ci if (status == 0) { 9858c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Firmware upgradation Done\n"); 9868c2ecf20Sopenharmony_ci goto load_image_cmd; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Firmware upgrade failed\n"); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS, 9918c2ecf20Sopenharmony_ci "AUTO_READ_MODE"); 9928c2ecf20Sopenharmony_ci if (status) 9938c2ecf20Sopenharmony_ci goto fail; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_cisuccess: 9968c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "***** Firmware Loading successful *****\n"); 9978c2ecf20Sopenharmony_ci release_firmware(fw_entry); 9988c2ecf20Sopenharmony_ci return 0; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_cifail: 10018c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "##### Firmware loading failed #####\n"); 10028c2ecf20Sopenharmony_ci release_firmware(fw_entry); 10038c2ecf20Sopenharmony_ci return status; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic int rsi_load_9116_firmware(struct rsi_hw *adapter) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 10098c2ecf20Sopenharmony_ci struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; 10108c2ecf20Sopenharmony_ci const struct firmware *fw_entry; 10118c2ecf20Sopenharmony_ci struct ta_metadata *metadata_p; 10128c2ecf20Sopenharmony_ci u8 *ta_firmware, *fw_p; 10138c2ecf20Sopenharmony_ci struct bootload_ds bootload_ds; 10148c2ecf20Sopenharmony_ci u32 instructions_sz, base_address; 10158c2ecf20Sopenharmony_ci u16 block_size = adapter->block_size; 10168c2ecf20Sopenharmony_ci u32 dest, len; 10178c2ecf20Sopenharmony_ci int status, cnt; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci rsi_dbg(INIT_ZONE, "***** Load 9116 TA Instructions *****\n"); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) { 10228c2ecf20Sopenharmony_ci status = bl_cmd(adapter, POLLING_MODE, CMD_PASS, 10238c2ecf20Sopenharmony_ci "POLLING_MODE"); 10248c2ecf20Sopenharmony_ci if (status < 0) 10258c2ecf20Sopenharmony_ci return status; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci status = hif_ops->master_reg_write(adapter, MEM_ACCESS_CTRL_FROM_HOST, 10298c2ecf20Sopenharmony_ci RAM_384K_ACCESS_FROM_TA, 10308c2ecf20Sopenharmony_ci RSI_9116_REG_SIZE); 10318c2ecf20Sopenharmony_ci if (status < 0) { 10328c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Unable to access full RAM memory\n", 10338c2ecf20Sopenharmony_ci __func__); 10348c2ecf20Sopenharmony_ci return status; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci metadata_p = &metadata[adapter->priv->coex_mode]; 10388c2ecf20Sopenharmony_ci rsi_dbg(INIT_ZONE, "%s: loading file %s\n", __func__, metadata_p->name); 10398c2ecf20Sopenharmony_ci status = request_firmware(&fw_entry, metadata_p->name, adapter->device); 10408c2ecf20Sopenharmony_ci if (status < 0) { 10418c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n", 10428c2ecf20Sopenharmony_ci __func__, metadata_p->name); 10438c2ecf20Sopenharmony_ci return status; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci ta_firmware = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); 10478c2ecf20Sopenharmony_ci if (!ta_firmware) { 10488c2ecf20Sopenharmony_ci status = -ENOMEM; 10498c2ecf20Sopenharmony_ci goto fail_release_fw; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci fw_p = ta_firmware; 10528c2ecf20Sopenharmony_ci instructions_sz = fw_entry->size; 10538c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", instructions_sz); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci common->lmac_ver.major = ta_firmware[LMAC_VER_OFFSET_9116]; 10568c2ecf20Sopenharmony_ci common->lmac_ver.minor = ta_firmware[LMAC_VER_OFFSET_9116 + 1]; 10578c2ecf20Sopenharmony_ci common->lmac_ver.release_num = ta_firmware[LMAC_VER_OFFSET_9116 + 2]; 10588c2ecf20Sopenharmony_ci common->lmac_ver.patch_num = ta_firmware[LMAC_VER_OFFSET_9116 + 3]; 10598c2ecf20Sopenharmony_ci common->lmac_ver.ver.info.fw_ver[0] = 10608c2ecf20Sopenharmony_ci ta_firmware[LMAC_VER_OFFSET_9116 + 4]; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (instructions_sz % FW_ALIGN_SIZE) 10638c2ecf20Sopenharmony_ci instructions_sz += 10648c2ecf20Sopenharmony_ci (FW_ALIGN_SIZE - (instructions_sz % FW_ALIGN_SIZE)); 10658c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "instructions_sz : %d\n", instructions_sz); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (*(u16 *)fw_p == RSI_9116_FW_MAGIC_WORD) { 10688c2ecf20Sopenharmony_ci memcpy(&bootload_ds, fw_p, sizeof(struct bootload_ds)); 10698c2ecf20Sopenharmony_ci fw_p += le16_to_cpu(bootload_ds.offset); 10708c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "FW start = %x\n", *(u32 *)fw_p); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci cnt = 0; 10738c2ecf20Sopenharmony_ci do { 10748c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Loading chunk %d\n", 10758c2ecf20Sopenharmony_ci __func__, cnt); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci dest = le32_to_cpu(bootload_ds.bl_entry[cnt].dst_addr); 10788c2ecf20Sopenharmony_ci len = le32_to_cpu(bootload_ds.bl_entry[cnt].control) & 10798c2ecf20Sopenharmony_ci RSI_BL_CTRL_LEN_MASK; 10808c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "length %d destination %x\n", 10818c2ecf20Sopenharmony_ci len, dest); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci status = hif_ops->load_data_master_write(adapter, dest, 10848c2ecf20Sopenharmony_ci len, 10858c2ecf20Sopenharmony_ci block_size, 10868c2ecf20Sopenharmony_ci fw_p); 10878c2ecf20Sopenharmony_ci if (status < 0) { 10888c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 10898c2ecf20Sopenharmony_ci "Failed to load chunk %d\n", cnt); 10908c2ecf20Sopenharmony_ci break; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci fw_p += len; 10938c2ecf20Sopenharmony_ci if (le32_to_cpu(bootload_ds.bl_entry[cnt].control) & 10948c2ecf20Sopenharmony_ci RSI_BL_CTRL_LAST_ENTRY) 10958c2ecf20Sopenharmony_ci break; 10968c2ecf20Sopenharmony_ci cnt++; 10978c2ecf20Sopenharmony_ci } while (1); 10988c2ecf20Sopenharmony_ci } else { 10998c2ecf20Sopenharmony_ci base_address = metadata_p->address; 11008c2ecf20Sopenharmony_ci status = hif_ops->load_data_master_write(adapter, 11018c2ecf20Sopenharmony_ci base_address, 11028c2ecf20Sopenharmony_ci instructions_sz, 11038c2ecf20Sopenharmony_ci block_size, 11048c2ecf20Sopenharmony_ci ta_firmware); 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci if (status) { 11078c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 11088c2ecf20Sopenharmony_ci "%s: Unable to load %s blk\n", 11098c2ecf20Sopenharmony_ci __func__, metadata_p->name); 11108c2ecf20Sopenharmony_ci goto fail_free_fw; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci rsi_dbg(INIT_ZONE, "%s: Successfully loaded %s instructions\n", 11148c2ecf20Sopenharmony_ci __func__, metadata_p->name); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (adapter->rsi_host_intf == RSI_HOST_INTF_SDIO) { 11178c2ecf20Sopenharmony_ci if (hif_ops->ta_reset(adapter)) 11188c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Unable to put ta in reset\n"); 11198c2ecf20Sopenharmony_ci } else { 11208c2ecf20Sopenharmony_ci if (bl_cmd(adapter, JUMP_TO_ZERO_PC, 11218c2ecf20Sopenharmony_ci CMD_PASS, "JUMP_TO_ZERO") < 0) 11228c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Jump to zero command failed\n"); 11238c2ecf20Sopenharmony_ci else 11248c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Jump to zero command successful\n"); 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cifail_free_fw: 11288c2ecf20Sopenharmony_ci kfree(ta_firmware); 11298c2ecf20Sopenharmony_cifail_release_fw: 11308c2ecf20Sopenharmony_ci release_firmware(fw_entry); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci return status; 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ciint rsi_hal_device_init(struct rsi_hw *adapter) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 11388c2ecf20Sopenharmony_ci int status; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci switch (adapter->device_model) { 11418c2ecf20Sopenharmony_ci case RSI_DEV_9113: 11428c2ecf20Sopenharmony_ci status = rsi_hal_prepare_fwload(adapter); 11438c2ecf20Sopenharmony_ci if (status < 0) 11448c2ecf20Sopenharmony_ci return status; 11458c2ecf20Sopenharmony_ci if (rsi_load_9113_firmware(adapter)) { 11468c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 11478c2ecf20Sopenharmony_ci "%s: Failed to load TA instructions\n", 11488c2ecf20Sopenharmony_ci __func__); 11498c2ecf20Sopenharmony_ci return -EINVAL; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci break; 11528c2ecf20Sopenharmony_ci case RSI_DEV_9116: 11538c2ecf20Sopenharmony_ci status = rsi_hal_prepare_fwload(adapter); 11548c2ecf20Sopenharmony_ci if (status < 0) 11558c2ecf20Sopenharmony_ci return status; 11568c2ecf20Sopenharmony_ci if (rsi_load_9116_firmware(adapter)) { 11578c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 11588c2ecf20Sopenharmony_ci "%s: Failed to load firmware to 9116 device\n", 11598c2ecf20Sopenharmony_ci __func__); 11608c2ecf20Sopenharmony_ci return -EINVAL; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci default: 11648c2ecf20Sopenharmony_ci return -EINVAL; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci common->fsm_state = FSM_CARD_NOT_READY; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci return 0; 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rsi_hal_device_init); 11718c2ecf20Sopenharmony_ci 1172