18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications 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/export.h> 188c2ecf20Sopenharmony_ci#include "hw.h" 198c2ecf20Sopenharmony_ci#include "hw-ops.h" 208c2ecf20Sopenharmony_ci#include "ar9003_phy.h" 218c2ecf20Sopenharmony_ci#include "ar9003_mci.h" 228c2ecf20Sopenharmony_ci#include "ar9003_aic.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic void ar9003_mci_reset_req_wakeup(struct ath_hw *ah) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MCI_COMMAND2, 278c2ecf20Sopenharmony_ci AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1); 288c2ecf20Sopenharmony_ci udelay(1); 298c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MCI_COMMAND2, 308c2ecf20Sopenharmony_ci AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 0); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address, 348c2ecf20Sopenharmony_ci u32 bit_position, int time_out) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci while (time_out) { 398c2ecf20Sopenharmony_ci if (!(REG_READ(ah, address) & bit_position)) { 408c2ecf20Sopenharmony_ci udelay(10); 418c2ecf20Sopenharmony_ci time_out -= 10; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (time_out < 0) 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci else 468c2ecf20Sopenharmony_ci continue; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci REG_WRITE(ah, address, bit_position); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (address != AR_MCI_INTERRUPT_RX_MSG_RAW) 518c2ecf20Sopenharmony_ci break; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (bit_position & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) 548c2ecf20Sopenharmony_ci ar9003_mci_reset_req_wakeup(ah); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (bit_position & (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING | 578c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) 588c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, 598c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_RX_MSG); 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (time_out <= 0) { 668c2ecf20Sopenharmony_ci ath_dbg(common, MCI, 678c2ecf20Sopenharmony_ci "MCI Wait for Reg 0x%08x = 0x%08x timeout\n", 688c2ecf20Sopenharmony_ci address, bit_position); 698c2ecf20Sopenharmony_ci ath_dbg(common, MCI, 708c2ecf20Sopenharmony_ci "MCI INT_RAW = 0x%08x, RX_MSG_RAW = 0x%08x\n", 718c2ecf20Sopenharmony_ci REG_READ(ah, AR_MCI_INTERRUPT_RAW), 728c2ecf20Sopenharmony_ci REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW)); 738c2ecf20Sopenharmony_ci time_out = 0; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return time_out; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16, 848c2ecf20Sopenharmony_ci wait_done, false); 858c2ecf20Sopenharmony_ci udelay(5); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci u32 payload = 0x00000000; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1, 938c2ecf20Sopenharmony_ci wait_done, false); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_REQ_WAKE, MCI_FLAG_DISABLE_TIMESTAMP, 998c2ecf20Sopenharmony_ci NULL, 0, wait_done, false); 1008c2ecf20Sopenharmony_ci udelay(5); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP, 1068c2ecf20Sopenharmony_ci NULL, 0, wait_done, false); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void ar9003_mci_send_lna_take(struct ath_hw *ah, bool wait_done) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci u32 payload = 0x70000000; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_LNA_TAKE, 0, &payload, 1, 1148c2ecf20Sopenharmony_ci wait_done, false); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_SYS_SLEEPING, 1208c2ecf20Sopenharmony_ci MCI_FLAG_DISABLE_TIMESTAMP, 1218c2ecf20Sopenharmony_ci NULL, 0, wait_done, false); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void ar9003_mci_send_coex_version_query(struct ath_hw *ah, 1258c2ecf20Sopenharmony_ci bool wait_done) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1288c2ecf20Sopenharmony_ci u32 payload[4] = {0, 0, 0, 0}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (mci->bt_version_known || 1318c2ecf20Sopenharmony_ci (mci->bt_state == MCI_BT_SLEEP)) 1328c2ecf20Sopenharmony_ci return; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, 1358c2ecf20Sopenharmony_ci MCI_GPM_COEX_VERSION_QUERY); 1368c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic void ar9003_mci_send_coex_version_response(struct ath_hw *ah, 1408c2ecf20Sopenharmony_ci bool wait_done) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1438c2ecf20Sopenharmony_ci u32 payload[4] = {0, 0, 0, 0}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, 1468c2ecf20Sopenharmony_ci MCI_GPM_COEX_VERSION_RESPONSE); 1478c2ecf20Sopenharmony_ci *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) = 1488c2ecf20Sopenharmony_ci mci->wlan_ver_major; 1498c2ecf20Sopenharmony_ci *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) = 1508c2ecf20Sopenharmony_ci mci->wlan_ver_minor; 1518c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah, 1558c2ecf20Sopenharmony_ci bool wait_done) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1588c2ecf20Sopenharmony_ci u32 *payload = &mci->wlan_channels[0]; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (!mci->wlan_channels_update || 1618c2ecf20Sopenharmony_ci (mci->bt_state == MCI_BT_SLEEP)) 1628c2ecf20Sopenharmony_ci return; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, 1658c2ecf20Sopenharmony_ci MCI_GPM_COEX_WLAN_CHANNELS); 1668c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); 1678c2ecf20Sopenharmony_ci MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah, 1718c2ecf20Sopenharmony_ci bool wait_done, u8 query_type) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1748c2ecf20Sopenharmony_ci u32 payload[4] = {0, 0, 0, 0}; 1758c2ecf20Sopenharmony_ci bool query_btinfo; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (mci->bt_state == MCI_BT_SLEEP) 1788c2ecf20Sopenharmony_ci return; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO | 1818c2ecf20Sopenharmony_ci MCI_GPM_COEX_QUERY_BT_TOPOLOGY)); 1828c2ecf20Sopenharmony_ci MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, 1838c2ecf20Sopenharmony_ci MCI_GPM_COEX_STATUS_QUERY); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* 1888c2ecf20Sopenharmony_ci * If bt_status_query message is not sent successfully, 1898c2ecf20Sopenharmony_ci * then need_flush_btinfo should be set again. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, 1928c2ecf20Sopenharmony_ci wait_done, true)) { 1938c2ecf20Sopenharmony_ci if (query_btinfo) 1948c2ecf20Sopenharmony_ci mci->need_flush_btinfo = true; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (query_btinfo) 1988c2ecf20Sopenharmony_ci mci->query_bt = false; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, 2028c2ecf20Sopenharmony_ci bool wait_done) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 2058c2ecf20Sopenharmony_ci u32 payload[4] = {0, 0, 0, 0}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, 2088c2ecf20Sopenharmony_ci MCI_GPM_COEX_HALT_BT_GPM); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (halt) { 2118c2ecf20Sopenharmony_ci mci->query_bt = true; 2128c2ecf20Sopenharmony_ci /* Send next unhalt no matter halt sent or not */ 2138c2ecf20Sopenharmony_ci mci->unhalt_bt_gpm = true; 2148c2ecf20Sopenharmony_ci mci->need_flush_btinfo = true; 2158c2ecf20Sopenharmony_ci *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) = 2168c2ecf20Sopenharmony_ci MCI_GPM_COEX_BT_GPM_HALT; 2178c2ecf20Sopenharmony_ci } else 2188c2ecf20Sopenharmony_ci *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) = 2198c2ecf20Sopenharmony_ci MCI_GPM_COEX_BT_GPM_UNHALT; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic void ar9003_mci_prep_interface(struct ath_hw *ah) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 2278c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 2288c2ecf20Sopenharmony_ci u32 saved_mci_int_en; 2298c2ecf20Sopenharmony_ci u32 mci_timeout = 150; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci mci->bt_state = MCI_BT_SLEEP; 2328c2ecf20Sopenharmony_ci saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); 2358c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 2368c2ecf20Sopenharmony_ci REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW)); 2378c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, 2388c2ecf20Sopenharmony_ci REG_READ(ah, AR_MCI_INTERRUPT_RAW)); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci ar9003_mci_remote_reset(ah, true); 2418c2ecf20Sopenharmony_ci ar9003_mci_send_req_wake(ah, true); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 2448c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) 2458c2ecf20Sopenharmony_ci goto clear_redunt; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci mci->bt_state = MCI_BT_AWAKE; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* 2508c2ecf20Sopenharmony_ci * we don't need to send more remote_reset at this moment. 2518c2ecf20Sopenharmony_ci * If BT receive first remote_reset, then BT HW will 2528c2ecf20Sopenharmony_ci * be cleaned up and will be able to receive req_wake 2538c2ecf20Sopenharmony_ci * and BT HW will respond sys_waking. 2548c2ecf20Sopenharmony_ci * In this case, WLAN will receive BT's HW sys_waking. 2558c2ecf20Sopenharmony_ci * Otherwise, if BT SW missed initial remote_reset, 2568c2ecf20Sopenharmony_ci * that remote_reset will still clean up BT MCI RX, 2578c2ecf20Sopenharmony_ci * and the req_wake will wake BT up, 2588c2ecf20Sopenharmony_ci * and BT SW will respond this req_wake with a remote_reset and 2598c2ecf20Sopenharmony_ci * sys_waking. In this case, WLAN will receive BT's SW 2608c2ecf20Sopenharmony_ci * sys_waking. In either case, BT's RX is cleaned up. So we 2618c2ecf20Sopenharmony_ci * don't need to reply BT's remote_reset now, if any. 2628c2ecf20Sopenharmony_ci * Similarly, if in any case, WLAN can receive BT's sys_waking, 2638c2ecf20Sopenharmony_ci * that means WLAN's RX is also fine. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_ci ar9003_mci_send_sys_waking(ah, true); 2668c2ecf20Sopenharmony_ci udelay(10); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * Set BT priority interrupt value to be 0xff to 2708c2ecf20Sopenharmony_ci * avoid having too many BT PRIORITY interrupts. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF); 2738c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF); 2748c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF); 2758c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF); 2768c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* 2798c2ecf20Sopenharmony_ci * A contention reset will be received after send out 2808c2ecf20Sopenharmony_ci * sys_waking. Also BT priority interrupt bits will be set. 2818c2ecf20Sopenharmony_ci * Clear those bits before the next step. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 2858c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_CONT_RST); 2868c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (mci->is_2g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { 2898c2ecf20Sopenharmony_ci ar9003_mci_send_lna_transfer(ah, true); 2908c2ecf20Sopenharmony_ci udelay(5); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (mci->is_2g && !mci->update_2g5g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { 2948c2ecf20Sopenharmony_ci if (ar9003_mci_wait_for_interrupt(ah, 2958c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_RAW, 2968c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_LNA_INFO, 2978c2ecf20Sopenharmony_ci mci_timeout)) 2988c2ecf20Sopenharmony_ci ath_dbg(common, MCI, 2998c2ecf20Sopenharmony_ci "MCI WLAN has control over the LNA & BT obeys it\n"); 3008c2ecf20Sopenharmony_ci else 3018c2ecf20Sopenharmony_ci ath_dbg(common, MCI, 3028c2ecf20Sopenharmony_ci "MCI BT didn't respond to LNA_TRANS\n"); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ciclear_redunt: 3068c2ecf20Sopenharmony_ci /* Clear the extra redundant SYS_WAKING from BT */ 3078c2ecf20Sopenharmony_ci if ((mci->bt_state == MCI_BT_AWAKE) && 3088c2ecf20Sopenharmony_ci (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 3098c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) && 3108c2ecf20Sopenharmony_ci (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 3118c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) { 3128c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 3138c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING); 3148c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, 3158c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_civoid ar9003_mci_set_full_sleep(struct ath_hw *ah) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (ar9003_mci_state(ah, MCI_STATE_ENABLE) && 3268c2ecf20Sopenharmony_ci (mci->bt_state != MCI_BT_SLEEP) && 3278c2ecf20Sopenharmony_ci !mci->halted_bt_gpm) { 3288c2ecf20Sopenharmony_ci ar9003_mci_send_coex_halt_bt_gpm(ah, true, true); 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci mci->ready = false; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic void ar9003_mci_disable_interrupt(struct ath_hw *ah) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); 3378c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void ar9003_mci_enable_interrupt(struct ath_hw *ah) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT); 3438c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 3448c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_DEFAULT); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci u32 intr; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); 3528c2ecf20Sopenharmony_ci return ((intr & ints) == ints); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_civoid ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, 3568c2ecf20Sopenharmony_ci u32 *rx_msg_intr) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci *raw_intr = mci->raw_intr; 3618c2ecf20Sopenharmony_ci *rx_msg_intr = mci->rx_msg_intr; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Clean int bits after the values are read. */ 3648c2ecf20Sopenharmony_ci mci->raw_intr = 0; 3658c2ecf20Sopenharmony_ci mci->rx_msg_intr = 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ar9003_mci_get_interrupt); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_civoid ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 3728c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 3738c2ecf20Sopenharmony_ci u32 raw_intr, rx_msg_intr; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); 3768c2ecf20Sopenharmony_ci raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) { 3798c2ecf20Sopenharmony_ci ath_dbg(common, MCI, 3808c2ecf20Sopenharmony_ci "MCI gets 0xdeadbeef during int processing\n"); 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci mci->rx_msg_intr |= rx_msg_intr; 3838c2ecf20Sopenharmony_ci mci->raw_intr |= raw_intr; 3848c2ecf20Sopenharmony_ci *masked |= ATH9K_INT_MCI; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) 3878c2ecf20Sopenharmony_ci mci->cont_status = REG_READ(ah, AR_MCI_CONT_STATUS); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr); 3908c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (!mci->update_2g5g && 3998c2ecf20Sopenharmony_ci (mci->is_2g != is_2g)) 4008c2ecf20Sopenharmony_ci mci->update_2g5g = true; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci mci->is_2g = is_2g; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 4088c2ecf20Sopenharmony_ci u32 *payload; 4098c2ecf20Sopenharmony_ci u32 recv_type, offset; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (msg_index == MCI_GPM_INVALID) 4128c2ecf20Sopenharmony_ci return false; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci offset = msg_index << 4; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci payload = (u32 *)(mci->gpm_buf + offset); 4178c2ecf20Sopenharmony_ci recv_type = MCI_GPM_TYPE(payload); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (recv_type == MCI_GPM_RSVD_PATTERN) 4208c2ecf20Sopenharmony_ci return false; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return true; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic void ar9003_mci_observation_set_up(struct ath_hw *ah) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) { 4308c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 3, NULL, 4318c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA); 4328c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 2, NULL, 4338c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK); 4348c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 1, NULL, 4358c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); 4368c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 0, NULL, 4378c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); 4388c2ecf20Sopenharmony_ci } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) { 4398c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 3, NULL, 4408c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX); 4418c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 2, NULL, 4428c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX); 4438c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 1, NULL, 4448c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); 4458c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 0, NULL, 4468c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); 4478c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 5, NULL, 4488c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_OUTPUT); 4498c2ecf20Sopenharmony_ci } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) { 4508c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 3, NULL, 4518c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); 4528c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 2, NULL, 4538c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); 4548c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 1, NULL, 4558c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); 4568c2ecf20Sopenharmony_ci ath9k_hw_gpio_request_out(ah, 0, NULL, 4578c2ecf20Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); 4588c2ecf20Sopenharmony_ci } else 4598c2ecf20Sopenharmony_ci return; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_DS_JTAG_DISABLE, 1); 4648c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_WLAN_UART_INTF_EN, 0); 4658c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL, ATH_MCI_CONFIG_MCI_OBS_GPIO); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0); 4688c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1); 4698c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_OBS, 0x4b); 4708c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL1, 0x03); 4718c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL2, 0x01); 4728c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_LSB, 0x02); 4738c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_MSB, 0x03); 4748c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, 4758c2ecf20Sopenharmony_ci AR_PHY_TEST_CTL_DEBUGPORT_SEL, 0x07); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done, 4798c2ecf20Sopenharmony_ci u8 opcode, u32 bt_flags) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci u32 pld[4] = {0, 0, 0, 0}; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci MCI_GPM_SET_TYPE_OPCODE(pld, MCI_GPM_COEX_AGENT, 4848c2ecf20Sopenharmony_ci MCI_GPM_COEX_BT_UPDATE_FLAGS); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP) = opcode; 4878c2ecf20Sopenharmony_ci *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF; 4888c2ecf20Sopenharmony_ci *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 1) = (bt_flags >> 8) & 0xFF; 4898c2ecf20Sopenharmony_ci *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF; 4908c2ecf20Sopenharmony_ci *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, 4938c2ecf20Sopenharmony_ci wait_done, true); 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic void ar9003_mci_sync_bt_state(struct ath_hw *ah) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 4998c2ecf20Sopenharmony_ci u32 cur_bt_state; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (mci->bt_state != cur_bt_state) 5048c2ecf20Sopenharmony_ci mci->bt_state = cur_bt_state; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (mci->bt_state != MCI_BT_SLEEP) { 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci ar9003_mci_send_coex_version_query(ah, true); 5098c2ecf20Sopenharmony_ci ar9003_mci_send_coex_wlan_channels(ah, true); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (mci->unhalt_bt_gpm == true) 5128c2ecf20Sopenharmony_ci ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_civoid ar9003_mci_check_bt(struct ath_hw *ah) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (!mci_hw->ready) 5218c2ecf20Sopenharmony_ci return; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* 5248c2ecf20Sopenharmony_ci * check BT state again to make 5258c2ecf20Sopenharmony_ci * sure it's not changed. 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_ci ar9003_mci_sync_bt_state(ah); 5288c2ecf20Sopenharmony_ci ar9003_mci_2g5g_switch(ah, true); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if ((mci_hw->bt_state == MCI_BT_AWAKE) && 5318c2ecf20Sopenharmony_ci (mci_hw->query_bt == true)) { 5328c2ecf20Sopenharmony_ci mci_hw->need_flush_btinfo = true; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type, 5378c2ecf20Sopenharmony_ci u8 gpm_opcode, u32 *p_gpm) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 5408c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 5418c2ecf20Sopenharmony_ci u8 *p_data = (u8 *) p_gpm; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (gpm_type != MCI_GPM_COEX_AGENT) 5448c2ecf20Sopenharmony_ci return; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci switch (gpm_opcode) { 5478c2ecf20Sopenharmony_ci case MCI_GPM_COEX_VERSION_QUERY: 5488c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n"); 5498c2ecf20Sopenharmony_ci ar9003_mci_send_coex_version_response(ah, true); 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci case MCI_GPM_COEX_VERSION_RESPONSE: 5528c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n"); 5538c2ecf20Sopenharmony_ci mci->bt_ver_major = 5548c2ecf20Sopenharmony_ci *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION); 5558c2ecf20Sopenharmony_ci mci->bt_ver_minor = 5568c2ecf20Sopenharmony_ci *(p_data + MCI_GPM_COEX_B_MINOR_VERSION); 5578c2ecf20Sopenharmony_ci mci->bt_version_known = true; 5588c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n", 5598c2ecf20Sopenharmony_ci mci->bt_ver_major, mci->bt_ver_minor); 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci case MCI_GPM_COEX_STATUS_QUERY: 5628c2ecf20Sopenharmony_ci ath_dbg(common, MCI, 5638c2ecf20Sopenharmony_ci "MCI Recv GPM COEX Status Query = 0x%02X\n", 5648c2ecf20Sopenharmony_ci *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP)); 5658c2ecf20Sopenharmony_ci mci->wlan_channels_update = true; 5668c2ecf20Sopenharmony_ci ar9003_mci_send_coex_wlan_channels(ah, true); 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci case MCI_GPM_COEX_BT_PROFILE_INFO: 5698c2ecf20Sopenharmony_ci mci->query_bt = true; 5708c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n"); 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci case MCI_GPM_COEX_BT_STATUS_UPDATE: 5738c2ecf20Sopenharmony_ci mci->query_bt = true; 5748c2ecf20Sopenharmony_ci ath_dbg(common, MCI, 5758c2ecf20Sopenharmony_ci "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n", 5768c2ecf20Sopenharmony_ci *(p_gpm + 3)); 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci default: 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, 5848c2ecf20Sopenharmony_ci u8 gpm_opcode, int time_out) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 5878c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 5888c2ecf20Sopenharmony_ci u32 *p_gpm = NULL, mismatch = 0, more_data; 5898c2ecf20Sopenharmony_ci u32 offset; 5908c2ecf20Sopenharmony_ci u8 recv_type = 0, recv_opcode = 0; 5918c2ecf20Sopenharmony_ci bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci while (time_out > 0) { 5968c2ecf20Sopenharmony_ci if (p_gpm) { 5978c2ecf20Sopenharmony_ci MCI_GPM_RECYCLE(p_gpm); 5988c2ecf20Sopenharmony_ci p_gpm = NULL; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (more_data != MCI_GPM_MORE) 6028c2ecf20Sopenharmony_ci time_out = ar9003_mci_wait_for_interrupt(ah, 6038c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_RAW, 6048c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_GPM, 6058c2ecf20Sopenharmony_ci time_out); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (!time_out) 6088c2ecf20Sopenharmony_ci break; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci offset = ar9003_mci_get_next_gpm_offset(ah, &more_data); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (offset == MCI_GPM_INVALID) 6138c2ecf20Sopenharmony_ci continue; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci p_gpm = (u32 *) (mci->gpm_buf + offset); 6168c2ecf20Sopenharmony_ci recv_type = MCI_GPM_TYPE(p_gpm); 6178c2ecf20Sopenharmony_ci recv_opcode = MCI_GPM_OPCODE(p_gpm); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (MCI_GPM_IS_CAL_TYPE(recv_type)) { 6208c2ecf20Sopenharmony_ci if (recv_type == gpm_type) { 6218c2ecf20Sopenharmony_ci if ((gpm_type == MCI_GPM_BT_CAL_DONE) && 6228c2ecf20Sopenharmony_ci !b_is_bt_cal_done) { 6238c2ecf20Sopenharmony_ci gpm_type = MCI_GPM_BT_CAL_GRANT; 6248c2ecf20Sopenharmony_ci continue; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci } else if ((recv_type == gpm_type) && 6298c2ecf20Sopenharmony_ci (recv_opcode == gpm_opcode)) 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* 6338c2ecf20Sopenharmony_ci * check if it's cal_grant 6348c2ecf20Sopenharmony_ci * 6358c2ecf20Sopenharmony_ci * When we're waiting for cal_grant in reset routine, 6368c2ecf20Sopenharmony_ci * it's possible that BT sends out cal_request at the 6378c2ecf20Sopenharmony_ci * same time. Since BT's calibration doesn't happen 6388c2ecf20Sopenharmony_ci * that often, we'll let BT completes calibration then 6398c2ecf20Sopenharmony_ci * we continue to wait for cal_grant from BT. 6408c2ecf20Sopenharmony_ci * Orginal: Wait BT_CAL_GRANT. 6418c2ecf20Sopenharmony_ci * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait 6428c2ecf20Sopenharmony_ci * BT_CAL_DONE -> Wait BT_CAL_GRANT. 6438c2ecf20Sopenharmony_ci */ 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if ((gpm_type == MCI_GPM_BT_CAL_GRANT) && 6468c2ecf20Sopenharmony_ci (recv_type == MCI_GPM_BT_CAL_REQ)) { 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci u32 payload[4] = {0, 0, 0, 0}; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci gpm_type = MCI_GPM_BT_CAL_DONE; 6518c2ecf20Sopenharmony_ci MCI_GPM_SET_CAL_TYPE(payload, 6528c2ecf20Sopenharmony_ci MCI_GPM_WLAN_CAL_GRANT); 6538c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, 6548c2ecf20Sopenharmony_ci false, false); 6558c2ecf20Sopenharmony_ci continue; 6568c2ecf20Sopenharmony_ci } else { 6578c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n", 6588c2ecf20Sopenharmony_ci *(p_gpm + 1)); 6598c2ecf20Sopenharmony_ci mismatch++; 6608c2ecf20Sopenharmony_ci ar9003_mci_process_gpm_extra(ah, recv_type, 6618c2ecf20Sopenharmony_ci recv_opcode, p_gpm); 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (p_gpm) { 6668c2ecf20Sopenharmony_ci MCI_GPM_RECYCLE(p_gpm); 6678c2ecf20Sopenharmony_ci p_gpm = NULL; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (time_out <= 0) 6718c2ecf20Sopenharmony_ci time_out = 0; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci while (more_data == MCI_GPM_MORE) { 6748c2ecf20Sopenharmony_ci offset = ar9003_mci_get_next_gpm_offset(ah, &more_data); 6758c2ecf20Sopenharmony_ci if (offset == MCI_GPM_INVALID) 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci p_gpm = (u32 *) (mci->gpm_buf + offset); 6798c2ecf20Sopenharmony_ci recv_type = MCI_GPM_TYPE(p_gpm); 6808c2ecf20Sopenharmony_ci recv_opcode = MCI_GPM_OPCODE(p_gpm); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (!MCI_GPM_IS_CAL_TYPE(recv_type)) 6838c2ecf20Sopenharmony_ci ar9003_mci_process_gpm_extra(ah, recv_type, 6848c2ecf20Sopenharmony_ci recv_opcode, p_gpm); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci MCI_GPM_RECYCLE(p_gpm); 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci return time_out; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cibool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 6958c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 6968c2ecf20Sopenharmony_ci u32 payload[4] = {0, 0, 0, 0}; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan)); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (mci_hw->bt_state != MCI_BT_CAL_START) 7018c2ecf20Sopenharmony_ci return false; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci mci_hw->bt_state = MCI_BT_CAL; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* 7068c2ecf20Sopenharmony_ci * MCI FIX: disable mci interrupt here. This is to avoid 7078c2ecf20Sopenharmony_ci * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and 7088c2ecf20Sopenharmony_ci * lead to mci_intr reentry. 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_ci ar9003_mci_disable_interrupt(ah); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); 7138c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 7148c2ecf20Sopenharmony_ci 16, true, false); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* Wait BT calibration to be completed for 25ms */ 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 7198c2ecf20Sopenharmony_ci 0, 25000)) 7208c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n"); 7218c2ecf20Sopenharmony_ci else 7228c2ecf20Sopenharmony_ci ath_dbg(common, MCI, 7238c2ecf20Sopenharmony_ci "MCI BT_CAL_DONE not received\n"); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci mci_hw->bt_state = MCI_BT_AWAKE; 7268c2ecf20Sopenharmony_ci /* MCI FIX: enable mci interrupt here */ 7278c2ecf20Sopenharmony_ci ar9003_mci_enable_interrupt(ah); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return true; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ciint ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, 7338c2ecf20Sopenharmony_ci struct ath9k_hw_cal_data *caldata) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (!mci_hw->ready) 7388c2ecf20Sopenharmony_ci return 0; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP)) 7418c2ecf20Sopenharmony_ci goto exit; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (!ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) && 7448c2ecf20Sopenharmony_ci !ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) 7458c2ecf20Sopenharmony_ci goto exit; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* 7488c2ecf20Sopenharmony_ci * BT is sleeping. Check if BT wakes up during 7498c2ecf20Sopenharmony_ci * WLAN calibration. If BT wakes up during 7508c2ecf20Sopenharmony_ci * WLAN calibration, need to go through all 7518c2ecf20Sopenharmony_ci * message exchanges again and recal. 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 7548c2ecf20Sopenharmony_ci (AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | 7558c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci ar9003_mci_remote_reset(ah, true); 7588c2ecf20Sopenharmony_ci ar9003_mci_send_sys_waking(ah, true); 7598c2ecf20Sopenharmony_ci udelay(1); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (IS_CHAN_2GHZ(chan)) 7628c2ecf20Sopenharmony_ci ar9003_mci_send_lna_transfer(ah, true); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci mci_hw->bt_state = MCI_BT_AWAKE; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_TIMING4, 7678c2ecf20Sopenharmony_ci 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (caldata) { 7708c2ecf20Sopenharmony_ci clear_bit(TXIQCAL_DONE, &caldata->cal_flags); 7718c2ecf20Sopenharmony_ci clear_bit(TXCLCAL_DONE, &caldata->cal_flags); 7728c2ecf20Sopenharmony_ci clear_bit(RTT_DONE, &caldata->cal_flags); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (!ath9k_hw_init_cal(ah, chan)) 7768c2ecf20Sopenharmony_ci return -EIO; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_TIMING4, 7798c2ecf20Sopenharmony_ci 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ciexit: 7828c2ecf20Sopenharmony_ci ar9003_mci_enable_interrupt(ah); 7838c2ecf20Sopenharmony_ci return 0; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic void ar9003_mci_mute_bt(struct ath_hw *ah) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci /* disable all MCI messages */ 7918c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000); 7928c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff); 7938c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff); 7948c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff); 7958c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff); 7968c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci /* wait pending HW messages to flush out */ 7998c2ecf20Sopenharmony_ci udelay(10); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci /* 8028c2ecf20Sopenharmony_ci * Send LNA_TAKE and SYS_SLEEPING when 8038c2ecf20Sopenharmony_ci * 1. reset not after resuming from full sleep 8048c2ecf20Sopenharmony_ci * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment 8058c2ecf20Sopenharmony_ci */ 8068c2ecf20Sopenharmony_ci if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { 8078c2ecf20Sopenharmony_ci ar9003_mci_send_lna_take(ah, true); 8088c2ecf20Sopenharmony_ci udelay(5); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci ar9003_mci_send_sys_sleeping(ah, true); 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 8178c2ecf20Sopenharmony_ci u32 thresh; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (!enable) { 8208c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_BTCOEX_CTRL, 8218c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); 8228c2ecf20Sopenharmony_ci return; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, AR_MCI_SCHD_TABLE_2_HW_BASED, 1); 8258c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, 8268c2ecf20Sopenharmony_ci AR_MCI_SCHD_TABLE_2_MEM_BASED, 1); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (AR_SREV_9565(ah)) 8298c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MCI_MISC, AR_MCI_MISC_HW_FIX_EN, 1); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) { 8328c2ecf20Sopenharmony_ci thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH); 8338c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, 8348c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL_AGGR_THRESH, thresh); 8358c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, 8368c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1); 8378c2ecf20Sopenharmony_ci } else 8388c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, 8398c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, 8428c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1); 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic void ar9003_mci_stat_setup(struct ath_hw *ah) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (!AR_SREV_9565(ah)) 8508c2ecf20Sopenharmony_ci return; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (mci->config & ATH_MCI_CONFIG_MCI_STAT_DBG) { 8538c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, 8548c2ecf20Sopenharmony_ci AR_MCI_DBG_CNT_CTRL_ENABLE, 1); 8558c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, 8568c2ecf20Sopenharmony_ci AR_MCI_DBG_CNT_CTRL_BT_LINKID, 8578c2ecf20Sopenharmony_ci MCI_STAT_ALL_BT_LINKID); 8588c2ecf20Sopenharmony_ci } else { 8598c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, 8608c2ecf20Sopenharmony_ci AR_MCI_DBG_CNT_CTRL_ENABLE, 0); 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic void ar9003_mci_set_btcoex_ctrl_9565_1ANT(struct ath_hw *ah) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci u32 regval; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | 8698c2ecf20Sopenharmony_ci SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | 8708c2ecf20Sopenharmony_ci SM(1, AR_BTCOEX_CTRL_PA_SHARED) | 8718c2ecf20Sopenharmony_ci SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | 8728c2ecf20Sopenharmony_ci SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) | 8738c2ecf20Sopenharmony_ci SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | 8748c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | 8758c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | 8768c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, 8798c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1); 8808c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_CTRL, regval); 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic void ar9003_mci_set_btcoex_ctrl_9565_2ANT(struct ath_hw *ah) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci u32 regval; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | 8888c2ecf20Sopenharmony_ci SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | 8898c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_PA_SHARED) | 8908c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_LNA_SHARED) | 8918c2ecf20Sopenharmony_ci SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | 8928c2ecf20Sopenharmony_ci SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | 8938c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | 8948c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | 8958c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, 8988c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x0); 8998c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_CTRL, regval); 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic void ar9003_mci_set_btcoex_ctrl_9462(struct ath_hw *ah) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci u32 regval; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | 9078c2ecf20Sopenharmony_ci SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | 9088c2ecf20Sopenharmony_ci SM(1, AR_BTCOEX_CTRL_PA_SHARED) | 9098c2ecf20Sopenharmony_ci SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | 9108c2ecf20Sopenharmony_ci SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | 9118c2ecf20Sopenharmony_ci SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | 9128c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | 9138c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | 9148c2ecf20Sopenharmony_ci SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_CTRL, regval); 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ciint ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, 9208c2ecf20Sopenharmony_ci bool is_full_sleep) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 9238c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 9248c2ecf20Sopenharmony_ci u32 regval, i; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n", 9278c2ecf20Sopenharmony_ci is_full_sleep, is_2g); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) { 9308c2ecf20Sopenharmony_ci ath_err(common, "BTCOEX control register is dead\n"); 9318c2ecf20Sopenharmony_ci return -EINVAL; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* Program MCI DMA related registers */ 9358c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr); 9368c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len); 9378c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci /* 9408c2ecf20Sopenharmony_ci * To avoid MCI state machine be affected by incoming remote MCI msgs, 9418c2ecf20Sopenharmony_ci * MCI mode will be enabled later, right before reset the MCI TX and RX. 9428c2ecf20Sopenharmony_ci */ 9438c2ecf20Sopenharmony_ci if (AR_SREV_9565(ah)) { 9448c2ecf20Sopenharmony_ci u8 ant = MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci if (ant == ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED) 9478c2ecf20Sopenharmony_ci ar9003_mci_set_btcoex_ctrl_9565_1ANT(ah); 9488c2ecf20Sopenharmony_ci else 9498c2ecf20Sopenharmony_ci ar9003_mci_set_btcoex_ctrl_9565_2ANT(ah); 9508c2ecf20Sopenharmony_ci } else { 9518c2ecf20Sopenharmony_ci ar9003_mci_set_btcoex_ctrl_9462(ah); 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) 9558c2ecf20Sopenharmony_ci ar9003_mci_osla_setup(ah, true); 9568c2ecf20Sopenharmony_ci else 9578c2ecf20Sopenharmony_ci ar9003_mci_osla_setup(ah, false); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, 9608c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL_SPDT_ENABLE); 9618c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3, 9628c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 0); 9658c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* Set the time out to 3.125ms (5 BT slots) */ 9688c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_WL_LNA, AR_BTCOEX_WL_LNA_TIMEOUT, 0x3D090); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci /* concurrent tx priority */ 9718c2ecf20Sopenharmony_ci if (mci->config & ATH_MCI_CONFIG_CONCUR_TX) { 9728c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, 9738c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE, 0); 9748c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, 9758c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL2_TXPWR_THRESH, 0x7f); 9768c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, 9778c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL_REDUCE_TXPWR, 0); 9788c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 9798c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_MAX_TXPWR(i), 0x7f7f7f7f); 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV); 9838c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval); 9848c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* Resetting the Rx and Tx paths of MCI */ 9878c2ecf20Sopenharmony_ci regval = REG_READ(ah, AR_MCI_COMMAND2); 9888c2ecf20Sopenharmony_ci regval |= SM(1, AR_MCI_COMMAND2_RESET_TX); 9898c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_COMMAND2, regval); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci udelay(1); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX); 9948c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_COMMAND2, regval); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (is_full_sleep) { 9978c2ecf20Sopenharmony_ci ar9003_mci_mute_bt(ah); 9988c2ecf20Sopenharmony_ci udelay(100); 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* Check pending GPM msg before MCI Reset Rx */ 10028c2ecf20Sopenharmony_ci ar9003_mci_check_gpm_offset(ah); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci regval |= SM(1, AR_MCI_COMMAND2_RESET_RX); 10058c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_COMMAND2, regval); 10068c2ecf20Sopenharmony_ci udelay(1); 10078c2ecf20Sopenharmony_ci regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX); 10088c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_COMMAND2, regval); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* Init GPM offset after MCI Reset Rx */ 10118c2ecf20Sopenharmony_ci ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 10148c2ecf20Sopenharmony_ci (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | 10158c2ecf20Sopenharmony_ci SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM))); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) 10188c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_MCI_TX_CTRL, 10198c2ecf20Sopenharmony_ci AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); 10208c2ecf20Sopenharmony_ci else 10218c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_MCI_TX_CTRL, 10228c2ecf20Sopenharmony_ci AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci ar9003_mci_observation_set_up(ah); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci mci->ready = true; 10278c2ecf20Sopenharmony_ci ar9003_mci_prep_interface(ah); 10288c2ecf20Sopenharmony_ci ar9003_mci_stat_setup(ah); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (en_int) 10318c2ecf20Sopenharmony_ci ar9003_mci_enable_interrupt(ah); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (ath9k_hw_is_aic_enabled(ah)) 10348c2ecf20Sopenharmony_ci ar9003_aic_start_normal(ah); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci return 0; 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_civoid ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci ar9003_mci_disable_interrupt(ah); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (mci_hw->ready && !save_fullsleep) { 10468c2ecf20Sopenharmony_ci ar9003_mci_mute_bt(ah); 10478c2ecf20Sopenharmony_ci udelay(20); 10488c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_CTRL, 0); 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci mci_hw->bt_state = MCI_BT_SLEEP; 10528c2ecf20Sopenharmony_ci mci_hw->ready = false; 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_cistatic void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 10588c2ecf20Sopenharmony_ci u32 to_set, to_clear; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP)) 10618c2ecf20Sopenharmony_ci return; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (mci->is_2g) { 10648c2ecf20Sopenharmony_ci to_clear = MCI_2G_FLAGS_CLEAR_MASK; 10658c2ecf20Sopenharmony_ci to_set = MCI_2G_FLAGS_SET_MASK; 10668c2ecf20Sopenharmony_ci } else { 10678c2ecf20Sopenharmony_ci to_clear = MCI_5G_FLAGS_CLEAR_MASK; 10688c2ecf20Sopenharmony_ci to_set = MCI_5G_FLAGS_SET_MASK; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (to_clear) 10728c2ecf20Sopenharmony_ci ar9003_mci_send_coex_bt_flags(ah, wait_done, 10738c2ecf20Sopenharmony_ci MCI_GPM_COEX_BT_FLAGS_CLEAR, 10748c2ecf20Sopenharmony_ci to_clear); 10758c2ecf20Sopenharmony_ci if (to_set) 10768c2ecf20Sopenharmony_ci ar9003_mci_send_coex_bt_flags(ah, wait_done, 10778c2ecf20Sopenharmony_ci MCI_GPM_COEX_BT_FLAGS_SET, 10788c2ecf20Sopenharmony_ci to_set); 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cistatic void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header, 10828c2ecf20Sopenharmony_ci u32 *payload, bool queue) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 10858c2ecf20Sopenharmony_ci u8 type, opcode; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* check if the message is to be queued */ 10888c2ecf20Sopenharmony_ci if (header != MCI_GPM) 10898c2ecf20Sopenharmony_ci return; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci type = MCI_GPM_TYPE(payload); 10928c2ecf20Sopenharmony_ci opcode = MCI_GPM_OPCODE(payload); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (type != MCI_GPM_COEX_AGENT) 10958c2ecf20Sopenharmony_ci return; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci switch (opcode) { 10988c2ecf20Sopenharmony_ci case MCI_GPM_COEX_BT_UPDATE_FLAGS: 10998c2ecf20Sopenharmony_ci if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) == 11008c2ecf20Sopenharmony_ci MCI_GPM_COEX_BT_FLAGS_READ) 11018c2ecf20Sopenharmony_ci break; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci mci->update_2g5g = queue; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci case MCI_GPM_COEX_WLAN_CHANNELS: 11078c2ecf20Sopenharmony_ci mci->wlan_channels_update = queue; 11088c2ecf20Sopenharmony_ci break; 11098c2ecf20Sopenharmony_ci case MCI_GPM_COEX_HALT_BT_GPM: 11108c2ecf20Sopenharmony_ci if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == 11118c2ecf20Sopenharmony_ci MCI_GPM_COEX_BT_GPM_UNHALT) { 11128c2ecf20Sopenharmony_ci mci->unhalt_bt_gpm = queue; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (!queue) 11158c2ecf20Sopenharmony_ci mci->halted_bt_gpm = false; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == 11198c2ecf20Sopenharmony_ci MCI_GPM_COEX_BT_GPM_HALT) { 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci mci->halted_bt_gpm = !queue; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci break; 11258c2ecf20Sopenharmony_ci default: 11268c2ecf20Sopenharmony_ci break; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_civoid ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci if (!mci->update_2g5g && !force) 11358c2ecf20Sopenharmony_ci return; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (mci->is_2g) { 11388c2ecf20Sopenharmony_ci ar9003_mci_send_2g5g_status(ah, true); 11398c2ecf20Sopenharmony_ci ar9003_mci_send_lna_transfer(ah, true); 11408c2ecf20Sopenharmony_ci udelay(5); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_MCI_TX_CTRL, 11438c2ecf20Sopenharmony_ci AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); 11448c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL, 11458c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) 11488c2ecf20Sopenharmony_ci ar9003_mci_osla_setup(ah, true); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci if (AR_SREV_9462(ah)) 11518c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_SELFGEN_MASK, 0x02); 11528c2ecf20Sopenharmony_ci } else { 11538c2ecf20Sopenharmony_ci ar9003_mci_send_lna_take(ah, true); 11548c2ecf20Sopenharmony_ci udelay(5); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_MCI_TX_CTRL, 11578c2ecf20Sopenharmony_ci AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); 11588c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, 11598c2ecf20Sopenharmony_ci AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci ar9003_mci_osla_setup(ah, false); 11628c2ecf20Sopenharmony_ci ar9003_mci_send_2g5g_status(ah, true); 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci} 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_cibool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, 11678c2ecf20Sopenharmony_ci u32 *payload, u8 len, bool wait_done, 11688c2ecf20Sopenharmony_ci bool check_bt) 11698c2ecf20Sopenharmony_ci{ 11708c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 11718c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 11728c2ecf20Sopenharmony_ci bool msg_sent = false; 11738c2ecf20Sopenharmony_ci u32 regval; 11748c2ecf20Sopenharmony_ci u32 saved_mci_int_en; 11758c2ecf20Sopenharmony_ci int i; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); 11788c2ecf20Sopenharmony_ci regval = REG_READ(ah, AR_BTCOEX_CTRL); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) { 11818c2ecf20Sopenharmony_ci ath_dbg(common, MCI, 11828c2ecf20Sopenharmony_ci "MCI Not sending 0x%x. MCI is not enabled. full_sleep = %d\n", 11838c2ecf20Sopenharmony_ci header, (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0); 11848c2ecf20Sopenharmony_ci ar9003_mci_queue_unsent_gpm(ah, header, payload, true); 11858c2ecf20Sopenharmony_ci return false; 11868c2ecf20Sopenharmony_ci } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) { 11878c2ecf20Sopenharmony_ci ath_dbg(common, MCI, 11888c2ecf20Sopenharmony_ci "MCI Don't send message 0x%x. BT is in sleep state\n", 11898c2ecf20Sopenharmony_ci header); 11908c2ecf20Sopenharmony_ci ar9003_mci_queue_unsent_gpm(ah, header, payload, true); 11918c2ecf20Sopenharmony_ci return false; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci if (wait_done) 11958c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci /* Need to clear SW_MSG_DONE raw bit before wait */ 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, 12008c2ecf20Sopenharmony_ci (AR_MCI_INTERRUPT_SW_MSG_DONE | 12018c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_MSG_FAIL_MASK)); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (payload) { 12048c2ecf20Sopenharmony_ci for (i = 0; (i * 4) < len; i++) 12058c2ecf20Sopenharmony_ci REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4), 12068c2ecf20Sopenharmony_ci *(payload + i)); 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_COMMAND0, 12108c2ecf20Sopenharmony_ci (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP), 12118c2ecf20Sopenharmony_ci AR_MCI_COMMAND0_DISABLE_TIMESTAMP) | 12128c2ecf20Sopenharmony_ci SM(len, AR_MCI_COMMAND0_LEN) | 12138c2ecf20Sopenharmony_ci SM(header, AR_MCI_COMMAND0_HEADER))); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (wait_done && 12168c2ecf20Sopenharmony_ci !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW, 12178c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_SW_MSG_DONE, 500))) 12188c2ecf20Sopenharmony_ci ar9003_mci_queue_unsent_gpm(ah, header, payload, true); 12198c2ecf20Sopenharmony_ci else { 12208c2ecf20Sopenharmony_ci ar9003_mci_queue_unsent_gpm(ah, header, payload, false); 12218c2ecf20Sopenharmony_ci msg_sent = true; 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (wait_done) 12258c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci return msg_sent; 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ar9003_mci_send_message); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_civoid ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable) 12328c2ecf20Sopenharmony_ci{ 12338c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 12348c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 12358c2ecf20Sopenharmony_ci u32 pld[4] = {0, 0, 0, 0}; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if ((mci_hw->bt_state != MCI_BT_AWAKE) || 12388c2ecf20Sopenharmony_ci (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) 12398c2ecf20Sopenharmony_ci return; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ); 12428c2ecf20Sopenharmony_ci pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) { 12478c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n"); 12488c2ecf20Sopenharmony_ci } else { 12498c2ecf20Sopenharmony_ci *is_reusable = false; 12508c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n"); 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_civoid ar9003_mci_init_cal_done(struct ath_hw *ah) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 12578c2ecf20Sopenharmony_ci u32 pld[4] = {0, 0, 0, 0}; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if ((mci_hw->bt_state != MCI_BT_AWAKE) || 12608c2ecf20Sopenharmony_ci (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) 12618c2ecf20Sopenharmony_ci return; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE); 12648c2ecf20Sopenharmony_ci pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++; 12658c2ecf20Sopenharmony_ci ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ciint ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, 12698c2ecf20Sopenharmony_ci u16 len, u32 sched_addr) 12708c2ecf20Sopenharmony_ci{ 12718c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci mci->gpm_addr = gpm_addr; 12748c2ecf20Sopenharmony_ci mci->gpm_buf = gpm_buf; 12758c2ecf20Sopenharmony_ci mci->gpm_len = len; 12768c2ecf20Sopenharmony_ci mci->sched_addr = sched_addr; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci return ar9003_mci_reset(ah, true, true, true); 12798c2ecf20Sopenharmony_ci} 12808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ar9003_mci_setup); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_civoid ar9003_mci_cleanup(struct ath_hw *ah) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci /* Turn off MCI and Jupiter mode. */ 12858c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00); 12868c2ecf20Sopenharmony_ci ar9003_mci_disable_interrupt(ah); 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ar9003_mci_cleanup); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ciu32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 12938c2ecf20Sopenharmony_ci u32 value = 0, tsf; 12948c2ecf20Sopenharmony_ci u8 query_type; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci switch (state_type) { 12978c2ecf20Sopenharmony_ci case MCI_STATE_ENABLE: 12988c2ecf20Sopenharmony_ci if (mci->ready) { 12998c2ecf20Sopenharmony_ci value = REG_READ(ah, AR_BTCOEX_CTRL); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci if ((value == 0xdeadbeef) || (value == 0xffffffff)) 13028c2ecf20Sopenharmony_ci value = 0; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci value &= AR_BTCOEX_CTRL_MCI_MODE_EN; 13058c2ecf20Sopenharmony_ci break; 13068c2ecf20Sopenharmony_ci case MCI_STATE_INIT_GPM_OFFSET: 13078c2ecf20Sopenharmony_ci value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (value < mci->gpm_len) 13108c2ecf20Sopenharmony_ci mci->gpm_idx = value; 13118c2ecf20Sopenharmony_ci else 13128c2ecf20Sopenharmony_ci mci->gpm_idx = 0; 13138c2ecf20Sopenharmony_ci break; 13148c2ecf20Sopenharmony_ci case MCI_STATE_LAST_SCHD_MSG_OFFSET: 13158c2ecf20Sopenharmony_ci value = MS(REG_READ(ah, AR_MCI_RX_STATUS), 13168c2ecf20Sopenharmony_ci AR_MCI_RX_LAST_SCHD_MSG_INDEX); 13178c2ecf20Sopenharmony_ci /* Make it in bytes */ 13188c2ecf20Sopenharmony_ci value <<= 4; 13198c2ecf20Sopenharmony_ci break; 13208c2ecf20Sopenharmony_ci case MCI_STATE_REMOTE_SLEEP: 13218c2ecf20Sopenharmony_ci value = MS(REG_READ(ah, AR_MCI_RX_STATUS), 13228c2ecf20Sopenharmony_ci AR_MCI_RX_REMOTE_SLEEP) ? 13238c2ecf20Sopenharmony_ci MCI_BT_SLEEP : MCI_BT_AWAKE; 13248c2ecf20Sopenharmony_ci break; 13258c2ecf20Sopenharmony_ci case MCI_STATE_SET_BT_AWAKE: 13268c2ecf20Sopenharmony_ci mci->bt_state = MCI_BT_AWAKE; 13278c2ecf20Sopenharmony_ci ar9003_mci_send_coex_version_query(ah, true); 13288c2ecf20Sopenharmony_ci ar9003_mci_send_coex_wlan_channels(ah, true); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci if (mci->unhalt_bt_gpm) 13318c2ecf20Sopenharmony_ci ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci ar9003_mci_2g5g_switch(ah, false); 13348c2ecf20Sopenharmony_ci break; 13358c2ecf20Sopenharmony_ci case MCI_STATE_RESET_REQ_WAKE: 13368c2ecf20Sopenharmony_ci ar9003_mci_reset_req_wakeup(ah); 13378c2ecf20Sopenharmony_ci mci->update_2g5g = true; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) { 13408c2ecf20Sopenharmony_ci /* Check if we still have control of the GPIOs */ 13418c2ecf20Sopenharmony_ci if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) & 13428c2ecf20Sopenharmony_ci ATH_MCI_CONFIG_MCI_OBS_GPIO) != 13438c2ecf20Sopenharmony_ci ATH_MCI_CONFIG_MCI_OBS_GPIO) { 13448c2ecf20Sopenharmony_ci ar9003_mci_observation_set_up(ah); 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci break; 13488c2ecf20Sopenharmony_ci case MCI_STATE_SEND_WLAN_COEX_VERSION: 13498c2ecf20Sopenharmony_ci ar9003_mci_send_coex_version_response(ah, true); 13508c2ecf20Sopenharmony_ci break; 13518c2ecf20Sopenharmony_ci case MCI_STATE_SEND_VERSION_QUERY: 13528c2ecf20Sopenharmony_ci ar9003_mci_send_coex_version_query(ah, true); 13538c2ecf20Sopenharmony_ci break; 13548c2ecf20Sopenharmony_ci case MCI_STATE_SEND_STATUS_QUERY: 13558c2ecf20Sopenharmony_ci query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY; 13568c2ecf20Sopenharmony_ci ar9003_mci_send_coex_bt_status_query(ah, true, query_type); 13578c2ecf20Sopenharmony_ci break; 13588c2ecf20Sopenharmony_ci case MCI_STATE_RECOVER_RX: 13598c2ecf20Sopenharmony_ci tsf = ath9k_hw_gettsf32(ah); 13608c2ecf20Sopenharmony_ci if ((tsf - mci->last_recovery) <= MCI_RECOVERY_DUR_TSF) { 13618c2ecf20Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), MCI, 13628c2ecf20Sopenharmony_ci "(MCI) ignore Rx recovery\n"); 13638c2ecf20Sopenharmony_ci break; 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), MCI, "(MCI) RECOVER RX\n"); 13668c2ecf20Sopenharmony_ci mci->last_recovery = tsf; 13678c2ecf20Sopenharmony_ci ar9003_mci_prep_interface(ah); 13688c2ecf20Sopenharmony_ci mci->query_bt = true; 13698c2ecf20Sopenharmony_ci mci->need_flush_btinfo = true; 13708c2ecf20Sopenharmony_ci ar9003_mci_send_coex_wlan_channels(ah, true); 13718c2ecf20Sopenharmony_ci ar9003_mci_2g5g_switch(ah, false); 13728c2ecf20Sopenharmony_ci break; 13738c2ecf20Sopenharmony_ci case MCI_STATE_NEED_FTP_STOMP: 13748c2ecf20Sopenharmony_ci value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); 13758c2ecf20Sopenharmony_ci break; 13768c2ecf20Sopenharmony_ci case MCI_STATE_NEED_FLUSH_BT_INFO: 13778c2ecf20Sopenharmony_ci value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; 13788c2ecf20Sopenharmony_ci mci->need_flush_btinfo = false; 13798c2ecf20Sopenharmony_ci break; 13808c2ecf20Sopenharmony_ci case MCI_STATE_AIC_CAL: 13818c2ecf20Sopenharmony_ci if (ath9k_hw_is_aic_enabled(ah)) 13828c2ecf20Sopenharmony_ci value = ar9003_aic_calibration(ah); 13838c2ecf20Sopenharmony_ci break; 13848c2ecf20Sopenharmony_ci case MCI_STATE_AIC_START: 13858c2ecf20Sopenharmony_ci if (ath9k_hw_is_aic_enabled(ah)) 13868c2ecf20Sopenharmony_ci ar9003_aic_start_normal(ah); 13878c2ecf20Sopenharmony_ci break; 13888c2ecf20Sopenharmony_ci case MCI_STATE_AIC_CAL_RESET: 13898c2ecf20Sopenharmony_ci if (ath9k_hw_is_aic_enabled(ah)) 13908c2ecf20Sopenharmony_ci value = ar9003_aic_cal_reset(ah); 13918c2ecf20Sopenharmony_ci break; 13928c2ecf20Sopenharmony_ci case MCI_STATE_AIC_CAL_SINGLE: 13938c2ecf20Sopenharmony_ci if (ath9k_hw_is_aic_enabled(ah)) 13948c2ecf20Sopenharmony_ci value = ar9003_aic_calibration_single(ah); 13958c2ecf20Sopenharmony_ci break; 13968c2ecf20Sopenharmony_ci default: 13978c2ecf20Sopenharmony_ci break; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci return value; 14018c2ecf20Sopenharmony_ci} 14028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ar9003_mci_state); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_civoid ar9003_mci_bt_gain_ctrl(struct ath_hw *ah) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 14078c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "Give LNA and SPDT control to BT\n"); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci ar9003_mci_send_lna_take(ah, true); 14128c2ecf20Sopenharmony_ci udelay(50); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); 14158c2ecf20Sopenharmony_ci mci->is_2g = false; 14168c2ecf20Sopenharmony_ci mci->update_2g5g = true; 14178c2ecf20Sopenharmony_ci ar9003_mci_send_2g5g_status(ah, true); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci /* Force another 2g5g update at next scanning */ 14208c2ecf20Sopenharmony_ci mci->update_2g5g = true; 14218c2ecf20Sopenharmony_ci} 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_civoid ar9003_mci_set_power_awake(struct ath_hw *ah) 14248c2ecf20Sopenharmony_ci{ 14258c2ecf20Sopenharmony_ci u32 btcoex_ctrl2, diag_sw; 14268c2ecf20Sopenharmony_ci int i; 14278c2ecf20Sopenharmony_ci u8 lna_ctrl, bt_sleep; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci for (i = 0; i < AH_WAIT_TIMEOUT; i++) { 14308c2ecf20Sopenharmony_ci btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2); 14318c2ecf20Sopenharmony_ci if (btcoex_ctrl2 != 0xdeadbeef) 14328c2ecf20Sopenharmony_ci break; 14338c2ecf20Sopenharmony_ci udelay(AH_TIME_QUANTUM); 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23))); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci for (i = 0; i < AH_WAIT_TIMEOUT; i++) { 14388c2ecf20Sopenharmony_ci diag_sw = REG_READ(ah, AR_DIAG_SW); 14398c2ecf20Sopenharmony_ci if (diag_sw != 0xdeadbeef) 14408c2ecf20Sopenharmony_ci break; 14418c2ecf20Sopenharmony_ci udelay(AH_TIME_QUANTUM); 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18))); 14448c2ecf20Sopenharmony_ci lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3; 14458c2ecf20Sopenharmony_ci bt_sleep = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2); 14488c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_DIAG_SW, diag_sw); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (bt_sleep && (lna_ctrl == 2)) { 14518c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1); 14528c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1); 14538c2ecf20Sopenharmony_ci udelay(50); 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_civoid ar9003_mci_check_gpm_offset(struct ath_hw *ah) 14588c2ecf20Sopenharmony_ci{ 14598c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 14608c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 14618c2ecf20Sopenharmony_ci u32 offset; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci /* 14648c2ecf20Sopenharmony_ci * This should only be called before "MAC Warm Reset" or "MCI Reset Rx". 14658c2ecf20Sopenharmony_ci */ 14668c2ecf20Sopenharmony_ci offset = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); 14678c2ecf20Sopenharmony_ci if (mci->gpm_idx == offset) 14688c2ecf20Sopenharmony_ci return; 14698c2ecf20Sopenharmony_ci ath_dbg(common, MCI, "GPM cached write pointer mismatch %d %d\n", 14708c2ecf20Sopenharmony_ci mci->gpm_idx, offset); 14718c2ecf20Sopenharmony_ci mci->query_bt = true; 14728c2ecf20Sopenharmony_ci mci->need_flush_btinfo = true; 14738c2ecf20Sopenharmony_ci mci->gpm_idx = 0; 14748c2ecf20Sopenharmony_ci} 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ciu32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, u32 *more) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 14798c2ecf20Sopenharmony_ci u32 offset, more_gpm = 0, gpm_ptr; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci /* 14828c2ecf20Sopenharmony_ci * This could be useful to avoid new GPM message interrupt which 14838c2ecf20Sopenharmony_ci * may lead to spurious interrupt after power sleep, or multiple 14848c2ecf20Sopenharmony_ci * entry of ath_mci_intr(). 14858c2ecf20Sopenharmony_ci * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can 14868c2ecf20Sopenharmony_ci * alleviate this effect, but clearing GPM RX interrupt bit is 14878c2ecf20Sopenharmony_ci * safe, because whether this is called from hw or driver code 14888c2ecf20Sopenharmony_ci * there must be an interrupt bit set/triggered initially 14898c2ecf20Sopenharmony_ci */ 14908c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 14918c2ecf20Sopenharmony_ci AR_MCI_INTERRUPT_RX_MSG_GPM); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); 14948c2ecf20Sopenharmony_ci offset = gpm_ptr; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci if (!offset) 14978c2ecf20Sopenharmony_ci offset = mci->gpm_len - 1; 14988c2ecf20Sopenharmony_ci else if (offset >= mci->gpm_len) { 14998c2ecf20Sopenharmony_ci if (offset != 0xFFFF) 15008c2ecf20Sopenharmony_ci offset = 0; 15018c2ecf20Sopenharmony_ci } else { 15028c2ecf20Sopenharmony_ci offset--; 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci if ((offset == 0xFFFF) || (gpm_ptr == mci->gpm_idx)) { 15068c2ecf20Sopenharmony_ci offset = MCI_GPM_INVALID; 15078c2ecf20Sopenharmony_ci more_gpm = MCI_GPM_NOMORE; 15088c2ecf20Sopenharmony_ci goto out; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci for (;;) { 15118c2ecf20Sopenharmony_ci u32 temp_index; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci /* skip reserved GPM if any */ 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci if (offset != mci->gpm_idx) 15168c2ecf20Sopenharmony_ci more_gpm = MCI_GPM_MORE; 15178c2ecf20Sopenharmony_ci else 15188c2ecf20Sopenharmony_ci more_gpm = MCI_GPM_NOMORE; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci temp_index = mci->gpm_idx; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (temp_index >= mci->gpm_len) 15238c2ecf20Sopenharmony_ci temp_index = 0; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci mci->gpm_idx++; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci if (mci->gpm_idx >= mci->gpm_len) 15288c2ecf20Sopenharmony_ci mci->gpm_idx = 0; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci if (ar9003_mci_is_gpm_valid(ah, temp_index)) { 15318c2ecf20Sopenharmony_ci offset = temp_index; 15328c2ecf20Sopenharmony_ci break; 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (more_gpm == MCI_GPM_NOMORE) { 15368c2ecf20Sopenharmony_ci offset = MCI_GPM_INVALID; 15378c2ecf20Sopenharmony_ci break; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (offset != MCI_GPM_INVALID) 15428c2ecf20Sopenharmony_ci offset <<= 4; 15438c2ecf20Sopenharmony_ciout: 15448c2ecf20Sopenharmony_ci if (more) 15458c2ecf20Sopenharmony_ci *more = more_gpm; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci return offset; 15488c2ecf20Sopenharmony_ci} 15498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ar9003_mci_get_next_gpm_offset); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_civoid ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor) 15528c2ecf20Sopenharmony_ci{ 15538c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci mci->bt_ver_major = major; 15568c2ecf20Sopenharmony_ci mci->bt_ver_minor = minor; 15578c2ecf20Sopenharmony_ci mci->bt_version_known = true; 15588c2ecf20Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), MCI, "MCI BT version set: %d.%d\n", 15598c2ecf20Sopenharmony_ci mci->bt_ver_major, mci->bt_ver_minor); 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ar9003_mci_set_bt_version); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_civoid ar9003_mci_send_wlan_channels(struct ath_hw *ah) 15648c2ecf20Sopenharmony_ci{ 15658c2ecf20Sopenharmony_ci struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci mci->wlan_channels_update = true; 15688c2ecf20Sopenharmony_ci ar9003_mci_send_coex_wlan_channels(ah, true); 15698c2ecf20Sopenharmony_ci} 15708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ar9003_mci_send_wlan_channels); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ciu16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode) 15738c2ecf20Sopenharmony_ci{ 15748c2ecf20Sopenharmony_ci if (!ah->btcoex_hw.mci.concur_tx) 15758c2ecf20Sopenharmony_ci goto out; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci if (ctlmode == CTL_2GHT20) 15788c2ecf20Sopenharmony_ci return ATH_BTCOEX_HT20_MAX_TXPOWER; 15798c2ecf20Sopenharmony_ci else if (ctlmode == CTL_2GHT40) 15808c2ecf20Sopenharmony_ci return ATH_BTCOEX_HT40_MAX_TXPOWER; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ciout: 15838c2ecf20Sopenharmony_ci return -1; 15848c2ecf20Sopenharmony_ci} 1585