linux/drivers/net/wireless/ath/ath9k/btcoex.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2009-2011 Atheros Communications Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include <linux/export.h>
  18#include "hw.h"
  19
  20enum ath_bt_mode {
  21        ATH_BT_COEX_MODE_LEGACY,        /* legacy rx_clear mode */
  22        ATH_BT_COEX_MODE_UNSLOTTED,     /* untimed/unslotted mode */
  23        ATH_BT_COEX_MODE_SLOTTED,       /* slotted mode */
  24        ATH_BT_COEX_MODE_DISABLED,      /* coexistence disabled */
  25};
  26
  27struct ath_btcoex_config {
  28        u8 bt_time_extend;
  29        bool bt_txstate_extend;
  30        bool bt_txframe_extend;
  31        enum ath_bt_mode bt_mode; /* coexistence mode */
  32        bool bt_quiet_collision;
  33        bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
  34        u8 bt_priority_time;
  35        u8 bt_first_slot_time;
  36        bool bt_hold_rx_clear;
  37};
  38
  39static const u32 ar9003_wlan_weights[ATH_BTCOEX_STOMP_MAX]
  40                                    [AR9300_NUM_WLAN_WEIGHTS] = {
  41        { 0xfffffff0, 0xfffffff0, 0xfffffff0, 0xfffffff0 }, /* STOMP_ALL */
  42        { 0x88888880, 0x88888880, 0x88888880, 0x88888880 }, /* STOMP_LOW */
  43        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* STOMP_NONE */
  44};
  45
  46static const u32 mci_wlan_weights[ATH_BTCOEX_STOMP_MAX]
  47                                 [AR9300_NUM_WLAN_WEIGHTS] = {
  48        { 0x01017d01, 0x41414101, 0x41414101, 0x41414141 }, /* STOMP_ALL */
  49        { 0x01017d01, 0x3b3b3b01, 0x3b3b3b01, 0x3b3b3b3b }, /* STOMP_LOW */
  50        { 0x01017d01, 0x01010101, 0x01010101, 0x01010101 }, /* STOMP_NONE */
  51        { 0x01017d01, 0x013b0101, 0x3b3b0101, 0x3b3b013b }, /* STOMP_LOW_FTP */
  52        { 0xffffff01, 0xffffffff, 0xffffff01, 0xffffffff }, /* STOMP_AUDIO */
  53};
  54
  55void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
  56{
  57        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
  58        const struct ath_btcoex_config ath_bt_config = {
  59                .bt_time_extend = 0,
  60                .bt_txstate_extend = true,
  61                .bt_txframe_extend = true,
  62                .bt_mode = ATH_BT_COEX_MODE_SLOTTED,
  63                .bt_quiet_collision = true,
  64                .bt_rxclear_polarity = true,
  65                .bt_priority_time = 2,
  66                .bt_first_slot_time = 5,
  67                .bt_hold_rx_clear = true,
  68        };
  69        bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
  70
  71        if (AR_SREV_9300_20_OR_LATER(ah))
  72                rxclear_polarity = !ath_bt_config.bt_rxclear_polarity;
  73
  74        btcoex_hw->bt_coex_mode =
  75                (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) |
  76                SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) |
  77                SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
  78                SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
  79                SM(ath_bt_config.bt_mode, AR_BT_MODE) |
  80                SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) |
  81                SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
  82                SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) |
  83                SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
  84                SM(qnum, AR_BT_QCU_THRESH);
  85
  86        btcoex_hw->bt_coex_mode2 =
  87                SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
  88                SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
  89                AR_BT_DISABLE_BT_ANT;
  90}
  91EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);
  92
  93void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah)
  94{
  95        struct ath_common *common = ath9k_hw_common(ah);
  96        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
  97
  98        /*
  99         * Check if BTCOEX is globally disabled.
 100         */
 101        if (!common->btcoex_enabled) {
 102                btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
 103                return;
 104        }
 105
 106        if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
 107                btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
 108        } else if (AR_SREV_9300_20_OR_LATER(ah)) {
 109                btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
 110                btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
 111                btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
 112                btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300;
 113        } else if (AR_SREV_9280_20_OR_LATER(ah)) {
 114                btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280;
 115                btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280;
 116
 117                if (AR_SREV_9285(ah)) {
 118                        btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
 119                        btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9285;
 120                } else {
 121                        btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
 122                }
 123        }
 124}
 125EXPORT_SYMBOL(ath9k_hw_btcoex_init_scheme);
 126
 127void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah)
 128{
 129        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 130
 131        /* connect bt_active to baseband */
 132        REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
 133                    (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
 134                     AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
 135
 136        REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
 137                    AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
 138
 139        /* Set input mux for bt_active to gpio pin */
 140        REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
 141                      AR_GPIO_INPUT_MUX1_BT_ACTIVE,
 142                      btcoex_hw->btactive_gpio);
 143
 144        /* Configure the desired gpio port for input */
 145        ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio);
 146}
 147EXPORT_SYMBOL(ath9k_hw_btcoex_init_2wire);
 148
 149void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah)
 150{
 151        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 152
 153        /* btcoex 3-wire */
 154        REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
 155                        (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
 156                         AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
 157
 158        /* Set input mux for bt_prority_async and
 159         *                  bt_active_async to GPIO pins */
 160        REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
 161                        AR_GPIO_INPUT_MUX1_BT_ACTIVE,
 162                        btcoex_hw->btactive_gpio);
 163
 164        REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
 165                        AR_GPIO_INPUT_MUX1_BT_PRIORITY,
 166                        btcoex_hw->btpriority_gpio);
 167
 168        /* Configure the desired GPIO ports for input */
 169
 170        ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio);
 171        ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btpriority_gpio);
 172}
 173EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire);
 174
 175void ath9k_hw_btcoex_init_mci(struct ath_hw *ah)
 176{
 177        ah->btcoex_hw.mci.ready = false;
 178        ah->btcoex_hw.mci.bt_state = 0;
 179        ah->btcoex_hw.mci.bt_ver_major = 3;
 180        ah->btcoex_hw.mci.bt_ver_minor = 0;
 181        ah->btcoex_hw.mci.bt_version_known = false;
 182        ah->btcoex_hw.mci.update_2g5g = true;
 183        ah->btcoex_hw.mci.is_2g = true;
 184        ah->btcoex_hw.mci.wlan_channels_update = false;
 185        ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000;
 186        ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff;
 187        ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff;
 188        ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff;
 189        ah->btcoex_hw.mci.query_bt = true;
 190        ah->btcoex_hw.mci.unhalt_bt_gpm = true;
 191        ah->btcoex_hw.mci.halted_bt_gpm = false;
 192        ah->btcoex_hw.mci.need_flush_btinfo = false;
 193        ah->btcoex_hw.mci.wlan_cal_seq = 0;
 194        ah->btcoex_hw.mci.wlan_cal_done = 0;
 195        ah->btcoex_hw.mci.config = (AR_SREV_9462(ah)) ? 0x2201 : 0xa4c1;
 196}
 197EXPORT_SYMBOL(ath9k_hw_btcoex_init_mci);
 198
 199static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah)
 200{
 201        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 202
 203        /* Configure the desired GPIO port for TX_FRAME output */
 204        ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
 205                            AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
 206}
 207
 208/*
 209 * For AR9002, bt_weight/wlan_weight are used.
 210 * For AR9003 and above, stomp_type is used.
 211 */
 212void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
 213                                u32 bt_weight,
 214                                u32 wlan_weight,
 215                                enum ath_stomp_type stomp_type)
 216{
 217        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 218        struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
 219        u8 txprio_shift[] = { 24, 16, 16, 0 }; /* tx priority weight */
 220        bool concur_tx = (mci_hw->concur_tx && btcoex_hw->tx_prio[stomp_type]);
 221        const u32 *weight = ar9003_wlan_weights[stomp_type];
 222        int i;
 223
 224        if (!AR_SREV_9300_20_OR_LATER(ah)) {
 225                btcoex_hw->bt_coex_weights =
 226                        SM(bt_weight, AR_BTCOEX_BT_WGHT) |
 227                        SM(wlan_weight, AR_BTCOEX_WL_WGHT);
 228                return;
 229        }
 230
 231        if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
 232                enum ath_stomp_type stype =
 233                        ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
 234                         btcoex_hw->mci.stomp_ftp) ?
 235                        ATH_BTCOEX_STOMP_LOW_FTP : stomp_type;
 236                weight = mci_wlan_weights[stype];
 237        }
 238
 239        for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
 240                btcoex_hw->bt_weight[i] = AR9300_BT_WGHT;
 241                btcoex_hw->wlan_weight[i] = weight[i];
 242                if (concur_tx && i) {
 243                        btcoex_hw->wlan_weight[i] &=
 244                                ~(0xff << txprio_shift[i-1]);
 245                        btcoex_hw->wlan_weight[i] |=
 246                                (btcoex_hw->tx_prio[stomp_type] <<
 247                                 txprio_shift[i-1]);
 248                }
 249        }
 250        /* Last WLAN weight has to be adjusted wrt tx priority */
 251        if (concur_tx) {
 252                btcoex_hw->wlan_weight[i-1] &= ~(0xff << txprio_shift[i-1]);
 253                btcoex_hw->wlan_weight[i-1] |= (btcoex_hw->tx_prio[stomp_type]
 254                                                      << txprio_shift[i-1]);
 255        }
 256
 257}
 258EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
 259
 260
 261static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
 262{
 263        struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
 264        u32  val;
 265        int i;
 266
 267        /*
 268         * Program coex mode and weight registers to
 269         * enable coex 3-wire
 270         */
 271        REG_WRITE(ah, AR_BT_COEX_MODE, btcoex->bt_coex_mode);
 272        REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2);
 273
 274
 275        if (AR_SREV_9300_20_OR_LATER(ah)) {
 276                REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, btcoex->wlan_weight[0]);
 277                REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, btcoex->wlan_weight[1]);
 278                for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
 279                        REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS(i),
 280                                  btcoex->bt_weight[i]);
 281        } else
 282                REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex->bt_coex_weights);
 283
 284
 285
 286        if (AR_SREV_9271(ah)) {
 287                val = REG_READ(ah, 0x50040);
 288                val &= 0xFFFFFEFF;
 289                REG_WRITE(ah, 0x50040, val);
 290        }
 291
 292        REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
 293        REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
 294
 295        ath9k_hw_cfg_output(ah, btcoex->wlanactive_gpio,
 296                            AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
 297}
 298
 299static void ath9k_hw_btcoex_enable_mci(struct ath_hw *ah)
 300{
 301        struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
 302        int i;
 303
 304        for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
 305                REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i),
 306                          btcoex->wlan_weight[i]);
 307
 308        REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
 309        btcoex->enabled = true;
 310}
 311
 312static void ath9k_hw_btcoex_disable_mci(struct ath_hw *ah)
 313{
 314        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 315        int i;
 316
 317        ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
 318
 319        for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
 320                REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i),
 321                          btcoex_hw->wlan_weight[i]);
 322}
 323
 324void ath9k_hw_btcoex_enable(struct ath_hw *ah)
 325{
 326        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 327
 328        switch (ath9k_hw_get_btcoex_scheme(ah)) {
 329        case ATH_BTCOEX_CFG_NONE:
 330                return;
 331        case ATH_BTCOEX_CFG_2WIRE:
 332                ath9k_hw_btcoex_enable_2wire(ah);
 333                break;
 334        case ATH_BTCOEX_CFG_3WIRE:
 335                ath9k_hw_btcoex_enable_3wire(ah);
 336                break;
 337        case ATH_BTCOEX_CFG_MCI:
 338                ath9k_hw_btcoex_enable_mci(ah);
 339                break;
 340        }
 341
 342        if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI) {
 343                REG_RMW(ah, AR_GPIO_PDPU,
 344                        (0x2 << (btcoex_hw->btactive_gpio * 2)),
 345                        (0x3 << (btcoex_hw->btactive_gpio * 2)));
 346        }
 347
 348        ah->btcoex_hw.enabled = true;
 349}
 350EXPORT_SYMBOL(ath9k_hw_btcoex_enable);
 351
 352void ath9k_hw_btcoex_disable(struct ath_hw *ah)
 353{
 354        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 355        int i;
 356
 357        btcoex_hw->enabled = false;
 358
 359        if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_MCI) {
 360                ath9k_hw_btcoex_disable_mci(ah);
 361                return;
 362        }
 363
 364        if (!AR_SREV_9300_20_OR_LATER(ah))
 365                ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0);
 366
 367        ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
 368                        AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 369
 370        if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) {
 371                REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
 372                REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
 373
 374                if (AR_SREV_9300_20_OR_LATER(ah)) {
 375                        REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0);
 376                        REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0);
 377                        for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
 378                                REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS(i), 0);
 379                } else
 380                        REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
 381
 382        }
 383}
 384EXPORT_SYMBOL(ath9k_hw_btcoex_disable);
 385
 386/*
 387 * Configures appropriate weight based on stomp type.
 388 */
 389void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
 390                              enum ath_stomp_type stomp_type)
 391{
 392        if (AR_SREV_9300_20_OR_LATER(ah)) {
 393                ath9k_hw_btcoex_set_weight(ah, 0, 0, stomp_type);
 394                return;
 395        }
 396
 397        switch (stomp_type) {
 398        case ATH_BTCOEX_STOMP_ALL:
 399                ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
 400                                           AR_STOMP_ALL_WLAN_WGHT, 0);
 401                break;
 402        case ATH_BTCOEX_STOMP_LOW:
 403                ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
 404                                           AR_STOMP_LOW_WLAN_WGHT, 0);
 405                break;
 406        case ATH_BTCOEX_STOMP_NONE:
 407                ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
 408                                           AR_STOMP_NONE_WLAN_WGHT, 0);
 409                break;
 410        default:
 411                ath_dbg(ath9k_hw_common(ah), BTCOEX, "Invalid Stomptype\n");
 412                break;
 413        }
 414}
 415EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp);
 416
 417void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio)
 418{
 419        struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
 420        int i;
 421
 422        for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++)
 423                btcoex->tx_prio[i] = stomp_txprio[i];
 424}
 425EXPORT_SYMBOL(ath9k_hw_btcoex_set_concur_txprio);
 426