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
ar5416SetBTCoexInfo(struct ath_hal * ah,HAL_BT_COEX_INFO * btinfo)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
ar5416BTCoexConfig(struct ath_hal * ah,HAL_BT_COEX_CONFIG * btconf)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
ar5416BTCoexSetQcuThresh(struct ath_hal * ah,int qnum)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
ar5416BTCoexSetWeights(struct ath_hal * ah,u_int32_t stompType)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_ALL:
101 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
102 ahp->ah_btCoexWLANWeight = AR5416_STOMP_ALL_WLAN_WGHT;
103 break;
104 case HAL_BT_COEX_STOMP_LOW:
105 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
106 ahp->ah_btCoexWLANWeight = AR5416_STOMP_LOW_WLAN_WGHT;
107 break;
108 case HAL_BT_COEX_STOMP_ALL_FORCE:
109 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
110 ahp->ah_btCoexWLANWeight =
111 AR5416_STOMP_ALL_FORCE_WLAN_WGHT;
112 break;
113 case HAL_BT_COEX_STOMP_LOW_FORCE:
114 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
115 ahp->ah_btCoexWLANWeight =
116 AR5416_STOMP_LOW_FORCE_WLAN_WGHT;
117 break;
118 case HAL_BT_COEX_STOMP_NONE:
119 case HAL_BT_COEX_NO_STOMP:
120 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
121 ahp->ah_btCoexWLANWeight = AR5416_STOMP_NONE_WLAN_WGHT;
122 break;
123 default:
124 /* There is a forceWeight from registry */
125 ahp->ah_btCoexBTWeight = stompType & 0xffff;
126 ahp->ah_btCoexWLANWeight = stompType >> 16;
127 break;
128 }
129 } else {
130 switch (stompType) {
131 case HAL_BT_COEX_STOMP_ALL:
132 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
133 ahp->ah_btCoexWLANWeight = AR5416_STOMP_ALL_WLAN_WGHT;
134 break;
135 case HAL_BT_COEX_STOMP_LOW:
136 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
137 ahp->ah_btCoexWLANWeight = AR5416_STOMP_LOW_WLAN_WGHT;
138 break;
139 case HAL_BT_COEX_STOMP_ALL_FORCE:
140 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
141 ahp->ah_btCoexWLANWeight =
142 AR5416_STOMP_ALL_FORCE_WLAN_WGHT;
143 break;
144 case HAL_BT_COEX_STOMP_LOW_FORCE:
145 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
146 ahp->ah_btCoexWLANWeight =
147 AR5416_STOMP_LOW_FORCE_WLAN_WGHT;
148 break;
149 case HAL_BT_COEX_STOMP_NONE:
150 case HAL_BT_COEX_NO_STOMP:
151 ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
152 ahp->ah_btCoexWLANWeight = AR5416_STOMP_NONE_WLAN_WGHT;
153 break;
154 default:
155 /* There is a forceWeight from registry */
156 ahp->ah_btCoexBTWeight = stompType & 0xffff;
157 ahp->ah_btCoexWLANWeight = stompType >> 16;
158 break;
159 }
160 }
161 }
162
163 void
ar5416BTCoexSetupBmissThresh(struct ath_hal * ah,u_int32_t thresh)164 ar5416BTCoexSetupBmissThresh(struct ath_hal *ah, u_int32_t thresh)
165 {
166 struct ath_hal_5416 *ahp = AH5416(ah);
167
168 ahp->ah_btCoexMode2 |= SM(thresh, AR_BT_BCN_MISS_THRESH);
169 }
170
171 /*
172 * There is no antenna diversity for Owl, Kiwi, etc.
173 *
174 * Kite will override this particular method.
175 */
176 void
ar5416BTCoexAntennaDiversity(struct ath_hal * ah)177 ar5416BTCoexAntennaDiversity(struct ath_hal *ah)
178 {
179 }
180
181 void
ar5416BTCoexSetParameter(struct ath_hal * ah,u_int32_t type,u_int32_t value)182 ar5416BTCoexSetParameter(struct ath_hal *ah, u_int32_t type, u_int32_t value)
183 {
184 struct ath_hal_5416 *ahp = AH5416(ah);
185
186 switch (type) {
187 case HAL_BT_COEX_SET_ACK_PWR:
188 if (value) {
189 ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_LOW_ACK_PWR;
190 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_LOW_ACK_POWER);
191 } else {
192 ahp->ah_btCoexFlag &= ~HAL_BT_COEX_FLAG_LOW_ACK_PWR;
193 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_HIGH_ACK_POWER);
194 }
195 break;
196 case HAL_BT_COEX_ANTENNA_DIVERSITY:
197 /* This is overridden for Kite */
198 break;
199 #if 0
200 case HAL_BT_COEX_LOWER_TX_PWR:
201 if (value) {
202 if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) == 0) {
203 ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_LOWER_TX_PWR;
204 AH_PRIVATE(ah)->ah_config.ath_hal_desc_tpc = 1;
205 ar5416SetTxPowerLimit(ah, AH_PRIVATE(ah)->ah_power_limit, AH_PRIVATE(ah)->ah_extra_txpow, 0);
206 }
207 }
208 else {
209 if (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) {
210 ahp->ah_btCoexFlag &= ~HAL_BT_COEX_FLAG_LOWER_TX_PWR;
211 AH_PRIVATE(ah)->ah_config.ath_hal_desc_tpc = 0;
212 ar5416SetTxPowerLimit(ah, AH_PRIVATE(ah)->ah_power_limit, AH_PRIVATE(ah)->ah_extra_txpow, 0);
213 }
214 }
215 break;
216 #endif
217 default:
218 break;
219 }
220 }
221
222 void
ar5416BTCoexDisable(struct ath_hal * ah)223 ar5416BTCoexDisable(struct ath_hal *ah)
224 {
225 struct ath_hal_5416 *ahp = AH5416(ah);
226
227 /* Always drive rx_clear_external output as 0 */
228 ar5416GpioSet(ah, ahp->ah_wlanActiveGpioSelect, 0);
229 ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect,
230 HAL_GPIO_OUTPUT_MUX_AS_OUTPUT);
231
232 if (AR_SREV_9271(ah)) {
233 /*
234 * Set wlanActiveGpio to input when disabling BT-COEX to
235 * reduce power consumption
236 */
237 ar5416GpioCfgInput(ah, ahp->ah_wlanActiveGpioSelect);
238 }
239
240 if (ahp->ah_btCoexSingleAnt == AH_TRUE) {
241 OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE,
242 1);
243 OS_REG_RMW_FIELD(ah, AR_MISC_MODE, AR_PCU_BT_ANT_PREVENT_RX,
244 0);
245 }
246
247 OS_REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
248 OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
249 if (AR_SREV_KIWI_10_OR_LATER(ah))
250 OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT2, 0);
251 OS_REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
252
253 ahp->ah_btCoexEnabled = AH_FALSE;
254 }
255
256 int
ar5416BTCoexEnable(struct ath_hal * ah)257 ar5416BTCoexEnable(struct ath_hal *ah)
258 {
259 struct ath_hal_5416 *ahp = AH5416(ah);
260
261 /* Program coex mode and weight registers to actually enable coex */
262 OS_REG_WRITE(ah, AR_BT_COEX_MODE, ahp->ah_btCoexMode);
263 OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT,
264 SM(ahp->ah_btCoexWLANWeight & 0xFFFF, AR_BT_WL_WGHT) |
265 SM(ahp->ah_btCoexBTWeight & 0xFFFF, AR_BT_BT_WGHT));
266 if (AR_SREV_KIWI_10_OR_LATER(ah)) {
267 OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT2,
268 SM(ahp->ah_btCoexWLANWeight >> 16, AR_BT_WL_WGHT));
269 }
270 OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
271
272 /* Added Select GPIO5~8 instaed SPI */
273 if (AR_SREV_9271(ah)) {
274 uint32_t val;
275
276 val = OS_REG_READ(ah, AR9271_CLOCK_CONTROL);
277 val &= 0xFFFFFEFF;
278 OS_REG_WRITE(ah, AR9271_CLOCK_CONTROL, val);
279 }
280
281 if (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOW_ACK_PWR)
282 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_LOW_ACK_POWER);
283 else
284 OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_HIGH_ACK_POWER);
285
286 if (ahp->ah_btCoexSingleAnt == AH_TRUE) {
287 OS_REG_RMW_FIELD(ah, AR_QUIET1,
288 AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
289 /* XXX should update miscMode? */
290 OS_REG_RMW_FIELD(ah, AR_MISC_MODE,
291 AR_PCU_BT_ANT_PREVENT_RX, 1);
292 } else {
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, 0);
298 }
299
300 if (ahp->ah_btCoexConfigType == HAL_BT_COEX_CFG_3WIRE) {
301 /* For 3-wire, configure the desired GPIO port for rx_clear */
302 ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect,
303 HAL_GPIO_OUTPUT_MUX_AS_WLAN_ACTIVE);
304 } else {
305 /*
306 * For 2-wire, configure the desired GPIO port
307 * for TX_FRAME output
308 */
309 ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect,
310 HAL_GPIO_OUTPUT_MUX_AS_TX_FRAME);
311 }
312
313 /*
314 * Enable a weak pull down on BT_ACTIVE.
315 * When BT device is disabled, BT_ACTIVE might be floating.
316 */
317 OS_REG_RMW(ah, AR_GPIO_PDPU,
318 (0x2 << (ahp->ah_btActiveGpioSelect * 2)),
319 (0x3 << (ahp->ah_btActiveGpioSelect * 2)));
320
321 ahp->ah_btCoexEnabled = AH_TRUE;
322
323 return (0);
324 }
325
326 void
ar5416InitBTCoex(struct ath_hal * ah)327 ar5416InitBTCoex(struct ath_hal *ah)
328 {
329 struct ath_hal_5416 *ahp = AH5416(ah);
330
331 HALDEBUG(ah, HAL_DEBUG_BT_COEX,
332 "%s: called; configType=%d\n",
333 __func__,
334 ahp->ah_btCoexConfigType);
335
336 if (ahp->ah_btCoexConfigType == HAL_BT_COEX_CFG_3WIRE) {
337 OS_REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
338 (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
339 AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
340
341 /*
342 * Set input mux for bt_prority_async and
343 * bt_active_async to GPIO pins
344 */
345 OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
346 AR_GPIO_INPUT_MUX1_BT_ACTIVE,
347 ahp->ah_btActiveGpioSelect);
348 OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
349 AR_GPIO_INPUT_MUX1_BT_PRIORITY,
350 ahp->ah_btPriorityGpioSelect);
351
352 /*
353 * Configure the desired GPIO ports for input
354 */
355 ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect);
356 ar5416GpioCfgInput(ah, ahp->ah_btPriorityGpioSelect);
357
358 /*
359 * Configure the antenna diversity setup.
360 * It's a no-op for AR9287; AR9285 overrides this
361 * as required.
362 */
363 AH5416(ah)->ah_btCoexSetDiversity(ah);
364
365 if (ahp->ah_btCoexEnabled)
366 ar5416BTCoexEnable(ah);
367 else
368 ar5416BTCoexDisable(ah);
369 } else if (ahp->ah_btCoexConfigType != HAL_BT_COEX_CFG_NONE) {
370 /* 2-wire */
371 if (ahp->ah_btCoexEnabled) {
372 /* Connect bt_active_async to baseband */
373 OS_REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
374 (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
375 AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
376 OS_REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
377 AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
378
379 /*
380 * Set input mux for bt_prority_async and
381 * bt_active_async to GPIO pins
382 */
383 OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
384 AR_GPIO_INPUT_MUX1_BT_ACTIVE,
385 ahp->ah_btActiveGpioSelect);
386
387 /* Configure the desired GPIO ports for input */
388 ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect);
389
390 /* Enable coexistence on initialization */
391 ar5416BTCoexEnable(ah);
392 }
393 }
394 }
395