xref: /dflybsd-src/sys/dev/netif/ath/ath_hal/ar5416/ar5416_btcoex.c (revision b14ca477c2f404b36ad553a9e4f1b8b18836304e)
1572ff6f6SMatthew Dillon /*
2572ff6f6SMatthew Dillon  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
3572ff6f6SMatthew Dillon  * Copyright (c) 2002-2005 Atheros Communications, Inc.
4572ff6f6SMatthew Dillon  * Copyright (c) 2008-2010, Atheros Communications Inc.
5572ff6f6SMatthew Dillon  *
6572ff6f6SMatthew Dillon  * Permission to use, copy, modify, and/or distribute this software for any
7572ff6f6SMatthew Dillon  * purpose with or without fee is hereby granted, provided that the above
8572ff6f6SMatthew Dillon  * copyright notice and this permission notice appear in all copies.
9572ff6f6SMatthew Dillon  *
10572ff6f6SMatthew Dillon  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11572ff6f6SMatthew Dillon  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12572ff6f6SMatthew Dillon  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13572ff6f6SMatthew Dillon  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14572ff6f6SMatthew Dillon  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15572ff6f6SMatthew Dillon  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16572ff6f6SMatthew Dillon  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17572ff6f6SMatthew Dillon  *
18572ff6f6SMatthew Dillon  * $FreeBSD$
19572ff6f6SMatthew Dillon  */
20572ff6f6SMatthew Dillon 
21572ff6f6SMatthew Dillon #include "opt_ah.h"
22572ff6f6SMatthew Dillon 
23572ff6f6SMatthew Dillon #include "ah.h"
24572ff6f6SMatthew Dillon #include "ah_internal.h"
25572ff6f6SMatthew Dillon #include "ah_devid.h"
26572ff6f6SMatthew Dillon #ifdef	AH_DEBUG
27572ff6f6SMatthew Dillon #include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
28572ff6f6SMatthew Dillon #endif
29572ff6f6SMatthew Dillon 
30572ff6f6SMatthew Dillon #include "ar5416/ar5416.h"
31572ff6f6SMatthew Dillon #include "ar5416/ar5416reg.h"
32572ff6f6SMatthew Dillon #include "ar5416/ar5416phy.h"
33572ff6f6SMatthew Dillon #include "ar5416/ar5416desc.h" /* AR5416_CONTTXMODE */
34572ff6f6SMatthew Dillon #include "ar5416/ar5416_btcoex.h"
35572ff6f6SMatthew Dillon 
36572ff6f6SMatthew Dillon void
ar5416SetBTCoexInfo(struct ath_hal * ah,HAL_BT_COEX_INFO * btinfo)37572ff6f6SMatthew Dillon ar5416SetBTCoexInfo(struct ath_hal *ah, HAL_BT_COEX_INFO *btinfo)
38572ff6f6SMatthew Dillon {
39572ff6f6SMatthew Dillon 	struct ath_hal_5416 *ahp = AH5416(ah);
40572ff6f6SMatthew Dillon 
41572ff6f6SMatthew Dillon 	ahp->ah_btModule = btinfo->bt_module;
42572ff6f6SMatthew Dillon 	ahp->ah_btCoexConfigType = btinfo->bt_coex_config;
43572ff6f6SMatthew Dillon 	ahp->ah_btActiveGpioSelect = btinfo->bt_gpio_bt_active;
44572ff6f6SMatthew Dillon 	ahp->ah_btPriorityGpioSelect = btinfo->bt_gpio_bt_priority;
45572ff6f6SMatthew Dillon 	ahp->ah_wlanActiveGpioSelect = btinfo->bt_gpio_wlan_active;
46572ff6f6SMatthew Dillon 	ahp->ah_btActivePolarity = btinfo->bt_active_polarity;
47572ff6f6SMatthew Dillon 	ahp->ah_btCoexSingleAnt = btinfo->bt_single_ant;
48572ff6f6SMatthew Dillon 	ahp->ah_btWlanIsolation = btinfo->bt_isolation;
49572ff6f6SMatthew Dillon }
50572ff6f6SMatthew Dillon 
51572ff6f6SMatthew Dillon void
ar5416BTCoexConfig(struct ath_hal * ah,HAL_BT_COEX_CONFIG * btconf)52572ff6f6SMatthew Dillon ar5416BTCoexConfig(struct ath_hal *ah, HAL_BT_COEX_CONFIG *btconf)
53572ff6f6SMatthew Dillon {
54572ff6f6SMatthew Dillon 	struct ath_hal_5416 *ahp = AH5416(ah);
55572ff6f6SMatthew Dillon 	HAL_BOOL rxClearPolarity = btconf->bt_rxclear_polarity;
56572ff6f6SMatthew Dillon 
57572ff6f6SMatthew Dillon 	/*
58572ff6f6SMatthew Dillon 	 * For Kiwi and Osprey, the polarity of rx_clear is active high.
59572ff6f6SMatthew Dillon 	 * The bt_rxclear_polarity flag from ath(4) needs to be inverted.
60572ff6f6SMatthew Dillon 	 */
61572ff6f6SMatthew Dillon 	if (AR_SREV_KIWI(ah)) {
62572ff6f6SMatthew Dillon 		rxClearPolarity = !btconf->bt_rxclear_polarity;
63572ff6f6SMatthew Dillon 	}
64572ff6f6SMatthew Dillon 
65572ff6f6SMatthew Dillon 	ahp->ah_btCoexMode = (ahp->ah_btCoexMode & AR_BT_QCU_THRESH) |
66572ff6f6SMatthew Dillon 	    SM(btconf->bt_time_extend, AR_BT_TIME_EXTEND) |
67572ff6f6SMatthew Dillon 	    SM(btconf->bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
68572ff6f6SMatthew Dillon 	    SM(btconf->bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
69572ff6f6SMatthew Dillon 	    SM(btconf->bt_mode, AR_BT_MODE) |
70572ff6f6SMatthew Dillon 	    SM(btconf->bt_quiet_collision, AR_BT_QUIET) |
71572ff6f6SMatthew Dillon 	    SM(rxClearPolarity, AR_BT_RX_CLEAR_POLARITY) |
72572ff6f6SMatthew Dillon 	    SM(btconf->bt_priority_time, AR_BT_PRIORITY_TIME) |
73572ff6f6SMatthew Dillon 	    SM(btconf->bt_first_slot_time, AR_BT_FIRST_SLOT_TIME);
74572ff6f6SMatthew Dillon 
75572ff6f6SMatthew Dillon 	ahp->ah_btCoexMode2 |= SM(btconf->bt_hold_rxclear,
76572ff6f6SMatthew Dillon 	    AR_BT_HOLD_RX_CLEAR);
77572ff6f6SMatthew Dillon 
78572ff6f6SMatthew Dillon 	if (ahp->ah_btCoexSingleAnt == AH_FALSE) {
79572ff6f6SMatthew Dillon 		/* Enable ACK to go out even though BT has higher priority. */
80572ff6f6SMatthew Dillon 		ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT;
81572ff6f6SMatthew Dillon 	}
82572ff6f6SMatthew Dillon }
83572ff6f6SMatthew Dillon 
84572ff6f6SMatthew Dillon void
ar5416BTCoexSetQcuThresh(struct ath_hal * ah,int qnum)85572ff6f6SMatthew Dillon ar5416BTCoexSetQcuThresh(struct ath_hal *ah, int qnum)
86572ff6f6SMatthew Dillon {
87572ff6f6SMatthew Dillon 	struct ath_hal_5416 *ahp = AH5416(ah);
88572ff6f6SMatthew Dillon 
89572ff6f6SMatthew Dillon 	ahp->ah_btCoexMode |= SM(qnum, AR_BT_QCU_THRESH);
90572ff6f6SMatthew Dillon }
91572ff6f6SMatthew Dillon 
92572ff6f6SMatthew Dillon void
ar5416BTCoexSetWeights(struct ath_hal * ah,u_int32_t stompType)93572ff6f6SMatthew Dillon ar5416BTCoexSetWeights(struct ath_hal *ah, u_int32_t stompType)
94572ff6f6SMatthew Dillon {
95572ff6f6SMatthew Dillon 	struct ath_hal_5416 *ahp = AH5416(ah);
96572ff6f6SMatthew Dillon 
97572ff6f6SMatthew Dillon 	if (AR_SREV_KIWI_10_OR_LATER(ah)) {
98*b14ca477SMatthew Dillon 		/* TODO: TX RX separate is not enabled. */
99572ff6f6SMatthew Dillon 		switch (stompType) {
100572ff6f6SMatthew Dillon 		case HAL_BT_COEX_STOMP_ALL:
101572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
102572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight = AR5416_STOMP_ALL_WLAN_WGHT;
103572ff6f6SMatthew Dillon 			break;
104572ff6f6SMatthew Dillon 		case HAL_BT_COEX_STOMP_LOW:
105572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
106572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight = AR5416_STOMP_LOW_WLAN_WGHT;
107572ff6f6SMatthew Dillon 			break;
108572ff6f6SMatthew Dillon 		case HAL_BT_COEX_STOMP_ALL_FORCE:
109572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
110572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight =
111572ff6f6SMatthew Dillon 			    AR5416_STOMP_ALL_FORCE_WLAN_WGHT;
112572ff6f6SMatthew Dillon 			break;
113572ff6f6SMatthew Dillon 		case HAL_BT_COEX_STOMP_LOW_FORCE:
114572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
115572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight =
116572ff6f6SMatthew Dillon 			    AR5416_STOMP_LOW_FORCE_WLAN_WGHT;
117572ff6f6SMatthew Dillon 			break;
118572ff6f6SMatthew Dillon 		case HAL_BT_COEX_STOMP_NONE:
119572ff6f6SMatthew Dillon 		case HAL_BT_COEX_NO_STOMP:
120572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
121572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight = AR5416_STOMP_NONE_WLAN_WGHT;
122572ff6f6SMatthew Dillon 			break;
123572ff6f6SMatthew Dillon 		default:
124572ff6f6SMatthew Dillon 			/* There is a forceWeight from registry */
125572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = stompType & 0xffff;
126572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight = stompType >> 16;
127572ff6f6SMatthew Dillon 			break;
128572ff6f6SMatthew Dillon 		}
129572ff6f6SMatthew Dillon 	} else {
130572ff6f6SMatthew Dillon 		switch (stompType) {
131572ff6f6SMatthew Dillon 		case HAL_BT_COEX_STOMP_ALL:
132572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
133572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight = AR5416_STOMP_ALL_WLAN_WGHT;
134572ff6f6SMatthew Dillon 			break;
135572ff6f6SMatthew Dillon 		case HAL_BT_COEX_STOMP_LOW:
136572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
137572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight = AR5416_STOMP_LOW_WLAN_WGHT;
138572ff6f6SMatthew Dillon 			break;
139572ff6f6SMatthew Dillon 		case HAL_BT_COEX_STOMP_ALL_FORCE:
140572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
141572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight =
142572ff6f6SMatthew Dillon 			    AR5416_STOMP_ALL_FORCE_WLAN_WGHT;
143572ff6f6SMatthew Dillon 			break;
144572ff6f6SMatthew Dillon 		case HAL_BT_COEX_STOMP_LOW_FORCE:
145572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
146572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight =
147572ff6f6SMatthew Dillon 			    AR5416_STOMP_LOW_FORCE_WLAN_WGHT;
148572ff6f6SMatthew Dillon 			break;
149572ff6f6SMatthew Dillon 		case HAL_BT_COEX_STOMP_NONE:
150572ff6f6SMatthew Dillon 		case HAL_BT_COEX_NO_STOMP:
151572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
152572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight = AR5416_STOMP_NONE_WLAN_WGHT;
153572ff6f6SMatthew Dillon 			break;
154572ff6f6SMatthew Dillon 		default:
155572ff6f6SMatthew Dillon 			/* There is a forceWeight from registry */
156572ff6f6SMatthew Dillon 			ahp->ah_btCoexBTWeight = stompType & 0xffff;
157572ff6f6SMatthew Dillon 			ahp->ah_btCoexWLANWeight = stompType >> 16;
158572ff6f6SMatthew Dillon 			break;
159572ff6f6SMatthew Dillon 		}
160572ff6f6SMatthew Dillon 	}
161572ff6f6SMatthew Dillon }
162572ff6f6SMatthew Dillon 
163572ff6f6SMatthew Dillon void
ar5416BTCoexSetupBmissThresh(struct ath_hal * ah,u_int32_t thresh)164572ff6f6SMatthew Dillon ar5416BTCoexSetupBmissThresh(struct ath_hal *ah, u_int32_t thresh)
165572ff6f6SMatthew Dillon {
166572ff6f6SMatthew Dillon 	struct ath_hal_5416 *ahp = AH5416(ah);
167572ff6f6SMatthew Dillon 
168572ff6f6SMatthew Dillon 	ahp->ah_btCoexMode2 |= SM(thresh, AR_BT_BCN_MISS_THRESH);
169572ff6f6SMatthew Dillon }
170572ff6f6SMatthew Dillon 
171572ff6f6SMatthew Dillon /*
172572ff6f6SMatthew Dillon  * There is no antenna diversity for Owl, Kiwi, etc.
173572ff6f6SMatthew Dillon  *
174572ff6f6SMatthew Dillon  * Kite will override this particular method.
175572ff6f6SMatthew Dillon  */
176572ff6f6SMatthew Dillon void
ar5416BTCoexAntennaDiversity(struct ath_hal * ah)177572ff6f6SMatthew Dillon ar5416BTCoexAntennaDiversity(struct ath_hal *ah)
178572ff6f6SMatthew Dillon {
179572ff6f6SMatthew Dillon }
180572ff6f6SMatthew Dillon 
181572ff6f6SMatthew Dillon void
ar5416BTCoexSetParameter(struct ath_hal * ah,u_int32_t type,u_int32_t value)182572ff6f6SMatthew Dillon ar5416BTCoexSetParameter(struct ath_hal *ah, u_int32_t type, u_int32_t value)
183572ff6f6SMatthew Dillon {
184572ff6f6SMatthew Dillon 	struct ath_hal_5416 *ahp = AH5416(ah);
185572ff6f6SMatthew Dillon 
186572ff6f6SMatthew Dillon 	switch (type) {
187572ff6f6SMatthew Dillon 	case HAL_BT_COEX_SET_ACK_PWR:
188572ff6f6SMatthew Dillon 		if (value) {
189572ff6f6SMatthew Dillon 			ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_LOW_ACK_PWR;
190572ff6f6SMatthew Dillon 			OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_LOW_ACK_POWER);
191572ff6f6SMatthew Dillon 		} else {
192572ff6f6SMatthew Dillon 			ahp->ah_btCoexFlag &= ~HAL_BT_COEX_FLAG_LOW_ACK_PWR;
193572ff6f6SMatthew Dillon 			OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_HIGH_ACK_POWER);
194572ff6f6SMatthew Dillon 		}
195572ff6f6SMatthew Dillon 		break;
196572ff6f6SMatthew Dillon 	case HAL_BT_COEX_ANTENNA_DIVERSITY:
197572ff6f6SMatthew Dillon 		/* This is overridden for Kite */
198572ff6f6SMatthew Dillon 		break;
199572ff6f6SMatthew Dillon #if 0
200572ff6f6SMatthew Dillon         case HAL_BT_COEX_LOWER_TX_PWR:
201572ff6f6SMatthew Dillon             if (value) {
202572ff6f6SMatthew Dillon                 if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) == 0) {
203572ff6f6SMatthew Dillon                     ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_LOWER_TX_PWR;
204572ff6f6SMatthew Dillon 		    AH_PRIVATE(ah)->ah_config.ath_hal_desc_tpc = 1;
205572ff6f6SMatthew Dillon                     ar5416SetTxPowerLimit(ah, AH_PRIVATE(ah)->ah_power_limit, AH_PRIVATE(ah)->ah_extra_txpow, 0);
206572ff6f6SMatthew Dillon                 }
207572ff6f6SMatthew Dillon             }
208572ff6f6SMatthew Dillon             else {
209572ff6f6SMatthew Dillon                 if (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) {
210572ff6f6SMatthew Dillon                     ahp->ah_btCoexFlag &= ~HAL_BT_COEX_FLAG_LOWER_TX_PWR;
211572ff6f6SMatthew Dillon 		    AH_PRIVATE(ah)->ah_config.ath_hal_desc_tpc = 0;
212572ff6f6SMatthew Dillon                     ar5416SetTxPowerLimit(ah, AH_PRIVATE(ah)->ah_power_limit, AH_PRIVATE(ah)->ah_extra_txpow, 0);
213572ff6f6SMatthew Dillon                 }
214572ff6f6SMatthew Dillon             }
215572ff6f6SMatthew Dillon             break;
216572ff6f6SMatthew Dillon #endif
217572ff6f6SMatthew Dillon 	default:
218572ff6f6SMatthew Dillon 			break;
219572ff6f6SMatthew Dillon 	}
220572ff6f6SMatthew Dillon }
221572ff6f6SMatthew Dillon 
222572ff6f6SMatthew Dillon void
ar5416BTCoexDisable(struct ath_hal * ah)223572ff6f6SMatthew Dillon ar5416BTCoexDisable(struct ath_hal *ah)
224572ff6f6SMatthew Dillon {
225572ff6f6SMatthew Dillon 	struct ath_hal_5416 *ahp = AH5416(ah);
226572ff6f6SMatthew Dillon 
227572ff6f6SMatthew Dillon 	/* Always drive rx_clear_external output as 0 */
228572ff6f6SMatthew Dillon 	ar5416GpioSet(ah, ahp->ah_wlanActiveGpioSelect, 0);
229572ff6f6SMatthew Dillon 	ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect,
230572ff6f6SMatthew Dillon 	    HAL_GPIO_OUTPUT_MUX_AS_OUTPUT);
231572ff6f6SMatthew Dillon 
232572ff6f6SMatthew Dillon 	if (AR_SREV_9271(ah)) {
233572ff6f6SMatthew Dillon 		/*
234572ff6f6SMatthew Dillon 		 * Set wlanActiveGpio to input when disabling BT-COEX to
235572ff6f6SMatthew Dillon 		 * reduce power consumption
236572ff6f6SMatthew Dillon 		 */
237572ff6f6SMatthew Dillon 		ar5416GpioCfgInput(ah, ahp->ah_wlanActiveGpioSelect);
238572ff6f6SMatthew Dillon 	}
239572ff6f6SMatthew Dillon 
240572ff6f6SMatthew Dillon 	if (ahp->ah_btCoexSingleAnt == AH_TRUE) {
241572ff6f6SMatthew Dillon 		OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE,
242572ff6f6SMatthew Dillon 		    1);
243572ff6f6SMatthew Dillon 		OS_REG_RMW_FIELD(ah, AR_MISC_MODE, AR_PCU_BT_ANT_PREVENT_RX,
244572ff6f6SMatthew Dillon 		    0);
245572ff6f6SMatthew Dillon 	}
246572ff6f6SMatthew Dillon 
247572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
248572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
249572ff6f6SMatthew Dillon 	if (AR_SREV_KIWI_10_OR_LATER(ah))
250572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT2, 0);
251572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
252572ff6f6SMatthew Dillon 
253572ff6f6SMatthew Dillon 	ahp->ah_btCoexEnabled = AH_FALSE;
254572ff6f6SMatthew Dillon }
255572ff6f6SMatthew Dillon 
256572ff6f6SMatthew Dillon int
ar5416BTCoexEnable(struct ath_hal * ah)257572ff6f6SMatthew Dillon ar5416BTCoexEnable(struct ath_hal *ah)
258572ff6f6SMatthew Dillon {
259572ff6f6SMatthew Dillon 	struct ath_hal_5416 *ahp = AH5416(ah);
260572ff6f6SMatthew Dillon 
261572ff6f6SMatthew Dillon 	/* Program coex mode and weight registers to actually enable coex */
262572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_BT_COEX_MODE, ahp->ah_btCoexMode);
263572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT,
264572ff6f6SMatthew Dillon 	    SM(ahp->ah_btCoexWLANWeight & 0xFFFF, AR_BT_WL_WGHT) |
265572ff6f6SMatthew Dillon 	    SM(ahp->ah_btCoexBTWeight & 0xFFFF, AR_BT_BT_WGHT));
266572ff6f6SMatthew Dillon 	if (AR_SREV_KIWI_10_OR_LATER(ah)) {
267572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT2,
268572ff6f6SMatthew Dillon 	    SM(ahp->ah_btCoexWLANWeight >> 16, AR_BT_WL_WGHT));
269572ff6f6SMatthew Dillon 	}
270572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
271572ff6f6SMatthew Dillon 
272572ff6f6SMatthew Dillon 	/* Added Select GPIO5~8 instaed SPI */
273572ff6f6SMatthew Dillon 	if (AR_SREV_9271(ah)) {
274572ff6f6SMatthew Dillon 		uint32_t val;
275572ff6f6SMatthew Dillon 
276572ff6f6SMatthew Dillon 		val = OS_REG_READ(ah, AR9271_CLOCK_CONTROL);
277572ff6f6SMatthew Dillon 		val &= 0xFFFFFEFF;
278572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR9271_CLOCK_CONTROL, val);
279572ff6f6SMatthew Dillon 	}
280572ff6f6SMatthew Dillon 
281572ff6f6SMatthew Dillon 	if (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOW_ACK_PWR)
282572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_LOW_ACK_POWER);
283572ff6f6SMatthew Dillon 	else
284572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_HIGH_ACK_POWER);
285572ff6f6SMatthew Dillon 
286572ff6f6SMatthew Dillon 	if (ahp->ah_btCoexSingleAnt == AH_TRUE) {
287572ff6f6SMatthew Dillon 		OS_REG_RMW_FIELD(ah, AR_QUIET1,
288572ff6f6SMatthew Dillon 		    AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
289572ff6f6SMatthew Dillon 		/* XXX should update miscMode? */
290572ff6f6SMatthew Dillon 		OS_REG_RMW_FIELD(ah, AR_MISC_MODE,
291572ff6f6SMatthew Dillon 		    AR_PCU_BT_ANT_PREVENT_RX, 1);
292572ff6f6SMatthew Dillon 	} else {
293572ff6f6SMatthew Dillon 		OS_REG_RMW_FIELD(ah, AR_QUIET1,
294572ff6f6SMatthew Dillon 		    AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
295572ff6f6SMatthew Dillon 		/* XXX should update miscMode? */
296572ff6f6SMatthew Dillon 		OS_REG_RMW_FIELD(ah, AR_MISC_MODE,
297572ff6f6SMatthew Dillon 		    AR_PCU_BT_ANT_PREVENT_RX, 0);
298572ff6f6SMatthew Dillon 	}
299572ff6f6SMatthew Dillon 
300572ff6f6SMatthew Dillon 	if (ahp->ah_btCoexConfigType == HAL_BT_COEX_CFG_3WIRE) {
301572ff6f6SMatthew Dillon 		/* For 3-wire, configure the desired GPIO port for rx_clear */
302572ff6f6SMatthew Dillon 		ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect,
303572ff6f6SMatthew Dillon 		    HAL_GPIO_OUTPUT_MUX_AS_WLAN_ACTIVE);
304572ff6f6SMatthew Dillon 	} else {
305572ff6f6SMatthew Dillon 		/*
306572ff6f6SMatthew Dillon 		 * For 2-wire, configure the desired GPIO port
307572ff6f6SMatthew Dillon 		 * for TX_FRAME output
308572ff6f6SMatthew Dillon 		 */
309572ff6f6SMatthew Dillon 		ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect,
310572ff6f6SMatthew Dillon 		    HAL_GPIO_OUTPUT_MUX_AS_TX_FRAME);
311572ff6f6SMatthew Dillon 	}
312572ff6f6SMatthew Dillon 
313572ff6f6SMatthew Dillon 	/*
314572ff6f6SMatthew Dillon 	 * Enable a weak pull down on BT_ACTIVE.
315572ff6f6SMatthew Dillon 	 * When BT device is disabled, BT_ACTIVE might be floating.
316572ff6f6SMatthew Dillon 	 */
317572ff6f6SMatthew Dillon 	OS_REG_RMW(ah, AR_GPIO_PDPU,
318572ff6f6SMatthew Dillon 	    (0x2 << (ahp->ah_btActiveGpioSelect * 2)),
319572ff6f6SMatthew Dillon 	    (0x3 << (ahp->ah_btActiveGpioSelect * 2)));
320572ff6f6SMatthew Dillon 
321572ff6f6SMatthew Dillon 	ahp->ah_btCoexEnabled = AH_TRUE;
322572ff6f6SMatthew Dillon 
323572ff6f6SMatthew Dillon 	return (0);
324572ff6f6SMatthew Dillon }
325572ff6f6SMatthew Dillon 
326572ff6f6SMatthew Dillon void
ar5416InitBTCoex(struct ath_hal * ah)327572ff6f6SMatthew Dillon ar5416InitBTCoex(struct ath_hal *ah)
328572ff6f6SMatthew Dillon {
329572ff6f6SMatthew Dillon 	struct ath_hal_5416 *ahp = AH5416(ah);
330572ff6f6SMatthew Dillon 
331572ff6f6SMatthew Dillon 	HALDEBUG(ah, HAL_DEBUG_BT_COEX,
332572ff6f6SMatthew Dillon 	    "%s: called; configType=%d\n",
333572ff6f6SMatthew Dillon 	    __func__,
334572ff6f6SMatthew Dillon 	    ahp->ah_btCoexConfigType);
335572ff6f6SMatthew Dillon 
336572ff6f6SMatthew Dillon 	if (ahp->ah_btCoexConfigType == HAL_BT_COEX_CFG_3WIRE) {
337572ff6f6SMatthew Dillon 		OS_REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
338572ff6f6SMatthew Dillon 		    (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
339572ff6f6SMatthew Dillon 		    AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
340572ff6f6SMatthew Dillon 
341572ff6f6SMatthew Dillon 		/*
342572ff6f6SMatthew Dillon 		 * Set input mux for bt_prority_async and
343572ff6f6SMatthew Dillon 		 * bt_active_async to GPIO pins
344572ff6f6SMatthew Dillon 		 */
345572ff6f6SMatthew Dillon 		OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
346572ff6f6SMatthew Dillon 		    AR_GPIO_INPUT_MUX1_BT_ACTIVE,
347572ff6f6SMatthew Dillon 		    ahp->ah_btActiveGpioSelect);
348572ff6f6SMatthew Dillon 		OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
349572ff6f6SMatthew Dillon 		    AR_GPIO_INPUT_MUX1_BT_PRIORITY,
350572ff6f6SMatthew Dillon 		    ahp->ah_btPriorityGpioSelect);
351572ff6f6SMatthew Dillon 
352572ff6f6SMatthew Dillon 		/*
353572ff6f6SMatthew Dillon 		 * Configure the desired GPIO ports for input
354572ff6f6SMatthew Dillon 		 */
355572ff6f6SMatthew Dillon 		ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect);
356572ff6f6SMatthew Dillon 		ar5416GpioCfgInput(ah, ahp->ah_btPriorityGpioSelect);
357572ff6f6SMatthew Dillon 
358572ff6f6SMatthew Dillon 		/*
359572ff6f6SMatthew Dillon 		 * Configure the antenna diversity setup.
360572ff6f6SMatthew Dillon 		 * It's a no-op for AR9287; AR9285 overrides this
361572ff6f6SMatthew Dillon 		 * as required.
362572ff6f6SMatthew Dillon 		 */
363572ff6f6SMatthew Dillon 		AH5416(ah)->ah_btCoexSetDiversity(ah);
364572ff6f6SMatthew Dillon 
365572ff6f6SMatthew Dillon 		if (ahp->ah_btCoexEnabled)
366572ff6f6SMatthew Dillon 			ar5416BTCoexEnable(ah);
367572ff6f6SMatthew Dillon 		else
368572ff6f6SMatthew Dillon 			ar5416BTCoexDisable(ah);
369572ff6f6SMatthew Dillon 	} else if (ahp->ah_btCoexConfigType != HAL_BT_COEX_CFG_NONE) {
370572ff6f6SMatthew Dillon 		/* 2-wire */
371572ff6f6SMatthew Dillon 		if (ahp->ah_btCoexEnabled) {
372572ff6f6SMatthew Dillon 			/* Connect bt_active_async to baseband */
373572ff6f6SMatthew Dillon 			OS_REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
374572ff6f6SMatthew Dillon 			    (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
375572ff6f6SMatthew Dillon 			     AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
376572ff6f6SMatthew Dillon 			OS_REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
377572ff6f6SMatthew Dillon 			    AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
378572ff6f6SMatthew Dillon 
379572ff6f6SMatthew Dillon 			/*
380572ff6f6SMatthew Dillon 			 * Set input mux for bt_prority_async and
381572ff6f6SMatthew Dillon 			 * bt_active_async to GPIO pins
382572ff6f6SMatthew Dillon 			 */
383572ff6f6SMatthew Dillon 			OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
384572ff6f6SMatthew Dillon 			    AR_GPIO_INPUT_MUX1_BT_ACTIVE,
385572ff6f6SMatthew Dillon                             ahp->ah_btActiveGpioSelect);
386572ff6f6SMatthew Dillon 
387572ff6f6SMatthew Dillon 			/* Configure the desired GPIO ports for input */
388572ff6f6SMatthew Dillon 			ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect);
389572ff6f6SMatthew Dillon 
390572ff6f6SMatthew Dillon 			/* Enable coexistence on initialization */
391572ff6f6SMatthew Dillon 			ar5416BTCoexEnable(ah);
392572ff6f6SMatthew Dillon 		}
393572ff6f6SMatthew Dillon 	}
394572ff6f6SMatthew Dillon }
395