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 20 enum 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 27 struct 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 39 static 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 46 static const u32 ar9462_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 }; 53 54 void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) 55 { 56 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; 57 const struct ath_btcoex_config ath_bt_config = { 58 .bt_time_extend = 0, 59 .bt_txstate_extend = true, 60 .bt_txframe_extend = true, 61 .bt_mode = ATH_BT_COEX_MODE_SLOTTED, 62 .bt_quiet_collision = true, 63 .bt_rxclear_polarity = true, 64 .bt_priority_time = 2, 65 .bt_first_slot_time = 5, 66 .bt_hold_rx_clear = true, 67 }; 68 u32 i, idx; 69 bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; 70 71 if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) 72 return; 73 74 if (AR_SREV_9300_20_OR_LATER(ah)) 75 rxclear_polarity = !ath_bt_config.bt_rxclear_polarity; 76 77 btcoex_hw->bt_coex_mode = 78 (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) | 79 SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) | 80 SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) | 81 SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | 82 SM(ath_bt_config.bt_mode, AR_BT_MODE) | 83 SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | 84 SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | 85 SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | 86 SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | 87 SM(qnum, AR_BT_QCU_THRESH); 88 89 btcoex_hw->bt_coex_mode2 = 90 SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | 91 SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | 92 AR_BT_DISABLE_BT_ANT; 93 94 for (i = 0; i < 32; i++) { 95 idx = (debruijn32 << i) >> 27; 96 ah->hw_gen_timers.gen_timer_index[idx] = i; 97 } 98 } 99 EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); 100 101 void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) 102 { 103 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; 104 105 if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) 106 return; 107 108 /* connect bt_active to baseband */ 109 REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, 110 (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | 111 AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); 112 113 REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, 114 AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); 115 116 /* Set input mux for bt_active to gpio pin */ 117 REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, 118 AR_GPIO_INPUT_MUX1_BT_ACTIVE, 119 btcoex_hw->btactive_gpio); 120 121 /* Configure the desired gpio port for input */ 122 ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio); 123 } 124 EXPORT_SYMBOL(ath9k_hw_btcoex_init_2wire); 125 126 void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) 127 { 128 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; 129 130 if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) 131 return; 132 133 /* btcoex 3-wire */ 134 REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, 135 (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | 136 AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB)); 137 138 /* Set input mux for bt_prority_async and 139 * bt_active_async to GPIO pins */ 140 REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, 141 AR_GPIO_INPUT_MUX1_BT_ACTIVE, 142 btcoex_hw->btactive_gpio); 143 144 REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, 145 AR_GPIO_INPUT_MUX1_BT_PRIORITY, 146 btcoex_hw->btpriority_gpio); 147 148 /* Configure the desired GPIO ports for input */ 149 150 ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio); 151 ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btpriority_gpio); 152 } 153 EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire); 154 155 static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah) 156 { 157 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; 158 159 if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) 160 return; 161 162 /* Configure the desired GPIO port for TX_FRAME output */ 163 ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, 164 AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); 165 } 166 167 void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, 168 u32 bt_weight, 169 u32 wlan_weight) 170 { 171 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; 172 173 if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) 174 return; 175 176 btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | 177 SM(wlan_weight, AR_BTCOEX_WL_WGHT); 178 } 179 EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); 180 181 182 static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) 183 { 184 struct ath_btcoex_hw *btcoex = &ah->btcoex_hw; 185 u32 val; 186 int i; 187 188 /* 189 * Program coex mode and weight registers to 190 * enable coex 3-wire 191 */ 192 REG_WRITE(ah, AR_BT_COEX_MODE, btcoex->bt_coex_mode); 193 REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2); 194 195 196 if (AR_SREV_9300_20_OR_LATER(ah)) { 197 REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, btcoex->wlan_weight[0]); 198 REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, btcoex->wlan_weight[1]); 199 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) 200 REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS(i), 201 btcoex->bt_weight[i]); 202 } else 203 REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex->bt_coex_weights); 204 205 206 207 if (AR_SREV_9271(ah)) { 208 val = REG_READ(ah, 0x50040); 209 val &= 0xFFFFFEFF; 210 REG_WRITE(ah, 0x50040, val); 211 } 212 213 REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); 214 REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); 215 216 ath9k_hw_cfg_output(ah, btcoex->wlanactive_gpio, 217 AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); 218 } 219 220 static void ath9k_hw_btcoex_enable_mci(struct ath_hw *ah) 221 { 222 struct ath_btcoex_hw *btcoex = &ah->btcoex_hw; 223 int i; 224 225 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) 226 REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i), 227 btcoex->wlan_weight[i]); 228 229 REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); 230 btcoex->enabled = true; 231 } 232 233 void ath9k_hw_btcoex_enable(struct ath_hw *ah) 234 { 235 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; 236 237 switch (ath9k_hw_get_btcoex_scheme(ah)) { 238 case ATH_BTCOEX_CFG_NONE: 239 return; 240 case ATH_BTCOEX_CFG_2WIRE: 241 ath9k_hw_btcoex_enable_2wire(ah); 242 break; 243 case ATH_BTCOEX_CFG_3WIRE: 244 ath9k_hw_btcoex_enable_3wire(ah); 245 break; 246 case ATH_BTCOEX_CFG_MCI: 247 ath9k_hw_btcoex_enable_mci(ah); 248 return; 249 } 250 251 REG_RMW(ah, AR_GPIO_PDPU, 252 (0x2 << (btcoex_hw->btactive_gpio * 2)), 253 (0x3 << (btcoex_hw->btactive_gpio * 2))); 254 255 ah->btcoex_hw.enabled = true; 256 } 257 EXPORT_SYMBOL(ath9k_hw_btcoex_enable); 258 259 void ath9k_hw_btcoex_disable(struct ath_hw *ah) 260 { 261 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; 262 int i; 263 264 if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) 265 return; 266 267 btcoex_hw->enabled = false; 268 if (btcoex_hw->scheme == ATH_BTCOEX_CFG_MCI) { 269 ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); 270 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) 271 REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i), 272 btcoex_hw->wlan_weight[i]); 273 } 274 ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0); 275 276 ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, 277 AR_GPIO_OUTPUT_MUX_AS_OUTPUT); 278 279 if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) { 280 REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); 281 REG_WRITE(ah, AR_BT_COEX_MODE2, 0); 282 283 if (AR_SREV_9300_20_OR_LATER(ah)) { 284 REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0); 285 REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0); 286 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) 287 REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS(i), 0); 288 } else 289 REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); 290 291 } 292 } 293 EXPORT_SYMBOL(ath9k_hw_btcoex_disable); 294 295 static void ar9003_btcoex_bt_stomp(struct ath_hw *ah, 296 enum ath_stomp_type stomp_type) 297 { 298 struct ath_btcoex_hw *btcoex = &ah->btcoex_hw; 299 const u32 *weight = AR_SREV_9462(ah) ? ar9003_wlan_weights[stomp_type] : 300 ar9462_wlan_weights[stomp_type]; 301 int i; 302 303 for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) { 304 btcoex->bt_weight[i] = AR9300_BT_WGHT; 305 btcoex->wlan_weight[i] = weight[i]; 306 } 307 } 308 309 /* 310 * Configures appropriate weight based on stomp type. 311 */ 312 void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, 313 enum ath_stomp_type stomp_type) 314 { 315 if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) 316 return; 317 318 if (AR_SREV_9300_20_OR_LATER(ah)) { 319 ar9003_btcoex_bt_stomp(ah, stomp_type); 320 return; 321 } 322 323 switch (stomp_type) { 324 case ATH_BTCOEX_STOMP_ALL: 325 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, 326 AR_STOMP_ALL_WLAN_WGHT); 327 break; 328 case ATH_BTCOEX_STOMP_LOW: 329 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, 330 AR_STOMP_LOW_WLAN_WGHT); 331 break; 332 case ATH_BTCOEX_STOMP_NONE: 333 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, 334 AR_STOMP_NONE_WLAN_WGHT); 335 break; 336 default: 337 ath_dbg(ath9k_hw_common(ah), BTCOEX, "Invalid Stomptype\n"); 338 break; 339 } 340 } 341 EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp); 342