2 * SPDX-License-Identifier: ISC
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.
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.
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.
26 #include "ah_internal.h"
29 #include "ah_desc.h" /* NB: for HAL_PHYERR* */
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"
39 ar5416SetBTCoexInfo(struct ath_hal *ah, HAL_BT_COEX_INFO *btinfo)
41 struct ath_hal_5416 *ahp = AH5416(ah);
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;
54 ar5416BTCoexConfig(struct ath_hal *ah, HAL_BT_COEX_CONFIG *btconf)
56 struct ath_hal_5416 *ahp = AH5416(ah);
57 HAL_BOOL rxClearPolarity = btconf->bt_rxclear_polarity;
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.
63 if (AR_SREV_KIWI(ah)) {
64 rxClearPolarity = !btconf->bt_rxclear_polarity;
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);
77 ahp->ah_btCoexMode2 |= SM(btconf->bt_hold_rxclear,
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;
87 ar5416BTCoexSetQcuThresh(struct ath_hal *ah, int qnum)
89 struct ath_hal_5416 *ahp = AH5416(ah);
91 ahp->ah_btCoexMode |= SM(qnum, AR_BT_QCU_THRESH);
95 ar5416BTCoexSetWeights(struct ath_hal *ah, u_int32_t stompType)
97 struct ath_hal_5416 *ahp = AH5416(ah);
99 if (AR_SREV_KIWI_10_OR_LATER(ah)) {
100 /* TODO: TX RX separate is not enabled. */
102 case HAL_BT_COEX_STOMP_AUDIO:
104 case HAL_BT_COEX_STOMP_ALL:
105 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
106 ahp->ah_btCoexWLANWeight = AR5416_STOMP_ALL_WLAN_WGHT;
108 case HAL_BT_COEX_STOMP_LOW:
109 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
110 ahp->ah_btCoexWLANWeight = AR5416_STOMP_LOW_WLAN_WGHT;
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;
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;
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;
128 /* There is a forceWeight from registry */
129 ahp->ah_btCoexBTWeight = stompType & 0xffff;
130 ahp->ah_btCoexWLANWeight = stompType >> 16;
135 case HAL_BT_COEX_STOMP_AUDIO:
137 case HAL_BT_COEX_STOMP_ALL:
138 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
139 ahp->ah_btCoexWLANWeight = AR5416_STOMP_ALL_WLAN_WGHT;
141 case HAL_BT_COEX_STOMP_LOW:
142 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
143 ahp->ah_btCoexWLANWeight = AR5416_STOMP_LOW_WLAN_WGHT;
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;
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;
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;
161 /* There is a forceWeight from registry */
162 ahp->ah_btCoexBTWeight = stompType & 0xffff;
163 ahp->ah_btCoexWLANWeight = stompType >> 16;
170 ar5416BTCoexSetupBmissThresh(struct ath_hal *ah, u_int32_t thresh)
172 struct ath_hal_5416 *ahp = AH5416(ah);
174 ahp->ah_btCoexMode2 |= SM(thresh, AR_BT_BCN_MISS_THRESH);
178 * There is no antenna diversity for Owl, Kiwi, etc.
180 * Kite will override this particular method.
183 ar5416BTCoexAntennaDiversity(struct ath_hal *ah)
188 ar5416BTCoexSetParameter(struct ath_hal *ah, u_int32_t type, u_int32_t value)
190 struct ath_hal_5416 *ahp = AH5416(ah);
193 case HAL_BT_COEX_SET_ACK_PWR:
195 ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_LOW_ACK_PWR;
196 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_LOW_ACK_POWER);
198 ahp->ah_btCoexFlag &= ~HAL_BT_COEX_FLAG_LOW_ACK_PWR;
199 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_HIGH_ACK_POWER);
202 case HAL_BT_COEX_ANTENNA_DIVERSITY:
203 /* This is overridden for Kite */
206 case HAL_BT_COEX_LOWER_TX_PWR:
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);
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);
229 ar5416BTCoexDisable(struct ath_hal *ah)
231 struct ath_hal_5416 *ahp = AH5416(ah);
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);
238 if (AR_SREV_9271(ah)) {
240 * Set wlanActiveGpio to input when disabling BT-COEX to
241 * reduce power consumption
243 ar5416GpioCfgInput(ah, ahp->ah_wlanActiveGpioSelect);
246 if (ahp->ah_btCoexSingleAnt == AH_TRUE) {
247 OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE,
249 OS_REG_RMW_FIELD(ah, AR_MISC_MODE, AR_PCU_BT_ANT_PREVENT_RX,
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);
259 ahp->ah_btCoexEnabled = AH_FALSE;
263 ar5416BTCoexEnable(struct ath_hal *ah)
265 struct ath_hal_5416 *ahp = AH5416(ah);
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));
276 OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
278 /* Added Select GPIO5~8 instaed SPI */
279 if (AR_SREV_9271(ah)) {
282 val = OS_REG_READ(ah, AR9271_CLOCK_CONTROL);
284 OS_REG_WRITE(ah, AR9271_CLOCK_CONTROL, val);
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);
290 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_HIGH_ACK_POWER);
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);
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);
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);
312 * For 2-wire, configure the desired GPIO port
313 * for TX_FRAME output
315 ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect,
316 HAL_GPIO_OUTPUT_MUX_AS_TX_FRAME);
320 * Enable a weak pull down on BT_ACTIVE.
321 * When BT device is disabled, BT_ACTIVE might be floating.
323 OS_REG_RMW(ah, AR_GPIO_PDPU,
324 (0x2 << (ahp->ah_btActiveGpioSelect * 2)),
325 (0x3 << (ahp->ah_btActiveGpioSelect * 2)));
327 ahp->ah_btCoexEnabled = AH_TRUE;
333 ar5416InitBTCoex(struct ath_hal *ah)
335 struct ath_hal_5416 *ahp = AH5416(ah);
337 HALDEBUG(ah, HAL_DEBUG_BT_COEX,
338 "%s: called; configType=%d\n",
340 ahp->ah_btCoexConfigType);
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));
348 * Set input mux for bt_prority_async and
349 * bt_active_async to GPIO pins
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);
359 * Configure the desired GPIO ports for input
361 ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect);
362 ar5416GpioCfgInput(ah, ahp->ah_btPriorityGpioSelect);
365 * Configure the antenna diversity setup.
366 * It's a no-op for AR9287; AR9285 overrides this
369 AH5416(ah)->ah_btCoexSetDiversity(ah);
371 if (ahp->ah_btCoexEnabled)
372 ar5416BTCoexEnable(ah);
374 ar5416BTCoexDisable(ah);
375 } else if (ahp->ah_btCoexConfigType != HAL_BT_COEX_CFG_NONE) {
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);
386 * Set input mux for bt_prority_async and
387 * bt_active_async to GPIO pins
389 OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
390 AR_GPIO_INPUT_MUX1_BT_ACTIVE,
391 ahp->ah_btActiveGpioSelect);
393 /* Configure the desired GPIO ports for input */
394 ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect);
396 /* Enable coexistence on initialization */
397 ar5416BTCoexEnable(ah);