1584 lines · c
1/*2 * Copyright (c) 2008-2011 Atheros Communications Inc.3 *4 * Permission to use, copy, modify, and/or distribute this software for any5 * purpose with or without fee is hereby granted, provided that the above6 * copyright notice and this permission notice appear in all copies.7 *8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.15 */16 17#include <linux/export.h>18#include "hw.h"19#include "hw-ops.h"20#include "ar9003_phy.h"21#include "ar9003_mci.h"22#include "ar9003_aic.h"23 24static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah)25{26 REG_RMW_FIELD(ah, AR_MCI_COMMAND2,27 AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1);28 udelay(1);29 REG_RMW_FIELD(ah, AR_MCI_COMMAND2,30 AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 0);31}32 33static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address,34 u32 bit_position, int time_out)35{36 struct ath_common *common = ath9k_hw_common(ah);37 38 while (time_out) {39 if (!(REG_READ(ah, address) & bit_position)) {40 udelay(10);41 time_out -= 10;42 43 if (time_out < 0)44 break;45 else46 continue;47 }48 REG_WRITE(ah, address, bit_position);49 50 if (address != AR_MCI_INTERRUPT_RX_MSG_RAW)51 break;52 53 if (bit_position & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)54 ar9003_mci_reset_req_wakeup(ah);55 56 if (bit_position & (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |57 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))58 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,59 AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);60 61 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_RX_MSG);62 break;63 }64 65 if (time_out <= 0) {66 ath_dbg(common, MCI,67 "MCI Wait for Reg 0x%08x = 0x%08x timeout\n",68 address, bit_position);69 ath_dbg(common, MCI,70 "MCI INT_RAW = 0x%08x, RX_MSG_RAW = 0x%08x\n",71 REG_READ(ah, AR_MCI_INTERRUPT_RAW),72 REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW));73 time_out = 0;74 }75 76 return time_out;77}78 79static void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done)80{81 u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00};82 83 ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16,84 wait_done, false);85 udelay(5);86}87 88static void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done)89{90 u32 payload = 0x00000000;91 92 ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1,93 wait_done, false);94}95 96static void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done)97{98 ar9003_mci_send_message(ah, MCI_REQ_WAKE, MCI_FLAG_DISABLE_TIMESTAMP,99 NULL, 0, wait_done, false);100 udelay(5);101}102 103static void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done)104{105 ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP,106 NULL, 0, wait_done, false);107}108 109static void ar9003_mci_send_lna_take(struct ath_hw *ah, bool wait_done)110{111 u32 payload = 0x70000000;112 113 ar9003_mci_send_message(ah, MCI_LNA_TAKE, 0, &payload, 1,114 wait_done, false);115}116 117static void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done)118{119 ar9003_mci_send_message(ah, MCI_SYS_SLEEPING,120 MCI_FLAG_DISABLE_TIMESTAMP,121 NULL, 0, wait_done, false);122}123 124static void ar9003_mci_send_coex_version_query(struct ath_hw *ah,125 bool wait_done)126{127 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;128 u32 payload[4] = {0, 0, 0, 0};129 130 if (mci->bt_version_known ||131 (mci->bt_state == MCI_BT_SLEEP))132 return;133 134 MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,135 MCI_GPM_COEX_VERSION_QUERY);136 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);137}138 139static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,140 bool wait_done)141{142 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;143 u32 payload[4] = {0, 0, 0, 0};144 145 MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,146 MCI_GPM_COEX_VERSION_RESPONSE);147 *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) =148 mci->wlan_ver_major;149 *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) =150 mci->wlan_ver_minor;151 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);152}153 154static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,155 bool wait_done)156{157 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;158 u32 *payload = &mci->wlan_channels[0];159 160 if (!mci->wlan_channels_update ||161 (mci->bt_state == MCI_BT_SLEEP))162 return;163 164 MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,165 MCI_GPM_COEX_WLAN_CHANNELS);166 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);167 MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);168}169 170static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,171 bool wait_done, u8 query_type)172{173 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;174 u32 payload[4] = {0, 0, 0, 0};175 bool query_btinfo;176 177 if (mci->bt_state == MCI_BT_SLEEP)178 return;179 180 query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |181 MCI_GPM_COEX_QUERY_BT_TOPOLOGY));182 MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,183 MCI_GPM_COEX_STATUS_QUERY);184 185 *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;186 187 /*188 * If bt_status_query message is not sent successfully,189 * then need_flush_btinfo should be set again.190 */191 if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,192 wait_done, true)) {193 if (query_btinfo)194 mci->need_flush_btinfo = true;195 }196 197 if (query_btinfo)198 mci->query_bt = false;199}200 201static void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,202 bool wait_done)203{204 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;205 u32 payload[4] = {0, 0, 0, 0};206 207 MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,208 MCI_GPM_COEX_HALT_BT_GPM);209 210 if (halt) {211 mci->query_bt = true;212 /* Send next unhalt no matter halt sent or not */213 mci->unhalt_bt_gpm = true;214 mci->need_flush_btinfo = true;215 *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) =216 MCI_GPM_COEX_BT_GPM_HALT;217 } else218 *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) =219 MCI_GPM_COEX_BT_GPM_UNHALT;220 221 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);222}223 224static void ar9003_mci_prep_interface(struct ath_hw *ah)225{226 struct ath_common *common = ath9k_hw_common(ah);227 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;228 u32 saved_mci_int_en;229 u32 mci_timeout = 150;230 231 mci->bt_state = MCI_BT_SLEEP;232 saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);233 234 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);235 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,236 REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW));237 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,238 REG_READ(ah, AR_MCI_INTERRUPT_RAW));239 240 ar9003_mci_remote_reset(ah, true);241 ar9003_mci_send_req_wake(ah, true);242 243 if (!ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,244 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500))245 goto clear_redunt;246 247 mci->bt_state = MCI_BT_AWAKE;248 249 /*250 * we don't need to send more remote_reset at this moment.251 * If BT receive first remote_reset, then BT HW will252 * be cleaned up and will be able to receive req_wake253 * and BT HW will respond sys_waking.254 * In this case, WLAN will receive BT's HW sys_waking.255 * Otherwise, if BT SW missed initial remote_reset,256 * that remote_reset will still clean up BT MCI RX,257 * and the req_wake will wake BT up,258 * and BT SW will respond this req_wake with a remote_reset and259 * sys_waking. In this case, WLAN will receive BT's SW260 * sys_waking. In either case, BT's RX is cleaned up. So we261 * don't need to reply BT's remote_reset now, if any.262 * Similarly, if in any case, WLAN can receive BT's sys_waking,263 * that means WLAN's RX is also fine.264 */265 ar9003_mci_send_sys_waking(ah, true);266 udelay(10);267 268 /*269 * Set BT priority interrupt value to be 0xff to270 * avoid having too many BT PRIORITY interrupts.271 */272 REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);273 REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);274 REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);275 REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);276 REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);277 278 /*279 * A contention reset will be received after send out280 * sys_waking. Also BT priority interrupt bits will be set.281 * Clear those bits before the next step.282 */283 284 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,285 AR_MCI_INTERRUPT_RX_MSG_CONT_RST);286 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI);287 288 if (mci->is_2g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) {289 ar9003_mci_send_lna_transfer(ah, true);290 udelay(5);291 }292 293 if (mci->is_2g && !mci->update_2g5g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) {294 if (ar9003_mci_wait_for_interrupt(ah,295 AR_MCI_INTERRUPT_RX_MSG_RAW,296 AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,297 mci_timeout))298 ath_dbg(common, MCI,299 "MCI WLAN has control over the LNA & BT obeys it\n");300 else301 ath_dbg(common, MCI,302 "MCI BT didn't respond to LNA_TRANS\n");303 }304 305clear_redunt:306 /* Clear the extra redundant SYS_WAKING from BT */307 if ((mci->bt_state == MCI_BT_AWAKE) &&308 (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,309 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&310 (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,311 AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {312 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,313 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING);314 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,315 AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);316 }317 318 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);319}320 321void ar9003_mci_set_full_sleep(struct ath_hw *ah)322{323 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;324 325 if (ar9003_mci_state(ah, MCI_STATE_ENABLE) &&326 (mci->bt_state != MCI_BT_SLEEP) &&327 !mci->halted_bt_gpm) {328 ar9003_mci_send_coex_halt_bt_gpm(ah, true, true);329 }330 331 mci->ready = false;332}333 334static void ar9003_mci_disable_interrupt(struct ath_hw *ah)335{336 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);337 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);338}339 340static void ar9003_mci_enable_interrupt(struct ath_hw *ah)341{342 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT);343 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN,344 AR_MCI_INTERRUPT_RX_MSG_DEFAULT);345}346 347static bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints)348{349 u32 intr;350 351 intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);352 return ((intr & ints) == ints);353}354 355void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,356 u32 *rx_msg_intr)357{358 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;359 360 *raw_intr = mci->raw_intr;361 *rx_msg_intr = mci->rx_msg_intr;362 363 /* Clean int bits after the values are read. */364 mci->raw_intr = 0;365 mci->rx_msg_intr = 0;366}367EXPORT_SYMBOL(ar9003_mci_get_interrupt);368 369void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)370{371 struct ath_common *common = ath9k_hw_common(ah);372 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;373 u32 raw_intr, rx_msg_intr;374 375 rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);376 raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW);377 378 if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) {379 ath_dbg(common, MCI,380 "MCI gets 0xdeadbeef during int processing\n");381 } else {382 mci->rx_msg_intr |= rx_msg_intr;383 mci->raw_intr |= raw_intr;384 *masked |= ATH9K_INT_MCI;385 386 if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO)387 mci->cont_status = REG_READ(ah, AR_MCI_CONT_STATUS);388 389 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr);390 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr);391 }392}393 394static void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g)395{396 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;397 398 if (!mci->update_2g5g &&399 (mci->is_2g != is_2g))400 mci->update_2g5g = true;401 402 mci->is_2g = is_2g;403}404 405static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index)406{407 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;408 u32 *payload;409 u32 recv_type, offset;410 411 if (msg_index == MCI_GPM_INVALID)412 return false;413 414 offset = msg_index << 4;415 416 payload = (u32 *)(mci->gpm_buf + offset);417 recv_type = MCI_GPM_TYPE(payload);418 419 if (recv_type == MCI_GPM_RSVD_PATTERN)420 return false;421 422 return true;423}424 425static void ar9003_mci_observation_set_up(struct ath_hw *ah)426{427 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;428 429 if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) {430 ath9k_hw_gpio_request_out(ah, 3, NULL,431 AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA);432 ath9k_hw_gpio_request_out(ah, 2, NULL,433 AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK);434 ath9k_hw_gpio_request_out(ah, 1, NULL,435 AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);436 ath9k_hw_gpio_request_out(ah, 0, NULL,437 AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);438 } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) {439 ath9k_hw_gpio_request_out(ah, 3, NULL,440 AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX);441 ath9k_hw_gpio_request_out(ah, 2, NULL,442 AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX);443 ath9k_hw_gpio_request_out(ah, 1, NULL,444 AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);445 ath9k_hw_gpio_request_out(ah, 0, NULL,446 AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);447 ath9k_hw_gpio_request_out(ah, 5, NULL,448 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);449 } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) {450 ath9k_hw_gpio_request_out(ah, 3, NULL,451 AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);452 ath9k_hw_gpio_request_out(ah, 2, NULL,453 AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);454 ath9k_hw_gpio_request_out(ah, 1, NULL,455 AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);456 ath9k_hw_gpio_request_out(ah, 0, NULL,457 AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);458 } else459 return;460 461 REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL(ah), AR_GPIO_JTAG_DISABLE);462 463 REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_DS_JTAG_DISABLE, 1);464 REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_WLAN_UART_INTF_EN, 0);465 REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL, ATH_MCI_CONFIG_MCI_OBS_GPIO);466 467 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0);468 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1);469 REG_WRITE(ah, AR_OBS(ah), 0x4b);470 REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL1, 0x03);471 REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL2, 0x01);472 REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_LSB, 0x02);473 REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_MSB, 0x03);474 REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS(ah),475 AR_PHY_TEST_CTL_DEBUGPORT_SEL, 0x07);476}477 478static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done,479 u8 opcode, u32 bt_flags)480{481 u32 pld[4] = {0, 0, 0, 0};482 483 MCI_GPM_SET_TYPE_OPCODE(pld, MCI_GPM_COEX_AGENT,484 MCI_GPM_COEX_BT_UPDATE_FLAGS);485 486 *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP) = opcode;487 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF;488 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 1) = (bt_flags >> 8) & 0xFF;489 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF;490 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF;491 492 return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16,493 wait_done, true);494}495 496static void ar9003_mci_sync_bt_state(struct ath_hw *ah)497{498 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;499 u32 cur_bt_state;500 501 cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP);502 503 if (mci->bt_state != cur_bt_state)504 mci->bt_state = cur_bt_state;505 506 if (mci->bt_state != MCI_BT_SLEEP) {507 508 ar9003_mci_send_coex_version_query(ah, true);509 ar9003_mci_send_coex_wlan_channels(ah, true);510 511 if (mci->unhalt_bt_gpm == true)512 ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);513 }514}515 516void ar9003_mci_check_bt(struct ath_hw *ah)517{518 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;519 520 if (!mci_hw->ready)521 return;522 523 /*524 * check BT state again to make525 * sure it's not changed.526 */527 ar9003_mci_sync_bt_state(ah);528 ar9003_mci_2g5g_switch(ah, true);529 530 if ((mci_hw->bt_state == MCI_BT_AWAKE) &&531 (mci_hw->query_bt == true)) {532 mci_hw->need_flush_btinfo = true;533 }534}535 536static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type,537 u8 gpm_opcode, u32 *p_gpm)538{539 struct ath_common *common = ath9k_hw_common(ah);540 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;541 u8 *p_data = (u8 *) p_gpm;542 543 if (gpm_type != MCI_GPM_COEX_AGENT)544 return;545 546 switch (gpm_opcode) {547 case MCI_GPM_COEX_VERSION_QUERY:548 ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n");549 ar9003_mci_send_coex_version_response(ah, true);550 break;551 case MCI_GPM_COEX_VERSION_RESPONSE:552 ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n");553 mci->bt_ver_major =554 *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION);555 mci->bt_ver_minor =556 *(p_data + MCI_GPM_COEX_B_MINOR_VERSION);557 mci->bt_version_known = true;558 ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n",559 mci->bt_ver_major, mci->bt_ver_minor);560 break;561 case MCI_GPM_COEX_STATUS_QUERY:562 ath_dbg(common, MCI,563 "MCI Recv GPM COEX Status Query = 0x%02X\n",564 *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP));565 mci->wlan_channels_update = true;566 ar9003_mci_send_coex_wlan_channels(ah, true);567 break;568 case MCI_GPM_COEX_BT_PROFILE_INFO:569 mci->query_bt = true;570 ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n");571 break;572 case MCI_GPM_COEX_BT_STATUS_UPDATE:573 mci->query_bt = true;574 ath_dbg(common, MCI,575 "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n",576 *(p_gpm + 3));577 break;578 default:579 break;580 }581}582 583static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,584 u8 gpm_opcode, int time_out)585{586 struct ath_common *common = ath9k_hw_common(ah);587 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;588 u32 *p_gpm = NULL, more_data;589 u32 offset;590 u8 recv_type = 0, recv_opcode = 0;591 bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE);592 593 more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE;594 595 while (time_out > 0) {596 if (p_gpm) {597 MCI_GPM_RECYCLE(p_gpm);598 p_gpm = NULL;599 }600 601 if (more_data != MCI_GPM_MORE)602 time_out = ar9003_mci_wait_for_interrupt(ah,603 AR_MCI_INTERRUPT_RX_MSG_RAW,604 AR_MCI_INTERRUPT_RX_MSG_GPM,605 time_out);606 607 if (!time_out)608 break;609 610 offset = ar9003_mci_get_next_gpm_offset(ah, &more_data);611 612 if (offset == MCI_GPM_INVALID)613 continue;614 615 p_gpm = (u32 *) (mci->gpm_buf + offset);616 recv_type = MCI_GPM_TYPE(p_gpm);617 recv_opcode = MCI_GPM_OPCODE(p_gpm);618 619 if (MCI_GPM_IS_CAL_TYPE(recv_type)) {620 if (recv_type == gpm_type) {621 if ((gpm_type == MCI_GPM_BT_CAL_DONE) &&622 !b_is_bt_cal_done) {623 gpm_type = MCI_GPM_BT_CAL_GRANT;624 continue;625 }626 break;627 }628 } else if ((recv_type == gpm_type) &&629 (recv_opcode == gpm_opcode))630 break;631 632 /*633 * check if it's cal_grant634 *635 * When we're waiting for cal_grant in reset routine,636 * it's possible that BT sends out cal_request at the637 * same time. Since BT's calibration doesn't happen638 * that often, we'll let BT completes calibration then639 * we continue to wait for cal_grant from BT.640 * Orginal: Wait BT_CAL_GRANT.641 * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait642 * BT_CAL_DONE -> Wait BT_CAL_GRANT.643 */644 645 if ((gpm_type == MCI_GPM_BT_CAL_GRANT) &&646 (recv_type == MCI_GPM_BT_CAL_REQ)) {647 648 u32 payload[4] = {0, 0, 0, 0};649 650 gpm_type = MCI_GPM_BT_CAL_DONE;651 MCI_GPM_SET_CAL_TYPE(payload,652 MCI_GPM_WLAN_CAL_GRANT);653 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,654 false, false);655 continue;656 } else {657 ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n",658 *(p_gpm + 1));659 ar9003_mci_process_gpm_extra(ah, recv_type,660 recv_opcode, p_gpm);661 }662 }663 664 if (p_gpm) {665 MCI_GPM_RECYCLE(p_gpm);666 p_gpm = NULL;667 }668 669 if (time_out <= 0)670 time_out = 0;671 672 while (more_data == MCI_GPM_MORE) {673 offset = ar9003_mci_get_next_gpm_offset(ah, &more_data);674 if (offset == MCI_GPM_INVALID)675 break;676 677 p_gpm = (u32 *) (mci->gpm_buf + offset);678 recv_type = MCI_GPM_TYPE(p_gpm);679 recv_opcode = MCI_GPM_OPCODE(p_gpm);680 681 if (!MCI_GPM_IS_CAL_TYPE(recv_type))682 ar9003_mci_process_gpm_extra(ah, recv_type,683 recv_opcode, p_gpm);684 685 MCI_GPM_RECYCLE(p_gpm);686 }687 688 return time_out;689}690 691bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan)692{693 struct ath_common *common = ath9k_hw_common(ah);694 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;695 u32 payload[4] = {0, 0, 0, 0};696 697 ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));698 699 if (mci_hw->bt_state != MCI_BT_CAL_START)700 return false;701 702 mci_hw->bt_state = MCI_BT_CAL;703 704 /*705 * MCI FIX: disable mci interrupt here. This is to avoid706 * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and707 * lead to mci_intr reentry.708 */709 ar9003_mci_disable_interrupt(ah);710 711 MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);712 ar9003_mci_send_message(ah, MCI_GPM, 0, payload,713 16, true, false);714 715 /* Wait BT calibration to be completed for 25ms */716 717 if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE,718 0, 25000))719 ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n");720 else721 ath_dbg(common, MCI,722 "MCI BT_CAL_DONE not received\n");723 724 mci_hw->bt_state = MCI_BT_AWAKE;725 /* MCI FIX: enable mci interrupt here */726 ar9003_mci_enable_interrupt(ah);727 728 return true;729}730 731int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,732 struct ath9k_hw_cal_data *caldata)733{734 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;735 736 if (!mci_hw->ready)737 return 0;738 739 if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP))740 goto exit;741 742 if (!ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) &&743 !ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE))744 goto exit;745 746 /*747 * BT is sleeping. Check if BT wakes up during748 * WLAN calibration. If BT wakes up during749 * WLAN calibration, need to go through all750 * message exchanges again and recal.751 */752 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,753 (AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |754 AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE));755 756 ar9003_mci_remote_reset(ah, true);757 ar9003_mci_send_sys_waking(ah, true);758 udelay(1);759 760 if (IS_CHAN_2GHZ(chan))761 ar9003_mci_send_lna_transfer(ah, true);762 763 mci_hw->bt_state = MCI_BT_AWAKE;764 765 REG_CLR_BIT(ah, AR_PHY_TIMING4,766 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT);767 768 if (caldata) {769 clear_bit(TXIQCAL_DONE, &caldata->cal_flags);770 clear_bit(TXCLCAL_DONE, &caldata->cal_flags);771 clear_bit(RTT_DONE, &caldata->cal_flags);772 }773 774 if (!ath9k_hw_init_cal(ah, chan))775 return -EIO;776 777 REG_SET_BIT(ah, AR_PHY_TIMING4,778 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT);779 780exit:781 ar9003_mci_enable_interrupt(ah);782 return 0;783}784 785static void ar9003_mci_mute_bt(struct ath_hw *ah)786{787 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;788 789 /* disable all MCI messages */790 REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000);791 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff);792 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff);793 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff);794 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff);795 REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);796 797 /* wait pending HW messages to flush out */798 udelay(10);799 800 /*801 * Send LNA_TAKE and SYS_SLEEPING when802 * 1. reset not after resuming from full sleep803 * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment804 */805 if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) {806 ar9003_mci_send_lna_take(ah, true);807 udelay(5);808 }809 810 ar9003_mci_send_sys_sleeping(ah, true);811}812 813static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable)814{815 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;816 u32 thresh;817 818 if (!enable) {819 REG_CLR_BIT(ah, AR_BTCOEX_CTRL,820 AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);821 return;822 }823 REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, AR_MCI_SCHD_TABLE_2_HW_BASED, 1);824 REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,825 AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);826 827 if (AR_SREV_9565(ah))828 REG_RMW_FIELD(ah, AR_MCI_MISC, AR_MCI_MISC_HW_FIX_EN, 1);829 830 if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {831 thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);832 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,833 AR_BTCOEX_CTRL_AGGR_THRESH, thresh);834 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,835 AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);836 } else837 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,838 AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);839 840 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,841 AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);842}843 844static void ar9003_mci_stat_setup(struct ath_hw *ah)845{846 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;847 848 if (!AR_SREV_9565(ah))849 return;850 851 if (mci->config & ATH_MCI_CONFIG_MCI_STAT_DBG) {852 REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL,853 AR_MCI_DBG_CNT_CTRL_ENABLE, 1);854 REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL,855 AR_MCI_DBG_CNT_CTRL_BT_LINKID,856 MCI_STAT_ALL_BT_LINKID);857 } else {858 REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL,859 AR_MCI_DBG_CNT_CTRL_ENABLE, 0);860 }861}862 863static void ar9003_mci_set_btcoex_ctrl_9565_1ANT(struct ath_hw *ah)864{865 u32 regval;866 867 regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |868 SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |869 SM(1, AR_BTCOEX_CTRL_PA_SHARED) |870 SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |871 SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) |872 SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |873 SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |874 SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |875 SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);876 877 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2,878 AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1);879 REG_WRITE(ah, AR_BTCOEX_CTRL, regval);880}881 882static void ar9003_mci_set_btcoex_ctrl_9565_2ANT(struct ath_hw *ah)883{884 u32 regval;885 886 regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |887 SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |888 SM(0, AR_BTCOEX_CTRL_PA_SHARED) |889 SM(0, AR_BTCOEX_CTRL_LNA_SHARED) |890 SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |891 SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |892 SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |893 SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |894 SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);895 896 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2,897 AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x0);898 REG_WRITE(ah, AR_BTCOEX_CTRL, regval);899}900 901static void ar9003_mci_set_btcoex_ctrl_9462(struct ath_hw *ah)902{903 u32 regval;904 905 regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |906 SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |907 SM(1, AR_BTCOEX_CTRL_PA_SHARED) |908 SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |909 SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |910 SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |911 SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |912 SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |913 SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);914 915 REG_WRITE(ah, AR_BTCOEX_CTRL, regval);916}917 918int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,919 bool is_full_sleep)920{921 struct ath_common *common = ath9k_hw_common(ah);922 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;923 u32 regval, i;924 925 ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n",926 is_full_sleep, is_2g);927 928 if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) {929 ath_err(common, "BTCOEX control register is dead\n");930 return -EINVAL;931 }932 933 /* Program MCI DMA related registers */934 REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr);935 REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len);936 REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr);937 938 /*939 * To avoid MCI state machine be affected by incoming remote MCI msgs,940 * MCI mode will be enabled later, right before reset the MCI TX and RX.941 */942 if (AR_SREV_9565(ah)) {943 u8 ant = MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH);944 945 if (ant == ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED)946 ar9003_mci_set_btcoex_ctrl_9565_1ANT(ah);947 else948 ar9003_mci_set_btcoex_ctrl_9565_2ANT(ah);949 } else {950 ar9003_mci_set_btcoex_ctrl_9462(ah);951 }952 953 if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))954 ar9003_mci_osla_setup(ah, true);955 else956 ar9003_mci_osla_setup(ah, false);957 958 REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,959 AR_BTCOEX_CTRL_SPDT_ENABLE);960 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3,961 AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20);962 963 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 0);964 REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);965 966 /* Set the time out to 3.125ms (5 BT slots) */967 REG_RMW_FIELD(ah, AR_BTCOEX_WL_LNA, AR_BTCOEX_WL_LNA_TIMEOUT, 0x3D090);968 969 /* concurrent tx priority */970 if (mci->config & ATH_MCI_CONFIG_CONCUR_TX) {971 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2,972 AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE, 0);973 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2,974 AR_BTCOEX_CTRL2_TXPWR_THRESH, 0x7f);975 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,976 AR_BTCOEX_CTRL_REDUCE_TXPWR, 0);977 for (i = 0; i < 8; i++)978 REG_WRITE(ah, AR_BTCOEX_MAX_TXPWR(i), 0x7f7f7f7f);979 }980 981 regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV);982 REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval);983 REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN);984 985 /* Resetting the Rx and Tx paths of MCI */986 regval = REG_READ(ah, AR_MCI_COMMAND2);987 regval |= SM(1, AR_MCI_COMMAND2_RESET_TX);988 REG_WRITE(ah, AR_MCI_COMMAND2, regval);989 990 udelay(1);991 992 regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX);993 REG_WRITE(ah, AR_MCI_COMMAND2, regval);994 995 if (is_full_sleep) {996 ar9003_mci_mute_bt(ah);997 udelay(100);998 }999 1000 /* Check pending GPM msg before MCI Reset Rx */1001 ar9003_mci_check_gpm_offset(ah);1002 1003 regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);1004 REG_WRITE(ah, AR_MCI_COMMAND2, regval);1005 udelay(1);1006 regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);1007 REG_WRITE(ah, AR_MCI_COMMAND2, regval);1008 1009 /* Init GPM offset after MCI Reset Rx */1010 ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET);1011 1012 REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,1013 (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |1014 SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM)));1015 1016 if (MCI_ANT_ARCH_PA_LNA_SHARED(mci))1017 REG_CLR_BIT(ah, AR_MCI_TX_CTRL,1018 AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);1019 else1020 REG_SET_BIT(ah, AR_MCI_TX_CTRL,1021 AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);1022 1023 ar9003_mci_observation_set_up(ah);1024 1025 mci->ready = true;1026 ar9003_mci_prep_interface(ah);1027 ar9003_mci_stat_setup(ah);1028 1029 if (en_int)1030 ar9003_mci_enable_interrupt(ah);1031 1032 if (ath9k_hw_is_aic_enabled(ah))1033 ar9003_aic_start_normal(ah);1034 1035 return 0;1036}1037 1038void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)1039{1040 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;1041 1042 ar9003_mci_disable_interrupt(ah);1043 1044 if (mci_hw->ready && !save_fullsleep) {1045 ar9003_mci_mute_bt(ah);1046 udelay(20);1047 REG_WRITE(ah, AR_BTCOEX_CTRL, 0);1048 }1049 1050 mci_hw->bt_state = MCI_BT_SLEEP;1051 mci_hw->ready = false;1052}1053 1054static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)1055{1056 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1057 u32 to_set, to_clear;1058 1059 if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP))1060 return;1061 1062 if (mci->is_2g) {1063 to_clear = MCI_2G_FLAGS_CLEAR_MASK;1064 to_set = MCI_2G_FLAGS_SET_MASK;1065 } else {1066 to_clear = MCI_5G_FLAGS_CLEAR_MASK;1067 to_set = MCI_5G_FLAGS_SET_MASK;1068 }1069 1070 if (to_clear)1071 ar9003_mci_send_coex_bt_flags(ah, wait_done,1072 MCI_GPM_COEX_BT_FLAGS_CLEAR,1073 to_clear);1074 if (to_set)1075 ar9003_mci_send_coex_bt_flags(ah, wait_done,1076 MCI_GPM_COEX_BT_FLAGS_SET,1077 to_set);1078}1079 1080static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,1081 u32 *payload, bool queue)1082{1083 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1084 u8 type, opcode;1085 1086 /* check if the message is to be queued */1087 if (header != MCI_GPM)1088 return;1089 1090 type = MCI_GPM_TYPE(payload);1091 opcode = MCI_GPM_OPCODE(payload);1092 1093 if (type != MCI_GPM_COEX_AGENT)1094 return;1095 1096 switch (opcode) {1097 case MCI_GPM_COEX_BT_UPDATE_FLAGS:1098 if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) ==1099 MCI_GPM_COEX_BT_FLAGS_READ)1100 break;1101 1102 mci->update_2g5g = queue;1103 1104 break;1105 case MCI_GPM_COEX_WLAN_CHANNELS:1106 mci->wlan_channels_update = queue;1107 break;1108 case MCI_GPM_COEX_HALT_BT_GPM:1109 if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==1110 MCI_GPM_COEX_BT_GPM_UNHALT) {1111 mci->unhalt_bt_gpm = queue;1112 1113 if (!queue)1114 mci->halted_bt_gpm = false;1115 }1116 1117 if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==1118 MCI_GPM_COEX_BT_GPM_HALT) {1119 1120 mci->halted_bt_gpm = !queue;1121 }1122 1123 break;1124 default:1125 break;1126 }1127}1128 1129void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)1130{1131 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1132 1133 if (!mci->update_2g5g && !force)1134 return;1135 1136 if (mci->is_2g) {1137 ar9003_mci_send_2g5g_status(ah, true);1138 ar9003_mci_send_lna_transfer(ah, true);1139 udelay(5);1140 1141 REG_CLR_BIT(ah, AR_MCI_TX_CTRL,1142 AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);1143 REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,1144 AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);1145 1146 if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))1147 ar9003_mci_osla_setup(ah, true);1148 1149 if (AR_SREV_9462(ah))1150 REG_WRITE(ah, AR_SELFGEN_MASK, 0x02);1151 } else {1152 ar9003_mci_send_lna_take(ah, true);1153 udelay(5);1154 1155 REG_SET_BIT(ah, AR_MCI_TX_CTRL,1156 AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);1157 REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,1158 AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);1159 1160 ar9003_mci_osla_setup(ah, false);1161 ar9003_mci_send_2g5g_status(ah, true);1162 }1163}1164 1165bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,1166 u32 *payload, u8 len, bool wait_done,1167 bool check_bt)1168{1169 struct ath_common *common = ath9k_hw_common(ah);1170 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1171 bool msg_sent = false;1172 u32 regval;1173 u32 saved_mci_int_en;1174 int i;1175 1176 saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);1177 regval = REG_READ(ah, AR_BTCOEX_CTRL);1178 1179 if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) {1180 ath_dbg(common, MCI,1181 "MCI Not sending 0x%x. MCI is not enabled. full_sleep = %d\n",1182 header, (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0);1183 ar9003_mci_queue_unsent_gpm(ah, header, payload, true);1184 return false;1185 } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) {1186 ath_dbg(common, MCI,1187 "MCI Don't send message 0x%x. BT is in sleep state\n",1188 header);1189 ar9003_mci_queue_unsent_gpm(ah, header, payload, true);1190 return false;1191 }1192 1193 if (wait_done)1194 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);1195 1196 /* Need to clear SW_MSG_DONE raw bit before wait */1197 1198 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,1199 (AR_MCI_INTERRUPT_SW_MSG_DONE |1200 AR_MCI_INTERRUPT_MSG_FAIL_MASK));1201 1202 if (payload) {1203 for (i = 0; (i * 4) < len; i++)1204 REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4),1205 *(payload + i));1206 }1207 1208 REG_WRITE(ah, AR_MCI_COMMAND0,1209 (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP),1210 AR_MCI_COMMAND0_DISABLE_TIMESTAMP) |1211 SM(len, AR_MCI_COMMAND0_LEN) |1212 SM(header, AR_MCI_COMMAND0_HEADER)));1213 1214 if (wait_done &&1215 !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW,1216 AR_MCI_INTERRUPT_SW_MSG_DONE, 500)))1217 ar9003_mci_queue_unsent_gpm(ah, header, payload, true);1218 else {1219 ar9003_mci_queue_unsent_gpm(ah, header, payload, false);1220 msg_sent = true;1221 }1222 1223 if (wait_done)1224 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);1225 1226 return msg_sent;1227}1228EXPORT_SYMBOL(ar9003_mci_send_message);1229 1230void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)1231{1232 struct ath_common *common = ath9k_hw_common(ah);1233 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;1234 u32 pld[4] = {0, 0, 0, 0};1235 1236 if ((mci_hw->bt_state != MCI_BT_AWAKE) ||1237 (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL))1238 return;1239 1240 MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ);1241 pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++;1242 1243 ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);1244 1245 if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) {1246 ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n");1247 } else {1248 *is_reusable = false;1249 ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n");1250 }1251}1252 1253void ar9003_mci_init_cal_done(struct ath_hw *ah)1254{1255 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;1256 u32 pld[4] = {0, 0, 0, 0};1257 1258 if ((mci_hw->bt_state != MCI_BT_AWAKE) ||1259 (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL))1260 return;1261 1262 MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE);1263 pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++;1264 ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);1265}1266 1267int ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,1268 u16 len, u32 sched_addr)1269{1270 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1271 1272 mci->gpm_addr = gpm_addr;1273 mci->gpm_buf = gpm_buf;1274 mci->gpm_len = len;1275 mci->sched_addr = sched_addr;1276 1277 return ar9003_mci_reset(ah, true, true, true);1278}1279EXPORT_SYMBOL(ar9003_mci_setup);1280 1281void ar9003_mci_cleanup(struct ath_hw *ah)1282{1283 /* Turn off MCI and Jupiter mode. */1284 REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00);1285 ar9003_mci_disable_interrupt(ah);1286}1287EXPORT_SYMBOL(ar9003_mci_cleanup);1288 1289u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)1290{1291 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1292 u32 value = 0, tsf;1293 u8 query_type;1294 1295 switch (state_type) {1296 case MCI_STATE_ENABLE:1297 if (mci->ready) {1298 value = REG_READ(ah, AR_BTCOEX_CTRL);1299 1300 if ((value == 0xdeadbeef) || (value == 0xffffffff))1301 value = 0;1302 }1303 value &= AR_BTCOEX_CTRL_MCI_MODE_EN;1304 break;1305 case MCI_STATE_INIT_GPM_OFFSET:1306 value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);1307 1308 if (value < mci->gpm_len)1309 mci->gpm_idx = value;1310 else1311 mci->gpm_idx = 0;1312 break;1313 case MCI_STATE_LAST_SCHD_MSG_OFFSET:1314 value = MS(REG_READ(ah, AR_MCI_RX_STATUS),1315 AR_MCI_RX_LAST_SCHD_MSG_INDEX);1316 /* Make it in bytes */1317 value <<= 4;1318 break;1319 case MCI_STATE_REMOTE_SLEEP:1320 value = MS(REG_READ(ah, AR_MCI_RX_STATUS),1321 AR_MCI_RX_REMOTE_SLEEP) ?1322 MCI_BT_SLEEP : MCI_BT_AWAKE;1323 break;1324 case MCI_STATE_SET_BT_AWAKE:1325 mci->bt_state = MCI_BT_AWAKE;1326 ar9003_mci_send_coex_version_query(ah, true);1327 ar9003_mci_send_coex_wlan_channels(ah, true);1328 1329 if (mci->unhalt_bt_gpm)1330 ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);1331 1332 ar9003_mci_2g5g_switch(ah, false);1333 break;1334 case MCI_STATE_RESET_REQ_WAKE:1335 ar9003_mci_reset_req_wakeup(ah);1336 mci->update_2g5g = true;1337 1338 if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) {1339 /* Check if we still have control of the GPIOs */1340 if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) &1341 ATH_MCI_CONFIG_MCI_OBS_GPIO) !=1342 ATH_MCI_CONFIG_MCI_OBS_GPIO) {1343 ar9003_mci_observation_set_up(ah);1344 }1345 }1346 break;1347 case MCI_STATE_SEND_WLAN_COEX_VERSION:1348 ar9003_mci_send_coex_version_response(ah, true);1349 break;1350 case MCI_STATE_SEND_VERSION_QUERY:1351 ar9003_mci_send_coex_version_query(ah, true);1352 break;1353 case MCI_STATE_SEND_STATUS_QUERY:1354 query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY;1355 ar9003_mci_send_coex_bt_status_query(ah, true, query_type);1356 break;1357 case MCI_STATE_RECOVER_RX:1358 tsf = ath9k_hw_gettsf32(ah);1359 if ((tsf - mci->last_recovery) <= MCI_RECOVERY_DUR_TSF) {1360 ath_dbg(ath9k_hw_common(ah), MCI,1361 "(MCI) ignore Rx recovery\n");1362 break;1363 }1364 ath_dbg(ath9k_hw_common(ah), MCI, "(MCI) RECOVER RX\n");1365 mci->last_recovery = tsf;1366 ar9003_mci_prep_interface(ah);1367 mci->query_bt = true;1368 mci->need_flush_btinfo = true;1369 ar9003_mci_send_coex_wlan_channels(ah, true);1370 ar9003_mci_2g5g_switch(ah, false);1371 break;1372 case MCI_STATE_NEED_FTP_STOMP:1373 value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);1374 break;1375 case MCI_STATE_NEED_FLUSH_BT_INFO:1376 value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0;1377 mci->need_flush_btinfo = false;1378 break;1379 case MCI_STATE_AIC_CAL:1380 if (ath9k_hw_is_aic_enabled(ah))1381 value = ar9003_aic_calibration(ah);1382 break;1383 case MCI_STATE_AIC_START:1384 if (ath9k_hw_is_aic_enabled(ah))1385 ar9003_aic_start_normal(ah);1386 break;1387 case MCI_STATE_AIC_CAL_RESET:1388 if (ath9k_hw_is_aic_enabled(ah))1389 value = ar9003_aic_cal_reset(ah);1390 break;1391 case MCI_STATE_AIC_CAL_SINGLE:1392 if (ath9k_hw_is_aic_enabled(ah))1393 value = ar9003_aic_calibration_single(ah);1394 break;1395 default:1396 break;1397 }1398 1399 return value;1400}1401EXPORT_SYMBOL(ar9003_mci_state);1402 1403void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)1404{1405 struct ath_common *common = ath9k_hw_common(ah);1406 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1407 1408 ath_dbg(common, MCI, "Give LNA and SPDT control to BT\n");1409 1410 ar9003_mci_send_lna_take(ah, true);1411 udelay(50);1412 1413 REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);1414 mci->is_2g = false;1415 mci->update_2g5g = true;1416 ar9003_mci_send_2g5g_status(ah, true);1417 1418 /* Force another 2g5g update at next scanning */1419 mci->update_2g5g = true;1420}1421 1422void ar9003_mci_set_power_awake(struct ath_hw *ah)1423{1424 u32 btcoex_ctrl2, diag_sw;1425 int i;1426 u8 lna_ctrl, bt_sleep;1427 1428 for (i = 0; i < AH_WAIT_TIMEOUT; i++) {1429 btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2);1430 if (btcoex_ctrl2 != 0xdeadbeef)1431 break;1432 udelay(AH_TIME_QUANTUM);1433 }1434 REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23)));1435 1436 for (i = 0; i < AH_WAIT_TIMEOUT; i++) {1437 diag_sw = REG_READ(ah, AR_DIAG_SW);1438 if (diag_sw != 0xdeadbeef)1439 break;1440 udelay(AH_TIME_QUANTUM);1441 }1442 REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18)));1443 lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3;1444 bt_sleep = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP);1445 1446 REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2);1447 REG_WRITE(ah, AR_DIAG_SW, diag_sw);1448 1449 if (bt_sleep && (lna_ctrl == 2)) {1450 REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1);1451 REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1);1452 udelay(50);1453 }1454}1455 1456void ar9003_mci_check_gpm_offset(struct ath_hw *ah)1457{1458 struct ath_common *common = ath9k_hw_common(ah);1459 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1460 u32 offset;1461 1462 /*1463 * This should only be called before "MAC Warm Reset" or "MCI Reset Rx".1464 */1465 offset = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);1466 if (mci->gpm_idx == offset)1467 return;1468 ath_dbg(common, MCI, "GPM cached write pointer mismatch %d %d\n",1469 mci->gpm_idx, offset);1470 mci->query_bt = true;1471 mci->need_flush_btinfo = true;1472 mci->gpm_idx = 0;1473}1474 1475u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, u32 *more)1476{1477 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1478 u32 offset, more_gpm = 0, gpm_ptr;1479 1480 /*1481 * This could be useful to avoid new GPM message interrupt which1482 * may lead to spurious interrupt after power sleep, or multiple1483 * entry of ath_mci_intr().1484 * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can1485 * alleviate this effect, but clearing GPM RX interrupt bit is1486 * safe, because whether this is called from hw or driver code1487 * there must be an interrupt bit set/triggered initially1488 */1489 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,1490 AR_MCI_INTERRUPT_RX_MSG_GPM);1491 1492 gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);1493 offset = gpm_ptr;1494 1495 if (!offset)1496 offset = mci->gpm_len - 1;1497 else if (offset >= mci->gpm_len) {1498 if (offset != 0xFFFF)1499 offset = 0;1500 } else {1501 offset--;1502 }1503 1504 if ((offset == 0xFFFF) || (gpm_ptr == mci->gpm_idx)) {1505 offset = MCI_GPM_INVALID;1506 more_gpm = MCI_GPM_NOMORE;1507 goto out;1508 }1509 for (;;) {1510 u32 temp_index;1511 1512 /* skip reserved GPM if any */1513 1514 if (offset != mci->gpm_idx)1515 more_gpm = MCI_GPM_MORE;1516 else1517 more_gpm = MCI_GPM_NOMORE;1518 1519 temp_index = mci->gpm_idx;1520 1521 if (temp_index >= mci->gpm_len)1522 temp_index = 0;1523 1524 mci->gpm_idx++;1525 1526 if (mci->gpm_idx >= mci->gpm_len)1527 mci->gpm_idx = 0;1528 1529 if (ar9003_mci_is_gpm_valid(ah, temp_index)) {1530 offset = temp_index;1531 break;1532 }1533 1534 if (more_gpm == MCI_GPM_NOMORE) {1535 offset = MCI_GPM_INVALID;1536 break;1537 }1538 }1539 1540 if (offset != MCI_GPM_INVALID)1541 offset <<= 4;1542out:1543 if (more)1544 *more = more_gpm;1545 1546 return offset;1547}1548EXPORT_SYMBOL(ar9003_mci_get_next_gpm_offset);1549 1550void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor)1551{1552 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1553 1554 mci->bt_ver_major = major;1555 mci->bt_ver_minor = minor;1556 mci->bt_version_known = true;1557 ath_dbg(ath9k_hw_common(ah), MCI, "MCI BT version set: %d.%d\n",1558 mci->bt_ver_major, mci->bt_ver_minor);1559}1560EXPORT_SYMBOL(ar9003_mci_set_bt_version);1561 1562void ar9003_mci_send_wlan_channels(struct ath_hw *ah)1563{1564 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;1565 1566 mci->wlan_channels_update = true;1567 ar9003_mci_send_coex_wlan_channels(ah, true);1568}1569EXPORT_SYMBOL(ar9003_mci_send_wlan_channels);1570 1571u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode)1572{1573 if (!ah->btcoex_hw.mci.concur_tx)1574 goto out;1575 1576 if (ctlmode == CTL_2GHT20)1577 return ATH_BTCOEX_HT20_MAX_TXPOWER;1578 else if (ctlmode == CTL_2GHT40)1579 return ATH_BTCOEX_HT40_MAX_TXPOWER;1580 1581out:1582 return -1;1583}1584