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