1bbefb871SMohammed Shafi Shajakhan /* 2bbefb871SMohammed Shafi Shajakhan * Copyright (c) 2008-2011 Atheros Communications Inc. 3bbefb871SMohammed Shafi Shajakhan * 4bbefb871SMohammed Shafi Shajakhan * Permission to use, copy, modify, and/or distribute this software for any 5bbefb871SMohammed Shafi Shajakhan * purpose with or without fee is hereby granted, provided that the above 6bbefb871SMohammed Shafi Shajakhan * copyright notice and this permission notice appear in all copies. 7bbefb871SMohammed Shafi Shajakhan * 8bbefb871SMohammed Shafi Shajakhan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9bbefb871SMohammed Shafi Shajakhan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10bbefb871SMohammed Shafi Shajakhan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11bbefb871SMohammed Shafi Shajakhan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12bbefb871SMohammed Shafi Shajakhan * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13bbefb871SMohammed Shafi Shajakhan * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14bbefb871SMohammed Shafi Shajakhan * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15bbefb871SMohammed Shafi Shajakhan */ 16bbefb871SMohammed Shafi Shajakhan 17bbefb871SMohammed Shafi Shajakhan #include <linux/export.h> 18bbefb871SMohammed Shafi Shajakhan #include "hw.h" 19528e5d36SSujith Manoharan #include "hw-ops.h" 20bbefb871SMohammed Shafi Shajakhan #include "ar9003_phy.h" 21bbefb871SMohammed Shafi Shajakhan #include "ar9003_mci.h" 22b6ab9ae2SSujith Manoharan #include "ar9003_aic.h" 23bbefb871SMohammed Shafi Shajakhan 24bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah) 25bbefb871SMohammed Shafi Shajakhan { 26bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_MCI_COMMAND2, 27bbefb871SMohammed Shafi Shajakhan AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1); 28bbefb871SMohammed Shafi Shajakhan udelay(1); 29bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_MCI_COMMAND2, 30bbefb871SMohammed Shafi Shajakhan AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 0); 31bbefb871SMohammed Shafi Shajakhan } 32bbefb871SMohammed Shafi Shajakhan 33bbefb871SMohammed Shafi Shajakhan static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address, 34bbefb871SMohammed Shafi Shajakhan u32 bit_position, int time_out) 35bbefb871SMohammed Shafi Shajakhan { 36bbefb871SMohammed Shafi Shajakhan struct ath_common *common = ath9k_hw_common(ah); 37bbefb871SMohammed Shafi Shajakhan 38bbefb871SMohammed Shafi Shajakhan while (time_out) { 394f6bd1a8SRajkumar Manoharan if (!(REG_READ(ah, address) & bit_position)) { 40bbefb871SMohammed Shafi Shajakhan udelay(10); 41bbefb871SMohammed Shafi Shajakhan time_out -= 10; 42bbefb871SMohammed Shafi Shajakhan 43bbefb871SMohammed Shafi Shajakhan if (time_out < 0) 44bbefb871SMohammed Shafi Shajakhan break; 454f6bd1a8SRajkumar Manoharan else 464f6bd1a8SRajkumar Manoharan continue; 474f6bd1a8SRajkumar Manoharan } 484f6bd1a8SRajkumar Manoharan REG_WRITE(ah, address, bit_position); 494f6bd1a8SRajkumar Manoharan 504f6bd1a8SRajkumar Manoharan if (address != AR_MCI_INTERRUPT_RX_MSG_RAW) 514f6bd1a8SRajkumar Manoharan break; 524f6bd1a8SRajkumar Manoharan 534f6bd1a8SRajkumar Manoharan if (bit_position & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) 544f6bd1a8SRajkumar Manoharan ar9003_mci_reset_req_wakeup(ah); 554f6bd1a8SRajkumar Manoharan 564f6bd1a8SRajkumar Manoharan if (bit_position & (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING | 574f6bd1a8SRajkumar Manoharan AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) 584f6bd1a8SRajkumar Manoharan REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, 594f6bd1a8SRajkumar Manoharan AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); 604f6bd1a8SRajkumar Manoharan 614f6bd1a8SRajkumar Manoharan REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_RX_MSG); 624f6bd1a8SRajkumar Manoharan break; 63bbefb871SMohammed Shafi Shajakhan } 64bbefb871SMohammed Shafi Shajakhan 65bbefb871SMohammed Shafi Shajakhan if (time_out <= 0) { 66d2182b69SJoe Perches ath_dbg(common, MCI, 67d2182b69SJoe Perches "MCI Wait for Reg 0x%08x = 0x%08x timeout\n", 68bbefb871SMohammed Shafi Shajakhan address, bit_position); 69d2182b69SJoe Perches ath_dbg(common, MCI, 70d2182b69SJoe Perches "MCI INT_RAW = 0x%08x, RX_MSG_RAW = 0x%08x\n", 71bbefb871SMohammed Shafi Shajakhan REG_READ(ah, AR_MCI_INTERRUPT_RAW), 72bbefb871SMohammed Shafi Shajakhan REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW)); 73bbefb871SMohammed Shafi Shajakhan time_out = 0; 74bbefb871SMohammed Shafi Shajakhan } 75bbefb871SMohammed Shafi Shajakhan 76bbefb871SMohammed Shafi Shajakhan return time_out; 77bbefb871SMohammed Shafi Shajakhan } 78bbefb871SMohammed Shafi Shajakhan 79a3f846f1SSujith Manoharan static void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done) 80bbefb871SMohammed Shafi Shajakhan { 81bbefb871SMohammed Shafi Shajakhan u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00}; 82bbefb871SMohammed Shafi Shajakhan 83bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16, 84bbefb871SMohammed Shafi Shajakhan wait_done, false); 85bbefb871SMohammed Shafi Shajakhan udelay(5); 86bbefb871SMohammed Shafi Shajakhan } 87bbefb871SMohammed Shafi Shajakhan 88a3f846f1SSujith Manoharan static void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done) 89bbefb871SMohammed Shafi Shajakhan { 90bbefb871SMohammed Shafi Shajakhan u32 payload = 0x00000000; 91bbefb871SMohammed Shafi Shajakhan 92bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1, 93bbefb871SMohammed Shafi Shajakhan wait_done, false); 94bbefb871SMohammed Shafi Shajakhan } 95bbefb871SMohammed Shafi Shajakhan 96bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done) 97bbefb871SMohammed Shafi Shajakhan { 98bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_message(ah, MCI_REQ_WAKE, MCI_FLAG_DISABLE_TIMESTAMP, 99bbefb871SMohammed Shafi Shajakhan NULL, 0, wait_done, false); 100bbefb871SMohammed Shafi Shajakhan udelay(5); 101bbefb871SMohammed Shafi Shajakhan } 102bbefb871SMohammed Shafi Shajakhan 103a3f846f1SSujith Manoharan static void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done) 104bbefb871SMohammed Shafi Shajakhan { 105bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP, 106bbefb871SMohammed Shafi Shajakhan NULL, 0, wait_done, false); 107bbefb871SMohammed Shafi Shajakhan } 108bbefb871SMohammed Shafi Shajakhan 109bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_send_lna_take(struct ath_hw *ah, bool wait_done) 110bbefb871SMohammed Shafi Shajakhan { 111bbefb871SMohammed Shafi Shajakhan u32 payload = 0x70000000; 112bbefb871SMohammed Shafi Shajakhan 113bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_message(ah, MCI_LNA_TAKE, 0, &payload, 1, 114bbefb871SMohammed Shafi Shajakhan wait_done, false); 115bbefb871SMohammed Shafi Shajakhan } 116bbefb871SMohammed Shafi Shajakhan 117bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done) 118bbefb871SMohammed Shafi Shajakhan { 119bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_message(ah, MCI_SYS_SLEEPING, 120bbefb871SMohammed Shafi Shajakhan MCI_FLAG_DISABLE_TIMESTAMP, 121bbefb871SMohammed Shafi Shajakhan NULL, 0, wait_done, false); 122bbefb871SMohammed Shafi Shajakhan } 123bbefb871SMohammed Shafi Shajakhan 124bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_send_coex_version_query(struct ath_hw *ah, 125bbefb871SMohammed Shafi Shajakhan bool wait_done) 126bbefb871SMohammed Shafi Shajakhan { 127bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 128bbefb871SMohammed Shafi Shajakhan u32 payload[4] = {0, 0, 0, 0}; 129bbefb871SMohammed Shafi Shajakhan 1304f6bd1a8SRajkumar Manoharan if (mci->bt_version_known || 1314f6bd1a8SRajkumar Manoharan (mci->bt_state == MCI_BT_SLEEP)) 1324f6bd1a8SRajkumar Manoharan return; 1334f6bd1a8SRajkumar Manoharan 1344f6bd1a8SRajkumar Manoharan MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, 13537cd9d78SSujith Manoharan MCI_GPM_COEX_VERSION_QUERY); 1364f6bd1a8SRajkumar Manoharan ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); 137bbefb871SMohammed Shafi Shajakhan } 138bbefb871SMohammed Shafi Shajakhan 139bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_send_coex_version_response(struct ath_hw *ah, 140bbefb871SMohammed Shafi Shajakhan bool wait_done) 141bbefb871SMohammed Shafi Shajakhan { 142bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 143bbefb871SMohammed Shafi Shajakhan u32 payload[4] = {0, 0, 0, 0}; 144bbefb871SMohammed Shafi Shajakhan 145bbefb871SMohammed Shafi Shajakhan MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, 146bbefb871SMohammed Shafi Shajakhan MCI_GPM_COEX_VERSION_RESPONSE); 147bbefb871SMohammed Shafi Shajakhan *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) = 148bbefb871SMohammed Shafi Shajakhan mci->wlan_ver_major; 149bbefb871SMohammed Shafi Shajakhan *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) = 150bbefb871SMohammed Shafi Shajakhan mci->wlan_ver_minor; 151bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); 152bbefb871SMohammed Shafi Shajakhan } 153bbefb871SMohammed Shafi Shajakhan 154bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah, 155bbefb871SMohammed Shafi Shajakhan bool wait_done) 156bbefb871SMohammed Shafi Shajakhan { 157bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 158bbefb871SMohammed Shafi Shajakhan u32 *payload = &mci->wlan_channels[0]; 159bbefb871SMohammed Shafi Shajakhan 1604f6bd1a8SRajkumar Manoharan if (!mci->wlan_channels_update || 1614f6bd1a8SRajkumar Manoharan (mci->bt_state == MCI_BT_SLEEP)) 1624f6bd1a8SRajkumar Manoharan return; 1634f6bd1a8SRajkumar Manoharan 1644f6bd1a8SRajkumar Manoharan MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, 16537cd9d78SSujith Manoharan MCI_GPM_COEX_WLAN_CHANNELS); 1664f6bd1a8SRajkumar Manoharan ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); 167bbefb871SMohammed Shafi Shajakhan MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff); 168bbefb871SMohammed Shafi Shajakhan } 169bbefb871SMohammed Shafi Shajakhan 170bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah, 171bbefb871SMohammed Shafi Shajakhan bool wait_done, u8 query_type) 172bbefb871SMohammed Shafi Shajakhan { 173bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 174bbefb871SMohammed Shafi Shajakhan u32 payload[4] = {0, 0, 0, 0}; 1754f6bd1a8SRajkumar Manoharan bool query_btinfo; 1764f6bd1a8SRajkumar Manoharan 1774f6bd1a8SRajkumar Manoharan if (mci->bt_state == MCI_BT_SLEEP) 1784f6bd1a8SRajkumar Manoharan return; 1794f6bd1a8SRajkumar Manoharan 1804f6bd1a8SRajkumar Manoharan query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO | 181bbefb871SMohammed Shafi Shajakhan MCI_GPM_COEX_QUERY_BT_TOPOLOGY)); 18237cd9d78SSujith Manoharan MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, 18337cd9d78SSujith Manoharan MCI_GPM_COEX_STATUS_QUERY); 184bbefb871SMohammed Shafi Shajakhan 185bbefb871SMohammed Shafi Shajakhan *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type; 18637cd9d78SSujith Manoharan 187bbefb871SMohammed Shafi Shajakhan /* 188bbefb871SMohammed Shafi Shajakhan * If bt_status_query message is not sent successfully, 189bbefb871SMohammed Shafi Shajakhan * then need_flush_btinfo should be set again. 190bbefb871SMohammed Shafi Shajakhan */ 191bbefb871SMohammed Shafi Shajakhan if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, 192bbefb871SMohammed Shafi Shajakhan wait_done, true)) { 19337cd9d78SSujith Manoharan if (query_btinfo) 194bbefb871SMohammed Shafi Shajakhan mci->need_flush_btinfo = true; 195bbefb871SMohammed Shafi Shajakhan } 196bbefb871SMohammed Shafi Shajakhan 197bbefb871SMohammed Shafi Shajakhan if (query_btinfo) 198bbefb871SMohammed Shafi Shajakhan mci->query_bt = false; 199bbefb871SMohammed Shafi Shajakhan } 200bbefb871SMohammed Shafi Shajakhan 201a3f846f1SSujith Manoharan static void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, 202bbefb871SMohammed Shafi Shajakhan bool wait_done) 203bbefb871SMohammed Shafi Shajakhan { 204bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 205bbefb871SMohammed Shafi Shajakhan u32 payload[4] = {0, 0, 0, 0}; 206bbefb871SMohammed Shafi Shajakhan 20737cd9d78SSujith Manoharan MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, 20837cd9d78SSujith Manoharan MCI_GPM_COEX_HALT_BT_GPM); 209bbefb871SMohammed Shafi Shajakhan 210bbefb871SMohammed Shafi Shajakhan if (halt) { 211bbefb871SMohammed Shafi Shajakhan mci->query_bt = true; 212bbefb871SMohammed Shafi Shajakhan /* Send next unhalt no matter halt sent or not */ 213bbefb871SMohammed Shafi Shajakhan mci->unhalt_bt_gpm = true; 214bbefb871SMohammed Shafi Shajakhan mci->need_flush_btinfo = true; 215bbefb871SMohammed Shafi Shajakhan *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) = 216bbefb871SMohammed Shafi Shajakhan MCI_GPM_COEX_BT_GPM_HALT; 217bbefb871SMohammed Shafi Shajakhan } else 218bbefb871SMohammed Shafi Shajakhan *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) = 219bbefb871SMohammed Shafi Shajakhan MCI_GPM_COEX_BT_GPM_UNHALT; 220bbefb871SMohammed Shafi Shajakhan 221bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); 222bbefb871SMohammed Shafi Shajakhan } 223bbefb871SMohammed Shafi Shajakhan 224bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_prep_interface(struct ath_hw *ah) 225bbefb871SMohammed Shafi Shajakhan { 226bbefb871SMohammed Shafi Shajakhan struct ath_common *common = ath9k_hw_common(ah); 227bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 228bbefb871SMohammed Shafi Shajakhan u32 saved_mci_int_en; 229bbefb871SMohammed Shafi Shajakhan u32 mci_timeout = 150; 230bbefb871SMohammed Shafi Shajakhan 231bbefb871SMohammed Shafi Shajakhan mci->bt_state = MCI_BT_SLEEP; 232bbefb871SMohammed Shafi Shajakhan saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); 233bbefb871SMohammed Shafi Shajakhan 234bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); 235bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 236bbefb871SMohammed Shafi Shajakhan REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW)); 237bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, 238bbefb871SMohammed Shafi Shajakhan REG_READ(ah, AR_MCI_INTERRUPT_RAW)); 239bbefb871SMohammed Shafi Shajakhan 240bbefb871SMohammed Shafi Shajakhan ar9003_mci_remote_reset(ah, true); 241bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_req_wake(ah, true); 242bbefb871SMohammed Shafi Shajakhan 2434f6bd1a8SRajkumar Manoharan if (!ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 2444f6bd1a8SRajkumar Manoharan AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) 2454f6bd1a8SRajkumar Manoharan goto clear_redunt; 246bbefb871SMohammed Shafi Shajakhan 247bbefb871SMohammed Shafi Shajakhan mci->bt_state = MCI_BT_AWAKE; 248bbefb871SMohammed Shafi Shajakhan 249bbefb871SMohammed Shafi Shajakhan /* 250bbefb871SMohammed Shafi Shajakhan * we don't need to send more remote_reset at this moment. 251bbefb871SMohammed Shafi Shajakhan * If BT receive first remote_reset, then BT HW will 252bbefb871SMohammed Shafi Shajakhan * be cleaned up and will be able to receive req_wake 253bbefb871SMohammed Shafi Shajakhan * and BT HW will respond sys_waking. 254bbefb871SMohammed Shafi Shajakhan * In this case, WLAN will receive BT's HW sys_waking. 255bbefb871SMohammed Shafi Shajakhan * Otherwise, if BT SW missed initial remote_reset, 256bbefb871SMohammed Shafi Shajakhan * that remote_reset will still clean up BT MCI RX, 257bbefb871SMohammed Shafi Shajakhan * and the req_wake will wake BT up, 258bbefb871SMohammed Shafi Shajakhan * and BT SW will respond this req_wake with a remote_reset and 259bbefb871SMohammed Shafi Shajakhan * sys_waking. In this case, WLAN will receive BT's SW 260bbefb871SMohammed Shafi Shajakhan * sys_waking. In either case, BT's RX is cleaned up. So we 261bbefb871SMohammed Shafi Shajakhan * don't need to reply BT's remote_reset now, if any. 262bbefb871SMohammed Shafi Shajakhan * Similarly, if in any case, WLAN can receive BT's sys_waking, 263bbefb871SMohammed Shafi Shajakhan * that means WLAN's RX is also fine. 264bbefb871SMohammed Shafi Shajakhan */ 265bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_sys_waking(ah, true); 266bbefb871SMohammed Shafi Shajakhan udelay(10); 267bbefb871SMohammed Shafi Shajakhan 268bbefb871SMohammed Shafi Shajakhan /* 269bbefb871SMohammed Shafi Shajakhan * Set BT priority interrupt value to be 0xff to 270bbefb871SMohammed Shafi Shajakhan * avoid having too many BT PRIORITY interrupts. 271bbefb871SMohammed Shafi Shajakhan */ 272bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF); 273bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF); 274bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF); 275bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF); 276bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF); 277bbefb871SMohammed Shafi Shajakhan 278bbefb871SMohammed Shafi Shajakhan /* 279bbefb871SMohammed Shafi Shajakhan * A contention reset will be received after send out 280bbefb871SMohammed Shafi Shajakhan * sys_waking. Also BT priority interrupt bits will be set. 281bbefb871SMohammed Shafi Shajakhan * Clear those bits before the next step. 282bbefb871SMohammed Shafi Shajakhan */ 283bbefb871SMohammed Shafi Shajakhan 284bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 285bbefb871SMohammed Shafi Shajakhan AR_MCI_INTERRUPT_RX_MSG_CONT_RST); 2864f6bd1a8SRajkumar Manoharan REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI); 287bbefb871SMohammed Shafi Shajakhan 288bc80d526SSujith Manoharan if (mci->is_2g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { 289bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_lna_transfer(ah, true); 290bbefb871SMohammed Shafi Shajakhan udelay(5); 291bbefb871SMohammed Shafi Shajakhan } 292bbefb871SMohammed Shafi Shajakhan 293bc80d526SSujith Manoharan if (mci->is_2g && !mci->update_2g5g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { 294bbefb871SMohammed Shafi Shajakhan if (ar9003_mci_wait_for_interrupt(ah, 295bbefb871SMohammed Shafi Shajakhan AR_MCI_INTERRUPT_RX_MSG_RAW, 296bbefb871SMohammed Shafi Shajakhan AR_MCI_INTERRUPT_RX_MSG_LNA_INFO, 297bbefb871SMohammed Shafi Shajakhan mci_timeout)) 298d2182b69SJoe Perches ath_dbg(common, MCI, 299d2182b69SJoe Perches "MCI WLAN has control over the LNA & BT obeys it\n"); 300bbefb871SMohammed Shafi Shajakhan else 301d2182b69SJoe Perches ath_dbg(common, MCI, 302d2182b69SJoe Perches "MCI BT didn't respond to LNA_TRANS\n"); 303bbefb871SMohammed Shafi Shajakhan } 304bbefb871SMohammed Shafi Shajakhan 3054f6bd1a8SRajkumar Manoharan clear_redunt: 306bbefb871SMohammed Shafi Shajakhan /* Clear the extra redundant SYS_WAKING from BT */ 307bbefb871SMohammed Shafi Shajakhan if ((mci->bt_state == MCI_BT_AWAKE) && 308bbefb871SMohammed Shafi Shajakhan (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 309bbefb871SMohammed Shafi Shajakhan AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) && 310bbefb871SMohammed Shafi Shajakhan (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 311bbefb871SMohammed Shafi Shajakhan AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) { 312bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 313bbefb871SMohammed Shafi Shajakhan AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING); 314bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, 315bbefb871SMohammed Shafi Shajakhan AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); 316bbefb871SMohammed Shafi Shajakhan } 317bbefb871SMohammed Shafi Shajakhan 318bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); 319bbefb871SMohammed Shafi Shajakhan } 320bbefb871SMohammed Shafi Shajakhan 321d1ca8b8eSSujith Manoharan void ar9003_mci_set_full_sleep(struct ath_hw *ah) 322d1ca8b8eSSujith Manoharan { 323d1ca8b8eSSujith Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 324d1ca8b8eSSujith Manoharan 325b98ccec0SRajkumar Manoharan if (ar9003_mci_state(ah, MCI_STATE_ENABLE) && 326d1ca8b8eSSujith Manoharan (mci->bt_state != MCI_BT_SLEEP) && 327d1ca8b8eSSujith Manoharan !mci->halted_bt_gpm) { 328d1ca8b8eSSujith Manoharan ar9003_mci_send_coex_halt_bt_gpm(ah, true, true); 329d1ca8b8eSSujith Manoharan } 330d1ca8b8eSSujith Manoharan 331d1ca8b8eSSujith Manoharan mci->ready = false; 332d1ca8b8eSSujith Manoharan } 333d1ca8b8eSSujith Manoharan 334a3f846f1SSujith Manoharan static void ar9003_mci_disable_interrupt(struct ath_hw *ah) 335bbefb871SMohammed Shafi Shajakhan { 336bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); 337bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0); 338bbefb871SMohammed Shafi Shajakhan } 339bbefb871SMohammed Shafi Shajakhan 340a3f846f1SSujith Manoharan static void ar9003_mci_enable_interrupt(struct ath_hw *ah) 341bbefb871SMohammed Shafi Shajakhan { 342bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT); 343bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 344bbefb871SMohammed Shafi Shajakhan AR_MCI_INTERRUPT_RX_MSG_DEFAULT); 345bbefb871SMohammed Shafi Shajakhan } 346bbefb871SMohammed Shafi Shajakhan 347a3f846f1SSujith Manoharan static bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints) 348bbefb871SMohammed Shafi Shajakhan { 349bbefb871SMohammed Shafi Shajakhan u32 intr; 350bbefb871SMohammed Shafi Shajakhan 351bbefb871SMohammed Shafi Shajakhan intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); 352bbefb871SMohammed Shafi Shajakhan return ((intr & ints) == ints); 353bbefb871SMohammed Shafi Shajakhan } 354bbefb871SMohammed Shafi Shajakhan 355bbefb871SMohammed Shafi Shajakhan void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, 356bbefb871SMohammed Shafi Shajakhan u32 *rx_msg_intr) 357bbefb871SMohammed Shafi Shajakhan { 358bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 3598a309305SFelix Fietkau 360bbefb871SMohammed Shafi Shajakhan *raw_intr = mci->raw_intr; 361bbefb871SMohammed Shafi Shajakhan *rx_msg_intr = mci->rx_msg_intr; 362bbefb871SMohammed Shafi Shajakhan 363bbefb871SMohammed Shafi Shajakhan /* Clean int bits after the values are read. */ 364bbefb871SMohammed Shafi Shajakhan mci->raw_intr = 0; 365bbefb871SMohammed Shafi Shajakhan mci->rx_msg_intr = 0; 366bbefb871SMohammed Shafi Shajakhan } 367bbefb871SMohammed Shafi Shajakhan EXPORT_SYMBOL(ar9003_mci_get_interrupt); 368bbefb871SMohammed Shafi Shajakhan 3695a1e2735SSujith Manoharan void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked) 3705a1e2735SSujith Manoharan { 3715a1e2735SSujith Manoharan struct ath_common *common = ath9k_hw_common(ah); 3725a1e2735SSujith Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 3735a1e2735SSujith Manoharan u32 raw_intr, rx_msg_intr; 3745a1e2735SSujith Manoharan 3755a1e2735SSujith Manoharan rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); 3765a1e2735SSujith Manoharan raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW); 3775a1e2735SSujith Manoharan 3785a1e2735SSujith Manoharan if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) { 3795a1e2735SSujith Manoharan ath_dbg(common, MCI, 3805a1e2735SSujith Manoharan "MCI gets 0xdeadbeef during int processing\n"); 3815a1e2735SSujith Manoharan } else { 3825a1e2735SSujith Manoharan mci->rx_msg_intr |= rx_msg_intr; 3835a1e2735SSujith Manoharan mci->raw_intr |= raw_intr; 3845a1e2735SSujith Manoharan *masked |= ATH9K_INT_MCI; 3855a1e2735SSujith Manoharan 3865a1e2735SSujith Manoharan if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) 3875a1e2735SSujith Manoharan mci->cont_status = REG_READ(ah, AR_MCI_CONT_STATUS); 3885a1e2735SSujith Manoharan 3895a1e2735SSujith Manoharan REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr); 3905a1e2735SSujith Manoharan REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr); 3915a1e2735SSujith Manoharan } 3925a1e2735SSujith Manoharan } 3935a1e2735SSujith Manoharan 394a3f846f1SSujith Manoharan static void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g) 395bbefb871SMohammed Shafi Shajakhan { 396bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 397bbefb871SMohammed Shafi Shajakhan 398bbefb871SMohammed Shafi Shajakhan if (!mci->update_2g5g && 399bbefb871SMohammed Shafi Shajakhan (mci->is_2g != is_2g)) 400bbefb871SMohammed Shafi Shajakhan mci->update_2g5g = true; 401bbefb871SMohammed Shafi Shajakhan 402bbefb871SMohammed Shafi Shajakhan mci->is_2g = is_2g; 403bbefb871SMohammed Shafi Shajakhan } 404bbefb871SMohammed Shafi Shajakhan 405bbefb871SMohammed Shafi Shajakhan static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index) 406bbefb871SMohammed Shafi Shajakhan { 407bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 408bbefb871SMohammed Shafi Shajakhan u32 *payload; 409bbefb871SMohammed Shafi Shajakhan u32 recv_type, offset; 410bbefb871SMohammed Shafi Shajakhan 411bbefb871SMohammed Shafi Shajakhan if (msg_index == MCI_GPM_INVALID) 412bbefb871SMohammed Shafi Shajakhan return false; 413bbefb871SMohammed Shafi Shajakhan 414bbefb871SMohammed Shafi Shajakhan offset = msg_index << 4; 415bbefb871SMohammed Shafi Shajakhan 416bbefb871SMohammed Shafi Shajakhan payload = (u32 *)(mci->gpm_buf + offset); 417bbefb871SMohammed Shafi Shajakhan recv_type = MCI_GPM_TYPE(payload); 418bbefb871SMohammed Shafi Shajakhan 41937cd9d78SSujith Manoharan if (recv_type == MCI_GPM_RSVD_PATTERN) 420bbefb871SMohammed Shafi Shajakhan return false; 421bbefb871SMohammed Shafi Shajakhan 422bbefb871SMohammed Shafi Shajakhan return true; 423bbefb871SMohammed Shafi Shajakhan } 424bbefb871SMohammed Shafi Shajakhan 425bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_observation_set_up(struct ath_hw *ah) 426bbefb871SMohammed Shafi Shajakhan { 427bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 428bbefb871SMohammed Shafi Shajakhan 42937cd9d78SSujith Manoharan if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) { 430b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 3, NULL, 431b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA); 432b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 2, NULL, 433b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK); 434b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 1, NULL, 435b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); 436b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 0, NULL, 437b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); 438bbefb871SMohammed Shafi Shajakhan } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) { 439b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 3, NULL, 440b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX); 441b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 2, NULL, 442b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX); 443b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 1, NULL, 444b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); 445b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 0, NULL, 446b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); 447b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 5, NULL, 448b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_OUTPUT); 449bbefb871SMohammed Shafi Shajakhan } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) { 450b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 3, NULL, 451b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); 452b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 2, NULL, 453b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); 454b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 1, NULL, 455b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); 456b2d70d49SMiaoqing Pan ath9k_hw_gpio_request_out(ah, 0, NULL, 457b2d70d49SMiaoqing Pan AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); 458bbefb871SMohammed Shafi Shajakhan } else 459bbefb871SMohammed Shafi Shajakhan return; 460bbefb871SMohammed Shafi Shajakhan 461bbefb871SMohammed Shafi Shajakhan REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); 462bbefb871SMohammed Shafi Shajakhan 4630cc4cdebSSujith Manoharan REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_DS_JTAG_DISABLE, 1); 4640cc4cdebSSujith Manoharan REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_WLAN_UART_INTF_EN, 0); 4650cc4cdebSSujith Manoharan REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL, ATH_MCI_CONFIG_MCI_OBS_GPIO); 466bbefb871SMohammed Shafi Shajakhan 467bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0); 468bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1); 469bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_OBS, 0x4b); 470bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL1, 0x03); 471bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL2, 0x01); 472bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_LSB, 0x02); 473bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_MSB, 0x03); 474bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, 475bbefb871SMohammed Shafi Shajakhan AR_PHY_TEST_CTL_DEBUGPORT_SEL, 0x07); 476bbefb871SMohammed Shafi Shajakhan } 477bbefb871SMohammed Shafi Shajakhan 478bbefb871SMohammed Shafi Shajakhan static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done, 479bbefb871SMohammed Shafi Shajakhan u8 opcode, u32 bt_flags) 480bbefb871SMohammed Shafi Shajakhan { 481bbefb871SMohammed Shafi Shajakhan u32 pld[4] = {0, 0, 0, 0}; 482bbefb871SMohammed Shafi Shajakhan 48337cd9d78SSujith Manoharan MCI_GPM_SET_TYPE_OPCODE(pld, MCI_GPM_COEX_AGENT, 48437cd9d78SSujith Manoharan MCI_GPM_COEX_BT_UPDATE_FLAGS); 485bbefb871SMohammed Shafi Shajakhan 486bbefb871SMohammed Shafi Shajakhan *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP) = opcode; 487bbefb871SMohammed Shafi Shajakhan *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF; 488bbefb871SMohammed Shafi Shajakhan *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 1) = (bt_flags >> 8) & 0xFF; 489bbefb871SMohammed Shafi Shajakhan *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF; 490bbefb871SMohammed Shafi Shajakhan *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF; 491bbefb871SMohammed Shafi Shajakhan 492bbefb871SMohammed Shafi Shajakhan return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, 493bbefb871SMohammed Shafi Shajakhan wait_done, true); 494bbefb871SMohammed Shafi Shajakhan } 495bbefb871SMohammed Shafi Shajakhan 496a3f846f1SSujith Manoharan static void ar9003_mci_sync_bt_state(struct ath_hw *ah) 497a3f846f1SSujith Manoharan { 498a3f846f1SSujith Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 499a3f846f1SSujith Manoharan u32 cur_bt_state; 500a3f846f1SSujith Manoharan 501b98ccec0SRajkumar Manoharan cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP); 502a3f846f1SSujith Manoharan 50337cd9d78SSujith Manoharan if (mci->bt_state != cur_bt_state) 504a3f846f1SSujith Manoharan mci->bt_state = cur_bt_state; 505a3f846f1SSujith Manoharan 506a3f846f1SSujith Manoharan if (mci->bt_state != MCI_BT_SLEEP) { 507a3f846f1SSujith Manoharan 508a3f846f1SSujith Manoharan ar9003_mci_send_coex_version_query(ah, true); 509a3f846f1SSujith Manoharan ar9003_mci_send_coex_wlan_channels(ah, true); 510a3f846f1SSujith Manoharan 51137cd9d78SSujith Manoharan if (mci->unhalt_bt_gpm == true) 512a3f846f1SSujith Manoharan ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); 513a3f846f1SSujith Manoharan } 514a3f846f1SSujith Manoharan } 515a3f846f1SSujith Manoharan 516528e5d36SSujith Manoharan void ar9003_mci_check_bt(struct ath_hw *ah) 517528e5d36SSujith Manoharan { 518528e5d36SSujith Manoharan struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 519528e5d36SSujith Manoharan 520528e5d36SSujith Manoharan if (!mci_hw->ready) 521528e5d36SSujith Manoharan return; 522528e5d36SSujith Manoharan 523528e5d36SSujith Manoharan /* 524528e5d36SSujith Manoharan * check BT state again to make 525528e5d36SSujith Manoharan * sure it's not changed. 526528e5d36SSujith Manoharan */ 527528e5d36SSujith Manoharan ar9003_mci_sync_bt_state(ah); 528528e5d36SSujith Manoharan ar9003_mci_2g5g_switch(ah, true); 529528e5d36SSujith Manoharan 530528e5d36SSujith Manoharan if ((mci_hw->bt_state == MCI_BT_AWAKE) && 531528e5d36SSujith Manoharan (mci_hw->query_bt == true)) { 532528e5d36SSujith Manoharan mci_hw->need_flush_btinfo = true; 533528e5d36SSujith Manoharan } 534528e5d36SSujith Manoharan } 535528e5d36SSujith Manoharan 536a3f846f1SSujith Manoharan static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type, 537a3f846f1SSujith Manoharan u8 gpm_opcode, u32 *p_gpm) 538a3f846f1SSujith Manoharan { 539a3f846f1SSujith Manoharan struct ath_common *common = ath9k_hw_common(ah); 540a3f846f1SSujith Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 541a3f846f1SSujith Manoharan u8 *p_data = (u8 *) p_gpm; 542a3f846f1SSujith Manoharan 543a3f846f1SSujith Manoharan if (gpm_type != MCI_GPM_COEX_AGENT) 544a3f846f1SSujith Manoharan return; 545a3f846f1SSujith Manoharan 546a3f846f1SSujith Manoharan switch (gpm_opcode) { 547a3f846f1SSujith Manoharan case MCI_GPM_COEX_VERSION_QUERY: 548a3f846f1SSujith Manoharan ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n"); 549a3f846f1SSujith Manoharan ar9003_mci_send_coex_version_response(ah, true); 550a3f846f1SSujith Manoharan break; 551a3f846f1SSujith Manoharan case MCI_GPM_COEX_VERSION_RESPONSE: 552a3f846f1SSujith Manoharan ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n"); 553a3f846f1SSujith Manoharan mci->bt_ver_major = 554a3f846f1SSujith Manoharan *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION); 555a3f846f1SSujith Manoharan mci->bt_ver_minor = 556a3f846f1SSujith Manoharan *(p_data + MCI_GPM_COEX_B_MINOR_VERSION); 557a3f846f1SSujith Manoharan mci->bt_version_known = true; 558a3f846f1SSujith Manoharan ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n", 559a3f846f1SSujith Manoharan mci->bt_ver_major, mci->bt_ver_minor); 560a3f846f1SSujith Manoharan break; 561a3f846f1SSujith Manoharan case MCI_GPM_COEX_STATUS_QUERY: 562a3f846f1SSujith Manoharan ath_dbg(common, MCI, 563a3f846f1SSujith Manoharan "MCI Recv GPM COEX Status Query = 0x%02X\n", 564a3f846f1SSujith Manoharan *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP)); 565a3f846f1SSujith Manoharan mci->wlan_channels_update = true; 566a3f846f1SSujith Manoharan ar9003_mci_send_coex_wlan_channels(ah, true); 567a3f846f1SSujith Manoharan break; 568a3f846f1SSujith Manoharan case MCI_GPM_COEX_BT_PROFILE_INFO: 569a3f846f1SSujith Manoharan mci->query_bt = true; 570a3f846f1SSujith Manoharan ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n"); 571a3f846f1SSujith Manoharan break; 572a3f846f1SSujith Manoharan case MCI_GPM_COEX_BT_STATUS_UPDATE: 573a3f846f1SSujith Manoharan mci->query_bt = true; 574a3f846f1SSujith Manoharan ath_dbg(common, MCI, 575a3f846f1SSujith Manoharan "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n", 576a3f846f1SSujith Manoharan *(p_gpm + 3)); 577a3f846f1SSujith Manoharan break; 578a3f846f1SSujith Manoharan default: 579a3f846f1SSujith Manoharan break; 580a3f846f1SSujith Manoharan } 581a3f846f1SSujith Manoharan } 582a3f846f1SSujith Manoharan 583a3f846f1SSujith Manoharan static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, 584a3f846f1SSujith Manoharan u8 gpm_opcode, int time_out) 585a3f846f1SSujith Manoharan { 586a3f846f1SSujith Manoharan struct ath_common *common = ath9k_hw_common(ah); 587a3f846f1SSujith Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 588a3f846f1SSujith Manoharan u32 *p_gpm = NULL, mismatch = 0, more_data; 589a3f846f1SSujith Manoharan u32 offset; 590a3f846f1SSujith Manoharan u8 recv_type = 0, recv_opcode = 0; 591a3f846f1SSujith Manoharan bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE); 592a3f846f1SSujith Manoharan 593a3f846f1SSujith Manoharan more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE; 594a3f846f1SSujith Manoharan 595a3f846f1SSujith Manoharan while (time_out > 0) { 596a3f846f1SSujith Manoharan if (p_gpm) { 597a3f846f1SSujith Manoharan MCI_GPM_RECYCLE(p_gpm); 598a3f846f1SSujith Manoharan p_gpm = NULL; 599a3f846f1SSujith Manoharan } 600a3f846f1SSujith Manoharan 601a3f846f1SSujith Manoharan if (more_data != MCI_GPM_MORE) 602a3f846f1SSujith Manoharan time_out = ar9003_mci_wait_for_interrupt(ah, 603a3f846f1SSujith Manoharan AR_MCI_INTERRUPT_RX_MSG_RAW, 604a3f846f1SSujith Manoharan AR_MCI_INTERRUPT_RX_MSG_GPM, 605a3f846f1SSujith Manoharan time_out); 606a3f846f1SSujith Manoharan 607a3f846f1SSujith Manoharan if (!time_out) 608a3f846f1SSujith Manoharan break; 609a3f846f1SSujith Manoharan 610ad1dc638SSujith Manoharan offset = ar9003_mci_get_next_gpm_offset(ah, &more_data); 611a3f846f1SSujith Manoharan 612a3f846f1SSujith Manoharan if (offset == MCI_GPM_INVALID) 613a3f846f1SSujith Manoharan continue; 614a3f846f1SSujith Manoharan 615a3f846f1SSujith Manoharan p_gpm = (u32 *) (mci->gpm_buf + offset); 616a3f846f1SSujith Manoharan recv_type = MCI_GPM_TYPE(p_gpm); 617a3f846f1SSujith Manoharan recv_opcode = MCI_GPM_OPCODE(p_gpm); 618a3f846f1SSujith Manoharan 619a3f846f1SSujith Manoharan if (MCI_GPM_IS_CAL_TYPE(recv_type)) { 620a3f846f1SSujith Manoharan if (recv_type == gpm_type) { 621a3f846f1SSujith Manoharan if ((gpm_type == MCI_GPM_BT_CAL_DONE) && 622a3f846f1SSujith Manoharan !b_is_bt_cal_done) { 623a3f846f1SSujith Manoharan gpm_type = MCI_GPM_BT_CAL_GRANT; 624a3f846f1SSujith Manoharan continue; 625a3f846f1SSujith Manoharan } 626a3f846f1SSujith Manoharan break; 627a3f846f1SSujith Manoharan } 6284f6bd1a8SRajkumar Manoharan } else if ((recv_type == gpm_type) && 6294f6bd1a8SRajkumar Manoharan (recv_opcode == gpm_opcode)) 630a3f846f1SSujith Manoharan break; 631a3f846f1SSujith Manoharan 632a3f846f1SSujith Manoharan /* 633a3f846f1SSujith Manoharan * check if it's cal_grant 634a3f846f1SSujith Manoharan * 635a3f846f1SSujith Manoharan * When we're waiting for cal_grant in reset routine, 636a3f846f1SSujith Manoharan * it's possible that BT sends out cal_request at the 637a3f846f1SSujith Manoharan * same time. Since BT's calibration doesn't happen 638a3f846f1SSujith Manoharan * that often, we'll let BT completes calibration then 639a3f846f1SSujith Manoharan * we continue to wait for cal_grant from BT. 640a3f846f1SSujith Manoharan * Orginal: Wait BT_CAL_GRANT. 641a3f846f1SSujith Manoharan * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait 642a3f846f1SSujith Manoharan * BT_CAL_DONE -> Wait BT_CAL_GRANT. 643a3f846f1SSujith Manoharan */ 644a3f846f1SSujith Manoharan 645a3f846f1SSujith Manoharan if ((gpm_type == MCI_GPM_BT_CAL_GRANT) && 646a3f846f1SSujith Manoharan (recv_type == MCI_GPM_BT_CAL_REQ)) { 647a3f846f1SSujith Manoharan 648a3f846f1SSujith Manoharan u32 payload[4] = {0, 0, 0, 0}; 649a3f846f1SSujith Manoharan 650a3f846f1SSujith Manoharan gpm_type = MCI_GPM_BT_CAL_DONE; 651a3f846f1SSujith Manoharan MCI_GPM_SET_CAL_TYPE(payload, 652a3f846f1SSujith Manoharan MCI_GPM_WLAN_CAL_GRANT); 653a3f846f1SSujith Manoharan ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, 654a3f846f1SSujith Manoharan false, false); 655a3f846f1SSujith Manoharan continue; 656a3f846f1SSujith Manoharan } else { 657a3f846f1SSujith Manoharan ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n", 658a3f846f1SSujith Manoharan *(p_gpm + 1)); 659a3f846f1SSujith Manoharan mismatch++; 660a3f846f1SSujith Manoharan ar9003_mci_process_gpm_extra(ah, recv_type, 661a3f846f1SSujith Manoharan recv_opcode, p_gpm); 662a3f846f1SSujith Manoharan } 663a3f846f1SSujith Manoharan } 66437cd9d78SSujith Manoharan 665a3f846f1SSujith Manoharan if (p_gpm) { 666a3f846f1SSujith Manoharan MCI_GPM_RECYCLE(p_gpm); 667a3f846f1SSujith Manoharan p_gpm = NULL; 668a3f846f1SSujith Manoharan } 669a3f846f1SSujith Manoharan 67037cd9d78SSujith Manoharan if (time_out <= 0) 671a3f846f1SSujith Manoharan time_out = 0; 672a3f846f1SSujith Manoharan 673a3f846f1SSujith Manoharan while (more_data == MCI_GPM_MORE) { 674ad1dc638SSujith Manoharan offset = ar9003_mci_get_next_gpm_offset(ah, &more_data); 675a3f846f1SSujith Manoharan if (offset == MCI_GPM_INVALID) 676a3f846f1SSujith Manoharan break; 677a3f846f1SSujith Manoharan 678a3f846f1SSujith Manoharan p_gpm = (u32 *) (mci->gpm_buf + offset); 679a3f846f1SSujith Manoharan recv_type = MCI_GPM_TYPE(p_gpm); 680a3f846f1SSujith Manoharan recv_opcode = MCI_GPM_OPCODE(p_gpm); 681a3f846f1SSujith Manoharan 682a3f846f1SSujith Manoharan if (!MCI_GPM_IS_CAL_TYPE(recv_type)) 683a3f846f1SSujith Manoharan ar9003_mci_process_gpm_extra(ah, recv_type, 684a3f846f1SSujith Manoharan recv_opcode, p_gpm); 685a3f846f1SSujith Manoharan 686a3f846f1SSujith Manoharan MCI_GPM_RECYCLE(p_gpm); 687a3f846f1SSujith Manoharan } 688a3f846f1SSujith Manoharan 689a3f846f1SSujith Manoharan return time_out; 690a3f846f1SSujith Manoharan } 691a3f846f1SSujith Manoharan 692528e5d36SSujith Manoharan bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) 693528e5d36SSujith Manoharan { 694528e5d36SSujith Manoharan struct ath_common *common = ath9k_hw_common(ah); 695528e5d36SSujith Manoharan struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 696528e5d36SSujith Manoharan u32 payload[4] = {0, 0, 0, 0}; 697528e5d36SSujith Manoharan 698528e5d36SSujith Manoharan ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan)); 699528e5d36SSujith Manoharan 700528e5d36SSujith Manoharan if (mci_hw->bt_state != MCI_BT_CAL_START) 701528e5d36SSujith Manoharan return false; 702528e5d36SSujith Manoharan 703528e5d36SSujith Manoharan mci_hw->bt_state = MCI_BT_CAL; 704528e5d36SSujith Manoharan 705528e5d36SSujith Manoharan /* 706528e5d36SSujith Manoharan * MCI FIX: disable mci interrupt here. This is to avoid 707528e5d36SSujith Manoharan * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and 708528e5d36SSujith Manoharan * lead to mci_intr reentry. 709528e5d36SSujith Manoharan */ 710528e5d36SSujith Manoharan ar9003_mci_disable_interrupt(ah); 711528e5d36SSujith Manoharan 712528e5d36SSujith Manoharan MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); 713528e5d36SSujith Manoharan ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 714528e5d36SSujith Manoharan 16, true, false); 715528e5d36SSujith Manoharan 716528e5d36SSujith Manoharan /* Wait BT calibration to be completed for 25ms */ 717528e5d36SSujith Manoharan 718528e5d36SSujith Manoharan if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 719528e5d36SSujith Manoharan 0, 25000)) 72037cd9d78SSujith Manoharan ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n"); 721528e5d36SSujith Manoharan else 722528e5d36SSujith Manoharan ath_dbg(common, MCI, 72337cd9d78SSujith Manoharan "MCI BT_CAL_DONE not received\n"); 724528e5d36SSujith Manoharan 725528e5d36SSujith Manoharan mci_hw->bt_state = MCI_BT_AWAKE; 726528e5d36SSujith Manoharan /* MCI FIX: enable mci interrupt here */ 727528e5d36SSujith Manoharan ar9003_mci_enable_interrupt(ah); 728528e5d36SSujith Manoharan 729528e5d36SSujith Manoharan return true; 730528e5d36SSujith Manoharan } 731528e5d36SSujith Manoharan 732528e5d36SSujith Manoharan int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, 733528e5d36SSujith Manoharan struct ath9k_hw_cal_data *caldata) 734528e5d36SSujith Manoharan { 735528e5d36SSujith Manoharan struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 736528e5d36SSujith Manoharan 737528e5d36SSujith Manoharan if (!mci_hw->ready) 738528e5d36SSujith Manoharan return 0; 739528e5d36SSujith Manoharan 740528e5d36SSujith Manoharan if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP)) 741528e5d36SSujith Manoharan goto exit; 742528e5d36SSujith Manoharan 7434f6bd1a8SRajkumar Manoharan if (!ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) && 7444f6bd1a8SRajkumar Manoharan !ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) 7454f6bd1a8SRajkumar Manoharan goto exit; 746528e5d36SSujith Manoharan 747528e5d36SSujith Manoharan /* 748528e5d36SSujith Manoharan * BT is sleeping. Check if BT wakes up during 749528e5d36SSujith Manoharan * WLAN calibration. If BT wakes up during 750528e5d36SSujith Manoharan * WLAN calibration, need to go through all 751528e5d36SSujith Manoharan * message exchanges again and recal. 752528e5d36SSujith Manoharan */ 753528e5d36SSujith Manoharan REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 7544f6bd1a8SRajkumar Manoharan (AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | 7554f6bd1a8SRajkumar Manoharan AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)); 756528e5d36SSujith Manoharan 757528e5d36SSujith Manoharan ar9003_mci_remote_reset(ah, true); 758528e5d36SSujith Manoharan ar9003_mci_send_sys_waking(ah, true); 759528e5d36SSujith Manoharan udelay(1); 760528e5d36SSujith Manoharan 761528e5d36SSujith Manoharan if (IS_CHAN_2GHZ(chan)) 762528e5d36SSujith Manoharan ar9003_mci_send_lna_transfer(ah, true); 763528e5d36SSujith Manoharan 764528e5d36SSujith Manoharan mci_hw->bt_state = MCI_BT_AWAKE; 765528e5d36SSujith Manoharan 766b55f6bb7SBala Shanmugam REG_CLR_BIT(ah, AR_PHY_TIMING4, 767b55f6bb7SBala Shanmugam 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); 768b55f6bb7SBala Shanmugam 769528e5d36SSujith Manoharan if (caldata) { 7704b9b42bfSSujith Manoharan clear_bit(TXIQCAL_DONE, &caldata->cal_flags); 7714b9b42bfSSujith Manoharan clear_bit(TXCLCAL_DONE, &caldata->cal_flags); 7724b9b42bfSSujith Manoharan clear_bit(RTT_DONE, &caldata->cal_flags); 773528e5d36SSujith Manoharan } 774528e5d36SSujith Manoharan 775528e5d36SSujith Manoharan if (!ath9k_hw_init_cal(ah, chan)) 776528e5d36SSujith Manoharan return -EIO; 777528e5d36SSujith Manoharan 778b55f6bb7SBala Shanmugam REG_SET_BIT(ah, AR_PHY_TIMING4, 779b55f6bb7SBala Shanmugam 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); 780b55f6bb7SBala Shanmugam 781528e5d36SSujith Manoharan exit: 782528e5d36SSujith Manoharan ar9003_mci_enable_interrupt(ah); 783528e5d36SSujith Manoharan return 0; 784528e5d36SSujith Manoharan } 785528e5d36SSujith Manoharan 786a3f846f1SSujith Manoharan static void ar9003_mci_mute_bt(struct ath_hw *ah) 787a3f846f1SSujith Manoharan { 7882f890cabSSujith Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 7892f890cabSSujith Manoharan 790a3f846f1SSujith Manoharan /* disable all MCI messages */ 791a3f846f1SSujith Manoharan REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000); 7922f890cabSSujith Manoharan REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff); 7932f890cabSSujith Manoharan REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff); 7942f890cabSSujith Manoharan REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff); 7952f890cabSSujith Manoharan REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff); 796a3f846f1SSujith Manoharan REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); 797a3f846f1SSujith Manoharan 798a3f846f1SSujith Manoharan /* wait pending HW messages to flush out */ 799a3f846f1SSujith Manoharan udelay(10); 800a3f846f1SSujith Manoharan 801a3f846f1SSujith Manoharan /* 802a3f846f1SSujith Manoharan * Send LNA_TAKE and SYS_SLEEPING when 803a3f846f1SSujith Manoharan * 1. reset not after resuming from full sleep 804a3f846f1SSujith Manoharan * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment 805a3f846f1SSujith Manoharan */ 8062f890cabSSujith Manoharan if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { 807a3f846f1SSujith Manoharan ar9003_mci_send_lna_take(ah, true); 808a3f846f1SSujith Manoharan udelay(5); 8092f890cabSSujith Manoharan } 810a3f846f1SSujith Manoharan 811a3f846f1SSujith Manoharan ar9003_mci_send_sys_sleeping(ah, true); 812a3f846f1SSujith Manoharan } 813a3f846f1SSujith Manoharan 8144f851df7SSujith Manoharan static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable) 8154f851df7SSujith Manoharan { 8164f851df7SSujith Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 8174f851df7SSujith Manoharan u32 thresh; 8184f851df7SSujith Manoharan 8194f6bd1a8SRajkumar Manoharan if (!enable) { 8204f6bd1a8SRajkumar Manoharan REG_CLR_BIT(ah, AR_BTCOEX_CTRL, 8214f6bd1a8SRajkumar Manoharan AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); 8224f6bd1a8SRajkumar Manoharan return; 8234f6bd1a8SRajkumar Manoharan } 8244f6bd1a8SRajkumar Manoharan REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, AR_MCI_SCHD_TABLE_2_HW_BASED, 1); 8254f851df7SSujith Manoharan REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, 8264f851df7SSujith Manoharan AR_MCI_SCHD_TABLE_2_MEM_BASED, 1); 8274f851df7SSujith Manoharan 8284c6231a4SRajkumar Manoharan if (AR_SREV_9565(ah)) 8294c6231a4SRajkumar Manoharan REG_RMW_FIELD(ah, AR_MCI_MISC, AR_MCI_MISC_HW_FIX_EN, 1); 8304c6231a4SRajkumar Manoharan 8314f851df7SSujith Manoharan if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) { 8324f851df7SSujith Manoharan thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH); 8334f851df7SSujith Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, 8344f851df7SSujith Manoharan AR_BTCOEX_CTRL_AGGR_THRESH, thresh); 8354f851df7SSujith Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, 8364f851df7SSujith Manoharan AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1); 8374f6bd1a8SRajkumar Manoharan } else 8384f851df7SSujith Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, 8394f851df7SSujith Manoharan AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0); 8404f851df7SSujith Manoharan 8414f851df7SSujith Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, 8424f851df7SSujith Manoharan AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1); 8434f851df7SSujith Manoharan } 8444f851df7SSujith Manoharan 8454d9f7c68SSujith Manoharan static void ar9003_mci_stat_setup(struct ath_hw *ah) 8464d9f7c68SSujith Manoharan { 8474d9f7c68SSujith Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 8484d9f7c68SSujith Manoharan 8494d9f7c68SSujith Manoharan if (!AR_SREV_9565(ah)) 8504d9f7c68SSujith Manoharan return; 8514d9f7c68SSujith Manoharan 8524d9f7c68SSujith Manoharan if (mci->config & ATH_MCI_CONFIG_MCI_STAT_DBG) { 8534d9f7c68SSujith Manoharan REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, 8544d9f7c68SSujith Manoharan AR_MCI_DBG_CNT_CTRL_ENABLE, 1); 8554d9f7c68SSujith Manoharan REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, 8564d9f7c68SSujith Manoharan AR_MCI_DBG_CNT_CTRL_BT_LINKID, 8574d9f7c68SSujith Manoharan MCI_STAT_ALL_BT_LINKID); 8584d9f7c68SSujith Manoharan } else { 8594d9f7c68SSujith Manoharan REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, 8604d9f7c68SSujith Manoharan AR_MCI_DBG_CNT_CTRL_ENABLE, 0); 8614d9f7c68SSujith Manoharan } 8624d9f7c68SSujith Manoharan } 8634d9f7c68SSujith Manoharan 864e18e164eSSujith Manoharan static void ar9003_mci_set_btcoex_ctrl_9565_1ANT(struct ath_hw *ah) 865e18e164eSSujith Manoharan { 866e18e164eSSujith Manoharan u32 regval; 867e18e164eSSujith Manoharan 868e18e164eSSujith Manoharan regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | 869e18e164eSSujith Manoharan SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | 870e18e164eSSujith Manoharan SM(1, AR_BTCOEX_CTRL_PA_SHARED) | 871e18e164eSSujith Manoharan SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | 872e18e164eSSujith Manoharan SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) | 873e18e164eSSujith Manoharan SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | 874e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | 875e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | 876e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); 877e18e164eSSujith Manoharan 878e18e164eSSujith Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, 879e18e164eSSujith Manoharan AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1); 880e18e164eSSujith Manoharan REG_WRITE(ah, AR_BTCOEX_CTRL, regval); 881e18e164eSSujith Manoharan } 882e18e164eSSujith Manoharan 883e18e164eSSujith Manoharan static void ar9003_mci_set_btcoex_ctrl_9565_2ANT(struct ath_hw *ah) 884e18e164eSSujith Manoharan { 885e18e164eSSujith Manoharan u32 regval; 886e18e164eSSujith Manoharan 887e18e164eSSujith Manoharan regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | 888e18e164eSSujith Manoharan SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | 889e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_PA_SHARED) | 890e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_LNA_SHARED) | 891e18e164eSSujith Manoharan SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | 892e18e164eSSujith Manoharan SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | 893e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | 894e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | 895e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); 896e18e164eSSujith Manoharan 897e18e164eSSujith Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, 898e18e164eSSujith Manoharan AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x0); 899e18e164eSSujith Manoharan REG_WRITE(ah, AR_BTCOEX_CTRL, regval); 900e18e164eSSujith Manoharan } 901e18e164eSSujith Manoharan 902e18e164eSSujith Manoharan static void ar9003_mci_set_btcoex_ctrl_9462(struct ath_hw *ah) 903e18e164eSSujith Manoharan { 904e18e164eSSujith Manoharan u32 regval; 905e18e164eSSujith Manoharan 906e18e164eSSujith Manoharan regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | 907e18e164eSSujith Manoharan SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | 908e18e164eSSujith Manoharan SM(1, AR_BTCOEX_CTRL_PA_SHARED) | 909e18e164eSSujith Manoharan SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | 910e18e164eSSujith Manoharan SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | 911e18e164eSSujith Manoharan SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | 912e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | 913e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | 914e18e164eSSujith Manoharan SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); 915e18e164eSSujith Manoharan 916e18e164eSSujith Manoharan REG_WRITE(ah, AR_BTCOEX_CTRL, regval); 917e18e164eSSujith Manoharan } 918e18e164eSSujith Manoharan 91969c6ac60SSujith Manoharan int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, 920bbefb871SMohammed Shafi Shajakhan bool is_full_sleep) 921bbefb871SMohammed Shafi Shajakhan { 922bbefb871SMohammed Shafi Shajakhan struct ath_common *common = ath9k_hw_common(ah); 923bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 924e82cb03fSRajkumar Manoharan u32 regval, i; 925bbefb871SMohammed Shafi Shajakhan 9264f851df7SSujith Manoharan ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n", 927bbefb871SMohammed Shafi Shajakhan is_full_sleep, is_2g); 928bbefb871SMohammed Shafi Shajakhan 929bbefb871SMohammed Shafi Shajakhan if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) { 93069c6ac60SSujith Manoharan ath_err(common, "BTCOEX control register is dead\n"); 93169c6ac60SSujith Manoharan return -EINVAL; 932bbefb871SMohammed Shafi Shajakhan } 933bbefb871SMohammed Shafi Shajakhan 934bbefb871SMohammed Shafi Shajakhan /* Program MCI DMA related registers */ 935bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr); 936bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len); 937bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr); 938bbefb871SMohammed Shafi Shajakhan 939bbefb871SMohammed Shafi Shajakhan /* 940bbefb871SMohammed Shafi Shajakhan * To avoid MCI state machine be affected by incoming remote MCI msgs, 941bbefb871SMohammed Shafi Shajakhan * MCI mode will be enabled later, right before reset the MCI TX and RX. 942bbefb871SMohammed Shafi Shajakhan */ 943d9575dadSBala Shanmugam if (AR_SREV_9565(ah)) { 944e18e164eSSujith Manoharan u8 ant = MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH); 945bbefb871SMohammed Shafi Shajakhan 946e18e164eSSujith Manoharan if (ant == ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED) 947e18e164eSSujith Manoharan ar9003_mci_set_btcoex_ctrl_9565_1ANT(ah); 948e18e164eSSujith Manoharan else 949e18e164eSSujith Manoharan ar9003_mci_set_btcoex_ctrl_9565_2ANT(ah); 950e18e164eSSujith Manoharan } else { 951e18e164eSSujith Manoharan ar9003_mci_set_btcoex_ctrl_9462(ah); 952e18e164eSSujith Manoharan } 953bbefb871SMohammed Shafi Shajakhan 9544f851df7SSujith Manoharan if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) 9554f851df7SSujith Manoharan ar9003_mci_osla_setup(ah, true); 9564f851df7SSujith Manoharan else 9574f851df7SSujith Manoharan ar9003_mci_osla_setup(ah, false); 9584f851df7SSujith Manoharan 959bbefb871SMohammed Shafi Shajakhan REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, 960bbefb871SMohammed Shafi Shajakhan AR_BTCOEX_CTRL_SPDT_ENABLE); 961bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3, 962bbefb871SMohammed Shafi Shajakhan AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); 963bbefb871SMohammed Shafi Shajakhan 964e75d4ed6SRajkumar Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 0); 965bbefb871SMohammed Shafi Shajakhan REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); 966bbefb871SMohammed Shafi Shajakhan 967e75d4ed6SRajkumar Manoharan /* Set the time out to 3.125ms (5 BT slots) */ 968e75d4ed6SRajkumar Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_WL_LNA, AR_BTCOEX_WL_LNA_TIMEOUT, 0x3D090); 969e75d4ed6SRajkumar Manoharan 970e82cb03fSRajkumar Manoharan /* concurrent tx priority */ 971e82cb03fSRajkumar Manoharan if (mci->config & ATH_MCI_CONFIG_CONCUR_TX) { 972e82cb03fSRajkumar Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, 973e82cb03fSRajkumar Manoharan AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE, 0); 974e82cb03fSRajkumar Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, 975e82cb03fSRajkumar Manoharan AR_BTCOEX_CTRL2_TXPWR_THRESH, 0x7f); 976e82cb03fSRajkumar Manoharan REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, 977e82cb03fSRajkumar Manoharan AR_BTCOEX_CTRL_REDUCE_TXPWR, 0); 978e82cb03fSRajkumar Manoharan for (i = 0; i < 8; i++) 979e82cb03fSRajkumar Manoharan REG_WRITE(ah, AR_BTCOEX_MAX_TXPWR(i), 0x7f7f7f7f); 980e82cb03fSRajkumar Manoharan } 981e82cb03fSRajkumar Manoharan 9824f851df7SSujith Manoharan regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV); 9834f851df7SSujith Manoharan REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval); 984bbefb871SMohammed Shafi Shajakhan REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN); 985bbefb871SMohammed Shafi Shajakhan 986bbefb871SMohammed Shafi Shajakhan /* Resetting the Rx and Tx paths of MCI */ 987bbefb871SMohammed Shafi Shajakhan regval = REG_READ(ah, AR_MCI_COMMAND2); 988bbefb871SMohammed Shafi Shajakhan regval |= SM(1, AR_MCI_COMMAND2_RESET_TX); 989bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_COMMAND2, regval); 990bbefb871SMohammed Shafi Shajakhan 991bbefb871SMohammed Shafi Shajakhan udelay(1); 992bbefb871SMohammed Shafi Shajakhan 993bbefb871SMohammed Shafi Shajakhan regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX); 994bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_COMMAND2, regval); 995bbefb871SMohammed Shafi Shajakhan 996bbefb871SMohammed Shafi Shajakhan if (is_full_sleep) { 997bbefb871SMohammed Shafi Shajakhan ar9003_mci_mute_bt(ah); 998bbefb871SMohammed Shafi Shajakhan udelay(100); 999bbefb871SMohammed Shafi Shajakhan } 1000bbefb871SMohammed Shafi Shajakhan 10013863495bSRajkumar Manoharan /* Check pending GPM msg before MCI Reset Rx */ 1002506847adSRajkumar Manoharan ar9003_mci_check_gpm_offset(ah); 10033863495bSRajkumar Manoharan 1004bbefb871SMohammed Shafi Shajakhan regval |= SM(1, AR_MCI_COMMAND2_RESET_RX); 1005bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_COMMAND2, regval); 1006bbefb871SMohammed Shafi Shajakhan udelay(1); 1007bbefb871SMohammed Shafi Shajakhan regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX); 1008bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_COMMAND2, regval); 1009bbefb871SMohammed Shafi Shajakhan 1010ad1dc638SSujith Manoharan /* Init GPM offset after MCI Reset Rx */ 1011ad1dc638SSujith Manoharan ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET); 10124f851df7SSujith Manoharan 1013bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 1014bbefb871SMohammed Shafi Shajakhan (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | 1015bbefb871SMohammed Shafi Shajakhan SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM))); 1016bbefb871SMohammed Shafi Shajakhan 1017d808ecd8SSujith Manoharan if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) 1018bbefb871SMohammed Shafi Shajakhan REG_CLR_BIT(ah, AR_MCI_TX_CTRL, 1019bbefb871SMohammed Shafi Shajakhan AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); 1020d808ecd8SSujith Manoharan else 1021d808ecd8SSujith Manoharan REG_SET_BIT(ah, AR_MCI_TX_CTRL, 1022d808ecd8SSujith Manoharan AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); 1023bbefb871SMohammed Shafi Shajakhan 1024bbefb871SMohammed Shafi Shajakhan ar9003_mci_observation_set_up(ah); 1025bbefb871SMohammed Shafi Shajakhan 1026bbefb871SMohammed Shafi Shajakhan mci->ready = true; 1027bbefb871SMohammed Shafi Shajakhan ar9003_mci_prep_interface(ah); 10284d9f7c68SSujith Manoharan ar9003_mci_stat_setup(ah); 1029bbefb871SMohammed Shafi Shajakhan 1030bbefb871SMohammed Shafi Shajakhan if (en_int) 1031bbefb871SMohammed Shafi Shajakhan ar9003_mci_enable_interrupt(ah); 103269c6ac60SSujith Manoharan 10337644317bSSujith Manoharan if (ath9k_hw_is_aic_enabled(ah)) 10347644317bSSujith Manoharan ar9003_aic_start_normal(ah); 10357644317bSSujith Manoharan 103669c6ac60SSujith Manoharan return 0; 1037bbefb871SMohammed Shafi Shajakhan } 1038bbefb871SMohammed Shafi Shajakhan 1039528e5d36SSujith Manoharan void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep) 1040528e5d36SSujith Manoharan { 1041528e5d36SSujith Manoharan struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 1042528e5d36SSujith Manoharan 1043528e5d36SSujith Manoharan ar9003_mci_disable_interrupt(ah); 1044528e5d36SSujith Manoharan 1045528e5d36SSujith Manoharan if (mci_hw->ready && !save_fullsleep) { 1046528e5d36SSujith Manoharan ar9003_mci_mute_bt(ah); 1047528e5d36SSujith Manoharan udelay(20); 1048528e5d36SSujith Manoharan REG_WRITE(ah, AR_BTCOEX_CTRL, 0); 1049528e5d36SSujith Manoharan } 1050528e5d36SSujith Manoharan 1051528e5d36SSujith Manoharan mci_hw->bt_state = MCI_BT_SLEEP; 1052528e5d36SSujith Manoharan mci_hw->ready = false; 1053528e5d36SSujith Manoharan } 1054528e5d36SSujith Manoharan 1055bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done) 1056bbefb871SMohammed Shafi Shajakhan { 1057bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1058*53d76f16Szhong jiang u32 to_set, to_clear; 1059bbefb871SMohammed Shafi Shajakhan 10604f6bd1a8SRajkumar Manoharan if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP)) 10614f6bd1a8SRajkumar Manoharan return; 10624f6bd1a8SRajkumar Manoharan 1063bbefb871SMohammed Shafi Shajakhan if (mci->is_2g) { 1064bbefb871SMohammed Shafi Shajakhan to_clear = MCI_2G_FLAGS_CLEAR_MASK; 1065bbefb871SMohammed Shafi Shajakhan to_set = MCI_2G_FLAGS_SET_MASK; 1066bbefb871SMohammed Shafi Shajakhan } else { 1067bbefb871SMohammed Shafi Shajakhan to_clear = MCI_5G_FLAGS_CLEAR_MASK; 1068bbefb871SMohammed Shafi Shajakhan to_set = MCI_5G_FLAGS_SET_MASK; 1069bbefb871SMohammed Shafi Shajakhan } 1070bbefb871SMohammed Shafi Shajakhan 1071bbefb871SMohammed Shafi Shajakhan if (to_clear) 1072bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_coex_bt_flags(ah, wait_done, 107337cd9d78SSujith Manoharan MCI_GPM_COEX_BT_FLAGS_CLEAR, 107437cd9d78SSujith Manoharan to_clear); 1075bbefb871SMohammed Shafi Shajakhan if (to_set) 1076bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_coex_bt_flags(ah, wait_done, 107737cd9d78SSujith Manoharan MCI_GPM_COEX_BT_FLAGS_SET, 107837cd9d78SSujith Manoharan to_set); 1079bbefb871SMohammed Shafi Shajakhan } 1080bbefb871SMohammed Shafi Shajakhan 1081bbefb871SMohammed Shafi Shajakhan static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header, 1082bbefb871SMohammed Shafi Shajakhan u32 *payload, bool queue) 1083bbefb871SMohammed Shafi Shajakhan { 1084bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1085bbefb871SMohammed Shafi Shajakhan u8 type, opcode; 1086bbefb871SMohammed Shafi Shajakhan 1087bbefb871SMohammed Shafi Shajakhan /* check if the message is to be queued */ 1088bbefb871SMohammed Shafi Shajakhan if (header != MCI_GPM) 1089bbefb871SMohammed Shafi Shajakhan return; 1090bbefb871SMohammed Shafi Shajakhan 1091bbefb871SMohammed Shafi Shajakhan type = MCI_GPM_TYPE(payload); 1092bbefb871SMohammed Shafi Shajakhan opcode = MCI_GPM_OPCODE(payload); 1093bbefb871SMohammed Shafi Shajakhan 1094bbefb871SMohammed Shafi Shajakhan if (type != MCI_GPM_COEX_AGENT) 1095bbefb871SMohammed Shafi Shajakhan return; 1096bbefb871SMohammed Shafi Shajakhan 1097bbefb871SMohammed Shafi Shajakhan switch (opcode) { 1098bbefb871SMohammed Shafi Shajakhan case MCI_GPM_COEX_BT_UPDATE_FLAGS: 1099bbefb871SMohammed Shafi Shajakhan if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) == 1100bbefb871SMohammed Shafi Shajakhan MCI_GPM_COEX_BT_FLAGS_READ) 1101bbefb871SMohammed Shafi Shajakhan break; 1102bbefb871SMohammed Shafi Shajakhan 1103bbefb871SMohammed Shafi Shajakhan mci->update_2g5g = queue; 1104bbefb871SMohammed Shafi Shajakhan 1105bbefb871SMohammed Shafi Shajakhan break; 1106bbefb871SMohammed Shafi Shajakhan case MCI_GPM_COEX_WLAN_CHANNELS: 1107bbefb871SMohammed Shafi Shajakhan mci->wlan_channels_update = queue; 1108bbefb871SMohammed Shafi Shajakhan break; 1109bbefb871SMohammed Shafi Shajakhan case MCI_GPM_COEX_HALT_BT_GPM: 1110bbefb871SMohammed Shafi Shajakhan if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == 1111bbefb871SMohammed Shafi Shajakhan MCI_GPM_COEX_BT_GPM_UNHALT) { 1112bbefb871SMohammed Shafi Shajakhan mci->unhalt_bt_gpm = queue; 1113bbefb871SMohammed Shafi Shajakhan 111437cd9d78SSujith Manoharan if (!queue) 1115bbefb871SMohammed Shafi Shajakhan mci->halted_bt_gpm = false; 1116bbefb871SMohammed Shafi Shajakhan } 1117bbefb871SMohammed Shafi Shajakhan 1118bbefb871SMohammed Shafi Shajakhan if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == 1119bbefb871SMohammed Shafi Shajakhan MCI_GPM_COEX_BT_GPM_HALT) { 1120bbefb871SMohammed Shafi Shajakhan 1121bbefb871SMohammed Shafi Shajakhan mci->halted_bt_gpm = !queue; 1122bbefb871SMohammed Shafi Shajakhan } 1123bbefb871SMohammed Shafi Shajakhan 1124bbefb871SMohammed Shafi Shajakhan break; 1125bbefb871SMohammed Shafi Shajakhan default: 1126bbefb871SMohammed Shafi Shajakhan break; 1127bbefb871SMohammed Shafi Shajakhan } 1128bbefb871SMohammed Shafi Shajakhan } 1129bbefb871SMohammed Shafi Shajakhan 11301bde95faSRajkumar Manoharan void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) 1131bbefb871SMohammed Shafi Shajakhan { 1132bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1133bbefb871SMohammed Shafi Shajakhan 11341bde95faSRajkumar Manoharan if (!mci->update_2g5g && !force) 11354f6bd1a8SRajkumar Manoharan return; 11364f6bd1a8SRajkumar Manoharan 1137bbefb871SMohammed Shafi Shajakhan if (mci->is_2g) { 1138bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_2g5g_status(ah, true); 11394ff6a9d2SRajkumar Manoharan ar9003_mci_send_lna_transfer(ah, true); 11404ff6a9d2SRajkumar Manoharan udelay(5); 11414ff6a9d2SRajkumar Manoharan 11424ff6a9d2SRajkumar Manoharan REG_CLR_BIT(ah, AR_MCI_TX_CTRL, 1143bbefb871SMohammed Shafi Shajakhan AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); 1144bbefb871SMohammed Shafi Shajakhan REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL, 1145bbefb871SMohammed Shafi Shajakhan AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); 11460cc4cdebSSujith Manoharan 11474f6bd1a8SRajkumar Manoharan if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) 11481bde95faSRajkumar Manoharan ar9003_mci_osla_setup(ah, true); 11497d47884fSRajkumar Manoharan 11507d47884fSRajkumar Manoharan if (AR_SREV_9462(ah)) 1151bfbee427SRajkumar Manoharan REG_WRITE(ah, AR_SELFGEN_MASK, 0x02); 1152bbefb871SMohammed Shafi Shajakhan } else { 11534ff6a9d2SRajkumar Manoharan ar9003_mci_send_lna_take(ah, true); 11544ff6a9d2SRajkumar Manoharan udelay(5); 11554ff6a9d2SRajkumar Manoharan 1156bbefb871SMohammed Shafi Shajakhan REG_SET_BIT(ah, AR_MCI_TX_CTRL, 1157bbefb871SMohammed Shafi Shajakhan AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); 1158bbefb871SMohammed Shafi Shajakhan REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, 1159bbefb871SMohammed Shafi Shajakhan AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); 1160bbefb871SMohammed Shafi Shajakhan 11611bde95faSRajkumar Manoharan ar9003_mci_osla_setup(ah, false); 1162bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_2g5g_status(ah, true); 1163bbefb871SMohammed Shafi Shajakhan } 1164bbefb871SMohammed Shafi Shajakhan } 1165bbefb871SMohammed Shafi Shajakhan 1166bbefb871SMohammed Shafi Shajakhan bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, 1167bbefb871SMohammed Shafi Shajakhan u32 *payload, u8 len, bool wait_done, 1168bbefb871SMohammed Shafi Shajakhan bool check_bt) 1169bbefb871SMohammed Shafi Shajakhan { 1170bbefb871SMohammed Shafi Shajakhan struct ath_common *common = ath9k_hw_common(ah); 1171bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1172bbefb871SMohammed Shafi Shajakhan bool msg_sent = false; 1173bbefb871SMohammed Shafi Shajakhan u32 regval; 1174bbefb871SMohammed Shafi Shajakhan u32 saved_mci_int_en; 1175bbefb871SMohammed Shafi Shajakhan int i; 1176bbefb871SMohammed Shafi Shajakhan 1177bbefb871SMohammed Shafi Shajakhan saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); 1178bbefb871SMohammed Shafi Shajakhan regval = REG_READ(ah, AR_BTCOEX_CTRL); 1179bbefb871SMohammed Shafi Shajakhan 1180bbefb871SMohammed Shafi Shajakhan if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) { 1181d2182b69SJoe Perches ath_dbg(common, MCI, 1182d2182b69SJoe Perches "MCI Not sending 0x%x. MCI is not enabled. full_sleep = %d\n", 118337cd9d78SSujith Manoharan header, (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0); 1184bbefb871SMohammed Shafi Shajakhan ar9003_mci_queue_unsent_gpm(ah, header, payload, true); 1185bbefb871SMohammed Shafi Shajakhan return false; 1186bbefb871SMohammed Shafi Shajakhan } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) { 1187d2182b69SJoe Perches ath_dbg(common, MCI, 1188d2182b69SJoe Perches "MCI Don't send message 0x%x. BT is in sleep state\n", 1189d2182b69SJoe Perches header); 1190bbefb871SMohammed Shafi Shajakhan ar9003_mci_queue_unsent_gpm(ah, header, payload, true); 1191bbefb871SMohammed Shafi Shajakhan return false; 1192bbefb871SMohammed Shafi Shajakhan } 1193bbefb871SMohammed Shafi Shajakhan 1194bbefb871SMohammed Shafi Shajakhan if (wait_done) 1195bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); 1196bbefb871SMohammed Shafi Shajakhan 1197bbefb871SMohammed Shafi Shajakhan /* Need to clear SW_MSG_DONE raw bit before wait */ 1198bbefb871SMohammed Shafi Shajakhan 1199bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, 1200bbefb871SMohammed Shafi Shajakhan (AR_MCI_INTERRUPT_SW_MSG_DONE | 1201bbefb871SMohammed Shafi Shajakhan AR_MCI_INTERRUPT_MSG_FAIL_MASK)); 1202bbefb871SMohammed Shafi Shajakhan 1203bbefb871SMohammed Shafi Shajakhan if (payload) { 1204bbefb871SMohammed Shafi Shajakhan for (i = 0; (i * 4) < len; i++) 1205bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4), 1206bbefb871SMohammed Shafi Shajakhan *(payload + i)); 1207bbefb871SMohammed Shafi Shajakhan } 1208bbefb871SMohammed Shafi Shajakhan 1209bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_COMMAND0, 1210bbefb871SMohammed Shafi Shajakhan (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP), 1211bbefb871SMohammed Shafi Shajakhan AR_MCI_COMMAND0_DISABLE_TIMESTAMP) | 1212bbefb871SMohammed Shafi Shajakhan SM(len, AR_MCI_COMMAND0_LEN) | 1213bbefb871SMohammed Shafi Shajakhan SM(header, AR_MCI_COMMAND0_HEADER))); 1214bbefb871SMohammed Shafi Shajakhan 1215bbefb871SMohammed Shafi Shajakhan if (wait_done && 1216bbefb871SMohammed Shafi Shajakhan !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW, 1217bbefb871SMohammed Shafi Shajakhan AR_MCI_INTERRUPT_SW_MSG_DONE, 500))) 1218bbefb871SMohammed Shafi Shajakhan ar9003_mci_queue_unsent_gpm(ah, header, payload, true); 1219bbefb871SMohammed Shafi Shajakhan else { 1220bbefb871SMohammed Shafi Shajakhan ar9003_mci_queue_unsent_gpm(ah, header, payload, false); 1221bbefb871SMohammed Shafi Shajakhan msg_sent = true; 1222bbefb871SMohammed Shafi Shajakhan } 1223bbefb871SMohammed Shafi Shajakhan 1224bbefb871SMohammed Shafi Shajakhan if (wait_done) 1225bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); 1226bbefb871SMohammed Shafi Shajakhan 1227bbefb871SMohammed Shafi Shajakhan return msg_sent; 1228bbefb871SMohammed Shafi Shajakhan } 1229bbefb871SMohammed Shafi Shajakhan EXPORT_SYMBOL(ar9003_mci_send_message); 1230bbefb871SMohammed Shafi Shajakhan 1231f2f408efSSujith Manoharan void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable) 1232f2f408efSSujith Manoharan { 1233f2f408efSSujith Manoharan struct ath_common *common = ath9k_hw_common(ah); 1234f2f408efSSujith Manoharan struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 1235f2f408efSSujith Manoharan u32 pld[4] = {0, 0, 0, 0}; 1236f2f408efSSujith Manoharan 1237f2f408efSSujith Manoharan if ((mci_hw->bt_state != MCI_BT_AWAKE) || 1238f2f408efSSujith Manoharan (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) 1239f2f408efSSujith Manoharan return; 1240f2f408efSSujith Manoharan 1241f2f408efSSujith Manoharan MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ); 1242f2f408efSSujith Manoharan pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++; 1243f2f408efSSujith Manoharan 1244f2f408efSSujith Manoharan ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); 1245f2f408efSSujith Manoharan 1246f2f408efSSujith Manoharan if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) { 124737cd9d78SSujith Manoharan ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n"); 1248f2f408efSSujith Manoharan } else { 12492fd5d35bSSujith Manoharan *is_reusable = false; 125037cd9d78SSujith Manoharan ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n"); 1251f2f408efSSujith Manoharan } 1252f2f408efSSujith Manoharan } 1253f2f408efSSujith Manoharan 1254f2f408efSSujith Manoharan void ar9003_mci_init_cal_done(struct ath_hw *ah) 1255f2f408efSSujith Manoharan { 1256f2f408efSSujith Manoharan struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 1257f2f408efSSujith Manoharan u32 pld[4] = {0, 0, 0, 0}; 1258f2f408efSSujith Manoharan 1259f2f408efSSujith Manoharan if ((mci_hw->bt_state != MCI_BT_AWAKE) || 1260f2f408efSSujith Manoharan (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) 1261f2f408efSSujith Manoharan return; 1262f2f408efSSujith Manoharan 1263f2f408efSSujith Manoharan MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE); 1264f2f408efSSujith Manoharan pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++; 1265f2f408efSSujith Manoharan ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); 1266f2f408efSSujith Manoharan } 1267f2f408efSSujith Manoharan 126869c6ac60SSujith Manoharan int ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, 1269bbefb871SMohammed Shafi Shajakhan u16 len, u32 sched_addr) 1270bbefb871SMohammed Shafi Shajakhan { 1271bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1272bbefb871SMohammed Shafi Shajakhan 1273bbefb871SMohammed Shafi Shajakhan mci->gpm_addr = gpm_addr; 1274bbefb871SMohammed Shafi Shajakhan mci->gpm_buf = gpm_buf; 1275bbefb871SMohammed Shafi Shajakhan mci->gpm_len = len; 1276bbefb871SMohammed Shafi Shajakhan mci->sched_addr = sched_addr; 1277bbefb871SMohammed Shafi Shajakhan 127869c6ac60SSujith Manoharan return ar9003_mci_reset(ah, true, true, true); 1279bbefb871SMohammed Shafi Shajakhan } 1280bbefb871SMohammed Shafi Shajakhan EXPORT_SYMBOL(ar9003_mci_setup); 1281bbefb871SMohammed Shafi Shajakhan 1282bbefb871SMohammed Shafi Shajakhan void ar9003_mci_cleanup(struct ath_hw *ah) 1283bbefb871SMohammed Shafi Shajakhan { 1284bbefb871SMohammed Shafi Shajakhan /* Turn off MCI and Jupiter mode. */ 1285bbefb871SMohammed Shafi Shajakhan REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00); 1286bbefb871SMohammed Shafi Shajakhan ar9003_mci_disable_interrupt(ah); 1287bbefb871SMohammed Shafi Shajakhan } 1288bbefb871SMohammed Shafi Shajakhan EXPORT_SYMBOL(ar9003_mci_cleanup); 1289bbefb871SMohammed Shafi Shajakhan 1290b98ccec0SRajkumar Manoharan u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) 1291bbefb871SMohammed Shafi Shajakhan { 1292bbefb871SMohammed Shafi Shajakhan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 12932097fdd7SRajkumar Manoharan u32 value = 0, tsf; 1294bbefb871SMohammed Shafi Shajakhan u8 query_type; 1295bbefb871SMohammed Shafi Shajakhan 1296bbefb871SMohammed Shafi Shajakhan switch (state_type) { 1297bbefb871SMohammed Shafi Shajakhan case MCI_STATE_ENABLE: 1298bbefb871SMohammed Shafi Shajakhan if (mci->ready) { 1299bbefb871SMohammed Shafi Shajakhan value = REG_READ(ah, AR_BTCOEX_CTRL); 1300bbefb871SMohammed Shafi Shajakhan 1301bbefb871SMohammed Shafi Shajakhan if ((value == 0xdeadbeef) || (value == 0xffffffff)) 1302bbefb871SMohammed Shafi Shajakhan value = 0; 1303bbefb871SMohammed Shafi Shajakhan } 1304bbefb871SMohammed Shafi Shajakhan value &= AR_BTCOEX_CTRL_MCI_MODE_EN; 1305bbefb871SMohammed Shafi Shajakhan break; 1306ad1dc638SSujith Manoharan case MCI_STATE_INIT_GPM_OFFSET: 1307ad1dc638SSujith Manoharan value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); 1308ad1dc638SSujith Manoharan 1309ad1dc638SSujith Manoharan if (value < mci->gpm_len) 1310ad1dc638SSujith Manoharan mci->gpm_idx = value; 1311ad1dc638SSujith Manoharan else 1312ad1dc638SSujith Manoharan mci->gpm_idx = 0; 1313ad1dc638SSujith Manoharan break; 1314bbefb871SMohammed Shafi Shajakhan case MCI_STATE_LAST_SCHD_MSG_OFFSET: 1315bbefb871SMohammed Shafi Shajakhan value = MS(REG_READ(ah, AR_MCI_RX_STATUS), 1316bbefb871SMohammed Shafi Shajakhan AR_MCI_RX_LAST_SCHD_MSG_INDEX); 1317bbefb871SMohammed Shafi Shajakhan /* Make it in bytes */ 1318bbefb871SMohammed Shafi Shajakhan value <<= 4; 1319bbefb871SMohammed Shafi Shajakhan break; 1320bbefb871SMohammed Shafi Shajakhan case MCI_STATE_REMOTE_SLEEP: 1321bbefb871SMohammed Shafi Shajakhan value = MS(REG_READ(ah, AR_MCI_RX_STATUS), 1322bbefb871SMohammed Shafi Shajakhan AR_MCI_RX_REMOTE_SLEEP) ? 1323bbefb871SMohammed Shafi Shajakhan MCI_BT_SLEEP : MCI_BT_AWAKE; 1324bbefb871SMohammed Shafi Shajakhan break; 1325bbefb871SMohammed Shafi Shajakhan case MCI_STATE_SET_BT_AWAKE: 1326bbefb871SMohammed Shafi Shajakhan mci->bt_state = MCI_BT_AWAKE; 1327bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_coex_version_query(ah, true); 1328bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_coex_wlan_channels(ah, true); 1329bbefb871SMohammed Shafi Shajakhan 133037cd9d78SSujith Manoharan if (mci->unhalt_bt_gpm) 1331bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); 1332bbefb871SMohammed Shafi Shajakhan 13331bde95faSRajkumar Manoharan ar9003_mci_2g5g_switch(ah, false); 1334bbefb871SMohammed Shafi Shajakhan break; 1335bbefb871SMohammed Shafi Shajakhan case MCI_STATE_RESET_REQ_WAKE: 1336bbefb871SMohammed Shafi Shajakhan ar9003_mci_reset_req_wakeup(ah); 1337bbefb871SMohammed Shafi Shajakhan mci->update_2g5g = true; 1338bbefb871SMohammed Shafi Shajakhan 13390cc4cdebSSujith Manoharan if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) { 1340bbefb871SMohammed Shafi Shajakhan /* Check if we still have control of the GPIOs */ 1341bbefb871SMohammed Shafi Shajakhan if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) & 1342bbefb871SMohammed Shafi Shajakhan ATH_MCI_CONFIG_MCI_OBS_GPIO) != 1343bbefb871SMohammed Shafi Shajakhan ATH_MCI_CONFIG_MCI_OBS_GPIO) { 1344bbefb871SMohammed Shafi Shajakhan ar9003_mci_observation_set_up(ah); 1345bbefb871SMohammed Shafi Shajakhan } 1346bbefb871SMohammed Shafi Shajakhan } 1347bbefb871SMohammed Shafi Shajakhan break; 1348bbefb871SMohammed Shafi Shajakhan case MCI_STATE_SEND_WLAN_COEX_VERSION: 1349bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_coex_version_response(ah, true); 1350bbefb871SMohammed Shafi Shajakhan break; 1351bbefb871SMohammed Shafi Shajakhan case MCI_STATE_SEND_VERSION_QUERY: 1352bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_coex_version_query(ah, true); 1353bbefb871SMohammed Shafi Shajakhan break; 1354bbefb871SMohammed Shafi Shajakhan case MCI_STATE_SEND_STATUS_QUERY: 1355c91ec465SSujith Manoharan query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY; 1356bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_coex_bt_status_query(ah, true, query_type); 1357bbefb871SMohammed Shafi Shajakhan break; 1358bbefb871SMohammed Shafi Shajakhan case MCI_STATE_RECOVER_RX: 13592097fdd7SRajkumar Manoharan tsf = ath9k_hw_gettsf32(ah); 13602097fdd7SRajkumar Manoharan if ((tsf - mci->last_recovery) <= MCI_RECOVERY_DUR_TSF) { 13612097fdd7SRajkumar Manoharan ath_dbg(ath9k_hw_common(ah), MCI, 13622097fdd7SRajkumar Manoharan "(MCI) ignore Rx recovery\n"); 13632097fdd7SRajkumar Manoharan break; 13642097fdd7SRajkumar Manoharan } 13652097fdd7SRajkumar Manoharan ath_dbg(ath9k_hw_common(ah), MCI, "(MCI) RECOVER RX\n"); 13662097fdd7SRajkumar Manoharan mci->last_recovery = tsf; 1367bbefb871SMohammed Shafi Shajakhan ar9003_mci_prep_interface(ah); 1368bbefb871SMohammed Shafi Shajakhan mci->query_bt = true; 1369bbefb871SMohammed Shafi Shajakhan mci->need_flush_btinfo = true; 1370bbefb871SMohammed Shafi Shajakhan ar9003_mci_send_coex_wlan_channels(ah, true); 13711bde95faSRajkumar Manoharan ar9003_mci_2g5g_switch(ah, false); 1372bbefb871SMohammed Shafi Shajakhan break; 1373bbefb871SMohammed Shafi Shajakhan case MCI_STATE_NEED_FTP_STOMP: 1374bbefb871SMohammed Shafi Shajakhan value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); 1375bbefb871SMohammed Shafi Shajakhan break; 1376d92bb98fSRajkumar Manoharan case MCI_STATE_NEED_FLUSH_BT_INFO: 1377d92bb98fSRajkumar Manoharan value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; 1378d92bb98fSRajkumar Manoharan mci->need_flush_btinfo = false; 1379d92bb98fSRajkumar Manoharan break; 138060544603SSujith Manoharan case MCI_STATE_AIC_CAL: 138160544603SSujith Manoharan if (ath9k_hw_is_aic_enabled(ah)) 138260544603SSujith Manoharan value = ar9003_aic_calibration(ah); 138360544603SSujith Manoharan break; 1384f2ef792aSSujith Manoharan case MCI_STATE_AIC_START: 1385f2ef792aSSujith Manoharan if (ath9k_hw_is_aic_enabled(ah)) 1386f2ef792aSSujith Manoharan ar9003_aic_start_normal(ah); 1387f2ef792aSSujith Manoharan break; 1388958b6827SSujith Manoharan case MCI_STATE_AIC_CAL_RESET: 1389958b6827SSujith Manoharan if (ath9k_hw_is_aic_enabled(ah)) 1390958b6827SSujith Manoharan value = ar9003_aic_cal_reset(ah); 1391958b6827SSujith Manoharan break; 1392b6ab9ae2SSujith Manoharan case MCI_STATE_AIC_CAL_SINGLE: 1393208837eeSSujith Manoharan if (ath9k_hw_is_aic_enabled(ah)) 1394b6ab9ae2SSujith Manoharan value = ar9003_aic_calibration_single(ah); 1395b6ab9ae2SSujith Manoharan break; 1396bbefb871SMohammed Shafi Shajakhan default: 1397bbefb871SMohammed Shafi Shajakhan break; 1398bbefb871SMohammed Shafi Shajakhan } 1399bbefb871SMohammed Shafi Shajakhan 1400bbefb871SMohammed Shafi Shajakhan return value; 1401bbefb871SMohammed Shafi Shajakhan } 1402bbefb871SMohammed Shafi Shajakhan EXPORT_SYMBOL(ar9003_mci_state); 140399922a45SRajkumar Manoharan 140499922a45SRajkumar Manoharan void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah) 140599922a45SRajkumar Manoharan { 140699922a45SRajkumar Manoharan struct ath_common *common = ath9k_hw_common(ah); 140799922a45SRajkumar Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 140899922a45SRajkumar Manoharan 140999922a45SRajkumar Manoharan ath_dbg(common, MCI, "Give LNA and SPDT control to BT\n"); 141099922a45SRajkumar Manoharan 14114ff6a9d2SRajkumar Manoharan ar9003_mci_send_lna_take(ah, true); 14124ff6a9d2SRajkumar Manoharan udelay(50); 14134ff6a9d2SRajkumar Manoharan 141499922a45SRajkumar Manoharan REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); 141599922a45SRajkumar Manoharan mci->is_2g = false; 141699922a45SRajkumar Manoharan mci->update_2g5g = true; 141799922a45SRajkumar Manoharan ar9003_mci_send_2g5g_status(ah, true); 141899922a45SRajkumar Manoharan 141999922a45SRajkumar Manoharan /* Force another 2g5g update at next scanning */ 142099922a45SRajkumar Manoharan mci->update_2g5g = true; 142199922a45SRajkumar Manoharan } 14229dd9b0dcSRajkumar Manoharan 14239dd9b0dcSRajkumar Manoharan void ar9003_mci_set_power_awake(struct ath_hw *ah) 14249dd9b0dcSRajkumar Manoharan { 14259dd9b0dcSRajkumar Manoharan u32 btcoex_ctrl2, diag_sw; 14269dd9b0dcSRajkumar Manoharan int i; 14279dd9b0dcSRajkumar Manoharan u8 lna_ctrl, bt_sleep; 14289dd9b0dcSRajkumar Manoharan 14299dd9b0dcSRajkumar Manoharan for (i = 0; i < AH_WAIT_TIMEOUT; i++) { 14309dd9b0dcSRajkumar Manoharan btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2); 14319dd9b0dcSRajkumar Manoharan if (btcoex_ctrl2 != 0xdeadbeef) 14329dd9b0dcSRajkumar Manoharan break; 14339dd9b0dcSRajkumar Manoharan udelay(AH_TIME_QUANTUM); 14349dd9b0dcSRajkumar Manoharan } 14359dd9b0dcSRajkumar Manoharan REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23))); 14369dd9b0dcSRajkumar Manoharan 14379dd9b0dcSRajkumar Manoharan for (i = 0; i < AH_WAIT_TIMEOUT; i++) { 14389dd9b0dcSRajkumar Manoharan diag_sw = REG_READ(ah, AR_DIAG_SW); 14399dd9b0dcSRajkumar Manoharan if (diag_sw != 0xdeadbeef) 14409dd9b0dcSRajkumar Manoharan break; 14419dd9b0dcSRajkumar Manoharan udelay(AH_TIME_QUANTUM); 14429dd9b0dcSRajkumar Manoharan } 14439dd9b0dcSRajkumar Manoharan REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18))); 14449dd9b0dcSRajkumar Manoharan lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3; 1445a50d1fd4SRajkumar Manoharan bt_sleep = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP); 14469dd9b0dcSRajkumar Manoharan 14479dd9b0dcSRajkumar Manoharan REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2); 14489dd9b0dcSRajkumar Manoharan REG_WRITE(ah, AR_DIAG_SW, diag_sw); 14499dd9b0dcSRajkumar Manoharan 14509dd9b0dcSRajkumar Manoharan if (bt_sleep && (lna_ctrl == 2)) { 14519dd9b0dcSRajkumar Manoharan REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1); 14529dd9b0dcSRajkumar Manoharan REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1); 14539dd9b0dcSRajkumar Manoharan udelay(50); 14549dd9b0dcSRajkumar Manoharan } 14559dd9b0dcSRajkumar Manoharan } 1456506847adSRajkumar Manoharan 1457506847adSRajkumar Manoharan void ar9003_mci_check_gpm_offset(struct ath_hw *ah) 1458506847adSRajkumar Manoharan { 1459506847adSRajkumar Manoharan struct ath_common *common = ath9k_hw_common(ah); 1460506847adSRajkumar Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1461506847adSRajkumar Manoharan u32 offset; 1462506847adSRajkumar Manoharan 1463506847adSRajkumar Manoharan /* 1464506847adSRajkumar Manoharan * This should only be called before "MAC Warm Reset" or "MCI Reset Rx". 1465506847adSRajkumar Manoharan */ 1466506847adSRajkumar Manoharan offset = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); 1467506847adSRajkumar Manoharan if (mci->gpm_idx == offset) 1468506847adSRajkumar Manoharan return; 1469506847adSRajkumar Manoharan ath_dbg(common, MCI, "GPM cached write pointer mismatch %d %d\n", 1470506847adSRajkumar Manoharan mci->gpm_idx, offset); 1471506847adSRajkumar Manoharan mci->query_bt = true; 1472506847adSRajkumar Manoharan mci->need_flush_btinfo = true; 1473506847adSRajkumar Manoharan mci->gpm_idx = 0; 1474506847adSRajkumar Manoharan } 1475506847adSRajkumar Manoharan 1476ad1dc638SSujith Manoharan u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, u32 *more) 1477506847adSRajkumar Manoharan { 1478506847adSRajkumar Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1479506847adSRajkumar Manoharan u32 offset, more_gpm = 0, gpm_ptr; 1480506847adSRajkumar Manoharan 1481506847adSRajkumar Manoharan /* 1482506847adSRajkumar Manoharan * This could be useful to avoid new GPM message interrupt which 1483506847adSRajkumar Manoharan * may lead to spurious interrupt after power sleep, or multiple 1484506847adSRajkumar Manoharan * entry of ath_mci_intr(). 1485506847adSRajkumar Manoharan * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can 1486506847adSRajkumar Manoharan * alleviate this effect, but clearing GPM RX interrupt bit is 1487506847adSRajkumar Manoharan * safe, because whether this is called from hw or driver code 1488506847adSRajkumar Manoharan * there must be an interrupt bit set/triggered initially 1489506847adSRajkumar Manoharan */ 1490506847adSRajkumar Manoharan REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 1491506847adSRajkumar Manoharan AR_MCI_INTERRUPT_RX_MSG_GPM); 1492506847adSRajkumar Manoharan 1493506847adSRajkumar Manoharan gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); 1494506847adSRajkumar Manoharan offset = gpm_ptr; 1495506847adSRajkumar Manoharan 1496506847adSRajkumar Manoharan if (!offset) 1497506847adSRajkumar Manoharan offset = mci->gpm_len - 1; 1498506847adSRajkumar Manoharan else if (offset >= mci->gpm_len) { 1499506847adSRajkumar Manoharan if (offset != 0xFFFF) 1500506847adSRajkumar Manoharan offset = 0; 1501506847adSRajkumar Manoharan } else { 1502506847adSRajkumar Manoharan offset--; 1503506847adSRajkumar Manoharan } 1504506847adSRajkumar Manoharan 1505506847adSRajkumar Manoharan if ((offset == 0xFFFF) || (gpm_ptr == mci->gpm_idx)) { 1506506847adSRajkumar Manoharan offset = MCI_GPM_INVALID; 1507506847adSRajkumar Manoharan more_gpm = MCI_GPM_NOMORE; 1508506847adSRajkumar Manoharan goto out; 1509506847adSRajkumar Manoharan } 1510506847adSRajkumar Manoharan for (;;) { 1511506847adSRajkumar Manoharan u32 temp_index; 1512506847adSRajkumar Manoharan 1513506847adSRajkumar Manoharan /* skip reserved GPM if any */ 1514506847adSRajkumar Manoharan 1515506847adSRajkumar Manoharan if (offset != mci->gpm_idx) 1516506847adSRajkumar Manoharan more_gpm = MCI_GPM_MORE; 1517506847adSRajkumar Manoharan else 1518506847adSRajkumar Manoharan more_gpm = MCI_GPM_NOMORE; 1519506847adSRajkumar Manoharan 1520506847adSRajkumar Manoharan temp_index = mci->gpm_idx; 152190be994cSMohammed Shafi Shajakhan 152290be994cSMohammed Shafi Shajakhan if (temp_index >= mci->gpm_len) 152390be994cSMohammed Shafi Shajakhan temp_index = 0; 152490be994cSMohammed Shafi Shajakhan 1525506847adSRajkumar Manoharan mci->gpm_idx++; 1526506847adSRajkumar Manoharan 1527506847adSRajkumar Manoharan if (mci->gpm_idx >= mci->gpm_len) 1528506847adSRajkumar Manoharan mci->gpm_idx = 0; 1529506847adSRajkumar Manoharan 1530506847adSRajkumar Manoharan if (ar9003_mci_is_gpm_valid(ah, temp_index)) { 1531506847adSRajkumar Manoharan offset = temp_index; 1532506847adSRajkumar Manoharan break; 1533506847adSRajkumar Manoharan } 1534506847adSRajkumar Manoharan 1535506847adSRajkumar Manoharan if (more_gpm == MCI_GPM_NOMORE) { 1536506847adSRajkumar Manoharan offset = MCI_GPM_INVALID; 1537506847adSRajkumar Manoharan break; 1538506847adSRajkumar Manoharan } 1539506847adSRajkumar Manoharan } 1540506847adSRajkumar Manoharan 1541506847adSRajkumar Manoharan if (offset != MCI_GPM_INVALID) 1542506847adSRajkumar Manoharan offset <<= 4; 1543506847adSRajkumar Manoharan out: 1544506847adSRajkumar Manoharan if (more) 1545506847adSRajkumar Manoharan *more = more_gpm; 1546506847adSRajkumar Manoharan 1547506847adSRajkumar Manoharan return offset; 1548506847adSRajkumar Manoharan } 1549506847adSRajkumar Manoharan EXPORT_SYMBOL(ar9003_mci_get_next_gpm_offset); 1550e1763d3fSRajkumar Manoharan 1551e1763d3fSRajkumar Manoharan void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor) 1552e1763d3fSRajkumar Manoharan { 1553e1763d3fSRajkumar Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 1554e1763d3fSRajkumar Manoharan 1555e1763d3fSRajkumar Manoharan mci->bt_ver_major = major; 1556e1763d3fSRajkumar Manoharan mci->bt_ver_minor = minor; 1557e1763d3fSRajkumar Manoharan mci->bt_version_known = true; 1558e1763d3fSRajkumar Manoharan ath_dbg(ath9k_hw_common(ah), MCI, "MCI BT version set: %d.%d\n", 1559e1763d3fSRajkumar Manoharan mci->bt_ver_major, mci->bt_ver_minor); 1560e1763d3fSRajkumar Manoharan } 1561e1763d3fSRajkumar Manoharan EXPORT_SYMBOL(ar9003_mci_set_bt_version); 15622d340ac8SRajkumar Manoharan 15632d340ac8SRajkumar Manoharan void ar9003_mci_send_wlan_channels(struct ath_hw *ah) 15642d340ac8SRajkumar Manoharan { 15652d340ac8SRajkumar Manoharan struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; 15662d340ac8SRajkumar Manoharan 15672d340ac8SRajkumar Manoharan mci->wlan_channels_update = true; 15682d340ac8SRajkumar Manoharan ar9003_mci_send_coex_wlan_channels(ah, true); 15692d340ac8SRajkumar Manoharan } 15702d340ac8SRajkumar Manoharan EXPORT_SYMBOL(ar9003_mci_send_wlan_channels); 1571e82cb03fSRajkumar Manoharan 1572e82cb03fSRajkumar Manoharan u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode) 1573e82cb03fSRajkumar Manoharan { 1574e82cb03fSRajkumar Manoharan if (!ah->btcoex_hw.mci.concur_tx) 1575e82cb03fSRajkumar Manoharan goto out; 1576e82cb03fSRajkumar Manoharan 1577e82cb03fSRajkumar Manoharan if (ctlmode == CTL_2GHT20) 1578e82cb03fSRajkumar Manoharan return ATH_BTCOEX_HT20_MAX_TXPOWER; 1579e82cb03fSRajkumar Manoharan else if (ctlmode == CTL_2GHT40) 1580e82cb03fSRajkumar Manoharan return ATH_BTCOEX_HT40_MAX_TXPOWER; 1581e82cb03fSRajkumar Manoharan 1582e82cb03fSRajkumar Manoharan out: 1583e82cb03fSRajkumar Manoharan return -1; 1584e82cb03fSRajkumar Manoharan } 1585