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
35 #include "ar9002/ar9285phy.h"
36 #include "ar9002/ar9285.h"
37
38 /*
39 * This is specific to Kite.
40 *
41 * Kiwi and others don't have antenna diversity like this.
42 */
43 void
ar9285BTCoexAntennaDiversity(struct ath_hal * ah)44 ar9285BTCoexAntennaDiversity(struct ath_hal *ah)
45 {
46 struct ath_hal_5416 *ahp = AH5416(ah);
47 u_int32_t regVal;
48 u_int8_t ant_div_control1, ant_div_control2;
49
50 HALDEBUG(ah, HAL_DEBUG_BT_COEX,
51 "%s: btCoexFlag: ALLOW=%d, ENABLE=%d\n",
52 __func__,
53 !! (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ALLOW),
54 !! (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ENABLE));
55
56 /* NOTE: disparate enum comparison must be cast */
57 if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ALLOW) ||
58 ((int)AH5212(ah)->ah_diversity != HAL_ANT_VARIABLE)) {
59 if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ENABLE) &&
60 (AH5212(ah)->ah_antControl == HAL_ANT_VARIABLE)) {
61 /* Enable antenna diversity */
62 ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_ENABLE;
63 ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_ENABLE;
64
65 /* Don't disable BT ant to allow BB to control SWCOM */
66 ahp->ah_btCoexMode2 &= (~(AR_BT_DISABLE_BT_ANT));
67 OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
68
69 /* Program the correct SWCOM table */
70 OS_REG_WRITE(ah, AR_PHY_SWITCH_COM,
71 HAL_BT_COEX_ANT_DIV_SWITCH_COM);
72 OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
73 } else if (AH5212(ah)->ah_antControl == HAL_ANT_FIXED_B) {
74 /* Disable antenna diversity. Use antenna B(LNA2) only. */
75 ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_FIXED_B;
76 ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_FIXED_B;
77
78 /* Disable BT ant to allow concurrent BT and WLAN receive */
79 ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT;
80 OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
81
82 /*
83 * Program SWCOM table to make sure RF switch always parks
84 * at WLAN side
85 */
86 OS_REG_WRITE(ah, AR_PHY_SWITCH_COM,
87 HAL_BT_COEX_ANT_DIV_SWITCH_COM);
88 OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0x60000000, 0xf0000000);
89 } else {
90 /* Disable antenna diversity. Use antenna A(LNA1) only */
91 ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_FIXED_A;
92 ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_FIXED_A;
93
94 /* Disable BT ant to allow concurrent BT and WLAN receive */
95 ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT;
96 OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
97
98 /*
99 * Program SWCOM table to make sure RF switch always
100 * parks at BT side
101 */
102 OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, 0);
103 OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
104 }
105
106 regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
107 regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL));
108 /*
109 * Clear ant_fast_div_bias [14:9] since for Janus the main LNA is
110 * always LNA1.
111 */
112 regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS));
113
114 regVal |= SM(ant_div_control1, AR_PHY_9285_ANT_DIV_CTL);
115 regVal |= SM(ant_div_control2, AR_PHY_9285_ANT_DIV_ALT_LNACONF);
116 regVal |= SM((ant_div_control2 >> 2), AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
117 regVal |= SM((ant_div_control1 >> 1), AR_PHY_9285_ANT_DIV_ALT_GAINTB);
118 regVal |= SM((ant_div_control1 >> 2), AR_PHY_9285_ANT_DIV_MAIN_GAINTB);
119 OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal);
120
121 regVal = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
122 regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
123 regVal |= SM((ant_div_control1 >> 3),
124 AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
125 OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal);
126 }
127 }
128
129 void
ar9285BTCoexSetParameter(struct ath_hal * ah,u_int32_t type,u_int32_t value)130 ar9285BTCoexSetParameter(struct ath_hal *ah, u_int32_t type, u_int32_t value)
131 {
132 struct ath_hal_5416 *ahp = AH5416(ah);
133
134 switch (type) {
135 case HAL_BT_COEX_ANTENNA_DIVERSITY:
136 if (AR_SREV_KITE(ah)) {
137 ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_ANT_DIV_ALLOW;
138 if (value)
139 ahp->ah_btCoexFlag |=
140 HAL_BT_COEX_FLAG_ANT_DIV_ENABLE;
141 else
142 ahp->ah_btCoexFlag &=
143 ~HAL_BT_COEX_FLAG_ANT_DIV_ENABLE;
144 ar9285BTCoexAntennaDiversity(ah);
145 }
146 break;
147 default:
148 ar5416BTCoexSetParameter(ah, type, value);
149 break;
150 }
151 }
152
153
154