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