xref: /dragonfly/sys/dev/netif/ath/ath_hal/ar5416/ar5416_btcoex.c (revision b14ca477c2f404b36ad553a9e4f1b8b18836304e)
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