1 /* 2 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2005 Atheros Communications, Inc. 4 * Copyright (c) 2008-2010, Atheros Communications Inc. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $FreeBSD$ 19 */ 20 21 #include "opt_ah.h" 22 23 #include "ah.h" 24 #include "ah_internal.h" 25 #include "ah_devid.h" 26 #ifdef AH_DEBUG 27 #include "ah_desc.h" /* NB: for HAL_PHYERR* */ 28 #endif 29 30 #include "ar5416/ar5416.h" 31 #include "ar5416/ar5416reg.h" 32 #include "ar5416/ar5416phy.h" 33 #include "ar5416/ar5416desc.h" /* AR5416_CONTTXMODE */ 34 #include "ar5416/ar5416_btcoex.h" 35 36 void 37 ar5416SetBTCoexInfo(struct ath_hal *ah, HAL_BT_COEX_INFO *btinfo) 38 { 39 struct ath_hal_5416 *ahp = AH5416(ah); 40 41 ahp->ah_btModule = btinfo->bt_module; 42 ahp->ah_btCoexConfigType = btinfo->bt_coex_config; 43 ahp->ah_btActiveGpioSelect = btinfo->bt_gpio_bt_active; 44 ahp->ah_btPriorityGpioSelect = btinfo->bt_gpio_bt_priority; 45 ahp->ah_wlanActiveGpioSelect = btinfo->bt_gpio_wlan_active; 46 ahp->ah_btActivePolarity = btinfo->bt_active_polarity; 47 ahp->ah_btCoexSingleAnt = btinfo->bt_single_ant; 48 ahp->ah_btWlanIsolation = btinfo->bt_isolation; 49 } 50 51 void 52 ar5416BTCoexConfig(struct ath_hal *ah, HAL_BT_COEX_CONFIG *btconf) 53 { 54 struct ath_hal_5416 *ahp = AH5416(ah); 55 HAL_BOOL rxClearPolarity = btconf->bt_rxclear_polarity; 56 57 /* 58 * For Kiwi and Osprey, the polarity of rx_clear is active high. 59 * The bt_rxclear_polarity flag from ath(4) needs to be inverted. 60 */ 61 if (AR_SREV_KIWI(ah)) { 62 rxClearPolarity = !btconf->bt_rxclear_polarity; 63 } 64 65 ahp->ah_btCoexMode = (ahp->ah_btCoexMode & AR_BT_QCU_THRESH) | 66 SM(btconf->bt_time_extend, AR_BT_TIME_EXTEND) | 67 SM(btconf->bt_txstate_extend, AR_BT_TXSTATE_EXTEND) | 68 SM(btconf->bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | 69 SM(btconf->bt_mode, AR_BT_MODE) | 70 SM(btconf->bt_quiet_collision, AR_BT_QUIET) | 71 SM(rxClearPolarity, AR_BT_RX_CLEAR_POLARITY) | 72 SM(btconf->bt_priority_time, AR_BT_PRIORITY_TIME) | 73 SM(btconf->bt_first_slot_time, AR_BT_FIRST_SLOT_TIME); 74 75 ahp->ah_btCoexMode2 |= SM(btconf->bt_hold_rxclear, 76 AR_BT_HOLD_RX_CLEAR); 77 78 if (ahp->ah_btCoexSingleAnt == AH_FALSE) { 79 /* Enable ACK to go out even though BT has higher priority. */ 80 ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT; 81 } 82 } 83 84 void 85 ar5416BTCoexSetQcuThresh(struct ath_hal *ah, int qnum) 86 { 87 struct ath_hal_5416 *ahp = AH5416(ah); 88 89 ahp->ah_btCoexMode |= SM(qnum, AR_BT_QCU_THRESH); 90 } 91 92 void 93 ar5416BTCoexSetWeights(struct ath_hal *ah, u_int32_t stompType) 94 { 95 struct ath_hal_5416 *ahp = AH5416(ah); 96 97 if (AR_SREV_KIWI_10_OR_LATER(ah)) { 98 /* TODO: TX RX separate is not enabled. */ 99 switch (stompType) { 100 case HAL_BT_COEX_STOMP_AUDIO: 101 /* XXX TODO */ 102 case HAL_BT_COEX_STOMP_ALL: 103 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT; 104 ahp->ah_btCoexWLANWeight = AR5416_STOMP_ALL_WLAN_WGHT; 105 break; 106 case HAL_BT_COEX_STOMP_LOW: 107 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT; 108 ahp->ah_btCoexWLANWeight = AR5416_STOMP_LOW_WLAN_WGHT; 109 break; 110 case HAL_BT_COEX_STOMP_ALL_FORCE: 111 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT; 112 ahp->ah_btCoexWLANWeight = 113 AR5416_STOMP_ALL_FORCE_WLAN_WGHT; 114 break; 115 case HAL_BT_COEX_STOMP_LOW_FORCE: 116 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT; 117 ahp->ah_btCoexWLANWeight = 118 AR5416_STOMP_LOW_FORCE_WLAN_WGHT; 119 break; 120 case HAL_BT_COEX_STOMP_NONE: 121 case HAL_BT_COEX_NO_STOMP: 122 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT; 123 ahp->ah_btCoexWLANWeight = AR5416_STOMP_NONE_WLAN_WGHT; 124 break; 125 default: 126 /* There is a forceWeight from registry */ 127 ahp->ah_btCoexBTWeight = stompType & 0xffff; 128 ahp->ah_btCoexWLANWeight = stompType >> 16; 129 break; 130 } 131 } else { 132 switch (stompType) { 133 case HAL_BT_COEX_STOMP_AUDIO: 134 /* XXX TODO */ 135 case HAL_BT_COEX_STOMP_ALL: 136 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT; 137 ahp->ah_btCoexWLANWeight = AR5416_STOMP_ALL_WLAN_WGHT; 138 break; 139 case HAL_BT_COEX_STOMP_LOW: 140 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT; 141 ahp->ah_btCoexWLANWeight = AR5416_STOMP_LOW_WLAN_WGHT; 142 break; 143 case HAL_BT_COEX_STOMP_ALL_FORCE: 144 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT; 145 ahp->ah_btCoexWLANWeight = 146 AR5416_STOMP_ALL_FORCE_WLAN_WGHT; 147 break; 148 case HAL_BT_COEX_STOMP_LOW_FORCE: 149 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT; 150 ahp->ah_btCoexWLANWeight = 151 AR5416_STOMP_LOW_FORCE_WLAN_WGHT; 152 break; 153 case HAL_BT_COEX_STOMP_NONE: 154 case HAL_BT_COEX_NO_STOMP: 155 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT; 156 ahp->ah_btCoexWLANWeight = AR5416_STOMP_NONE_WLAN_WGHT; 157 break; 158 default: 159 /* There is a forceWeight from registry */ 160 ahp->ah_btCoexBTWeight = stompType & 0xffff; 161 ahp->ah_btCoexWLANWeight = stompType >> 16; 162 break; 163 } 164 } 165 } 166 167 void 168 ar5416BTCoexSetupBmissThresh(struct ath_hal *ah, u_int32_t thresh) 169 { 170 struct ath_hal_5416 *ahp = AH5416(ah); 171 172 ahp->ah_btCoexMode2 |= SM(thresh, AR_BT_BCN_MISS_THRESH); 173 } 174 175 /* 176 * There is no antenna diversity for Owl, Kiwi, etc. 177 * 178 * Kite will override this particular method. 179 */ 180 void 181 ar5416BTCoexAntennaDiversity(struct ath_hal *ah) 182 { 183 } 184 185 void 186 ar5416BTCoexSetParameter(struct ath_hal *ah, u_int32_t type, u_int32_t value) 187 { 188 struct ath_hal_5416 *ahp = AH5416(ah); 189 190 switch (type) { 191 case HAL_BT_COEX_SET_ACK_PWR: 192 if (value) { 193 ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_LOW_ACK_PWR; 194 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_LOW_ACK_POWER); 195 } else { 196 ahp->ah_btCoexFlag &= ~HAL_BT_COEX_FLAG_LOW_ACK_PWR; 197 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_HIGH_ACK_POWER); 198 } 199 break; 200 case HAL_BT_COEX_ANTENNA_DIVERSITY: 201 /* This is overridden for Kite */ 202 break; 203 #if 0 204 case HAL_BT_COEX_LOWER_TX_PWR: 205 if (value) { 206 if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) == 0) { 207 ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_LOWER_TX_PWR; 208 AH_PRIVATE(ah)->ah_config.ath_hal_desc_tpc = 1; 209 ar5416SetTxPowerLimit(ah, AH_PRIVATE(ah)->ah_power_limit, AH_PRIVATE(ah)->ah_extra_txpow, 0); 210 } 211 } 212 else { 213 if (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) { 214 ahp->ah_btCoexFlag &= ~HAL_BT_COEX_FLAG_LOWER_TX_PWR; 215 AH_PRIVATE(ah)->ah_config.ath_hal_desc_tpc = 0; 216 ar5416SetTxPowerLimit(ah, AH_PRIVATE(ah)->ah_power_limit, AH_PRIVATE(ah)->ah_extra_txpow, 0); 217 } 218 } 219 break; 220 #endif 221 default: 222 break; 223 } 224 } 225 226 void 227 ar5416BTCoexDisable(struct ath_hal *ah) 228 { 229 struct ath_hal_5416 *ahp = AH5416(ah); 230 231 /* Always drive rx_clear_external output as 0 */ 232 ar5416GpioSet(ah, ahp->ah_wlanActiveGpioSelect, 0); 233 ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect, 234 HAL_GPIO_OUTPUT_MUX_AS_OUTPUT); 235 236 if (AR_SREV_9271(ah)) { 237 /* 238 * Set wlanActiveGpio to input when disabling BT-COEX to 239 * reduce power consumption 240 */ 241 ar5416GpioCfgInput(ah, ahp->ah_wlanActiveGpioSelect); 242 } 243 244 if (ahp->ah_btCoexSingleAnt == AH_TRUE) { 245 OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 246 1); 247 OS_REG_RMW_FIELD(ah, AR_MISC_MODE, AR_PCU_BT_ANT_PREVENT_RX, 248 0); 249 } 250 251 OS_REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); 252 OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); 253 if (AR_SREV_KIWI_10_OR_LATER(ah)) 254 OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT2, 0); 255 OS_REG_WRITE(ah, AR_BT_COEX_MODE2, 0); 256 257 ahp->ah_btCoexEnabled = AH_FALSE; 258 } 259 260 int 261 ar5416BTCoexEnable(struct ath_hal *ah) 262 { 263 struct ath_hal_5416 *ahp = AH5416(ah); 264 265 /* Program coex mode and weight registers to actually enable coex */ 266 OS_REG_WRITE(ah, AR_BT_COEX_MODE, ahp->ah_btCoexMode); 267 OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT, 268 SM(ahp->ah_btCoexWLANWeight & 0xFFFF, AR_BT_WL_WGHT) | 269 SM(ahp->ah_btCoexBTWeight & 0xFFFF, AR_BT_BT_WGHT)); 270 if (AR_SREV_KIWI_10_OR_LATER(ah)) { 271 OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT2, 272 SM(ahp->ah_btCoexWLANWeight >> 16, AR_BT_WL_WGHT)); 273 } 274 OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2); 275 276 /* Added Select GPIO5~8 instaed SPI */ 277 if (AR_SREV_9271(ah)) { 278 uint32_t val; 279 280 val = OS_REG_READ(ah, AR9271_CLOCK_CONTROL); 281 val &= 0xFFFFFEFF; 282 OS_REG_WRITE(ah, AR9271_CLOCK_CONTROL, val); 283 } 284 285 if (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOW_ACK_PWR) 286 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_LOW_ACK_POWER); 287 else 288 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_HIGH_ACK_POWER); 289 290 if (ahp->ah_btCoexSingleAnt == AH_TRUE) { 291 OS_REG_RMW_FIELD(ah, AR_QUIET1, 292 AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); 293 /* XXX should update miscMode? */ 294 OS_REG_RMW_FIELD(ah, AR_MISC_MODE, 295 AR_PCU_BT_ANT_PREVENT_RX, 1); 296 } else { 297 OS_REG_RMW_FIELD(ah, AR_QUIET1, 298 AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); 299 /* XXX should update miscMode? */ 300 OS_REG_RMW_FIELD(ah, AR_MISC_MODE, 301 AR_PCU_BT_ANT_PREVENT_RX, 0); 302 } 303 304 if (ahp->ah_btCoexConfigType == HAL_BT_COEX_CFG_3WIRE) { 305 /* For 3-wire, configure the desired GPIO port for rx_clear */ 306 ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect, 307 HAL_GPIO_OUTPUT_MUX_AS_WLAN_ACTIVE); 308 } else { 309 /* 310 * For 2-wire, configure the desired GPIO port 311 * for TX_FRAME output 312 */ 313 ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect, 314 HAL_GPIO_OUTPUT_MUX_AS_TX_FRAME); 315 } 316 317 /* 318 * Enable a weak pull down on BT_ACTIVE. 319 * When BT device is disabled, BT_ACTIVE might be floating. 320 */ 321 OS_REG_RMW(ah, AR_GPIO_PDPU, 322 (0x2 << (ahp->ah_btActiveGpioSelect * 2)), 323 (0x3 << (ahp->ah_btActiveGpioSelect * 2))); 324 325 ahp->ah_btCoexEnabled = AH_TRUE; 326 327 return (0); 328 } 329 330 void 331 ar5416InitBTCoex(struct ath_hal *ah) 332 { 333 struct ath_hal_5416 *ahp = AH5416(ah); 334 335 HALDEBUG(ah, HAL_DEBUG_BT_COEX, 336 "%s: called; configType=%d\n", 337 __func__, 338 ahp->ah_btCoexConfigType); 339 340 if (ahp->ah_btCoexConfigType == HAL_BT_COEX_CFG_3WIRE) { 341 OS_REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, 342 (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | 343 AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB)); 344 345 /* 346 * Set input mux for bt_prority_async and 347 * bt_active_async to GPIO pins 348 */ 349 OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, 350 AR_GPIO_INPUT_MUX1_BT_ACTIVE, 351 ahp->ah_btActiveGpioSelect); 352 OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, 353 AR_GPIO_INPUT_MUX1_BT_PRIORITY, 354 ahp->ah_btPriorityGpioSelect); 355 356 /* 357 * Configure the desired GPIO ports for input 358 */ 359 ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect); 360 ar5416GpioCfgInput(ah, ahp->ah_btPriorityGpioSelect); 361 362 /* 363 * Configure the antenna diversity setup. 364 * It's a no-op for AR9287; AR9285 overrides this 365 * as required. 366 */ 367 AH5416(ah)->ah_btCoexSetDiversity(ah); 368 369 if (ahp->ah_btCoexEnabled) 370 ar5416BTCoexEnable(ah); 371 else 372 ar5416BTCoexDisable(ah); 373 } else if (ahp->ah_btCoexConfigType != HAL_BT_COEX_CFG_NONE) { 374 /* 2-wire */ 375 if (ahp->ah_btCoexEnabled) { 376 /* Connect bt_active_async to baseband */ 377 OS_REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, 378 (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | 379 AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); 380 OS_REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, 381 AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); 382 383 /* 384 * Set input mux for bt_prority_async and 385 * bt_active_async to GPIO pins 386 */ 387 OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, 388 AR_GPIO_INPUT_MUX1_BT_ACTIVE, 389 ahp->ah_btActiveGpioSelect); 390 391 /* Configure the desired GPIO ports for input */ 392 ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect); 393 394 /* Enable coexistence on initialization */ 395 ar5416BTCoexEnable(ah); 396 } 397 } 398 } 399