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