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: releng/12.0/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c 326695 2017-12-08 15:57:29Z pfg $
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
38void
39ar5416SetBTCoexInfo(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
53void
54ar5416BTCoexConfig(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
86void
87ar5416BTCoexSetQcuThresh(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
94void
95ar5416BTCoexSetWeights(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
169void
170ar5416BTCoexSetupBmissThresh(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 */
182void
183ar5416BTCoexAntennaDiversity(struct ath_hal *ah)
184{
185}
186
187void
188ar5416BTCoexSetParameter(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
228void
229ar5416BTCoexDisable(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
262int
263ar5416BTCoexEnable(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
332void
333ar5416InitBTCoex(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