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
36void
37ar5416SetBTCoexInfo(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
51void
52ar5416BTCoexConfig(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
84void
85ar5416BTCoexSetQcuThresh(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
92void
93ar5416BTCoexSetWeights(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 seperate 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
163void
164ar5416BTCoexSetupBmissThresh(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 */
176void
177ar5416BTCoexAntennaDiversity(struct ath_hal *ah)
178{
179}
180
181void
182ar5416BTCoexSetParameter(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
222void
223ar5416BTCoexDisable(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
256int
257ar5416BTCoexEnable(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
326void
327ar5416InitBTCoex(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