0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/export.h>
0018 #include <linux/types.h>
0019 #include <linux/ath9k_platform.h>
0020 #include "hw.h"
0021
0022 enum ath_bt_mode {
0023 ATH_BT_COEX_MODE_LEGACY,
0024 ATH_BT_COEX_MODE_UNSLOTTED,
0025 ATH_BT_COEX_MODE_SLOTTED,
0026 ATH_BT_COEX_MODE_DISABLED,
0027 };
0028
0029 struct ath_btcoex_config {
0030 u8 bt_time_extend;
0031 bool bt_txstate_extend;
0032 bool bt_txframe_extend;
0033 enum ath_bt_mode bt_mode;
0034 bool bt_quiet_collision;
0035 bool bt_rxclear_polarity;
0036 u8 bt_priority_time;
0037 u8 bt_first_slot_time;
0038 bool bt_hold_rx_clear;
0039 u8 wl_active_time;
0040 u8 wl_qc_time;
0041 };
0042
0043 static const u32 ar9003_wlan_weights[ATH_BTCOEX_STOMP_MAX]
0044 [AR9300_NUM_WLAN_WEIGHTS] = {
0045 { 0xfffffff0, 0xfffffff0, 0xfffffff0, 0xfffffff0 },
0046 { 0x88888880, 0x88888880, 0x88888880, 0x88888880 },
0047 { 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
0048 };
0049
0050 static const u32 mci_wlan_weights[ATH_BTCOEX_STOMP_MAX]
0051 [AR9300_NUM_WLAN_WEIGHTS] = {
0052 { 0x01017d01, 0x41414101, 0x41414101, 0x41414141 },
0053 { 0x01017d01, 0x3b3b3b01, 0x3b3b3b01, 0x3b3b3b3b },
0054 { 0x01017d01, 0x01010101, 0x01010101, 0x01010101 },
0055 { 0x01017d01, 0x013b0101, 0x3b3b0101, 0x3b3b013b },
0056 { 0xffffff01, 0xffffffff, 0xffffff01, 0xffffffff },
0057 };
0058
0059 void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
0060 {
0061 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0062 const struct ath_btcoex_config ath_bt_config = {
0063 .bt_time_extend = 0,
0064 .bt_txstate_extend = true,
0065 .bt_txframe_extend = true,
0066 .bt_mode = ATH_BT_COEX_MODE_SLOTTED,
0067 .bt_quiet_collision = true,
0068 .bt_rxclear_polarity = true,
0069 .bt_priority_time = 2,
0070 .bt_first_slot_time = 5,
0071 .bt_hold_rx_clear = true,
0072 .wl_active_time = 0x20,
0073 .wl_qc_time = 0x20,
0074 };
0075 bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
0076 u8 time_extend = ath_bt_config.bt_time_extend;
0077 u8 first_slot_time = ath_bt_config.bt_first_slot_time;
0078
0079 if (AR_SREV_9300_20_OR_LATER(ah))
0080 rxclear_polarity = !ath_bt_config.bt_rxclear_polarity;
0081
0082 if (AR_SREV_SOC(ah)) {
0083 first_slot_time = 0x1d;
0084 time_extend = 0xa;
0085
0086 btcoex_hw->bt_coex_mode3 =
0087 SM(ath_bt_config.wl_active_time, AR_BT_WL_ACTIVE_TIME) |
0088 SM(ath_bt_config.wl_qc_time, AR_BT_WL_QC_TIME);
0089
0090 btcoex_hw->bt_coex_mode2 =
0091 AR_BT_PROTECT_BT_AFTER_WAKEUP |
0092 AR_BT_PHY_ERR_BT_COLL_ENABLE;
0093 }
0094
0095 btcoex_hw->bt_coex_mode =
0096 (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) |
0097 SM(time_extend, AR_BT_TIME_EXTEND) |
0098 SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
0099 SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
0100 SM(ath_bt_config.bt_mode, AR_BT_MODE) |
0101 SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) |
0102 SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
0103 SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) |
0104 SM(first_slot_time, AR_BT_FIRST_SLOT_TIME) |
0105 SM(qnum, AR_BT_QCU_THRESH);
0106
0107 btcoex_hw->bt_coex_mode2 |=
0108 SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
0109 SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
0110 AR_BT_DISABLE_BT_ANT;
0111 }
0112 EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);
0113
0114 static void ath9k_hw_btcoex_pin_init(struct ath_hw *ah, u8 wlanactive_gpio,
0115 u8 btactive_gpio, u8 btpriority_gpio)
0116 {
0117 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0118 struct ath9k_platform_data *pdata = ah->dev->platform_data;
0119
0120 if (btcoex_hw->scheme != ATH_BTCOEX_CFG_2WIRE &&
0121 btcoex_hw->scheme != ATH_BTCOEX_CFG_3WIRE)
0122 return;
0123
0124
0125 if (pdata && (pdata->bt_active_pin || pdata->bt_priority_pin ||
0126 pdata->wlan_active_pin)) {
0127 btcoex_hw->btactive_gpio = pdata->bt_active_pin;
0128 btcoex_hw->wlanactive_gpio = pdata->wlan_active_pin;
0129 btcoex_hw->btpriority_gpio = pdata->bt_priority_pin;
0130 } else {
0131 btcoex_hw->btactive_gpio = btactive_gpio;
0132 btcoex_hw->wlanactive_gpio = wlanactive_gpio;
0133 btcoex_hw->btpriority_gpio = btpriority_gpio;
0134 }
0135 }
0136
0137 void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah)
0138 {
0139 struct ath_common *common = ath9k_hw_common(ah);
0140 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0141
0142
0143
0144
0145 if (!common->btcoex_enabled) {
0146 btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
0147 return;
0148 }
0149
0150 if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
0151 btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
0152 } else if (AR_SREV_9300_20_OR_LATER(ah)) {
0153 btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
0154
0155 ath9k_hw_btcoex_pin_init(ah, ATH_WLANACTIVE_GPIO_9300,
0156 ATH_BTACTIVE_GPIO_9300,
0157 ATH_BTPRIORITY_GPIO_9300);
0158 } else if (AR_SREV_9280_20_OR_LATER(ah)) {
0159 if (AR_SREV_9285(ah))
0160 btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
0161 else
0162 btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
0163
0164 ath9k_hw_btcoex_pin_init(ah, ATH_WLANACTIVE_GPIO_9280,
0165 ATH_BTACTIVE_GPIO_9280,
0166 ATH_BTPRIORITY_GPIO_9285);
0167 }
0168 }
0169 EXPORT_SYMBOL(ath9k_hw_btcoex_init_scheme);
0170
0171 void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah)
0172 {
0173 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0174
0175
0176 REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
0177 (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
0178 AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
0179
0180 REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
0181 AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
0182
0183
0184 if (!AR_SREV_SOC(ah))
0185 REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
0186 AR_GPIO_INPUT_MUX1_BT_ACTIVE,
0187 btcoex_hw->btactive_gpio);
0188
0189
0190 ath9k_hw_gpio_request_in(ah, btcoex_hw->btactive_gpio,
0191 "ath9k-btactive");
0192 }
0193 EXPORT_SYMBOL(ath9k_hw_btcoex_init_2wire);
0194
0195 void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah)
0196 {
0197 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0198
0199
0200 REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
0201 (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
0202 AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
0203
0204
0205
0206 if (!AR_SREV_SOC(ah)) {
0207 REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
0208 AR_GPIO_INPUT_MUX1_BT_ACTIVE,
0209 btcoex_hw->btactive_gpio);
0210 REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
0211 AR_GPIO_INPUT_MUX1_BT_PRIORITY,
0212 btcoex_hw->btpriority_gpio);
0213 }
0214
0215
0216 ath9k_hw_gpio_request_in(ah, btcoex_hw->btactive_gpio,
0217 "ath9k-btactive");
0218 ath9k_hw_gpio_request_in(ah, btcoex_hw->btpriority_gpio,
0219 "ath9k-btpriority");
0220 }
0221 EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire);
0222
0223 void ath9k_hw_btcoex_deinit(struct ath_hw *ah)
0224 {
0225 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0226
0227 ath9k_hw_gpio_free(ah, btcoex_hw->btactive_gpio);
0228 ath9k_hw_gpio_free(ah, btcoex_hw->btpriority_gpio);
0229 ath9k_hw_gpio_free(ah, btcoex_hw->wlanactive_gpio);
0230 }
0231 EXPORT_SYMBOL(ath9k_hw_btcoex_deinit);
0232
0233 void ath9k_hw_btcoex_init_mci(struct ath_hw *ah)
0234 {
0235 ah->btcoex_hw.mci.ready = false;
0236 ah->btcoex_hw.mci.bt_state = 0;
0237 ah->btcoex_hw.mci.bt_ver_major = 3;
0238 ah->btcoex_hw.mci.bt_ver_minor = 0;
0239 ah->btcoex_hw.mci.bt_version_known = false;
0240 ah->btcoex_hw.mci.update_2g5g = true;
0241 ah->btcoex_hw.mci.is_2g = true;
0242 ah->btcoex_hw.mci.wlan_channels_update = false;
0243 ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000;
0244 ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff;
0245 ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff;
0246 ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff;
0247 ah->btcoex_hw.mci.query_bt = true;
0248 ah->btcoex_hw.mci.unhalt_bt_gpm = true;
0249 ah->btcoex_hw.mci.halted_bt_gpm = false;
0250 ah->btcoex_hw.mci.need_flush_btinfo = false;
0251 ah->btcoex_hw.mci.wlan_cal_seq = 0;
0252 ah->btcoex_hw.mci.wlan_cal_done = 0;
0253 ah->btcoex_hw.mci.config = (AR_SREV_9462(ah)) ? 0x2201 : 0xa4c1;
0254 }
0255 EXPORT_SYMBOL(ath9k_hw_btcoex_init_mci);
0256
0257 static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah)
0258 {
0259 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0260
0261
0262 ath9k_hw_gpio_request_out(ah, btcoex_hw->wlanactive_gpio,
0263 "ath9k-wlanactive",
0264 AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
0265 }
0266
0267
0268
0269
0270
0271 void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
0272 u32 bt_weight,
0273 u32 wlan_weight,
0274 enum ath_stomp_type stomp_type)
0275 {
0276 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0277 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
0278 u8 txprio_shift[] = { 24, 16, 16, 0 };
0279 bool concur_tx = (mci_hw->concur_tx && btcoex_hw->tx_prio[stomp_type]);
0280 const u32 *weight = ar9003_wlan_weights[stomp_type];
0281 int i;
0282
0283 if (!AR_SREV_9300_20_OR_LATER(ah)) {
0284 btcoex_hw->bt_coex_weights =
0285 SM(bt_weight, AR_BTCOEX_BT_WGHT) |
0286 SM(wlan_weight, AR_BTCOEX_WL_WGHT);
0287 return;
0288 }
0289
0290 if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
0291 enum ath_stomp_type stype =
0292 ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
0293 btcoex_hw->mci.stomp_ftp) ?
0294 ATH_BTCOEX_STOMP_LOW_FTP : stomp_type;
0295 weight = mci_wlan_weights[stype];
0296 }
0297
0298 for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
0299 btcoex_hw->bt_weight[i] = AR9300_BT_WGHT;
0300 btcoex_hw->wlan_weight[i] = weight[i];
0301 if (concur_tx && i) {
0302 btcoex_hw->wlan_weight[i] &=
0303 ~(0xff << txprio_shift[i-1]);
0304 btcoex_hw->wlan_weight[i] |=
0305 (btcoex_hw->tx_prio[stomp_type] <<
0306 txprio_shift[i-1]);
0307 }
0308 }
0309
0310
0311 if (concur_tx) {
0312 btcoex_hw->wlan_weight[i-1] &= ~(0xff << txprio_shift[i-1]);
0313 btcoex_hw->wlan_weight[i-1] |= (btcoex_hw->tx_prio[stomp_type]
0314 << txprio_shift[i-1]);
0315 }
0316 }
0317 EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
0318
0319
0320 static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
0321 {
0322 struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
0323 u32 val;
0324 int i;
0325
0326
0327
0328
0329
0330 if (AR_SREV_SOC(ah))
0331 REG_CLR_BIT(ah, AR_BT_COEX_MODE2, AR_BT_PHY_ERR_BT_COLL_ENABLE);
0332
0333 REG_WRITE(ah, AR_BT_COEX_MODE, btcoex->bt_coex_mode);
0334 REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2);
0335
0336 if (AR_SREV_SOC(ah))
0337 REG_WRITE(ah, AR_BT_COEX_MODE3, btcoex->bt_coex_mode3);
0338
0339 if (AR_SREV_9300_20_OR_LATER(ah)) {
0340 REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, btcoex->wlan_weight[0]);
0341 REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, btcoex->wlan_weight[1]);
0342 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
0343 REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS(i),
0344 btcoex->bt_weight[i]);
0345 } else
0346 REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex->bt_coex_weights);
0347
0348 if (AR_SREV_9271(ah)) {
0349 val = REG_READ(ah, 0x50040);
0350 val &= 0xFFFFFEFF;
0351 REG_WRITE(ah, 0x50040, val);
0352 }
0353
0354 REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
0355 REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
0356
0357 ath9k_hw_gpio_request_out(ah, btcoex->wlanactive_gpio,
0358 "ath9k-wlanactive",
0359 AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
0360 }
0361
0362 static void ath9k_hw_btcoex_enable_mci(struct ath_hw *ah)
0363 {
0364 struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
0365 int i;
0366
0367 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
0368 REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i),
0369 btcoex->wlan_weight[i]);
0370
0371 REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
0372 btcoex->enabled = true;
0373 }
0374
0375 static void ath9k_hw_btcoex_disable_mci(struct ath_hw *ah)
0376 {
0377 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0378 int i;
0379
0380 ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
0381
0382 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
0383 REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i),
0384 btcoex_hw->wlan_weight[i]);
0385 }
0386
0387 void ath9k_hw_btcoex_enable(struct ath_hw *ah)
0388 {
0389 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0390
0391 switch (ath9k_hw_get_btcoex_scheme(ah)) {
0392 case ATH_BTCOEX_CFG_NONE:
0393 return;
0394 case ATH_BTCOEX_CFG_2WIRE:
0395 ath9k_hw_btcoex_enable_2wire(ah);
0396 break;
0397 case ATH_BTCOEX_CFG_3WIRE:
0398 ath9k_hw_btcoex_enable_3wire(ah);
0399 break;
0400 case ATH_BTCOEX_CFG_MCI:
0401 ath9k_hw_btcoex_enable_mci(ah);
0402 break;
0403 }
0404
0405 if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI &&
0406 !AR_SREV_SOC(ah)) {
0407 REG_RMW(ah, AR_GPIO_PDPU,
0408 (0x2 << (btcoex_hw->btactive_gpio * 2)),
0409 (0x3 << (btcoex_hw->btactive_gpio * 2)));
0410 }
0411
0412 ah->btcoex_hw.enabled = true;
0413 }
0414 EXPORT_SYMBOL(ath9k_hw_btcoex_enable);
0415
0416 void ath9k_hw_btcoex_disable(struct ath_hw *ah)
0417 {
0418 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0419 int i;
0420
0421 btcoex_hw->enabled = false;
0422
0423 if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_MCI) {
0424 ath9k_hw_btcoex_disable_mci(ah);
0425 return;
0426 }
0427
0428 if (!AR_SREV_9300_20_OR_LATER(ah))
0429 ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0);
0430
0431 ath9k_hw_gpio_request_out(ah, btcoex_hw->wlanactive_gpio,
0432 NULL, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
0433
0434 if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) {
0435 REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
0436 REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
0437
0438 if (AR_SREV_9300_20_OR_LATER(ah)) {
0439 REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0);
0440 REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0);
0441 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
0442 REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS(i), 0);
0443 } else
0444 REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
0445
0446 }
0447 }
0448 EXPORT_SYMBOL(ath9k_hw_btcoex_disable);
0449
0450
0451
0452
0453 void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
0454 enum ath_stomp_type stomp_type)
0455 {
0456 if (AR_SREV_9300_20_OR_LATER(ah)) {
0457 ath9k_hw_btcoex_set_weight(ah, 0, 0, stomp_type);
0458 return;
0459 }
0460
0461 switch (stomp_type) {
0462 case ATH_BTCOEX_STOMP_ALL:
0463 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
0464 AR_STOMP_ALL_WLAN_WGHT, 0);
0465 break;
0466 case ATH_BTCOEX_STOMP_LOW:
0467 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
0468 AR_STOMP_LOW_WLAN_WGHT, 0);
0469 break;
0470 case ATH_BTCOEX_STOMP_NONE:
0471 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
0472 AR_STOMP_NONE_WLAN_WGHT, 0);
0473 break;
0474 default:
0475 ath_dbg(ath9k_hw_common(ah), BTCOEX, "Invalid Stomptype\n");
0476 break;
0477 }
0478 }
0479 EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp);
0480
0481 void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio)
0482 {
0483 struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
0484 int i;
0485
0486 for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++)
0487 btcoex->tx_prio[i] = stomp_txprio[i];
0488 }
0489 EXPORT_SYMBOL(ath9k_hw_btcoex_set_concur_txprio);