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