xref: /freebsd/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
16e778a7eSPedro F. Giffuni /*-
26e778a7eSPedro F. Giffuni  * SPDX-License-Identifier: ISC
36e778a7eSPedro F. Giffuni  *
459efa8b5SSam Leffler  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
514779705SSam Leffler  * Copyright (c) 2002-2008 Atheros Communications, Inc.
614779705SSam Leffler  *
714779705SSam Leffler  * Permission to use, copy, modify, and/or distribute this software for any
814779705SSam Leffler  * purpose with or without fee is hereby granted, provided that the above
914779705SSam Leffler  * copyright notice and this permission notice appear in all copies.
1014779705SSam Leffler  *
1114779705SSam Leffler  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1214779705SSam Leffler  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1314779705SSam Leffler  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1414779705SSam Leffler  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1514779705SSam Leffler  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1614779705SSam Leffler  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1714779705SSam Leffler  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1814779705SSam Leffler  */
1914779705SSam Leffler #include "opt_ah.h"
2014779705SSam Leffler 
2114779705SSam Leffler #include "ah.h"
2214779705SSam Leffler #include "ah_internal.h"
2314779705SSam Leffler #include "ah_devid.h"
2414779705SSam Leffler 
2514779705SSam Leffler #include "ah_eeprom_v14.h"
2614779705SSam Leffler 
2714779705SSam Leffler #include "ar5416/ar5416.h"
2814779705SSam Leffler #include "ar5416/ar5416reg.h"
2914779705SSam Leffler #include "ar5416/ar5416phy.h"
3014779705SSam Leffler 
3114779705SSam Leffler /* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */
3214779705SSam Leffler #define	EEP_MINOR(_ah) \
3314779705SSam Leffler 	(AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK)
3414779705SSam Leffler #define IS_EEP_MINOR_V2(_ah)	(EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2)
3514779705SSam Leffler #define IS_EEP_MINOR_V3(_ah)	(EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3)
3614779705SSam Leffler 
3714779705SSam Leffler /* Additional Time delay to wait after activiting the Base band */
3814779705SSam Leffler #define BASE_ACTIVATE_DELAY	100	/* 100 usec */
3914779705SSam Leffler #define PLL_SETTLE_DELAY	300	/* 300 usec */
4014779705SSam Leffler #define RTC_PLL_SETTLE_DELAY    1000    /* 1 ms     */
4114779705SSam Leffler 
4214779705SSam Leffler static void ar5416InitDMA(struct ath_hal *ah);
4359efa8b5SSam Leffler static void ar5416InitBB(struct ath_hal *ah, const struct ieee80211_channel *);
4414779705SSam Leffler static void ar5416InitIMR(struct ath_hal *ah, HAL_OPMODE opmode);
4514779705SSam Leffler static void ar5416InitQoS(struct ath_hal *ah);
4614779705SSam Leffler static void ar5416InitUserSettings(struct ath_hal *ah);
479d6de76dSAdrian Chadd static void ar5416OverrideIni(struct ath_hal *ah, const struct ieee80211_channel *);
4814779705SSam Leffler 
4914779705SSam Leffler #if 0
5059efa8b5SSam Leffler static HAL_BOOL	ar5416ChannelChange(struct ath_hal *, const struct ieee80211_channel *);
5114779705SSam Leffler #endif
5259efa8b5SSam Leffler static void ar5416SetDeltaSlope(struct ath_hal *, const struct ieee80211_channel *);
5314779705SSam Leffler 
5414779705SSam Leffler static HAL_BOOL ar5416SetResetPowerOn(struct ath_hal *ah);
5514779705SSam Leffler static HAL_BOOL ar5416SetReset(struct ath_hal *ah, int type);
5614779705SSam Leffler static HAL_BOOL ar5416SetPowerPerRateTable(struct ath_hal *ah,
5714779705SSam Leffler 	struct ar5416eeprom *pEepData,
5859efa8b5SSam Leffler 	const struct ieee80211_channel *chan, int16_t *ratesArray,
5914779705SSam Leffler 	uint16_t cfgCtl, uint16_t AntennaReduction,
6014779705SSam Leffler 	uint16_t twiceMaxRegulatoryPower,
6114779705SSam Leffler 	uint16_t powerLimit);
6259efa8b5SSam Leffler static void ar5416Set11nRegs(struct ath_hal *ah, const struct ieee80211_channel *chan);
63d10f1cdcSAdrian Chadd static void ar5416MarkPhyInactive(struct ath_hal *ah);
64ce801478SAdrian Chadd static void ar5416SetIFSTiming(struct ath_hal *ah,
65ce801478SAdrian Chadd    const struct ieee80211_channel *chan);
6614779705SSam Leffler 
6714779705SSam Leffler /*
6814779705SSam Leffler  * Places the device in and out of reset and then places sane
6914779705SSam Leffler  * values in the registers based on EEPROM config, initialization
7014779705SSam Leffler  * vectors (as determined by the mode), and station configuration
7114779705SSam Leffler  *
7214779705SSam Leffler  * bChannelChange is used to preserve DMA/PCU registers across
7314779705SSam Leffler  * a HW Reset during channel change.
7414779705SSam Leffler  */
7514779705SSam Leffler HAL_BOOL
ar5416Reset(struct ath_hal * ah,HAL_OPMODE opmode,struct ieee80211_channel * chan,HAL_BOOL bChannelChange,HAL_RESET_TYPE resetType,HAL_STATUS * status)7614779705SSam Leffler ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode,
7759efa8b5SSam Leffler 	struct ieee80211_channel *chan,
78f50e4ebfSAdrian Chadd 	HAL_BOOL bChannelChange,
79f50e4ebfSAdrian Chadd 	HAL_RESET_TYPE resetType,
80f50e4ebfSAdrian Chadd 	HAL_STATUS *status)
8114779705SSam Leffler {
8214779705SSam Leffler #define	N(a)	(sizeof (a) / sizeof (a[0]))
8314779705SSam Leffler #define	FAIL(_code)	do { ecode = _code; goto bad; } while (0)
8414779705SSam Leffler 	struct ath_hal_5212 *ahp = AH5212(ah);
8514779705SSam Leffler 	HAL_CHANNEL_INTERNAL *ichan;
8614779705SSam Leffler 	uint32_t saveDefAntenna, saveLedState;
8714779705SSam Leffler 	uint32_t macStaId1;
8814779705SSam Leffler 	uint16_t rfXpdGain[2];
8914779705SSam Leffler 	HAL_STATUS ecode;
9014779705SSam Leffler 	uint32_t powerVal, rssiThrReg;
9114779705SSam Leffler 	uint32_t ackTpcPow, ctsTpcPow, chirpTpcPow;
924a948799SSam Leffler 	int i;
93beb4faf3SAdrian Chadd 	uint64_t tsf = 0;
9414779705SSam Leffler 
9514779705SSam Leffler 	OS_MARK(ah, AH_MARK_RESET, bChannelChange);
9614779705SSam Leffler 
9714779705SSam Leffler 	/* Bring out of sleep mode */
9814779705SSam Leffler 	if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {
9914779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip did not wakeup\n",
10014779705SSam Leffler 		    __func__);
101f5d71263SPoul-Henning Kamp 		FAIL(HAL_EIO);
10214779705SSam Leffler 	}
10314779705SSam Leffler 
10414779705SSam Leffler 	/*
10514779705SSam Leffler 	 * Map public channel to private.
10614779705SSam Leffler 	 */
10714779705SSam Leffler 	ichan = ath_hal_checkchannel(ah, chan);
10859efa8b5SSam Leffler 	if (ichan == AH_NULL)
10914779705SSam Leffler 		FAIL(HAL_EINVAL);
11014779705SSam Leffler 	switch (opmode) {
11114779705SSam Leffler 	case HAL_M_STA:
11214779705SSam Leffler 	case HAL_M_IBSS:
11314779705SSam Leffler 	case HAL_M_HOSTAP:
11414779705SSam Leffler 	case HAL_M_MONITOR:
11514779705SSam Leffler 		break;
11614779705SSam Leffler 	default:
11714779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n",
11814779705SSam Leffler 		    __func__, opmode);
11914779705SSam Leffler 		FAIL(HAL_EINVAL);
12014779705SSam Leffler 		break;
12114779705SSam Leffler 	}
12214779705SSam Leffler 	HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);
12314779705SSam Leffler 
1246af85006SAdrian Chadd 	/* Blank the channel survey statistics */
125b0602becSAdrian Chadd 	ath_hal_survey_clear(ah);
1266af85006SAdrian Chadd 
12714779705SSam Leffler 	/* XXX Turn on fast channel change for 5416 */
128b0602becSAdrian Chadd 
12914779705SSam Leffler 	/*
13014779705SSam Leffler 	 * Preserve the bmiss rssi threshold and count threshold
13114779705SSam Leffler 	 * across resets
13214779705SSam Leffler 	 */
13314779705SSam Leffler 	rssiThrReg = OS_REG_READ(ah, AR_RSSI_THR);
13414779705SSam Leffler 	/* If reg is zero, first time thru set to default val */
13514779705SSam Leffler 	if (rssiThrReg == 0)
13614779705SSam Leffler 		rssiThrReg = INIT_RSSI_THR;
13714779705SSam Leffler 
13814779705SSam Leffler 	/*
13914779705SSam Leffler 	 * Preserve the antenna on a channel change
14014779705SSam Leffler 	 */
14114779705SSam Leffler 	saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA);
142cc7b47ddSAdrian Chadd 
143cc7b47ddSAdrian Chadd 	/*
144cc7b47ddSAdrian Chadd 	 * Don't do this for the AR9285 - it breaks RX for single
145cc7b47ddSAdrian Chadd 	 * antenna designs when diversity is disabled.
146cc7b47ddSAdrian Chadd 	 *
147cc7b47ddSAdrian Chadd 	 * I'm not sure what this was working around; it may be
148cc7b47ddSAdrian Chadd 	 * something to do with the AR5416.  Certainly this register
149cc7b47ddSAdrian Chadd 	 * isn't supposed to be used by the MIMO chips for anything
150cc7b47ddSAdrian Chadd 	 * except for defining the default antenna when an external
151cc7b47ddSAdrian Chadd 	 * phase array / smart antenna is connected.
152cc7b47ddSAdrian Chadd 	 *
153cc7b47ddSAdrian Chadd 	 * See PR: kern/179269 .
154cc7b47ddSAdrian Chadd 	 */
155cc7b47ddSAdrian Chadd 	if ((! AR_SREV_KITE(ah)) && saveDefAntenna == 0)	/* XXX magic constants */
15614779705SSam Leffler 		saveDefAntenna = 1;
15714779705SSam Leffler 
15814779705SSam Leffler 	/* Save hardware flag before chip reset clears the register */
15914779705SSam Leffler 	macStaId1 = OS_REG_READ(ah, AR_STA_ID1) &
16014779705SSam Leffler 		(AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT);
16114779705SSam Leffler 
16214779705SSam Leffler 	/* Save led state from pci config register */
16314779705SSam Leffler 	saveLedState = OS_REG_READ(ah, AR_MAC_LED) &
16414779705SSam Leffler 		(AR_MAC_LED_ASSOC | AR_MAC_LED_MODE |
16514779705SSam Leffler 		 AR_MAC_LED_BLINK_THRESH_SEL | AR_MAC_LED_BLINK_SLOW);
16614779705SSam Leffler 
167beb4faf3SAdrian Chadd 	/* For chips on which the RTC reset is done, save TSF before it gets cleared */
1689f25ad52SAdrian Chadd 	if (AR_SREV_HOWL(ah) ||
169d3054f72SAdrian Chadd 	    (AR_SREV_MERLIN(ah) &&
170d3054f72SAdrian Chadd 	     ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) ||
1718c01c3dcSAdrian Chadd 	    (resetType == HAL_RESET_FORCE_COLD) ||
1728c01c3dcSAdrian Chadd 	    (resetType == HAL_RESET_BBPANIC) ||
173d3054f72SAdrian Chadd 	    (ah->ah_config.ah_force_full_reset))
174fc4de9b7SAdrian Chadd 		tsf = ar5416GetTsf64(ah);
175beb4faf3SAdrian Chadd 
176d10f1cdcSAdrian Chadd 	/* Mark PHY as inactive; marked active in ar5416InitBB() */
177d10f1cdcSAdrian Chadd 	ar5416MarkPhyInactive(ah);
178d10f1cdcSAdrian Chadd 
1798c01c3dcSAdrian Chadd 	if (!ar5416ChipReset(ah, chan, resetType)) {
18014779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);
18114779705SSam Leffler 		FAIL(HAL_EIO);
18214779705SSam Leffler 	}
18314779705SSam Leffler 
184beb4faf3SAdrian Chadd 	/* Restore TSF */
185beb4faf3SAdrian Chadd 	if (tsf)
186fc4de9b7SAdrian Chadd 		ar5416SetTsf64(ah, tsf);
187beb4faf3SAdrian Chadd 
18814779705SSam Leffler 	OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
1894f49ef43SRui Paulo 	if (AR_SREV_MERLIN_10_OR_LATER(ah))
1904f49ef43SRui Paulo 		OS_REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
1914f49ef43SRui Paulo 
1924a948799SSam Leffler 	AH5416(ah)->ah_writeIni(ah, chan);
19314779705SSam Leffler 
194d8daa2e3SAdrian Chadd 	if(AR_SREV_KIWI_13_OR_LATER(ah) ) {
195d8daa2e3SAdrian Chadd 		/* Enable ASYNC FIFO */
196d8daa2e3SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
197d8daa2e3SAdrian Chadd 		    AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
198d8daa2e3SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
199d8daa2e3SAdrian Chadd 		OS_REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
200d8daa2e3SAdrian Chadd 		    AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
201d8daa2e3SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
202d8daa2e3SAdrian Chadd 		    AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
203d8daa2e3SAdrian Chadd 	}
204d8daa2e3SAdrian Chadd 
205*f9a9fe46SGordon Bergling 	/* Override ini values (that can be overridden in this fashion) */
2069d6de76dSAdrian Chadd 	ar5416OverrideIni(ah, chan);
2079d6de76dSAdrian Chadd 
20814779705SSam Leffler 	/* Setup 11n MAC/Phy mode registers */
20914779705SSam Leffler 	ar5416Set11nRegs(ah, chan);
21014779705SSam Leffler 
21114779705SSam Leffler 	OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
21214779705SSam Leffler 
2139f25ad52SAdrian Chadd 	/*
2149f25ad52SAdrian Chadd 	 * Some AR91xx SoC devices frequently fail to accept TSF writes
2159f25ad52SAdrian Chadd 	 * right after the chip reset. When that happens, write a new
2169f25ad52SAdrian Chadd 	 * value after the initvals have been applied, with an offset
2179f25ad52SAdrian Chadd 	 * based on measured time difference
2189f25ad52SAdrian Chadd 	 */
219fc4de9b7SAdrian Chadd 	if (AR_SREV_HOWL(ah) && (ar5416GetTsf64(ah) < tsf)) {
2209f25ad52SAdrian Chadd 		tsf += 1500;
221fc4de9b7SAdrian Chadd 		ar5416SetTsf64(ah, tsf);
2229f25ad52SAdrian Chadd 	}
2239f25ad52SAdrian Chadd 
22414779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_RESET, ">>>2 %s: AR_PHY_DAG_CTRLCCK=0x%x\n",
22514779705SSam Leffler 		__func__, OS_REG_READ(ah,AR_PHY_DAG_CTRLCCK));
22614779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_RESET, ">>>2 %s: AR_PHY_ADC_CTL=0x%x\n",
22714779705SSam Leffler 		__func__, OS_REG_READ(ah,AR_PHY_ADC_CTL));
22814779705SSam Leffler 
22960a507a5SAdrian Chadd 	/*
23060a507a5SAdrian Chadd 	 * This routine swaps the analog chains - it should be done
23160a507a5SAdrian Chadd 	 * before any radio register twiddling is done.
23260a507a5SAdrian Chadd 	 */
23360a507a5SAdrian Chadd 	ar5416InitChainMasks(ah);
23414227797SAdrian Chadd 
2354342b610SAdrian Chadd 	/* Setup the open-loop power calibration if required */
2364342b610SAdrian Chadd 	if (ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
23748c1d364SAdrian Chadd 		AH5416(ah)->ah_olcInit(ah);
2384342b610SAdrian Chadd 		AH5416(ah)->ah_olcTempCompensation(ah);
2394342b610SAdrian Chadd 	}
24014779705SSam Leffler 
24114779705SSam Leffler 	/* Setup the transmit power values. */
2427d4f72b3SRui Paulo 	if (!ah->ah_setTxPower(ah, chan, rfXpdGain)) {
24314779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY,
24414779705SSam Leffler 		    "%s: error init'ing transmit power\n", __func__);
24514779705SSam Leffler 		FAIL(HAL_EIO);
24614779705SSam Leffler 	}
24714779705SSam Leffler 
24814779705SSam Leffler 	/* Write the analog registers */
2494a948799SSam Leffler 	if (!ahp->ah_rfHal->setRfRegs(ah, chan,
2504a948799SSam Leffler 	    IEEE80211_IS_CHAN_2GHZ(chan) ? 2: 1, rfXpdGain)) {
25114779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY,
25214779705SSam Leffler 		    "%s: ar5212SetRfRegs failed\n", __func__);
25314779705SSam Leffler 		FAIL(HAL_EIO);
25414779705SSam Leffler 	}
25514779705SSam Leffler 
25614779705SSam Leffler 	/* Write delta slope for OFDM enabled modes (A, G, Turbo) */
25759efa8b5SSam Leffler 	if (IEEE80211_IS_CHAN_OFDM(chan)|| IEEE80211_IS_CHAN_HT(chan))
25859efa8b5SSam Leffler 		ar5416SetDeltaSlope(ah, chan);
25914779705SSam Leffler 
2604a948799SSam Leffler 	AH5416(ah)->ah_spurMitigate(ah, chan);
26114779705SSam Leffler 
26214779705SSam Leffler 	/* Setup board specific options for EEPROM version 3 */
2637d4f72b3SRui Paulo 	if (!ah->ah_setBoardValues(ah, chan)) {
26414779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY,
26514779705SSam Leffler 		    "%s: error setting board options\n", __func__);
26614779705SSam Leffler 		FAIL(HAL_EIO);
26714779705SSam Leffler 	}
26814779705SSam Leffler 
26914779705SSam Leffler 	OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
27014779705SSam Leffler 
27114779705SSam Leffler 	OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));
27214779705SSam Leffler 	OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)
27314779705SSam Leffler 		| macStaId1
27414779705SSam Leffler 		| AR_STA_ID1_RTS_USE_DEF
27514779705SSam Leffler 		| ahp->ah_staId1Defaults
27614779705SSam Leffler 	);
27714779705SSam Leffler 	ar5212SetOperatingMode(ah, opmode);
27814779705SSam Leffler 
27914779705SSam Leffler 	/* Set Venice BSSID mask according to current state */
28014779705SSam Leffler 	OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));
28114779705SSam Leffler 	OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));
28214779705SSam Leffler 
28314779705SSam Leffler 	/* Restore previous led state */
28459298273SAdrian Chadd 	if (AR_SREV_HOWL(ah))
28559298273SAdrian Chadd 		OS_REG_WRITE(ah, AR_MAC_LED,
28659298273SAdrian Chadd 		    AR_MAC_LED_ASSOC_ACTIVE | AR_CFG_SCLK_32KHZ);
28759298273SAdrian Chadd 	else
28859298273SAdrian Chadd 		OS_REG_WRITE(ah, AR_MAC_LED, OS_REG_READ(ah, AR_MAC_LED) |
28959298273SAdrian Chadd 		    saveLedState);
29014779705SSam Leffler 
291d8daa2e3SAdrian Chadd         /* Start TSF2 for generic timer 8-15 */
292d8daa2e3SAdrian Chadd #ifdef	NOTYET
293d8daa2e3SAdrian Chadd 	if (AR_SREV_KIWI(ah))
294d8daa2e3SAdrian Chadd 		ar5416StartTsf2(ah);
295d8daa2e3SAdrian Chadd #endif
296d8daa2e3SAdrian Chadd 
2970c20aadbSAdrian Chadd 	/*
2980c20aadbSAdrian Chadd 	 * Enable Bluetooth Coexistence if it's enabled.
2990c20aadbSAdrian Chadd 	 */
3000c20aadbSAdrian Chadd 	if (AH5416(ah)->ah_btCoexConfigType != HAL_BT_COEX_CFG_NONE)
3010c20aadbSAdrian Chadd 		ar5416InitBTCoex(ah);
3020c20aadbSAdrian Chadd 
30314779705SSam Leffler 	/* Restore previous antenna */
30414779705SSam Leffler 	OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
30514779705SSam Leffler 
3060047ff70SAdrian Chadd 	/* then our BSSID and associate id */
30714779705SSam Leffler 	OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
3080047ff70SAdrian Chadd 	OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4) |
3090047ff70SAdrian Chadd 	    (ahp->ah_assocId & 0x3fff) << AR_BSS_ID1_AID_S);
31014779705SSam Leffler 
31114779705SSam Leffler 	/* Restore bmiss rssi & count thresholds */
31214779705SSam Leffler 	OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
31314779705SSam Leffler 
31414779705SSam Leffler 	OS_REG_WRITE(ah, AR_ISR, ~0);		/* cleared on write */
31514779705SSam Leffler 
316c454afe2SAdrian Chadd 	/* Restore bmiss rssi & count thresholds */
317c454afe2SAdrian Chadd 	OS_REG_WRITE(ah, AR_RSSI_THR, rssiThrReg);
318c454afe2SAdrian Chadd 
31959efa8b5SSam Leffler 	if (!ar5212SetChannel(ah, chan))
32014779705SSam Leffler 		FAIL(HAL_EIO);
32114779705SSam Leffler 
32214779705SSam Leffler 	OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
32314779705SSam Leffler 
32414779705SSam Leffler 	/* Set 1:1 QCU to DCU mapping for all queues */
32514779705SSam Leffler 	for (i = 0; i < AR_NUM_DCU; i++)
32614779705SSam Leffler 		OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
32714779705SSam Leffler 
32814779705SSam Leffler 	ahp->ah_intrTxqs = 0;
32914779705SSam Leffler 	for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++)
330a85eaa77SAdrian Chadd 		ah->ah_resetTxQueue(ah, i);
33114779705SSam Leffler 
33214779705SSam Leffler 	ar5416InitIMR(ah, opmode);
333ce801478SAdrian Chadd 	ar5416SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1);
33414779705SSam Leffler 	ar5416InitQoS(ah);
33560d38784SAdrian Chadd 	/* This may override the AR_DIAG_SW register */
33614779705SSam Leffler 	ar5416InitUserSettings(ah);
33714779705SSam Leffler 
338ce801478SAdrian Chadd 	/* XXX this won't work for AR9287! */
339ce801478SAdrian Chadd 	if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) {
340ce801478SAdrian Chadd 		ar5416SetIFSTiming(ah, chan);
341ce801478SAdrian Chadd #if 0
342ce801478SAdrian Chadd 			/*
343ce801478SAdrian Chadd 			 * AR5413?
344ce801478SAdrian Chadd 			 * Force window_length for 1/2 and 1/4 rate channels,
345ce801478SAdrian Chadd 			 * the ini file sets this to zero otherwise.
346ce801478SAdrian Chadd 			 */
347ce801478SAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
348ce801478SAdrian Chadd 			    AR_PHY_FRAME_CTL_WINLEN, 3);
349ce801478SAdrian Chadd 		}
350ce801478SAdrian Chadd #endif
351ce801478SAdrian Chadd 	}
352ce801478SAdrian Chadd 
353d8daa2e3SAdrian Chadd 	if (AR_SREV_KIWI_13_OR_LATER(ah)) {
354d8daa2e3SAdrian Chadd 		/*
355d8daa2e3SAdrian Chadd 		 * Enable ASYNC FIFO
356d8daa2e3SAdrian Chadd 		 *
357d8daa2e3SAdrian Chadd 		 * If Async FIFO is enabled, the following counters change
358d8daa2e3SAdrian Chadd 		 * as MAC now runs at 117 Mhz instead of 88/44MHz when
359d8daa2e3SAdrian Chadd 		 * async FIFO is disabled.
360d8daa2e3SAdrian Chadd 		 *
361d8daa2e3SAdrian Chadd 		 * Overwrite the delay/timeouts initialized in ProcessIni()
362d8daa2e3SAdrian Chadd 		 * above.
363d8daa2e3SAdrian Chadd 		 */
364d8daa2e3SAdrian Chadd 		OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
365d8daa2e3SAdrian Chadd 		    AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
366d8daa2e3SAdrian Chadd 		OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
367d8daa2e3SAdrian Chadd 		    AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
368d8daa2e3SAdrian Chadd 		OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
369d8daa2e3SAdrian Chadd 		    AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
370d8daa2e3SAdrian Chadd 
371d8daa2e3SAdrian Chadd 		OS_REG_WRITE(ah, AR_TIME_OUT,
372d8daa2e3SAdrian Chadd 		    AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
373d8daa2e3SAdrian Chadd 		OS_REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
374d8daa2e3SAdrian Chadd 
375d8daa2e3SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
376d8daa2e3SAdrian Chadd 		    AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
377d8daa2e3SAdrian Chadd 		OS_REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
378d8daa2e3SAdrian Chadd 		    AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
379d8daa2e3SAdrian Chadd 	}
380d8daa2e3SAdrian Chadd 
381d8daa2e3SAdrian Chadd 	if (AR_SREV_KIWI_13_OR_LATER(ah)) {
382d8daa2e3SAdrian Chadd 		/* Enable AGGWEP to accelerate encryption engine */
383d8daa2e3SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
384d8daa2e3SAdrian Chadd 		    AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
385d8daa2e3SAdrian Chadd 	}
386d8daa2e3SAdrian Chadd 
38714779705SSam Leffler 	/*
38814779705SSam Leffler 	 * disable seq number generation in hw
38914779705SSam Leffler 	 */
39014779705SSam Leffler 	 OS_REG_WRITE(ah, AR_STA_ID1,
39114779705SSam Leffler 	     OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
39214779705SSam Leffler 
39314779705SSam Leffler 	ar5416InitDMA(ah);
39414779705SSam Leffler 
39514779705SSam Leffler 	/*
39614779705SSam Leffler 	 * program OBS bus to see MAC interrupts
39714779705SSam Leffler 	 */
39814779705SSam Leffler 	OS_REG_WRITE(ah, AR_OBS, 8);
39914779705SSam Leffler 
4007e132ca3SAdrian Chadd 	/*
4017e132ca3SAdrian Chadd 	 * Disable the "general" TX/RX mitigation timers.
4027e132ca3SAdrian Chadd 	 */
40314779705SSam Leffler 	OS_REG_WRITE(ah, AR_MIRT, 0);
4046893df41SAdrian Chadd 
40500d829daSAdrian Chadd #ifdef	AH_AR5416_INTERRUPT_MITIGATION
4067e132ca3SAdrian Chadd 	/*
4077e132ca3SAdrian Chadd 	 * This initialises the RX interrupt mitigation timers.
4087e132ca3SAdrian Chadd 	 *
4097e132ca3SAdrian Chadd 	 * The mitigation timers begin at idle and are triggered
4107e132ca3SAdrian Chadd 	 * upon the RXOK of a single frame (or sub-frame, for A-MPDU.)
4117e132ca3SAdrian Chadd 	 * Then, the RX mitigation interrupt will fire:
4127e132ca3SAdrian Chadd 	 *
4137e132ca3SAdrian Chadd 	 * + 250uS after the last RX'ed frame, or
4147e132ca3SAdrian Chadd 	 * + 700uS after the first RX'ed frame
4157e132ca3SAdrian Chadd 	 *
4167e132ca3SAdrian Chadd 	 * Thus, the LAST field dictates the extra latency
4177e132ca3SAdrian Chadd 	 * induced by the RX mitigation method and the FIRST
4187e132ca3SAdrian Chadd 	 * field dictates how long to delay before firing an
4197e132ca3SAdrian Chadd 	 * RX mitigation interrupt.
4207e132ca3SAdrian Chadd 	 *
4217e132ca3SAdrian Chadd 	 * Please note this only seems to be for RXOK frames;
4227e132ca3SAdrian Chadd 	 * not CRC or PHY error frames.
4237e132ca3SAdrian Chadd 	 *
4247e132ca3SAdrian Chadd 	 */
4259bf15204SAdrian Chadd 	OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 250);
4269bf15204SAdrian Chadd 	OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 700);
42714779705SSam Leffler #endif
42814779705SSam Leffler 	ar5416InitBB(ah, chan);
42914779705SSam Leffler 
43014779705SSam Leffler 	/* Setup compression registers */
43114779705SSam Leffler 	ar5212SetCompRegs(ah);		/* XXX not needed? */
43214779705SSam Leffler 
43314779705SSam Leffler 	/*
43414779705SSam Leffler 	 * 5416 baseband will check the per rate power table
43514779705SSam Leffler 	 * and select the lower of the two
43614779705SSam Leffler 	 */
43714779705SSam Leffler 	ackTpcPow = 63;
43814779705SSam Leffler 	ctsTpcPow = 63;
43914779705SSam Leffler 	chirpTpcPow = 63;
44014779705SSam Leffler 	powerVal = SM(ackTpcPow, AR_TPC_ACK) |
44114779705SSam Leffler 		SM(ctsTpcPow, AR_TPC_CTS) |
44214779705SSam Leffler 		SM(chirpTpcPow, AR_TPC_CHIRP);
44314779705SSam Leffler 	OS_REG_WRITE(ah, AR_TPC, powerVal);
44414779705SSam Leffler 
44514779705SSam Leffler 	if (!ar5416InitCal(ah, chan))
44614779705SSam Leffler 		FAIL(HAL_ESELFTEST);
44714779705SSam Leffler 
448f68a9f06SAdrian Chadd 	ar5416RestoreChainMask(ah);
449f68a9f06SAdrian Chadd 
45014779705SSam Leffler 	AH_PRIVATE(ah)->ah_opmode = opmode;	/* record operating mode */
45114779705SSam Leffler 
45259efa8b5SSam Leffler 	if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan))
45359efa8b5SSam Leffler 		chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;
45414779705SSam Leffler 
45559298273SAdrian Chadd 	if (AR_SREV_HOWL(ah)) {
45659298273SAdrian Chadd 		/*
45759298273SAdrian Chadd 		 * Enable the MBSSID block-ack fix for HOWL.
45859298273SAdrian Chadd 		 * This feature is only supported on Howl 1.4, but it is safe to
45959298273SAdrian Chadd 		 * set bit 22 of STA_ID1 on other Howl revisions (1.1, 1.2, 1.3),
46059298273SAdrian Chadd 		 * since bit 22 is unused in those Howl revisions.
46159298273SAdrian Chadd 		 */
46259298273SAdrian Chadd 		unsigned int reg;
46359298273SAdrian Chadd 		reg = (OS_REG_READ(ah, AR_STA_ID1) | (1<<22));
46459298273SAdrian Chadd 		OS_REG_WRITE(ah,AR_STA_ID1, reg);
46559298273SAdrian Chadd 		ath_hal_printf(ah, "MBSSID Set bit 22 of AR_STA_ID 0x%x\n", reg);
46659298273SAdrian Chadd 	}
46759298273SAdrian Chadd 
46814779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__);
46914779705SSam Leffler 
47014779705SSam Leffler 	OS_MARK(ah, AH_MARK_RESET_DONE, 0);
47114779705SSam Leffler 
47214779705SSam Leffler 	return AH_TRUE;
47314779705SSam Leffler bad:
47414779705SSam Leffler 	OS_MARK(ah, AH_MARK_RESET_DONE, ecode);
4758698ea65SSam Leffler 	if (status != AH_NULL)
47614779705SSam Leffler 		*status = ecode;
47714779705SSam Leffler 	return AH_FALSE;
47814779705SSam Leffler #undef FAIL
47914779705SSam Leffler #undef N
48014779705SSam Leffler }
48114779705SSam Leffler 
48214779705SSam Leffler #if 0
48314779705SSam Leffler /*
48414779705SSam Leffler  * This channel change evaluates whether the selected hardware can
48514779705SSam Leffler  * perform a synthesizer-only channel change (no reset).  If the
48614779705SSam Leffler  * TX is not stopped, or the RFBus cannot be granted in the given
48714779705SSam Leffler  * time, the function returns false as a reset is necessary
48814779705SSam Leffler  */
48914779705SSam Leffler HAL_BOOL
49059efa8b5SSam Leffler ar5416ChannelChange(struct ath_hal *ah, const structu ieee80211_channel *chan)
49114779705SSam Leffler {
49214779705SSam Leffler 	uint32_t       ulCount;
49314779705SSam Leffler 	uint32_t   data, synthDelay, qnum;
49414779705SSam Leffler 	uint16_t   rfXpdGain[4];
49514779705SSam Leffler 	struct ath_hal_5212 *ahp = AH5212(ah);
49614779705SSam Leffler 	HAL_CHANNEL_INTERNAL *ichan;
49714779705SSam Leffler 
49814779705SSam Leffler 	/*
49914779705SSam Leffler 	 * Map public channel to private.
50014779705SSam Leffler 	 */
50114779705SSam Leffler 	ichan = ath_hal_checkchannel(ah, chan);
50214779705SSam Leffler 
50314779705SSam Leffler 	/* TX must be stopped or RF Bus grant will not work */
50414779705SSam Leffler 	for (qnum = 0; qnum < AH_PRIVATE(ah)->ah_caps.halTotalQueues; qnum++) {
50514779705SSam Leffler 		if (ar5212NumTxPending(ah, qnum)) {
50614779705SSam Leffler 			HALDEBUG(ah, HAL_DEBUG_ANY,
50714779705SSam Leffler 			    "%s: frames pending on queue %d\n", __func__, qnum);
50814779705SSam Leffler 			return AH_FALSE;
50914779705SSam Leffler 		}
51014779705SSam Leffler 	}
51114779705SSam Leffler 
51214779705SSam Leffler 	/*
51314779705SSam Leffler 	 * Kill last Baseband Rx Frame - Request analog bus grant
51414779705SSam Leffler 	 */
51514779705SSam Leffler 	OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_REQUEST);
51614779705SSam Leffler 	if (!ath_hal_wait(ah, AR_PHY_RFBUS_GNT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN)) {
51714779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: could not kill baseband rx\n",
51814779705SSam Leffler 		    __func__);
51914779705SSam Leffler 		return AH_FALSE;
52014779705SSam Leffler 	}
52114779705SSam Leffler 
52214779705SSam Leffler 	ar5416Set11nRegs(ah, chan);	/* NB: setup 5416-specific regs */
52314779705SSam Leffler 
52414779705SSam Leffler 	/* Change the synth */
52559efa8b5SSam Leffler 	if (!ar5212SetChannel(ah, chan))
52614779705SSam Leffler 		return AH_FALSE;
52714779705SSam Leffler 
52814779705SSam Leffler 	/* Setup the transmit power values. */
5299ec9578eSAdrian Chadd 	if (!ah->ah_setTxPower(ah, chan, rfXpdGain)) {
53014779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY,
53114779705SSam Leffler 		    "%s: error init'ing transmit power\n", __func__);
53214779705SSam Leffler 		return AH_FALSE;
53314779705SSam Leffler 	}
53414779705SSam Leffler 
53514779705SSam Leffler 	/*
53614779705SSam Leffler 	 * Wait for the frequency synth to settle (synth goes on
53714779705SSam Leffler 	 * via PHY_ACTIVE_EN).  Read the phy active delay register.
53814779705SSam Leffler 	 * Value is in 100ns increments.
53914779705SSam Leffler 	 */
54014779705SSam Leffler 	data = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
54114779705SSam Leffler 	if (IS_CHAN_CCK(ichan)) {
54214779705SSam Leffler 		synthDelay = (4 * data) / 22;
54314779705SSam Leffler 	} else {
54414779705SSam Leffler 		synthDelay = data / 10;
54514779705SSam Leffler 	}
54614779705SSam Leffler 
54714779705SSam Leffler 	OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY);
54814779705SSam Leffler 
54914779705SSam Leffler 	/* Release the RFBus Grant */
55014779705SSam Leffler 	OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
55114779705SSam Leffler 
55214779705SSam Leffler 	/* Write delta slope for OFDM enabled modes (A, G, Turbo) */
55359efa8b5SSam Leffler 	if (IEEE80211_IS_CHAN_OFDM(ichan)|| IEEE80211_IS_CHAN_HT(chan)) {
55459efa8b5SSam Leffler 		HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3);
55559efa8b5SSam Leffler 		ar5212SetSpurMitigation(ah, chan);
55659efa8b5SSam Leffler 		ar5416SetDeltaSlope(ah, chan);
55714779705SSam Leffler 	}
55814779705SSam Leffler 
55914779705SSam Leffler 	/* XXX spur mitigation for Melin */
56014779705SSam Leffler 
56159efa8b5SSam Leffler 	if (!IEEE80211_IS_CHAN_DFS(chan))
56259efa8b5SSam Leffler 		chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;
56314779705SSam Leffler 
56459efa8b5SSam Leffler 	ichan->channel_time = 0;
565fc4de9b7SAdrian Chadd 	ichan->tsf_last = ar5416GetTsf64(ah);
56614779705SSam Leffler 	ar5212TxEnable(ah, AH_TRUE);
56714779705SSam Leffler 	return AH_TRUE;
56814779705SSam Leffler }
56914779705SSam Leffler #endif
57014779705SSam Leffler 
57114779705SSam Leffler static void
ar5416InitDMA(struct ath_hal * ah)57214779705SSam Leffler ar5416InitDMA(struct ath_hal *ah)
57314779705SSam Leffler {
574256796dbSRui Paulo 	struct ath_hal_5212 *ahp = AH5212(ah);
57514779705SSam Leffler 
57614779705SSam Leffler 	/*
57714779705SSam Leffler 	 * set AHB_MODE not to do cacheline prefetches
57814779705SSam Leffler 	 */
57914779705SSam Leffler 	OS_REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN);
58014779705SSam Leffler 
58114779705SSam Leffler 	/*
58214779705SSam Leffler 	 * let mac dma reads be in 128 byte chunks
58314779705SSam Leffler 	 */
58414779705SSam Leffler 	OS_REG_WRITE(ah, AR_TXCFG,
58514779705SSam Leffler 		(OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK) | AR_TXCFG_DMASZ_128B);
58614779705SSam Leffler 
58714779705SSam Leffler 	/*
58814779705SSam Leffler 	 * let mac dma writes be in 128 byte chunks
58914779705SSam Leffler 	 */
590de2d9111SAdrian Chadd 	/*
591de2d9111SAdrian Chadd 	 * XXX If you change this, you must change the headroom
592de2d9111SAdrian Chadd 	 * assigned in ah_maxTxTrigLev - see ar5416InitState().
593de2d9111SAdrian Chadd 	 */
59414779705SSam Leffler 	OS_REG_WRITE(ah, AR_RXCFG,
59514779705SSam Leffler 		(OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK) | AR_RXCFG_DMASZ_128B);
59614779705SSam Leffler 
5979425e26bSRui Paulo 	/* restore TX trigger level */
5989425e26bSRui Paulo 	OS_REG_WRITE(ah, AR_TXCFG,
5999425e26bSRui Paulo 		(OS_REG_READ(ah, AR_TXCFG) &~ AR_FTRIG) |
600256796dbSRui Paulo 		    SM(ahp->ah_txTrigLev, AR_FTRIG));
60114779705SSam Leffler 
60214779705SSam Leffler 	/*
60314779705SSam Leffler 	 * Setup receive FIFO threshold to hold off TX activities
60414779705SSam Leffler 	 */
60514779705SSam Leffler 	OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
60614779705SSam Leffler 
60714779705SSam Leffler 	/*
60814779705SSam Leffler 	 * reduce the number of usable entries in PCU TXBUF to avoid
60914779705SSam Leffler 	 * wrap around.
61014779705SSam Leffler 	 */
611c5596869SAdrian Chadd 	if (AR_SREV_KITE(ah))
612c5596869SAdrian Chadd 		/*
613c5596869SAdrian Chadd 		 * For AR9285 the number of Fifos are reduced to half.
614c5596869SAdrian Chadd 		 * So set the usable tx buf size also to half to
615c5596869SAdrian Chadd 		 * avoid data/delimiter underruns
616c5596869SAdrian Chadd 		 */
617c5596869SAdrian Chadd 		OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
618c5596869SAdrian Chadd 	else
61912fefae2SRui Paulo 		OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE);
62014779705SSam Leffler }
62114779705SSam Leffler 
62214779705SSam Leffler static void
ar5416InitBB(struct ath_hal * ah,const struct ieee80211_channel * chan)62359efa8b5SSam Leffler ar5416InitBB(struct ath_hal *ah, const struct ieee80211_channel *chan)
62414779705SSam Leffler {
62514779705SSam Leffler 	uint32_t synthDelay;
62614779705SSam Leffler 
62714779705SSam Leffler 	/*
62814779705SSam Leffler 	 * Wait for the frequency synth to settle (synth goes on
62914779705SSam Leffler 	 * via AR_PHY_ACTIVE_EN).  Read the phy active delay register.
63014779705SSam Leffler 	 * Value is in 100ns increments.
63114779705SSam Leffler 	  */
63214779705SSam Leffler 	synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
63359efa8b5SSam Leffler 	if (IEEE80211_IS_CHAN_CCK(chan)) {
63414779705SSam Leffler 		synthDelay = (4 * synthDelay) / 22;
63514779705SSam Leffler 	} else {
63614779705SSam Leffler 		synthDelay /= 10;
63714779705SSam Leffler 	}
63814779705SSam Leffler 
63914779705SSam Leffler 	/* Turn on PLL on 5416 */
64014779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_RESET, "%s %s channel\n",
64159efa8b5SSam Leffler 	    __func__, IEEE80211_IS_CHAN_5GHZ(chan) ? "5GHz" : "2GHz");
64214779705SSam Leffler 
64314779705SSam Leffler 	/* Activate the PHY (includes baseband activate and synthesizer on) */
64414779705SSam Leffler 	OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
64514779705SSam Leffler 
64614779705SSam Leffler 	/*
64714779705SSam Leffler 	 * If the AP starts the calibration before the base band timeout
64814779705SSam Leffler 	 * completes  we could get rx_clear false triggering.  Add an
64914779705SSam Leffler 	 * extra BASE_ACTIVATE_DELAY usecs to ensure this condition
65014779705SSam Leffler 	 * does not happen.
65114779705SSam Leffler 	 */
65259efa8b5SSam Leffler 	if (IEEE80211_IS_CHAN_HALF(chan)) {
65314779705SSam Leffler 		OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY);
65459efa8b5SSam Leffler 	} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
65514779705SSam Leffler 		OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY);
65614779705SSam Leffler 	} else {
65714779705SSam Leffler 		OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY);
65814779705SSam Leffler 	}
65914779705SSam Leffler }
66014779705SSam Leffler 
66114779705SSam Leffler static void
ar5416InitIMR(struct ath_hal * ah,HAL_OPMODE opmode)66214779705SSam Leffler ar5416InitIMR(struct ath_hal *ah, HAL_OPMODE opmode)
66314779705SSam Leffler {
66414779705SSam Leffler 	struct ath_hal_5212 *ahp = AH5212(ah);
66514779705SSam Leffler 
66614779705SSam Leffler 	/*
66714779705SSam Leffler 	 * Setup interrupt handling.  Note that ar5212ResetTxQueue
66814779705SSam Leffler 	 * manipulates the secondary IMR's as queues are enabled
66914779705SSam Leffler 	 * and disabled.  This is done with RMW ops to insure the
67014779705SSam Leffler 	 * settings we make here are preserved.
67114779705SSam Leffler 	 */
67214779705SSam Leffler         ahp->ah_maskReg = AR_IMR_TXERR | AR_IMR_TXURN
67314779705SSam Leffler 			| AR_IMR_RXERR | AR_IMR_RXORN
67414779705SSam Leffler                         | AR_IMR_BCNMISC;
67514779705SSam Leffler 
676b569f9f5SAdrian Chadd #ifdef	AH_AR5416_INTERRUPT_MITIGATION
67700d829daSAdrian Chadd 	ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
67814779705SSam Leffler #else
67900d829daSAdrian Chadd 	ahp->ah_maskReg |= AR_IMR_RXOK;
68014779705SSam Leffler #endif
68100d829daSAdrian Chadd 	ahp->ah_maskReg |= AR_IMR_TXOK;
6829f25ad52SAdrian Chadd 
68314779705SSam Leffler 	if (opmode == HAL_M_HOSTAP)
68414779705SSam Leffler 		ahp->ah_maskReg |= AR_IMR_MIB;
68514779705SSam Leffler 	OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
6869f25ad52SAdrian Chadd 
6879f25ad52SAdrian Chadd #ifdef  ADRIAN_NOTYET
6889f25ad52SAdrian Chadd 	/* This is straight from ath9k */
6899f25ad52SAdrian Chadd 	if (! AR_SREV_HOWL(ah)) {
6909f25ad52SAdrian Chadd 		OS_REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
6919f25ad52SAdrian Chadd 		OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
6929f25ad52SAdrian Chadd 		OS_REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
6939f25ad52SAdrian Chadd 	}
6949f25ad52SAdrian Chadd #endif
6959f25ad52SAdrian Chadd 
69614779705SSam Leffler 	/* Enable bus errors that are OR'd to set the HIUERR bit */
69714779705SSam Leffler #if 0
69814779705SSam Leffler 	OS_REG_WRITE(ah, AR_IMR_S2,
69914779705SSam Leffler 	    	OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT | AR_IMR_S2_CST);
70014779705SSam Leffler #endif
70114779705SSam Leffler }
70214779705SSam Leffler 
70314779705SSam Leffler static void
ar5416InitQoS(struct ath_hal * ah)70414779705SSam Leffler ar5416InitQoS(struct ath_hal *ah)
70514779705SSam Leffler {
70614779705SSam Leffler 	/* QoS support */
70714779705SSam Leffler 	OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa);	/* XXX magic */
70814779705SSam Leffler 	OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210);	/* XXX magic */
70914779705SSam Leffler 
71014779705SSam Leffler 	/* Turn on NOACK Support for QoS packets */
71114779705SSam Leffler 	OS_REG_WRITE(ah, AR_NOACK,
71214779705SSam Leffler 		SM(2, AR_NOACK_2BIT_VALUE) |
71314779705SSam Leffler 		SM(5, AR_NOACK_BIT_OFFSET) |
71414779705SSam Leffler 		SM(0, AR_NOACK_BYTE_OFFSET));
71514779705SSam Leffler 
71614779705SSam Leffler     	/*
71714779705SSam Leffler     	 * initialize TXOP for all TIDs
71814779705SSam Leffler     	 */
71914779705SSam Leffler 	OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);
72014779705SSam Leffler 	OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);
72114779705SSam Leffler 	OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
72214779705SSam Leffler 	OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
72314779705SSam Leffler 	OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
72414779705SSam Leffler }
72514779705SSam Leffler 
72614779705SSam Leffler static void
ar5416InitUserSettings(struct ath_hal * ah)72714779705SSam Leffler ar5416InitUserSettings(struct ath_hal *ah)
72814779705SSam Leffler {
72914779705SSam Leffler 	struct ath_hal_5212 *ahp = AH5212(ah);
73014779705SSam Leffler 
73114779705SSam Leffler 	/* Restore user-specified settings */
73214779705SSam Leffler 	if (ahp->ah_miscMode != 0)
733d780702eSAdrian Chadd 		OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE)
734d780702eSAdrian Chadd 		    | ahp->ah_miscMode);
73514779705SSam Leffler 	if (ahp->ah_sifstime != (u_int) -1)
73614779705SSam Leffler 		ar5212SetSifsTime(ah, ahp->ah_sifstime);
73714779705SSam Leffler 	if (ahp->ah_slottime != (u_int) -1)
73814779705SSam Leffler 		ar5212SetSlotTime(ah, ahp->ah_slottime);
73914779705SSam Leffler 	if (ahp->ah_acktimeout != (u_int) -1)
74014779705SSam Leffler 		ar5212SetAckTimeout(ah, ahp->ah_acktimeout);
74114779705SSam Leffler 	if (ahp->ah_ctstimeout != (u_int) -1)
74214779705SSam Leffler 		ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout);
74314779705SSam Leffler 	if (AH_PRIVATE(ah)->ah_diagreg != 0)
74414779705SSam Leffler 		OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
7456ad02dbaSAdrian Chadd 	if (AH5416(ah)->ah_globaltxtimeout != (u_int) -1)
7466ad02dbaSAdrian Chadd         	ar5416SetGlobalTxTimeout(ah, AH5416(ah)->ah_globaltxtimeout);
74714779705SSam Leffler }
74814779705SSam Leffler 
7496359b573SAdrian Chadd static void
ar5416SetRfMode(struct ath_hal * ah,const struct ieee80211_channel * chan)7506359b573SAdrian Chadd ar5416SetRfMode(struct ath_hal *ah, const struct ieee80211_channel *chan)
7516359b573SAdrian Chadd {
7526359b573SAdrian Chadd 	uint32_t rfMode;
7536359b573SAdrian Chadd 
7546359b573SAdrian Chadd 	if (chan == AH_NULL)
7556359b573SAdrian Chadd 		return;
7566359b573SAdrian Chadd 
7576359b573SAdrian Chadd 	/* treat channel B as channel G , no  B mode suport in owl */
7586359b573SAdrian Chadd 	rfMode = IEEE80211_IS_CHAN_CCK(chan) ?
7596359b573SAdrian Chadd 	    AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
7606359b573SAdrian Chadd 
7616359b573SAdrian Chadd 	if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {
7626359b573SAdrian Chadd 		/* phy mode bits for 5GHz channels require Fast Clock */
7636359b573SAdrian Chadd 		rfMode |= AR_PHY_MODE_DYNAMIC
7646359b573SAdrian Chadd 		       |  AR_PHY_MODE_DYN_CCK_DISABLE;
7656359b573SAdrian Chadd 	} else if (!AR_SREV_MERLIN_10_OR_LATER(ah)) {
7666359b573SAdrian Chadd 		rfMode |= IEEE80211_IS_CHAN_5GHZ(chan) ?
7676359b573SAdrian Chadd 			AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;
7686359b573SAdrian Chadd 	}
7696bf0b868SAdrian Chadd 
7706359b573SAdrian Chadd 	OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
7716359b573SAdrian Chadd }
7726359b573SAdrian Chadd 
77314779705SSam Leffler /*
77414779705SSam Leffler  * Places the hardware into reset and then pulls it out of reset
77514779705SSam Leffler  */
77614779705SSam Leffler HAL_BOOL
ar5416ChipReset(struct ath_hal * ah,const struct ieee80211_channel * chan,HAL_RESET_TYPE resetType)7778c01c3dcSAdrian Chadd ar5416ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan,
7788c01c3dcSAdrian Chadd     HAL_RESET_TYPE resetType)
77914779705SSam Leffler {
78059efa8b5SSam Leffler 	OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);
78114779705SSam Leffler 	/*
782d3054f72SAdrian Chadd 	 * Warm reset is optimistic for open-loop TX power control.
78314779705SSam Leffler 	 */
78498cdd904SAdrian Chadd 	if (AR_SREV_MERLIN(ah) &&
78514779705SSam Leffler 	    ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
78614779705SSam Leffler 		if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))
78714779705SSam Leffler 			return AH_FALSE;
788d3054f72SAdrian Chadd 	} else if (ah->ah_config.ah_force_full_reset) {
789d3054f72SAdrian Chadd 		if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))
790d3054f72SAdrian Chadd 			return AH_FALSE;
7918c01c3dcSAdrian Chadd 	} else if ((resetType == HAL_RESET_FORCE_COLD) ||
7928c01c3dcSAdrian Chadd 	    (resetType == HAL_RESET_BBPANIC)) {
7938c01c3dcSAdrian Chadd 		HALDEBUG(ah, HAL_DEBUG_RESET,
7948c01c3dcSAdrian Chadd 		    "%s: full reset; resetType=%d\n",
7958c01c3dcSAdrian Chadd 		    __func__, resetType);
7968c01c3dcSAdrian Chadd 		if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))
7978c01c3dcSAdrian Chadd 			return AH_FALSE;
79814779705SSam Leffler 	} else {
79914779705SSam Leffler 		if (!ar5416SetResetReg(ah, HAL_RESET_WARM))
80014779705SSam Leffler 			return AH_FALSE;
80114779705SSam Leffler 	}
80214779705SSam Leffler 
80314779705SSam Leffler 	/* Bring out of sleep mode (AGAIN) */
80414779705SSam Leffler 	if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
80514779705SSam Leffler 	       return AH_FALSE;
80614779705SSam Leffler 
8075c892e74SAdrian Chadd #ifdef notyet
8085c892e74SAdrian Chadd 	ahp->ah_chipFullSleep = AH_FALSE;
8095c892e74SAdrian Chadd #endif
8105c892e74SAdrian Chadd 
811c2442d27SAdrian Chadd 	AH5416(ah)->ah_initPLL(ah, chan);
81214779705SSam Leffler 
81314779705SSam Leffler 	/*
81414779705SSam Leffler 	 * Perform warm reset before the mode/PLL/turbo registers
81514779705SSam Leffler 	 * are changed in order to deactivate the radio.  Mode changes
81614779705SSam Leffler 	 * with an active radio can result in corrupted shifts to the
81714779705SSam Leffler 	 * radio device.
81814779705SSam Leffler 	 */
8196359b573SAdrian Chadd 	ar5416SetRfMode(ah, chan);
8204a948799SSam Leffler 
82114779705SSam Leffler 	return AH_TRUE;
82214779705SSam Leffler }
82314779705SSam Leffler 
82414779705SSam Leffler /*
82514779705SSam Leffler  * Delta slope coefficient computation.
82614779705SSam Leffler  * Required for OFDM operation.
82714779705SSam Leffler  */
82814779705SSam Leffler static void
ar5416GetDeltaSlopeValues(struct ath_hal * ah,uint32_t coef_scaled,uint32_t * coef_mantissa,uint32_t * coef_exponent)82914779705SSam Leffler ar5416GetDeltaSlopeValues(struct ath_hal *ah, uint32_t coef_scaled,
83014779705SSam Leffler                           uint32_t *coef_mantissa, uint32_t *coef_exponent)
83114779705SSam Leffler {
83214779705SSam Leffler #define COEF_SCALE_S 24
83314779705SSam Leffler     uint32_t coef_exp, coef_man;
83414779705SSam Leffler     /*
83514779705SSam Leffler      * ALGO -> coef_exp = 14-floor(log2(coef));
83614779705SSam Leffler      * floor(log2(x)) is the highest set bit position
83714779705SSam Leffler      */
83814779705SSam Leffler     for (coef_exp = 31; coef_exp > 0; coef_exp--)
83914779705SSam Leffler             if ((coef_scaled >> coef_exp) & 0x1)
84014779705SSam Leffler                     break;
84114779705SSam Leffler     /* A coef_exp of 0 is a legal bit position but an unexpected coef_exp */
84214779705SSam Leffler     HALASSERT(coef_exp);
84314779705SSam Leffler     coef_exp = 14 - (coef_exp - COEF_SCALE_S);
84414779705SSam Leffler 
84514779705SSam Leffler     /*
84614779705SSam Leffler      * ALGO -> coef_man = floor(coef* 2^coef_exp+0.5);
84714779705SSam Leffler      * The coefficient is already shifted up for scaling
84814779705SSam Leffler      */
84914779705SSam Leffler     coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1));
85014779705SSam Leffler 
85114779705SSam Leffler     *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp);
85214779705SSam Leffler     *coef_exponent = coef_exp - 16;
85314779705SSam Leffler 
85414779705SSam Leffler #undef COEF_SCALE_S
85514779705SSam Leffler }
85614779705SSam Leffler 
85714779705SSam Leffler void
ar5416SetDeltaSlope(struct ath_hal * ah,const struct ieee80211_channel * chan)85859efa8b5SSam Leffler ar5416SetDeltaSlope(struct ath_hal *ah, const struct ieee80211_channel *chan)
85914779705SSam Leffler {
86014779705SSam Leffler #define INIT_CLOCKMHZSCALED	0x64000000
86114779705SSam Leffler 	uint32_t coef_scaled, ds_coef_exp, ds_coef_man;
862a0a2aa79SSam Leffler 	uint32_t clockMhzScaled;
86314779705SSam Leffler 
86414779705SSam Leffler 	CHAN_CENTERS centers;
86514779705SSam Leffler 
86614779705SSam Leffler 	/* half and quarter rate can divide the scaled clock by 2 or 4 respectively */
86714779705SSam Leffler 	/* scale for selected channel bandwidth */
868a0a2aa79SSam Leffler 	clockMhzScaled = INIT_CLOCKMHZSCALED;
869a0a2aa79SSam Leffler 	if (IEEE80211_IS_CHAN_TURBO(chan))
870a0a2aa79SSam Leffler 		clockMhzScaled <<= 1;
871a0a2aa79SSam Leffler 	else if (IEEE80211_IS_CHAN_HALF(chan))
872a0a2aa79SSam Leffler 		clockMhzScaled >>= 1;
873a0a2aa79SSam Leffler 	else if (IEEE80211_IS_CHAN_QUARTER(chan))
874a0a2aa79SSam Leffler 		clockMhzScaled >>= 2;
87514779705SSam Leffler 
87614779705SSam Leffler 	/*
87714779705SSam Leffler 	 * ALGO -> coef = 1e8/fcarrier*fclock/40;
87814779705SSam Leffler 	 * scaled coef to provide precision for this floating calculation
87914779705SSam Leffler 	 */
88014779705SSam Leffler 	ar5416GetChannelCenters(ah, chan, &centers);
88114779705SSam Leffler 	coef_scaled = clockMhzScaled / centers.synth_center;
88214779705SSam Leffler 
88314779705SSam Leffler  	ar5416GetDeltaSlopeValues(ah, coef_scaled, &ds_coef_man, &ds_coef_exp);
88414779705SSam Leffler 
88514779705SSam Leffler 	OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3,
88614779705SSam Leffler 		AR_PHY_TIMING3_DSC_MAN, ds_coef_man);
88714779705SSam Leffler 	OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3,
88814779705SSam Leffler 		AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);
88914779705SSam Leffler 
89014779705SSam Leffler         /*
89114779705SSam Leffler          * For Short GI,
89214779705SSam Leffler          * scaled coeff is 9/10 that of normal coeff
89314779705SSam Leffler          */
89414779705SSam Leffler         coef_scaled = (9 * coef_scaled)/10;
89514779705SSam Leffler 
89614779705SSam Leffler         ar5416GetDeltaSlopeValues(ah, coef_scaled, &ds_coef_man, &ds_coef_exp);
89714779705SSam Leffler 
89814779705SSam Leffler         /* for short gi */
89914779705SSam Leffler         OS_REG_RMW_FIELD(ah, AR_PHY_HALFGI,
90014779705SSam Leffler                 AR_PHY_HALFGI_DSC_MAN, ds_coef_man);
90114779705SSam Leffler         OS_REG_RMW_FIELD(ah, AR_PHY_HALFGI,
90214779705SSam Leffler                 AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
90314779705SSam Leffler #undef INIT_CLOCKMHZSCALED
90414779705SSam Leffler }
90514779705SSam Leffler 
90614779705SSam Leffler /*
90714779705SSam Leffler  * Set a limit on the overall output power.  Used for dynamic
90814779705SSam Leffler  * transmit power control and the like.
90914779705SSam Leffler  *
91014779705SSam Leffler  * NB: limit is in units of 0.5 dbM.
91114779705SSam Leffler  */
91214779705SSam Leffler HAL_BOOL
ar5416SetTxPowerLimit(struct ath_hal * ah,uint32_t limit)91314779705SSam Leffler ar5416SetTxPowerLimit(struct ath_hal *ah, uint32_t limit)
91414779705SSam Leffler {
91514779705SSam Leffler 	uint16_t dummyXpdGains[2];
91614779705SSam Leffler 
91714779705SSam Leffler 	AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER);
9189ec9578eSAdrian Chadd 	return ah->ah_setTxPower(ah, AH_PRIVATE(ah)->ah_curchan,
91914779705SSam Leffler 			dummyXpdGains);
92014779705SSam Leffler }
92114779705SSam Leffler 
92214779705SSam Leffler HAL_BOOL
ar5416GetChipPowerLimits(struct ath_hal * ah,struct ieee80211_channel * chan)92359efa8b5SSam Leffler ar5416GetChipPowerLimits(struct ath_hal *ah,
92459efa8b5SSam Leffler 	struct ieee80211_channel *chan)
92514779705SSam Leffler {
92614779705SSam Leffler 	struct ath_hal_5212 *ahp = AH5212(ah);
92714779705SSam Leffler 	int16_t minPower, maxPower;
92814779705SSam Leffler 
92914779705SSam Leffler 	/*
93014779705SSam Leffler 	 * Get Pier table max and min powers.
93114779705SSam Leffler 	 */
93214779705SSam Leffler 	if (ahp->ah_rfHal->getChannelMaxMinPower(ah, chan, &maxPower, &minPower)) {
93314779705SSam Leffler 		/* NB: rf code returns 1/4 dBm units, convert */
93459efa8b5SSam Leffler 		chan->ic_maxpower = maxPower / 2;
93559efa8b5SSam Leffler 		chan->ic_minpower = minPower / 2;
93614779705SSam Leffler 	} else {
93714779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY,
93814779705SSam Leffler 		    "%s: no min/max power for %u/0x%x\n",
93959efa8b5SSam Leffler 		    __func__, chan->ic_freq, chan->ic_flags);
94059efa8b5SSam Leffler 		chan->ic_maxpower = AR5416_MAX_RATE_POWER;
94159efa8b5SSam Leffler 		chan->ic_minpower = 0;
94214779705SSam Leffler 	}
94314779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_RESET,
94414779705SSam Leffler 	    "Chan %d: MaxPow = %d MinPow = %d\n",
94559efa8b5SSam Leffler 	    chan->ic_freq, chan->ic_maxpower, chan->ic_minpower);
94614779705SSam Leffler 	return AH_TRUE;
94714779705SSam Leffler }
94814779705SSam Leffler 
94914779705SSam Leffler /**************************************************************
950b998ae64SAdrian Chadd  * ar5416WriteTxPowerRateRegisters
951b998ae64SAdrian Chadd  *
952b998ae64SAdrian Chadd  * Write the TX power rate registers from the raw values given
953b998ae64SAdrian Chadd  * in ratesArray[].
954b998ae64SAdrian Chadd  *
955b998ae64SAdrian Chadd  * The CCK and HT40 rate registers are only written if needed.
956b998ae64SAdrian Chadd  * HT20 and 11g/11a OFDM rate registers are always written.
957b998ae64SAdrian Chadd  *
958b998ae64SAdrian Chadd  * The values written are raw values which should be written
959b998ae64SAdrian Chadd  * to the registers - so it's up to the caller to pre-adjust
960b998ae64SAdrian Chadd  * them (eg CCK power offset value, or Merlin TX power offset,
961b998ae64SAdrian Chadd  * etc.)
962b998ae64SAdrian Chadd  */
963b998ae64SAdrian Chadd void
ar5416WriteTxPowerRateRegisters(struct ath_hal * ah,const struct ieee80211_channel * chan,const int16_t ratesArray[])964b998ae64SAdrian Chadd ar5416WriteTxPowerRateRegisters(struct ath_hal *ah,
965b998ae64SAdrian Chadd     const struct ieee80211_channel *chan, const int16_t ratesArray[])
966b998ae64SAdrian Chadd {
967b998ae64SAdrian Chadd #define POW_SM(_r, _s)     (((_r) & 0x3f) << (_s))
968b998ae64SAdrian Chadd 
969b998ae64SAdrian Chadd     /* Write the OFDM power per rate set */
970b998ae64SAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
971b998ae64SAdrian Chadd         POW_SM(ratesArray[rate18mb], 24)
972b998ae64SAdrian Chadd           | POW_SM(ratesArray[rate12mb], 16)
973b998ae64SAdrian Chadd           | POW_SM(ratesArray[rate9mb], 8)
974b998ae64SAdrian Chadd           | POW_SM(ratesArray[rate6mb], 0)
975b998ae64SAdrian Chadd     );
976b998ae64SAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
977b998ae64SAdrian Chadd         POW_SM(ratesArray[rate54mb], 24)
978b998ae64SAdrian Chadd           | POW_SM(ratesArray[rate48mb], 16)
979b998ae64SAdrian Chadd           | POW_SM(ratesArray[rate36mb], 8)
980b998ae64SAdrian Chadd           | POW_SM(ratesArray[rate24mb], 0)
981b998ae64SAdrian Chadd     );
982b998ae64SAdrian Chadd 
983b998ae64SAdrian Chadd     if (IEEE80211_IS_CHAN_2GHZ(chan)) {
984b998ae64SAdrian Chadd         /* Write the CCK power per rate set */
985b998ae64SAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
986b998ae64SAdrian Chadd             POW_SM(ratesArray[rate2s], 24)
987b998ae64SAdrian Chadd               | POW_SM(ratesArray[rate2l],  16)
988b998ae64SAdrian Chadd               | POW_SM(ratesArray[rateXr],  8) /* XR target power */
989b998ae64SAdrian Chadd               | POW_SM(ratesArray[rate1l],   0)
990b998ae64SAdrian Chadd         );
991b998ae64SAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
992b998ae64SAdrian Chadd             POW_SM(ratesArray[rate11s], 24)
993b998ae64SAdrian Chadd               | POW_SM(ratesArray[rate11l], 16)
994b998ae64SAdrian Chadd               | POW_SM(ratesArray[rate5_5s], 8)
995b998ae64SAdrian Chadd               | POW_SM(ratesArray[rate5_5l], 0)
996b998ae64SAdrian Chadd         );
997b998ae64SAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_RESET,
998b998ae64SAdrian Chadd 	"%s AR_PHY_POWER_TX_RATE3=0x%x AR_PHY_POWER_TX_RATE4=0x%x\n",
999b998ae64SAdrian Chadd 	    __func__, OS_REG_READ(ah,AR_PHY_POWER_TX_RATE3),
1000b998ae64SAdrian Chadd 	    OS_REG_READ(ah,AR_PHY_POWER_TX_RATE4));
1001b998ae64SAdrian Chadd     }
1002b998ae64SAdrian Chadd 
1003b998ae64SAdrian Chadd     /* Write the HT20 power per rate set */
1004b998ae64SAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
1005b998ae64SAdrian Chadd         POW_SM(ratesArray[rateHt20_3], 24)
1006b998ae64SAdrian Chadd           | POW_SM(ratesArray[rateHt20_2], 16)
1007b998ae64SAdrian Chadd           | POW_SM(ratesArray[rateHt20_1], 8)
1008b998ae64SAdrian Chadd           | POW_SM(ratesArray[rateHt20_0], 0)
1009b998ae64SAdrian Chadd     );
1010b998ae64SAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
1011b998ae64SAdrian Chadd         POW_SM(ratesArray[rateHt20_7], 24)
1012b998ae64SAdrian Chadd           | POW_SM(ratesArray[rateHt20_6], 16)
1013b998ae64SAdrian Chadd           | POW_SM(ratesArray[rateHt20_5], 8)
1014b998ae64SAdrian Chadd           | POW_SM(ratesArray[rateHt20_4], 0)
1015b998ae64SAdrian Chadd     );
1016b998ae64SAdrian Chadd 
1017b998ae64SAdrian Chadd     if (IEEE80211_IS_CHAN_HT40(chan)) {
1018b998ae64SAdrian Chadd         /* Write the HT40 power per rate set */
1019b998ae64SAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
1020b998ae64SAdrian Chadd             POW_SM(ratesArray[rateHt40_3], 24)
1021b998ae64SAdrian Chadd               | POW_SM(ratesArray[rateHt40_2], 16)
1022b998ae64SAdrian Chadd               | POW_SM(ratesArray[rateHt40_1], 8)
1023b998ae64SAdrian Chadd               | POW_SM(ratesArray[rateHt40_0], 0)
1024b998ae64SAdrian Chadd         );
1025b998ae64SAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
1026b998ae64SAdrian Chadd             POW_SM(ratesArray[rateHt40_7], 24)
1027b998ae64SAdrian Chadd               | POW_SM(ratesArray[rateHt40_6], 16)
1028b998ae64SAdrian Chadd               | POW_SM(ratesArray[rateHt40_5], 8)
1029b998ae64SAdrian Chadd               | POW_SM(ratesArray[rateHt40_4], 0)
1030b998ae64SAdrian Chadd         );
1031b998ae64SAdrian Chadd         /* Write the Dup/Ext 40 power per rate set */
1032b998ae64SAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
1033b998ae64SAdrian Chadd             POW_SM(ratesArray[rateExtOfdm], 24)
1034b998ae64SAdrian Chadd               | POW_SM(ratesArray[rateExtCck], 16)
1035b998ae64SAdrian Chadd               | POW_SM(ratesArray[rateDupOfdm], 8)
1036b998ae64SAdrian Chadd               | POW_SM(ratesArray[rateDupCck], 0)
1037b998ae64SAdrian Chadd         );
1038b998ae64SAdrian Chadd     }
103991046e9cSAdrian Chadd 
104091046e9cSAdrian Chadd     /*
104191046e9cSAdrian Chadd      * Set max power to 30 dBm and, optionally,
104291046e9cSAdrian Chadd      * enable TPC in tx descriptors.
104391046e9cSAdrian Chadd      */
104491046e9cSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER |
104591046e9cSAdrian Chadd       (AH5212(ah)->ah_tpcEnabled ? AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE : 0));
104691046e9cSAdrian Chadd #undef POW_SM
1047b998ae64SAdrian Chadd }
1048b998ae64SAdrian Chadd 
1049b998ae64SAdrian Chadd /**************************************************************
105014779705SSam Leffler  * ar5416SetTransmitPower
105114779705SSam Leffler  *
105214779705SSam Leffler  * Set the transmit power in the baseband for the given
105314779705SSam Leffler  * operating channel and mode.
105414779705SSam Leffler  */
10557d4f72b3SRui Paulo HAL_BOOL
ar5416SetTransmitPower(struct ath_hal * ah,const struct ieee80211_channel * chan,uint16_t * rfXpdGain)105659efa8b5SSam Leffler ar5416SetTransmitPower(struct ath_hal *ah,
105759efa8b5SSam Leffler 	const struct ieee80211_channel *chan, uint16_t *rfXpdGain)
105814779705SSam Leffler {
105914779705SSam Leffler #define N(a)            (sizeof (a) / sizeof (a[0]))
106091046e9cSAdrian Chadd #define POW_SM(_r, _s)     (((_r) & 0x3f) << (_s))
106114779705SSam Leffler 
106214779705SSam Leffler     MODAL_EEP_HEADER	*pModal;
106314779705SSam Leffler     struct ath_hal_5212 *ahp = AH5212(ah);
106414779705SSam Leffler     int16_t		txPowerIndexOffset = 0;
106514779705SSam Leffler     int			i;
106614779705SSam Leffler 
106714779705SSam Leffler     uint16_t		cfgCtl;
106814779705SSam Leffler     uint16_t		powerLimit;
106914779705SSam Leffler     uint16_t		twiceAntennaReduction;
107014779705SSam Leffler     uint16_t		twiceMaxRegulatoryPower;
107114779705SSam Leffler     int16_t		maxPower;
107212fefae2SRui Paulo     HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
107312fefae2SRui Paulo     struct ar5416eeprom	*pEepData = &ee->ee_base;
107414779705SSam Leffler 
107514779705SSam Leffler     HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);
107614779705SSam Leffler 
107791046e9cSAdrian Chadd     /*
107891046e9cSAdrian Chadd      * Default to 2, is overridden based on the EEPROM version / value.
107991046e9cSAdrian Chadd      */
108091046e9cSAdrian Chadd     AH5416(ah)->ah_ht40PowerIncForPdadc = 2;
108191046e9cSAdrian Chadd 
108214779705SSam Leffler     /* Setup info for the actual eeprom */
108391046e9cSAdrian Chadd     OS_MEMZERO(AH5416(ah)->ah_ratesArray, sizeof(AH5416(ah)->ah_ratesArray));
108459efa8b5SSam Leffler     cfgCtl = ath_hal_getctl(ah, chan);
108559efa8b5SSam Leffler     powerLimit = chan->ic_maxregpower * 2;
108659efa8b5SSam Leffler     twiceAntennaReduction = chan->ic_maxantgain;
108714779705SSam Leffler     twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit);
108859efa8b5SSam Leffler     pModal = &pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)];
108914779705SSam Leffler     HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n",
109059efa8b5SSam Leffler 	__func__,chan->ic_freq, cfgCtl );
109114779705SSam Leffler 
109214779705SSam Leffler     if (IS_EEP_MINOR_V2(ah)) {
109391046e9cSAdrian Chadd         AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
109414779705SSam Leffler     }
109514779705SSam Leffler 
109612fefae2SRui Paulo     if (!ar5416SetPowerPerRateTable(ah, pEepData,  chan,
109791046e9cSAdrian Chadd                                     &AH5416(ah)->ah_ratesArray[0],
109891046e9cSAdrian Chadd 				    cfgCtl,
109914779705SSam Leffler                                     twiceAntennaReduction,
110014779705SSam Leffler 				    twiceMaxRegulatoryPower, powerLimit)) {
110114779705SSam Leffler         HALDEBUG(ah, HAL_DEBUG_ANY,
110214779705SSam Leffler 	    "%s: unable to set tx power per rate table\n", __func__);
110314779705SSam Leffler         return AH_FALSE;
110414779705SSam Leffler     }
110514779705SSam Leffler 
110648c1d364SAdrian Chadd     if (!AH5416(ah)->ah_setPowerCalTable(ah,  pEepData, chan, &txPowerIndexOffset)) {
110714779705SSam Leffler         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set power table\n",
110814779705SSam Leffler 	    __func__);
110914779705SSam Leffler         return AH_FALSE;
111014779705SSam Leffler     }
111114779705SSam Leffler 
111291046e9cSAdrian Chadd     maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb],
111391046e9cSAdrian Chadd       AH5416(ah)->ah_ratesArray[rateHt20_0]);
111414779705SSam Leffler 
111559efa8b5SSam Leffler     if (IEEE80211_IS_CHAN_2GHZ(chan)) {
111691046e9cSAdrian Chadd         maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rate1l]);
111714779705SSam Leffler     }
111814779705SSam Leffler 
111959efa8b5SSam Leffler     if (IEEE80211_IS_CHAN_HT40(chan)) {
112091046e9cSAdrian Chadd         maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rateHt40_0]);
112114779705SSam Leffler     }
112214779705SSam Leffler 
112314779705SSam Leffler     ahp->ah_tx6PowerInHalfDbm = maxPower;
112414779705SSam Leffler     AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower;
112514779705SSam Leffler     ahp->ah_txPowerIndexOffset = txPowerIndexOffset;
112614779705SSam Leffler 
112714779705SSam Leffler     /*
112814779705SSam Leffler      * txPowerIndexOffset is set by the SetPowerTable() call -
112914779705SSam Leffler      *  adjust the rate table (0 offset if rates EEPROM not loaded)
113014779705SSam Leffler      */
113191046e9cSAdrian Chadd     for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {
113291046e9cSAdrian Chadd         AH5416(ah)->ah_ratesArray[i] =
113391046e9cSAdrian Chadd           (int16_t)(txPowerIndexOffset + AH5416(ah)->ah_ratesArray[i]);
113491046e9cSAdrian Chadd         if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)
113591046e9cSAdrian Chadd             AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;
113614779705SSam Leffler     }
113714779705SSam Leffler 
113814779705SSam Leffler #ifdef AH_EEPROM_DUMP
113948c1d364SAdrian Chadd     /*
114048c1d364SAdrian Chadd      * Dump the rate array whilst it represents the intended dBm*2
114148c1d364SAdrian Chadd      * values versus what's being adjusted before being programmed
114248c1d364SAdrian Chadd      * in. Keep this in mind if you code up this function and enable
114348c1d364SAdrian Chadd      * this debugging; the values won't necessarily be what's being
114448c1d364SAdrian Chadd      * programmed into the hardware.
114548c1d364SAdrian Chadd      */
114691046e9cSAdrian Chadd     ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray);
114714779705SSam Leffler #endif
114814779705SSam Leffler 
114948c1d364SAdrian Chadd     /*
115048c1d364SAdrian Chadd      * Merlin and later have a power offset, so subtract
115148c1d364SAdrian Chadd      * pwr_table_offset * 2 from each value. The default
115248c1d364SAdrian Chadd      * power offset is -5 dBm - ie, a register value of 0
115348c1d364SAdrian Chadd      * equates to a TX power of -5 dBm.
115448c1d364SAdrian Chadd      */
115548c1d364SAdrian Chadd     if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
115648c1d364SAdrian Chadd         int8_t pwr_table_offset;
115748c1d364SAdrian Chadd 
115848c1d364SAdrian Chadd 	(void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET,
115948c1d364SAdrian Chadd 	    &pwr_table_offset);
116048c1d364SAdrian Chadd 	/* Underflow power gets clamped at raw value 0 */
116148c1d364SAdrian Chadd 	/* Overflow power gets camped at AR5416_MAX_RATE_POWER */
116291046e9cSAdrian Chadd 	for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {
116348c1d364SAdrian Chadd 		/*
116448c1d364SAdrian Chadd 		 * + pwr_table_offset is in dBm
116548c1d364SAdrian Chadd 		 * + ratesArray is in 1/2 dBm
116648c1d364SAdrian Chadd 		 */
116791046e9cSAdrian Chadd 		AH5416(ah)->ah_ratesArray[i] -= (pwr_table_offset * 2);
116891046e9cSAdrian Chadd 		if (AH5416(ah)->ah_ratesArray[i] < 0)
116991046e9cSAdrian Chadd 			AH5416(ah)->ah_ratesArray[i] = 0;
117091046e9cSAdrian Chadd 		else if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)
117191046e9cSAdrian Chadd 		    AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;
117248c1d364SAdrian Chadd 	}
117348c1d364SAdrian Chadd     }
117448c1d364SAdrian Chadd 
117548c1d364SAdrian Chadd     /*
117648c1d364SAdrian Chadd      * Adjust rates for OLC where needed
117748c1d364SAdrian Chadd      *
117848c1d364SAdrian Chadd      * The following CCK rates need adjusting when doing 2.4ghz
117948c1d364SAdrian Chadd      * CCK transmission.
118048c1d364SAdrian Chadd      *
118148c1d364SAdrian Chadd      * + rate2s, rate2l, rate1l, rate11s, rate11l, rate5_5s, rate5_5l
118248c1d364SAdrian Chadd      * + rateExtCck, rateDupCck
118348c1d364SAdrian Chadd      *
118448c1d364SAdrian Chadd      * They're adjusted here regardless. The hardware then gets
118548c1d364SAdrian Chadd      * programmed as needed. 5GHz operation doesn't program in CCK
118648c1d364SAdrian Chadd      * rates for legacy mode but they seem to be initialised for
118748c1d364SAdrian Chadd      * HT40 regardless of channel type.
118848c1d364SAdrian Chadd      */
118948c1d364SAdrian Chadd     if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
119048c1d364SAdrian Chadd 	    ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
119148c1d364SAdrian Chadd         int adj[] = {
119248c1d364SAdrian Chadd 	              rate2s, rate2l, rate1l, rate11s, rate11l,
119348c1d364SAdrian Chadd 	              rate5_5s, rate5_5l, rateExtCck, rateDupCck
119448c1d364SAdrian Chadd 		    };
119548c1d364SAdrian Chadd         int cck_ofdm_delta = 2;
119648c1d364SAdrian Chadd 	int i;
119748c1d364SAdrian Chadd 	for (i = 0; i < N(adj); i++) {
119891046e9cSAdrian Chadd             AH5416(ah)->ah_ratesArray[adj[i]] -= cck_ofdm_delta;
119991046e9cSAdrian Chadd 	    if (AH5416(ah)->ah_ratesArray[adj[i]] < 0)
120091046e9cSAdrian Chadd 	        AH5416(ah)->ah_ratesArray[adj[i]] = 0;
120148c1d364SAdrian Chadd         }
120248c1d364SAdrian Chadd     }
120348c1d364SAdrian Chadd 
1204b998ae64SAdrian Chadd     /*
1205b998ae64SAdrian Chadd      * Adjust the HT40 power to meet the correct target TX power
1206b998ae64SAdrian Chadd      * for 40MHz mode, based on TX power curves that are established
1207b998ae64SAdrian Chadd      * for 20MHz mode.
1208b998ae64SAdrian Chadd      *
1209b998ae64SAdrian Chadd      * XXX handle overflow/too high power level?
1210b998ae64SAdrian Chadd      */
121159efa8b5SSam Leffler     if (IEEE80211_IS_CHAN_HT40(chan)) {
121291046e9cSAdrian Chadd 	AH5416(ah)->ah_ratesArray[rateHt40_0] +=
121391046e9cSAdrian Chadd 	  AH5416(ah)->ah_ht40PowerIncForPdadc;
121491046e9cSAdrian Chadd 	AH5416(ah)->ah_ratesArray[rateHt40_1] +=
121591046e9cSAdrian Chadd 	  AH5416(ah)->ah_ht40PowerIncForPdadc;
121691046e9cSAdrian Chadd 	AH5416(ah)->ah_ratesArray[rateHt40_2] += AH5416(ah)->ah_ht40PowerIncForPdadc;
121791046e9cSAdrian Chadd 	AH5416(ah)->ah_ratesArray[rateHt40_3] += AH5416(ah)->ah_ht40PowerIncForPdadc;
121891046e9cSAdrian Chadd 	AH5416(ah)->ah_ratesArray[rateHt40_4] += AH5416(ah)->ah_ht40PowerIncForPdadc;
121991046e9cSAdrian Chadd 	AH5416(ah)->ah_ratesArray[rateHt40_5] += AH5416(ah)->ah_ht40PowerIncForPdadc;
122091046e9cSAdrian Chadd 	AH5416(ah)->ah_ratesArray[rateHt40_6] += AH5416(ah)->ah_ht40PowerIncForPdadc;
122191046e9cSAdrian Chadd 	AH5416(ah)->ah_ratesArray[rateHt40_7] += AH5416(ah)->ah_ht40PowerIncForPdadc;
122214779705SSam Leffler     }
122314779705SSam Leffler 
1224b998ae64SAdrian Chadd     /* Write the TX power rate registers */
122591046e9cSAdrian Chadd     ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray);
1226b998ae64SAdrian Chadd 
122714779705SSam Leffler     /* Write the Power subtraction for dynamic chain changing, for per-packet powertx */
122814779705SSam Leffler     OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
122914779705SSam Leffler         POW_SM(pModal->pwrDecreaseFor3Chain, 6)
123014779705SSam Leffler           | POW_SM(pModal->pwrDecreaseFor2Chain, 0)
123114779705SSam Leffler     );
123214779705SSam Leffler     return AH_TRUE;
123314779705SSam Leffler #undef POW_SM
123414779705SSam Leffler #undef N
123514779705SSam Leffler }
123614779705SSam Leffler 
123714779705SSam Leffler /*
123814779705SSam Leffler  * Exported call to check for a recent gain reading and return
123914779705SSam Leffler  * the current state of the thermal calibration gain engine.
124014779705SSam Leffler  */
124114779705SSam Leffler HAL_RFGAIN
ar5416GetRfgain(struct ath_hal * ah)124214779705SSam Leffler ar5416GetRfgain(struct ath_hal *ah)
124314779705SSam Leffler {
1244d780702eSAdrian Chadd 
1245d780702eSAdrian Chadd 	return (HAL_RFGAIN_INACTIVE);
124614779705SSam Leffler }
124714779705SSam Leffler 
124814779705SSam Leffler /*
124914779705SSam Leffler  * Places all of hardware into reset
125014779705SSam Leffler  */
125114779705SSam Leffler HAL_BOOL
ar5416Disable(struct ath_hal * ah)125214779705SSam Leffler ar5416Disable(struct ath_hal *ah)
125314779705SSam Leffler {
1254d780702eSAdrian Chadd 
1255543d97bbSAdrian Chadd 	if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
125614779705SSam Leffler 		return AH_FALSE;
12575c892e74SAdrian Chadd 	if (! ar5416SetResetReg(ah, HAL_RESET_COLD))
12585c892e74SAdrian Chadd 		return AH_FALSE;
12595c892e74SAdrian Chadd 
12605c892e74SAdrian Chadd 	AH5416(ah)->ah_initPLL(ah, AH_NULL);
1261d780702eSAdrian Chadd 	return (AH_TRUE);
126214779705SSam Leffler }
126314779705SSam Leffler 
126414779705SSam Leffler /*
126514779705SSam Leffler  * Places the PHY and Radio chips into reset.  A full reset
126614779705SSam Leffler  * must be called to leave this state.  The PCI/MAC/PCU are
126714779705SSam Leffler  * not placed into reset as we must receive interrupt to
126814779705SSam Leffler  * re-enable the hardware.
126914779705SSam Leffler  */
127014779705SSam Leffler HAL_BOOL
ar5416PhyDisable(struct ath_hal * ah)127114779705SSam Leffler ar5416PhyDisable(struct ath_hal *ah)
127214779705SSam Leffler {
1273d780702eSAdrian Chadd 
12745c892e74SAdrian Chadd 	if (! ar5416SetResetReg(ah, HAL_RESET_WARM))
12755c892e74SAdrian Chadd 		return AH_FALSE;
12765c892e74SAdrian Chadd 
12775c892e74SAdrian Chadd 	AH5416(ah)->ah_initPLL(ah, AH_NULL);
1278d780702eSAdrian Chadd 	return (AH_TRUE);
127914779705SSam Leffler }
128014779705SSam Leffler 
128114779705SSam Leffler /*
128214779705SSam Leffler  * Write the given reset bit mask into the reset register
128314779705SSam Leffler  */
128414779705SSam Leffler HAL_BOOL
ar5416SetResetReg(struct ath_hal * ah,uint32_t type)128514779705SSam Leffler ar5416SetResetReg(struct ath_hal *ah, uint32_t type)
128614779705SSam Leffler {
1287ac3fb727SAdrian Chadd 	/*
1288ac3fb727SAdrian Chadd 	 * Set force wake
1289ac3fb727SAdrian Chadd 	 */
1290ac3fb727SAdrian Chadd 	OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,
1291ac3fb727SAdrian Chadd 	    AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
1292ac3fb727SAdrian Chadd 
129314779705SSam Leffler 	switch (type) {
129414779705SSam Leffler 	case HAL_RESET_POWER_ON:
129514779705SSam Leffler 		return ar5416SetResetPowerOn(ah);
129614779705SSam Leffler 	case HAL_RESET_WARM:
129714779705SSam Leffler 	case HAL_RESET_COLD:
129814779705SSam Leffler 		return ar5416SetReset(ah, type);
129914779705SSam Leffler 	default:
13004a948799SSam Leffler 		HALASSERT(AH_FALSE);
130114779705SSam Leffler 		return AH_FALSE;
130214779705SSam Leffler 	}
130314779705SSam Leffler }
130414779705SSam Leffler 
130514779705SSam Leffler static HAL_BOOL
ar5416SetResetPowerOn(struct ath_hal * ah)130614779705SSam Leffler ar5416SetResetPowerOn(struct ath_hal *ah)
130714779705SSam Leffler {
130814779705SSam Leffler     /* Power On Reset (Hard Reset) */
130914779705SSam Leffler 
131014779705SSam Leffler     /*
131114779705SSam Leffler      * Set force wake
131214779705SSam Leffler      *
131314779705SSam Leffler      * If the MAC was running, previously calling
131414779705SSam Leffler      * reset will wake up the MAC but it may go back to sleep
131514779705SSam Leffler      * before we can start polling.
131614779705SSam Leffler      * Set force wake  stops that
131714779705SSam Leffler      * This must be called before initiating a hard reset.
131814779705SSam Leffler      */
131914779705SSam Leffler     OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,
132014779705SSam Leffler             AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
132114779705SSam Leffler 
132214779705SSam Leffler     /*
1323ac3fb727SAdrian Chadd      * PowerOn reset can be used in open loop power control or failure recovery.
1324ac3fb727SAdrian Chadd      * If we do RTC reset while DMA is still running, hardware may corrupt memory.
1325ac3fb727SAdrian Chadd      * Therefore, we need to reset AHB first to stop DMA.
132614779705SSam Leffler      */
13279f25ad52SAdrian Chadd     if (! AR_SREV_HOWL(ah))
13284f49ef43SRui Paulo     	OS_REG_WRITE(ah, AR_RC, AR_RC_AHB);
1329ac3fb727SAdrian Chadd     /*
1330ac3fb727SAdrian Chadd      * RTC reset and clear
1331ac3fb727SAdrian Chadd      */
133214779705SSam Leffler     OS_REG_WRITE(ah, AR_RTC_RESET, 0);
133314779705SSam Leffler     OS_DELAY(20);
13349f25ad52SAdrian Chadd 
13359f25ad52SAdrian Chadd     if (! AR_SREV_HOWL(ah))
13364f49ef43SRui Paulo     	OS_REG_WRITE(ah, AR_RC, 0);
13374f49ef43SRui Paulo 
133814779705SSam Leffler     OS_REG_WRITE(ah, AR_RTC_RESET, 1);
133914779705SSam Leffler 
134014779705SSam Leffler     /*
134114779705SSam Leffler      * Poll till RTC is ON
134214779705SSam Leffler      */
134314779705SSam Leffler     if (!ath_hal_wait(ah, AR_RTC_STATUS, AR_RTC_PM_STATUS_M, AR_RTC_STATUS_ON)) {
134414779705SSam Leffler         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RTC not waking up\n", __func__);
134514779705SSam Leffler         return AH_FALSE;
134614779705SSam Leffler     }
134714779705SSam Leffler 
134814779705SSam Leffler     return ar5416SetReset(ah, HAL_RESET_COLD);
134914779705SSam Leffler }
135014779705SSam Leffler 
135114779705SSam Leffler static HAL_BOOL
ar5416SetReset(struct ath_hal * ah,int type)135214779705SSam Leffler ar5416SetReset(struct ath_hal *ah, int type)
135314779705SSam Leffler {
135465526983SSam Leffler     uint32_t tmpReg, mask;
13559f25ad52SAdrian Chadd     uint32_t rst_flags;
13569f25ad52SAdrian Chadd 
13579f25ad52SAdrian Chadd #ifdef	AH_SUPPORT_AR9130	/* Because of the AR9130 specific registers */
13589f25ad52SAdrian Chadd     if (AR_SREV_HOWL(ah)) {
13599f25ad52SAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_ANY, "[ath] HOWL: Fiddling with derived clk!\n");
13609f25ad52SAdrian Chadd         uint32_t val = OS_REG_READ(ah, AR_RTC_DERIVED_CLK);
13619f25ad52SAdrian Chadd         val &= ~AR_RTC_DERIVED_CLK_PERIOD;
13629f25ad52SAdrian Chadd         val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD);
13639f25ad52SAdrian Chadd         OS_REG_WRITE(ah, AR_RTC_DERIVED_CLK, val);
13649f25ad52SAdrian Chadd         (void) OS_REG_READ(ah, AR_RTC_DERIVED_CLK);
13659f25ad52SAdrian Chadd     }
13669f25ad52SAdrian Chadd #endif	/* AH_SUPPORT_AR9130 */
136714779705SSam Leffler 
136814779705SSam Leffler     /*
136914779705SSam Leffler      * Force wake
137014779705SSam Leffler      */
137114779705SSam Leffler     OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,
137214779705SSam Leffler 	AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
137314779705SSam Leffler 
13749f25ad52SAdrian Chadd #ifdef	AH_SUPPORT_AR9130
13759f25ad52SAdrian Chadd     if (AR_SREV_HOWL(ah)) {
13769f25ad52SAdrian Chadd         rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |
13779f25ad52SAdrian Chadd           AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
13789f25ad52SAdrian Chadd     } else {
13799f25ad52SAdrian Chadd #endif	/* AH_SUPPORT_AR9130 */
138014779705SSam Leffler         /*
138114779705SSam Leffler          * Reset AHB
1382ac3fb727SAdrian Chadd          *
1383ac3fb727SAdrian Chadd          * (In case the last interrupt source was a bus timeout.)
1384ac3fb727SAdrian Chadd          * XXX TODO: this is not the way to do it! It should be recorded
1385ac3fb727SAdrian Chadd          * XXX by the interrupt handler and passed _into_ the
1386ac3fb727SAdrian Chadd          * XXX reset path routine so this occurs.
138714779705SSam Leffler          */
138814779705SSam Leffler         tmpReg = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE);
138914779705SSam Leffler         if (tmpReg & (AR_INTR_SYNC_LOCAL_TIMEOUT|AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
139014779705SSam Leffler             OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
139114779705SSam Leffler             OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF);
139214779705SSam Leffler         } else {
139314779705SSam Leffler 	    OS_REG_WRITE(ah, AR_RC, AR_RC_AHB);
139414779705SSam Leffler         }
13959f25ad52SAdrian Chadd         rst_flags = AR_RTC_RC_MAC_WARM;
13969f25ad52SAdrian Chadd         if (type == HAL_RESET_COLD)
13979f25ad52SAdrian Chadd             rst_flags |= AR_RTC_RC_MAC_COLD;
13989f25ad52SAdrian Chadd #ifdef	AH_SUPPORT_AR9130
139914779705SSam Leffler     }
14009f25ad52SAdrian Chadd #endif	/* AH_SUPPORT_AR9130 */
14019f25ad52SAdrian Chadd 
14029f25ad52SAdrian Chadd     OS_REG_WRITE(ah, AR_RTC_RC, rst_flags);
140359298273SAdrian Chadd 
140459298273SAdrian Chadd     if (AR_SREV_HOWL(ah))
140559298273SAdrian Chadd         OS_DELAY(10000);
140659298273SAdrian Chadd     else
140759298273SAdrian Chadd         OS_DELAY(100);
140814779705SSam Leffler 
140914779705SSam Leffler     /*
141014779705SSam Leffler      * Clear resets and force wakeup
141114779705SSam Leffler      */
141214779705SSam Leffler     OS_REG_WRITE(ah, AR_RTC_RC, 0);
141314779705SSam Leffler     if (!ath_hal_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) {
141414779705SSam Leffler         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RTC stuck in MAC reset\n", __func__);
141514779705SSam Leffler         return AH_FALSE;
141614779705SSam Leffler     }
141714779705SSam Leffler 
141814779705SSam Leffler     /* Clear AHB reset */
14199f25ad52SAdrian Chadd     if (! AR_SREV_HOWL(ah))
142014779705SSam Leffler         OS_REG_WRITE(ah, AR_RC, 0);
142114779705SSam Leffler 
14229f25ad52SAdrian Chadd     if (AR_SREV_HOWL(ah))
14239f25ad52SAdrian Chadd         OS_DELAY(50);
14249f25ad52SAdrian Chadd 
14259f25ad52SAdrian Chadd     if (AR_SREV_HOWL(ah)) {
14269f25ad52SAdrian Chadd                 uint32_t mask;
14279f25ad52SAdrian Chadd                 mask = OS_REG_READ(ah, AR_CFG);
14289f25ad52SAdrian Chadd                 if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
14299f25ad52SAdrian Chadd                         HALDEBUG(ah, HAL_DEBUG_RESET,
14309f25ad52SAdrian Chadd                                 "CFG Byte Swap Set 0x%x\n", mask);
14319f25ad52SAdrian Chadd                 } else {
14329f25ad52SAdrian Chadd                         mask =
14339f25ad52SAdrian Chadd                                 INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
14349f25ad52SAdrian Chadd                         OS_REG_WRITE(ah, AR_CFG, mask);
14359f25ad52SAdrian Chadd                         HALDEBUG(ah, HAL_DEBUG_RESET,
14369f25ad52SAdrian Chadd                                 "Setting CFG 0x%x\n", OS_REG_READ(ah, AR_CFG));
14379f25ad52SAdrian Chadd                 }
14389f25ad52SAdrian Chadd     } else {
143914779705SSam Leffler 	if (type == HAL_RESET_COLD) {
144065526983SSam Leffler 		if (isBigEndian()) {
144165526983SSam Leffler 			/*
1442a47f39daSAdrian Chadd 			 * Set CFG, little-endian for descriptor accesses.
144365526983SSam Leffler 			 */
1444a47f39daSAdrian Chadd 			mask = INIT_CONFIG_STATUS | AR_CFG_SWRD;
144514779705SSam Leffler #ifndef AH_NEED_DESC_SWAP
144614779705SSam Leffler 			mask |= AR_CFG_SWTD;
144714779705SSam Leffler #endif
144865526983SSam Leffler 			HALDEBUG(ah, HAL_DEBUG_RESET,
144965526983SSam Leffler 			    "%s Applying descriptor swap\n", __func__);
1450a47f39daSAdrian Chadd 			OS_REG_WRITE(ah, AR_CFG, mask);
145165526983SSam Leffler 		} else
145265526983SSam Leffler 			OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);
145314779705SSam Leffler 	}
14549f25ad52SAdrian Chadd     }
145514779705SSam Leffler 
145614779705SSam Leffler     return AH_TRUE;
145714779705SSam Leffler }
145814779705SSam Leffler 
145960a507a5SAdrian Chadd void
ar5416InitChainMasks(struct ath_hal * ah)146060a507a5SAdrian Chadd ar5416InitChainMasks(struct ath_hal *ah)
146160a507a5SAdrian Chadd {
14625accb5fdSAdrian Chadd 	int rx_chainmask = AH5416(ah)->ah_rx_chainmask;
14635accb5fdSAdrian Chadd 
146448d813efSAdrian Chadd 	/* Flip this for this chainmask regardless of chip */
146548d813efSAdrian Chadd 	if (rx_chainmask == 0x5)
14665accb5fdSAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN);
14675accb5fdSAdrian Chadd 
14685accb5fdSAdrian Chadd 	/*
14695accb5fdSAdrian Chadd 	 * Workaround for OWL 1.0 calibration failure; enable multi-chain;
14705accb5fdSAdrian Chadd 	 * then set true mask after calibration.
14715accb5fdSAdrian Chadd 	 */
14725accb5fdSAdrian Chadd 	if (IS_5416V1(ah) && (rx_chainmask == 0x5 || rx_chainmask == 0x3)) {
14735accb5fdSAdrian Chadd 		OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
14745accb5fdSAdrian Chadd 		OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
14755accb5fdSAdrian Chadd 	} else {
147660a507a5SAdrian Chadd 		OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, AH5416(ah)->ah_rx_chainmask);
147760a507a5SAdrian Chadd 		OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, AH5416(ah)->ah_rx_chainmask);
14785accb5fdSAdrian Chadd 	}
147960a507a5SAdrian Chadd 	OS_REG_WRITE(ah, AR_SELFGEN_MASK, AH5416(ah)->ah_tx_chainmask);
14809f25ad52SAdrian Chadd 
14815accb5fdSAdrian Chadd 	if (AH5416(ah)->ah_tx_chainmask == 0x5)
14825accb5fdSAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN);
14835accb5fdSAdrian Chadd 
14849f25ad52SAdrian Chadd 	if (AR_SREV_HOWL(ah)) {
14859f25ad52SAdrian Chadd 		OS_REG_WRITE(ah, AR_PHY_ANALOG_SWAP,
14869f25ad52SAdrian Chadd 		OS_REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
14879f25ad52SAdrian Chadd 	}
148860a507a5SAdrian Chadd }
148960a507a5SAdrian Chadd 
14905accb5fdSAdrian Chadd /*
14915accb5fdSAdrian Chadd  * Work-around for Owl 1.0 calibration failure.
14925accb5fdSAdrian Chadd  *
14935accb5fdSAdrian Chadd  * ar5416InitChainMasks sets the RX chainmask to 0x7 if it's Owl 1.0
14945accb5fdSAdrian Chadd  * due to init calibration failures. ar5416RestoreChainMask restores
14955accb5fdSAdrian Chadd  * these registers to the correct setting.
14965accb5fdSAdrian Chadd  */
1497f68a9f06SAdrian Chadd void
ar5416RestoreChainMask(struct ath_hal * ah)1498f68a9f06SAdrian Chadd ar5416RestoreChainMask(struct ath_hal *ah)
1499f68a9f06SAdrian Chadd {
1500f68a9f06SAdrian Chadd 	int rx_chainmask = AH5416(ah)->ah_rx_chainmask;
1501f68a9f06SAdrian Chadd 
15025accb5fdSAdrian Chadd 	if (IS_5416V1(ah) && (rx_chainmask == 0x5 || rx_chainmask == 0x3)) {
1503f68a9f06SAdrian Chadd 		OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
1504f68a9f06SAdrian Chadd 		OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
1505f68a9f06SAdrian Chadd 	}
1506f68a9f06SAdrian Chadd }
1507f68a9f06SAdrian Chadd 
1508c2442d27SAdrian Chadd void
ar5416InitPLL(struct ath_hal * ah,const struct ieee80211_channel * chan)150959efa8b5SSam Leffler ar5416InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan)
151014779705SSam Leffler {
151164d6d2d3SAdrian Chadd 	uint32_t pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
151259efa8b5SSam Leffler 	if (chan != AH_NULL) {
151359efa8b5SSam Leffler 		if (IEEE80211_IS_CHAN_HALF(chan))
151414779705SSam Leffler 			pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
151559efa8b5SSam Leffler 		else if (IEEE80211_IS_CHAN_QUARTER(chan))
151614779705SSam Leffler 			pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
1517003df2a9SAdrian Chadd 
1518003df2a9SAdrian Chadd 		if (IEEE80211_IS_CHAN_5GHZ(chan))
151914779705SSam Leffler 			pll |= SM(0xa, AR_RTC_PLL_DIV);
152059efa8b5SSam Leffler 		else
152114779705SSam Leffler 			pll |= SM(0xb, AR_RTC_PLL_DIV);
152259efa8b5SSam Leffler 	} else
152359efa8b5SSam Leffler 		pll |= SM(0xb, AR_RTC_PLL_DIV);
152464d6d2d3SAdrian Chadd 
152514779705SSam Leffler 	OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
152614779705SSam Leffler 
152714779705SSam Leffler 	/* TODO:
152814779705SSam Leffler 	* For multi-band owl, switch between bands by reiniting the PLL.
152914779705SSam Leffler 	*/
153014779705SSam Leffler 
153114779705SSam Leffler 	OS_DELAY(RTC_PLL_SETTLE_DELAY);
153214779705SSam Leffler 
153314779705SSam Leffler 	OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_SLEEP_DERIVED_CLK);
153414779705SSam Leffler }
153514779705SSam Leffler 
15368f699719SAdrian Chadd static void
ar5416SetDefGainValues(struct ath_hal * ah,const MODAL_EEP_HEADER * pModal,const struct ar5416eeprom * eep,uint8_t txRxAttenLocal,int regChainOffset,int i)15378f699719SAdrian Chadd ar5416SetDefGainValues(struct ath_hal *ah,
15388f699719SAdrian Chadd     const MODAL_EEP_HEADER *pModal,
15398f699719SAdrian Chadd     const struct ar5416eeprom *eep,
15408f699719SAdrian Chadd     uint8_t txRxAttenLocal, int regChainOffset, int i)
15418f699719SAdrian Chadd {
1542d780702eSAdrian Chadd 
15438f699719SAdrian Chadd 	if (IS_EEP_MINOR_V3(ah)) {
15448f699719SAdrian Chadd 		txRxAttenLocal = pModal->txRxAttenCh[i];
15458f699719SAdrian Chadd 
154698cdd904SAdrian Chadd 		if (AR_SREV_MERLIN_10_OR_LATER(ah)) {
15478f699719SAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
15488f699719SAdrian Chadd 			      AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
15498f699719SAdrian Chadd 			      pModal->bswMargin[i]);
15508f699719SAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
15518f699719SAdrian Chadd 			      AR_PHY_GAIN_2GHZ_XATTEN1_DB,
15528f699719SAdrian Chadd 			      pModal->bswAtten[i]);
15538f699719SAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
15548f699719SAdrian Chadd 			      AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
15558f699719SAdrian Chadd 			      pModal->xatten2Margin[i]);
15568f699719SAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
15578f699719SAdrian Chadd 			      AR_PHY_GAIN_2GHZ_XATTEN2_DB,
15588f699719SAdrian Chadd 			      pModal->xatten2Db[i]);
15598f699719SAdrian Chadd 		} else {
1560b335ecffSAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
1561b335ecffSAdrian Chadd 			      AR_PHY_GAIN_2GHZ_BSW_MARGIN,
1562b335ecffSAdrian Chadd 			      pModal->bswMargin[i]);
1563b335ecffSAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
1564b335ecffSAdrian Chadd 			      AR_PHY_GAIN_2GHZ_BSW_ATTEN,
1565b335ecffSAdrian Chadd 			      pModal->bswAtten[i]);
15668f699719SAdrian Chadd 		}
15678f699719SAdrian Chadd 	}
15688f699719SAdrian Chadd 
156998cdd904SAdrian Chadd 	if (AR_SREV_MERLIN_10_OR_LATER(ah)) {
15708f699719SAdrian Chadd 		OS_REG_RMW_FIELD(ah,
15718f699719SAdrian Chadd 		      AR_PHY_RXGAIN + regChainOffset,
15728f699719SAdrian Chadd 		      AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
15738f699719SAdrian Chadd 		OS_REG_RMW_FIELD(ah,
15748f699719SAdrian Chadd 		      AR_PHY_RXGAIN + regChainOffset,
15758f699719SAdrian Chadd 		      AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]);
15768f699719SAdrian Chadd 	} else {
1577b335ecffSAdrian Chadd 		OS_REG_RMW_FIELD(ah,
15788f699719SAdrian Chadd 			  AR_PHY_RXGAIN + regChainOffset,
1579b335ecffSAdrian Chadd 			  AR_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
1580b335ecffSAdrian Chadd 		OS_REG_RMW_FIELD(ah,
15818f699719SAdrian Chadd 			  AR_PHY_GAIN_2GHZ + regChainOffset,
1582b335ecffSAdrian Chadd 			  AR_PHY_GAIN_2GHZ_RXTX_MARGIN, pModal->rxTxMarginCh[i]);
15838f699719SAdrian Chadd 	}
15848f699719SAdrian Chadd }
15858f699719SAdrian Chadd 
158648c1d364SAdrian Chadd /*
158748c1d364SAdrian Chadd  * Get the register chain offset for the given chain.
158848c1d364SAdrian Chadd  *
158948c1d364SAdrian Chadd  * Take into account the register chain swapping with AR5416 v2.0.
159048c1d364SAdrian Chadd  *
159148c1d364SAdrian Chadd  * XXX make sure that the reg chain swapping is only done for
159248c1d364SAdrian Chadd  * XXX AR5416 v2.0 or greater, and not later chips?
159348c1d364SAdrian Chadd  */
159448c1d364SAdrian Chadd int
ar5416GetRegChainOffset(struct ath_hal * ah,int i)159548c1d364SAdrian Chadd ar5416GetRegChainOffset(struct ath_hal *ah, int i)
159648c1d364SAdrian Chadd {
159748c1d364SAdrian Chadd 	int regChainOffset;
15988f699719SAdrian Chadd 
1599ef1901a3SAdrian Chadd 	if (AR_SREV_5416_V20_OR_LATER(ah) &&
160048c1d364SAdrian Chadd 	    (AH5416(ah)->ah_rx_chainmask == 0x5 ||
160148c1d364SAdrian Chadd 	    AH5416(ah)->ah_tx_chainmask == 0x5) && (i != 0)) {
160248c1d364SAdrian Chadd 		/* Regs are swapped from chain 2 to 1 for 5416 2_0 with
160348c1d364SAdrian Chadd 		 * only chains 0 and 2 populated
160448c1d364SAdrian Chadd 		 */
160548c1d364SAdrian Chadd 		regChainOffset = (i == 1) ? 0x2000 : 0x1000;
160648c1d364SAdrian Chadd 	} else {
160748c1d364SAdrian Chadd 		regChainOffset = i * 0x1000;
160848c1d364SAdrian Chadd 	}
160948c1d364SAdrian Chadd 
161048c1d364SAdrian Chadd 	return regChainOffset;
161148c1d364SAdrian Chadd }
16128f699719SAdrian Chadd 
161314779705SSam Leffler /*
161414779705SSam Leffler  * Read EEPROM header info and program the device for correct operation
161514779705SSam Leffler  * given the channel value.
161614779705SSam Leffler  */
16177d4f72b3SRui Paulo HAL_BOOL
ar5416SetBoardValues(struct ath_hal * ah,const struct ieee80211_channel * chan)161859efa8b5SSam Leffler ar5416SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan)
161914779705SSam Leffler {
162012fefae2SRui Paulo     const HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
162112fefae2SRui Paulo     const struct ar5416eeprom *eep = &ee->ee_base;
162214779705SSam Leffler     const MODAL_EEP_HEADER *pModal;
162312fefae2SRui Paulo     int			i, regChainOffset;
162414779705SSam Leffler     uint8_t		txRxAttenLocal;    /* workaround for eeprom versions <= 14.2 */
162514779705SSam Leffler 
162614779705SSam Leffler     HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);
162759efa8b5SSam Leffler     pModal = &eep->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)];
162814779705SSam Leffler 
162959efa8b5SSam Leffler     /* NB: workaround for eeprom versions <= 14.2 */
163059efa8b5SSam Leffler     txRxAttenLocal = IEEE80211_IS_CHAN_2GHZ(chan) ? 23 : 44;
163114779705SSam Leffler 
163212fefae2SRui Paulo     OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
163314779705SSam Leffler     for (i = 0; i < AR5416_MAX_CHAINS; i++) {
163412fefae2SRui Paulo 	   if (AR_SREV_MERLIN(ah)) {
163512fefae2SRui Paulo 		if (i >= 2) break;
163612fefae2SRui Paulo 	   }
163748c1d364SAdrian Chadd 	regChainOffset = ar5416GetRegChainOffset(ah, i);
163814779705SSam Leffler 
163912fefae2SRui Paulo         OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, pModal->antCtrlChain[i]);
16408f699719SAdrian Chadd 
164114779705SSam Leffler         OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4 + regChainOffset,
164214779705SSam Leffler         	(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4 + regChainOffset) &
164314779705SSam Leffler         	~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
164412fefae2SRui Paulo         	SM(pModal->iqCalICh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
164512fefae2SRui Paulo         	SM(pModal->iqCalQCh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
164614779705SSam Leffler 
164714779705SSam Leffler         /*
164898cdd904SAdrian Chadd          * Large signal upgrade,
164998cdd904SAdrian Chadd 	 * If 14.3 or later EEPROM, use
165098cdd904SAdrian Chadd 	 * txRxAttenLocal = pModal->txRxAttenCh[i]
165198cdd904SAdrian Chadd 	 * else txRxAttenLocal is fixed value above.
165214779705SSam Leffler          */
165314779705SSam Leffler 
1654ef1901a3SAdrian Chadd         if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah))
16558f699719SAdrian Chadd 	    ar5416SetDefGainValues(ah, pModal, eep, txRxAttenLocal, regChainOffset, i);
165614779705SSam Leffler     }
16578f699719SAdrian Chadd 
165898cdd904SAdrian Chadd 	if (AR_SREV_MERLIN_10_OR_LATER(ah)) {
16598f699719SAdrian Chadd                 if (IEEE80211_IS_CHAN_2GHZ(chan)) {
16608f699719SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_RF2G1_CH0, AR_AN_RF2G1_CH0_OB, pModal->ob);
16618f699719SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_RF2G1_CH0, AR_AN_RF2G1_CH0_DB, pModal->db);
16628f699719SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_RF2G1_CH1, AR_AN_RF2G1_CH1_OB, pModal->ob_ch1);
16638f699719SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_RF2G1_CH1, AR_AN_RF2G1_CH1_DB, pModal->db_ch1);
16648f699719SAdrian Chadd                 } else {
16658f699719SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_RF5G1_CH0, AR_AN_RF5G1_CH0_OB5, pModal->ob);
16668f699719SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_RF5G1_CH0, AR_AN_RF5G1_CH0_DB5, pModal->db);
16678f699719SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_RF5G1_CH1, AR_AN_RF5G1_CH1_OB5, pModal->ob_ch1);
16688f699719SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_RF5G1_CH1, AR_AN_RF5G1_CH1_DB5, pModal->db_ch1);
16698f699719SAdrian Chadd                 }
16708f699719SAdrian Chadd                 OS_A_REG_RMW_FIELD(ah, AR_AN_TOP2, AR_AN_TOP2_XPABIAS_LVL, pModal->xpaBiasLvl);
16710d07bcbaSAdrian Chadd                 OS_A_REG_RMW_FIELD(ah, AR_AN_TOP2, AR_AN_TOP2_LOCALBIAS,
16720d07bcbaSAdrian Chadd 		    !!(pModal->flagBits & AR5416_EEP_FLAG_LOCALBIAS));
16730d07bcbaSAdrian Chadd                 OS_A_REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
16740d07bcbaSAdrian Chadd 		    !!(pModal->flagBits & AR5416_EEP_FLAG_FORCEXPAON));
167521d18f0eSRui Paulo         }
167614779705SSam Leffler 
167712fefae2SRui Paulo     OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->switchSettling);
167812fefae2SRui Paulo     OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize);
16798f699719SAdrian Chadd 
168098cdd904SAdrian Chadd     if (! AR_SREV_MERLIN_10_OR_LATER(ah))
168112fefae2SRui Paulo     	OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_PGA, pModal->pgaDesiredSize);
16828f699719SAdrian Chadd 
168314779705SSam Leffler     OS_REG_WRITE(ah, AR_PHY_RF_CTL4,
168412fefae2SRui Paulo         SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
168512fefae2SRui Paulo         | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
168612fefae2SRui Paulo         | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)
168712fefae2SRui Paulo         | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
168814779705SSam Leffler 
168998cdd904SAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
169098cdd904SAdrian Chadd 	pModal->txEndToRxOn);
169114779705SSam Leffler 
169214779705SSam Leffler     if (AR_SREV_MERLIN_10_OR_LATER(ah)) {
169314779705SSam Leffler 	OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
169412fefae2SRui Paulo 	    pModal->thresh62);
169514779705SSam Leffler 	OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62,
169612fefae2SRui Paulo 	    pModal->thresh62);
169714779705SSam Leffler     } else {
169814779705SSam Leffler 	OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
169912fefae2SRui Paulo 	    pModal->thresh62);
1700fdb9c24cSAdrian Chadd 	OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CCA_THRESH62,
170112fefae2SRui Paulo 	    pModal->thresh62);
170214779705SSam Leffler     }
170314779705SSam Leffler 
170414779705SSam Leffler     /* Minor Version Specific application */
170514779705SSam Leffler     if (IS_EEP_MINOR_V2(ah)) {
170698cdd904SAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_DATA_START,
170798cdd904SAdrian Chadd 	    pModal->txFrameToDataStart);
170898cdd904SAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_PA_ON,
170998cdd904SAdrian Chadd 	    pModal->txFrameToPaOn);
171014779705SSam Leffler     }
171114779705SSam Leffler 
17128f699719SAdrian Chadd     if (IS_EEP_MINOR_V3(ah) && IEEE80211_IS_CHAN_HT40(chan))
171314779705SSam Leffler 		/* Overwrite switch settling with HT40 value */
171498cdd904SAdrian Chadd 		OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
171598cdd904SAdrian Chadd 		    pModal->swSettleHt40);
17168f699719SAdrian Chadd 
17178f699719SAdrian Chadd     if (AR_SREV_MERLIN_20_OR_LATER(ah) && EEP_MINOR(ah) >= AR5416_EEP_MINOR_VER_19)
17188f699719SAdrian Chadd          OS_REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, pModal->miscBits);
17198f699719SAdrian Chadd 
17208f699719SAdrian Chadd         if (AR_SREV_MERLIN_20(ah) && EEP_MINOR(ah) >= AR5416_EEP_MINOR_VER_20) {
17218f699719SAdrian Chadd                 if (IEEE80211_IS_CHAN_2GHZ(chan))
172298cdd904SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
172398cdd904SAdrian Chadd 			    eep->baseEepHeader.dacLpMode);
17248f699719SAdrian Chadd                 else if (eep->baseEepHeader.dacHiPwrMode_5G)
17258f699719SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0);
17268f699719SAdrian Chadd                 else
172798cdd904SAdrian Chadd                         OS_A_REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
172898cdd904SAdrian Chadd 			    eep->baseEepHeader.dacLpMode);
17298f699719SAdrian Chadd 
173098cdd904SAdrian Chadd 		OS_DELAY(100);
173198cdd904SAdrian Chadd 
173298cdd904SAdrian Chadd                 OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP,
173398cdd904SAdrian Chadd 		    pModal->miscBits >> 2);
173498cdd904SAdrian Chadd                 OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, AR_PHY_TX_DESIRED_SCALE_CCK,
173598cdd904SAdrian Chadd 		    eep->baseEepHeader.desiredScaleCCK);
173614779705SSam Leffler         }
173714779705SSam Leffler 
1738d780702eSAdrian Chadd     return (AH_TRUE);
173914779705SSam Leffler }
174014779705SSam Leffler 
174114779705SSam Leffler /*
174214779705SSam Leffler  * Helper functions common for AP/CB/XB
174314779705SSam Leffler  */
174414779705SSam Leffler 
174514779705SSam Leffler /*
17462f399d37SAdrian Chadd  * Set the target power array "ratesArray" from the
17472f399d37SAdrian Chadd  * given set of target powers.
17482f399d37SAdrian Chadd  *
17492f399d37SAdrian Chadd  * This is used by the various chipset/EEPROM TX power
17502f399d37SAdrian Chadd  * setup routines.
17512f399d37SAdrian Chadd  */
17522f399d37SAdrian Chadd void
ar5416SetRatesArrayFromTargetPower(struct ath_hal * ah,const struct ieee80211_channel * chan,int16_t * ratesArray,const CAL_TARGET_POWER_LEG * targetPowerCck,const CAL_TARGET_POWER_LEG * targetPowerCckExt,const CAL_TARGET_POWER_LEG * targetPowerOfdm,const CAL_TARGET_POWER_LEG * targetPowerOfdmExt,const CAL_TARGET_POWER_HT * targetPowerHt20,const CAL_TARGET_POWER_HT * targetPowerHt40)17532f399d37SAdrian Chadd ar5416SetRatesArrayFromTargetPower(struct ath_hal *ah,
17542f399d37SAdrian Chadd     const struct ieee80211_channel *chan,
17552f399d37SAdrian Chadd     int16_t *ratesArray,
17562f399d37SAdrian Chadd     const CAL_TARGET_POWER_LEG *targetPowerCck,
17572f399d37SAdrian Chadd     const CAL_TARGET_POWER_LEG *targetPowerCckExt,
17582f399d37SAdrian Chadd     const CAL_TARGET_POWER_LEG *targetPowerOfdm,
17592f399d37SAdrian Chadd     const CAL_TARGET_POWER_LEG *targetPowerOfdmExt,
17602f399d37SAdrian Chadd     const CAL_TARGET_POWER_HT *targetPowerHt20,
17612f399d37SAdrian Chadd     const CAL_TARGET_POWER_HT *targetPowerHt40)
17622f399d37SAdrian Chadd {
17632f399d37SAdrian Chadd #define	N(a)	(sizeof(a)/sizeof(a[0]))
17642f399d37SAdrian Chadd 	int i;
17652f399d37SAdrian Chadd 
17662f399d37SAdrian Chadd 	/* Blank the rates array, to be consistent */
17672f399d37SAdrian Chadd 	for (i = 0; i < Ar5416RateSize; i++)
17682f399d37SAdrian Chadd 		ratesArray[i] = 0;
17692f399d37SAdrian Chadd 
17702f399d37SAdrian Chadd 	/* Set rates Array from collected data */
17712f399d37SAdrian Chadd 	ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
1772d780702eSAdrian Chadd 	ratesArray[rate18mb] = ratesArray[rate24mb] =
1773d780702eSAdrian Chadd 	    targetPowerOfdm->tPow2x[0];
17742f399d37SAdrian Chadd 	ratesArray[rate36mb] = targetPowerOfdm->tPow2x[1];
17752f399d37SAdrian Chadd 	ratesArray[rate48mb] = targetPowerOfdm->tPow2x[2];
17762f399d37SAdrian Chadd 	ratesArray[rate54mb] = targetPowerOfdm->tPow2x[3];
17772f399d37SAdrian Chadd 	ratesArray[rateXr] = targetPowerOfdm->tPow2x[0];
17782f399d37SAdrian Chadd 
17792f399d37SAdrian Chadd 	for (i = 0; i < N(targetPowerHt20->tPow2x); i++) {
17802f399d37SAdrian Chadd 		ratesArray[rateHt20_0 + i] = targetPowerHt20->tPow2x[i];
17812f399d37SAdrian Chadd 	}
17822f399d37SAdrian Chadd 
17832f399d37SAdrian Chadd 	if (IEEE80211_IS_CHAN_2GHZ(chan)) {
17842f399d37SAdrian Chadd 		ratesArray[rate1l]  = targetPowerCck->tPow2x[0];
17852f399d37SAdrian Chadd 		ratesArray[rate2s] = ratesArray[rate2l]  = targetPowerCck->tPow2x[1];
17862f399d37SAdrian Chadd 		ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck->tPow2x[2];
17872f399d37SAdrian Chadd 		ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck->tPow2x[3];
17882f399d37SAdrian Chadd 	}
17892f399d37SAdrian Chadd 	if (IEEE80211_IS_CHAN_HT40(chan)) {
17902f399d37SAdrian Chadd 		for (i = 0; i < N(targetPowerHt40->tPow2x); i++) {
17912f399d37SAdrian Chadd 			ratesArray[rateHt40_0 + i] = targetPowerHt40->tPow2x[i];
17922f399d37SAdrian Chadd 		}
17932f399d37SAdrian Chadd 		ratesArray[rateDupOfdm] = targetPowerHt40->tPow2x[0];
17942f399d37SAdrian Chadd 		ratesArray[rateDupCck]  = targetPowerHt40->tPow2x[0];
17952f399d37SAdrian Chadd 		ratesArray[rateExtOfdm] = targetPowerOfdmExt->tPow2x[0];
17962f399d37SAdrian Chadd 		if (IEEE80211_IS_CHAN_2GHZ(chan)) {
17972f399d37SAdrian Chadd 			ratesArray[rateExtCck]  = targetPowerCckExt->tPow2x[0];
17982f399d37SAdrian Chadd 		}
17992f399d37SAdrian Chadd 	}
18002f399d37SAdrian Chadd #undef	N
18012f399d37SAdrian Chadd }
18022f399d37SAdrian Chadd 
18032f399d37SAdrian Chadd /*
180414779705SSam Leffler  * ar5416SetPowerPerRateTable
180514779705SSam Leffler  *
180614779705SSam Leffler  * Sets the transmit power in the baseband for the given
180714779705SSam Leffler  * operating channel and mode.
180814779705SSam Leffler  */
180912fefae2SRui Paulo static HAL_BOOL
ar5416SetPowerPerRateTable(struct ath_hal * ah,struct ar5416eeprom * pEepData,const struct ieee80211_channel * chan,int16_t * ratesArray,uint16_t cfgCtl,uint16_t AntennaReduction,uint16_t twiceMaxRegulatoryPower,uint16_t powerLimit)181014779705SSam Leffler ar5416SetPowerPerRateTable(struct ath_hal *ah, struct ar5416eeprom *pEepData,
181159efa8b5SSam Leffler                            const struct ieee80211_channel *chan,
181214779705SSam Leffler                            int16_t *ratesArray, uint16_t cfgCtl,
181314779705SSam Leffler                            uint16_t AntennaReduction,
181414779705SSam Leffler                            uint16_t twiceMaxRegulatoryPower,
181514779705SSam Leffler                            uint16_t powerLimit)
181614779705SSam Leffler {
181714779705SSam Leffler #define	N(a)	(sizeof(a)/sizeof(a[0]))
181814779705SSam Leffler /* Local defines to distinguish between extension and control CTL's */
181914779705SSam Leffler #define EXT_ADDITIVE (0x8000)
182014779705SSam Leffler #define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
182114779705SSam Leffler #define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
182214779705SSam Leffler #define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
182314779705SSam Leffler 
182414779705SSam Leffler 	uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
182514779705SSam Leffler 	int i;
182614779705SSam Leffler 	int16_t  twiceLargestAntenna;
182714779705SSam Leffler 	CAL_CTL_DATA *rep;
182814779705SSam Leffler 	CAL_TARGET_POWER_LEG targetPowerOfdm, targetPowerCck = {0, {0, 0, 0, 0}};
182914779705SSam Leffler 	CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}, targetPowerCckExt = {0, {0, 0, 0, 0}};
183014779705SSam Leffler 	CAL_TARGET_POWER_HT  targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0}};
183114779705SSam Leffler 	int16_t scaledPower, minCtlPower;
183214779705SSam Leffler 
183314779705SSam Leffler #define SUB_NUM_CTL_MODES_AT_5G_40 2   /* excluding HT40, EXT-OFDM */
183414779705SSam Leffler #define SUB_NUM_CTL_MODES_AT_2G_40 3   /* excluding HT40, EXT-OFDM, EXT-CCK */
183514779705SSam Leffler 	static const uint16_t ctlModesFor11a[] = {
183614779705SSam Leffler 	   CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
183714779705SSam Leffler 	};
183814779705SSam Leffler 	static const uint16_t ctlModesFor11g[] = {
183914779705SSam Leffler 	   CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
184014779705SSam Leffler 	};
184114779705SSam Leffler 	const uint16_t *pCtlMode;
184214779705SSam Leffler 	uint16_t numCtlModes, ctlMode, freq;
184314779705SSam Leffler 	CHAN_CENTERS centers;
184414779705SSam Leffler 
184514779705SSam Leffler 	ar5416GetChannelCenters(ah,  chan, &centers);
184614779705SSam Leffler 
184714779705SSam Leffler 	/* Compute TxPower reduction due to Antenna Gain */
184814779705SSam Leffler 
184959efa8b5SSam Leffler 	twiceLargestAntenna = AH_MAX(AH_MAX(
185059efa8b5SSam Leffler 	    pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[0],
185159efa8b5SSam Leffler 	    pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[1]),
185259efa8b5SSam Leffler 	    pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
185314779705SSam Leffler #if 0
185414779705SSam Leffler 	/* Turn it back on if we need to calculate per chain antenna gain reduction */
185514779705SSam Leffler 	/* Use only if the expected gain > 6dbi */
185614779705SSam Leffler 	/* Chain 0 is always used */
185759efa8b5SSam Leffler 	twiceLargestAntenna = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[0];
185814779705SSam Leffler 
185914779705SSam Leffler 	/* Look at antenna gains of Chains 1 and 2 if the TX mask is set */
186014779705SSam Leffler 	if (ahp->ah_tx_chainmask & 0x2)
186114779705SSam Leffler 		twiceLargestAntenna = AH_MAX(twiceLargestAntenna,
186259efa8b5SSam Leffler 			pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
186314779705SSam Leffler 
186414779705SSam Leffler 	if (ahp->ah_tx_chainmask & 0x4)
186514779705SSam Leffler 		twiceLargestAntenna = AH_MAX(twiceLargestAntenna,
186659efa8b5SSam Leffler 			pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
186714779705SSam Leffler #endif
186814779705SSam Leffler 	twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0);
186914779705SSam Leffler 
187014779705SSam Leffler 	/* XXX setup for 5212 use (really used?) */
187114779705SSam Leffler 	ath_hal_eepromSet(ah,
187259efa8b5SSam Leffler 	    IEEE80211_IS_CHAN_2GHZ(chan) ? AR_EEP_ANTGAINMAX_2 : AR_EEP_ANTGAINMAX_5,
187314779705SSam Leffler 	    twiceLargestAntenna);
187414779705SSam Leffler 
187514779705SSam Leffler 	/*
187614779705SSam Leffler 	 * scaledPower is the minimum of the user input power level and
187714779705SSam Leffler 	 * the regulatory allowed power level
187814779705SSam Leffler 	 */
187914779705SSam Leffler 	scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna);
188014779705SSam Leffler 
188114779705SSam Leffler 	/* Reduce scaled Power by number of chains active to get to per chain tx power level */
188214779705SSam Leffler 	/* TODO: better value than these? */
188314779705SSam Leffler 	switch (owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask)) {
188414779705SSam Leffler 	case 1:
188514779705SSam Leffler 		break;
188614779705SSam Leffler 	case 2:
188759efa8b5SSam Leffler 		scaledPower -= pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pwrDecreaseFor2Chain;
188814779705SSam Leffler 		break;
188914779705SSam Leffler 	case 3:
189059efa8b5SSam Leffler 		scaledPower -= pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pwrDecreaseFor3Chain;
189114779705SSam Leffler 		break;
189214779705SSam Leffler 	default:
189314779705SSam Leffler 		return AH_FALSE; /* Unsupported number of chains */
189414779705SSam Leffler 	}
189514779705SSam Leffler 
189614779705SSam Leffler 	scaledPower = AH_MAX(0, scaledPower);
189714779705SSam Leffler 
189814779705SSam Leffler 	/* Get target powers from EEPROM - our baseline for TX Power */
189959efa8b5SSam Leffler 	if (IEEE80211_IS_CHAN_2GHZ(chan)) {
190014779705SSam Leffler 		/* Setup for CTL modes */
190114779705SSam Leffler 		numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */
190214779705SSam Leffler 		pCtlMode = ctlModesFor11g;
190314779705SSam Leffler 
190412fefae2SRui Paulo 		ar5416GetTargetPowersLeg(ah,  chan, pEepData->calTargetPowerCck,
190512fefae2SRui Paulo 				AR5416_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE);
190612fefae2SRui Paulo 		ar5416GetTargetPowersLeg(ah,  chan, pEepData->calTargetPower2G,
190712fefae2SRui Paulo 				AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE);
190812fefae2SRui Paulo 		ar5416GetTargetPowers(ah,  chan, pEepData->calTargetPower2GHT20,
190912fefae2SRui Paulo 				AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE);
191014779705SSam Leffler 
191159efa8b5SSam Leffler 		if (IEEE80211_IS_CHAN_HT40(chan)) {
191214779705SSam Leffler 			numCtlModes = N(ctlModesFor11g);    /* All 2G CTL's */
191314779705SSam Leffler 
191412fefae2SRui Paulo 			ar5416GetTargetPowers(ah,  chan, pEepData->calTargetPower2GHT40,
191512fefae2SRui Paulo 				AR5416_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE);
191614779705SSam Leffler 			/* Get target powers for extension channels */
191712fefae2SRui Paulo 			ar5416GetTargetPowersLeg(ah,  chan, pEepData->calTargetPowerCck,
191812fefae2SRui Paulo 				AR5416_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE);
191912fefae2SRui Paulo 			ar5416GetTargetPowersLeg(ah,  chan, pEepData->calTargetPower2G,
192012fefae2SRui Paulo 				AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE);
192114779705SSam Leffler 		}
192214779705SSam Leffler 	} else {
192314779705SSam Leffler 		/* Setup for CTL modes */
192414779705SSam Leffler 		numCtlModes = N(ctlModesFor11a) - SUB_NUM_CTL_MODES_AT_5G_40; /* CTL_11A, CTL_5GHT20 */
192514779705SSam Leffler 		pCtlMode = ctlModesFor11a;
192614779705SSam Leffler 
192714779705SSam Leffler 		ar5416GetTargetPowersLeg(ah,  chan, pEepData->calTargetPower5G,
192814779705SSam Leffler 				AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE);
192914779705SSam Leffler 		ar5416GetTargetPowers(ah,  chan, pEepData->calTargetPower5GHT20,
193014779705SSam Leffler 				AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE);
193114779705SSam Leffler 
193259efa8b5SSam Leffler 		if (IEEE80211_IS_CHAN_HT40(chan)) {
193314779705SSam Leffler 			numCtlModes = N(ctlModesFor11a); /* All 5G CTL's */
193414779705SSam Leffler 
193514779705SSam Leffler 			ar5416GetTargetPowers(ah,  chan, pEepData->calTargetPower5GHT40,
193614779705SSam Leffler 				AR5416_NUM_5G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE);
193714779705SSam Leffler 			ar5416GetTargetPowersLeg(ah,  chan, pEepData->calTargetPower5G,
193814779705SSam Leffler 				AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE);
193914779705SSam Leffler 		}
194014779705SSam Leffler 	}
194114779705SSam Leffler 
194214779705SSam Leffler 	/*
194314779705SSam Leffler 	 * For MIMO, need to apply regulatory caps individually across dynamically
194414779705SSam Leffler 	 * running modes: CCK, OFDM, HT20, HT40
194514779705SSam Leffler 	 *
194614779705SSam Leffler 	 * The outer loop walks through each possible applicable runtime mode.
194714779705SSam Leffler 	 * The inner loop walks through each ctlIndex entry in EEPROM.
194814779705SSam Leffler 	 * The ctl value is encoded as [7:4] == test group, [3:0] == test mode.
194914779705SSam Leffler 	 *
195014779705SSam Leffler 	 */
195114779705SSam Leffler 	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
195214779705SSam Leffler 		HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
195314779705SSam Leffler 		    (pCtlMode[ctlMode] == CTL_2GHT40);
195414779705SSam Leffler 		if (isHt40CtlMode) {
195514779705SSam Leffler 			freq = centers.ctl_center;
195614779705SSam Leffler 		} else if (pCtlMode[ctlMode] & EXT_ADDITIVE) {
195714779705SSam Leffler 			freq = centers.ext_center;
195814779705SSam Leffler 		} else {
195914779705SSam Leffler 			freq = centers.ctl_center;
196014779705SSam Leffler 		}
196114779705SSam Leffler 
196214779705SSam Leffler 		/* walk through each CTL index stored in EEPROM */
196312fefae2SRui Paulo 		for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
196414779705SSam Leffler 			uint16_t twiceMinEdgePower;
196514779705SSam Leffler 
196614779705SSam Leffler 			/* compare test group from regulatory channel list with test mode from pCtlMode list */
196712fefae2SRui Paulo 			if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) ||
196814779705SSam Leffler 				(((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) ==
196912fefae2SRui Paulo 				 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
197014779705SSam Leffler 				rep = &(pEepData->ctlData[i]);
197112fefae2SRui Paulo 				twiceMinEdgePower = ar5416GetMaxEdgePower(freq,
197212fefae2SRui Paulo 							rep->ctlEdges[owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1],
197359efa8b5SSam Leffler 							IEEE80211_IS_CHAN_2GHZ(chan));
197414779705SSam Leffler 				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
197514779705SSam Leffler 					/* Find the minimum of all CTL edge powers that apply to this channel */
197614779705SSam Leffler 					twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower);
197714779705SSam Leffler 				} else {
197814779705SSam Leffler 					/* specific */
197914779705SSam Leffler 					twiceMaxEdgePower = twiceMinEdgePower;
198014779705SSam Leffler 					break;
198114779705SSam Leffler 				}
198214779705SSam Leffler 			}
198314779705SSam Leffler 		}
198414779705SSam Leffler 		minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower);
198514779705SSam Leffler 		/* Apply ctl mode to correct target power set */
198614779705SSam Leffler 		switch(pCtlMode[ctlMode]) {
198714779705SSam Leffler 		case CTL_11B:
198814779705SSam Leffler 			for (i = 0; i < N(targetPowerCck.tPow2x); i++) {
198914779705SSam Leffler 				targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower);
199014779705SSam Leffler 			}
199114779705SSam Leffler 			break;
199214779705SSam Leffler 		case CTL_11A:
199314779705SSam Leffler 		case CTL_11G:
199414779705SSam Leffler 			for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) {
199514779705SSam Leffler 				targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower);
199614779705SSam Leffler 			}
199714779705SSam Leffler 			break;
199814779705SSam Leffler 		case CTL_5GHT20:
199914779705SSam Leffler 		case CTL_2GHT20:
200014779705SSam Leffler 			for (i = 0; i < N(targetPowerHt20.tPow2x); i++) {
200114779705SSam Leffler 				targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower);
200214779705SSam Leffler 			}
200314779705SSam Leffler 			break;
200414779705SSam Leffler 		case CTL_11B_EXT:
200514779705SSam Leffler 			targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower);
200614779705SSam Leffler 			break;
200714779705SSam Leffler 		case CTL_11A_EXT:
200814779705SSam Leffler 		case CTL_11G_EXT:
200914779705SSam Leffler 			targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower);
201014779705SSam Leffler 			break;
201114779705SSam Leffler 		case CTL_5GHT40:
201214779705SSam Leffler 		case CTL_2GHT40:
201314779705SSam Leffler 			for (i = 0; i < N(targetPowerHt40.tPow2x); i++) {
201414779705SSam Leffler 				targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower);
201514779705SSam Leffler 			}
201614779705SSam Leffler 			break;
201714779705SSam Leffler 		default:
201814779705SSam Leffler 			return AH_FALSE;
201914779705SSam Leffler 			break;
202014779705SSam Leffler 		}
202114779705SSam Leffler 	} /* end ctl mode checking */
202214779705SSam Leffler 
202314779705SSam Leffler 	/* Set rates Array from collected data */
20242f399d37SAdrian Chadd 	ar5416SetRatesArrayFromTargetPower(ah, chan, ratesArray,
20252f399d37SAdrian Chadd 	    &targetPowerCck,
20262f399d37SAdrian Chadd 	    &targetPowerCckExt,
20272f399d37SAdrian Chadd 	    &targetPowerOfdm,
20282f399d37SAdrian Chadd 	    &targetPowerOfdmExt,
20292f399d37SAdrian Chadd 	    &targetPowerHt20,
20302f399d37SAdrian Chadd 	    &targetPowerHt40);
203114779705SSam Leffler 	return AH_TRUE;
203214779705SSam Leffler #undef EXT_ADDITIVE
203314779705SSam Leffler #undef CTL_11A_EXT
203414779705SSam Leffler #undef CTL_11G_EXT
203514779705SSam Leffler #undef CTL_11B_EXT
203614779705SSam Leffler #undef SUB_NUM_CTL_MODES_AT_5G_40
203714779705SSam Leffler #undef SUB_NUM_CTL_MODES_AT_2G_40
203814779705SSam Leffler #undef N
203914779705SSam Leffler }
204014779705SSam Leffler 
204114779705SSam Leffler /**************************************************************************
204214779705SSam Leffler  * fbin2freq
204314779705SSam Leffler  *
204414779705SSam Leffler  * Get channel value from binary representation held in eeprom
204514779705SSam Leffler  * RETURNS: the frequency in MHz
204614779705SSam Leffler  */
204714779705SSam Leffler static uint16_t
fbin2freq(uint8_t fbin,HAL_BOOL is2GHz)204814779705SSam Leffler fbin2freq(uint8_t fbin, HAL_BOOL is2GHz)
204914779705SSam Leffler {
205014779705SSam Leffler     /*
205114779705SSam Leffler      * Reserved value 0xFF provides an empty definition both as
205214779705SSam Leffler      * an fbin and as a frequency - do not convert
205314779705SSam Leffler      */
205414779705SSam Leffler     if (fbin == AR5416_BCHAN_UNUSED) {
205514779705SSam Leffler         return fbin;
205614779705SSam Leffler     }
205714779705SSam Leffler 
205814779705SSam Leffler     return (uint16_t)((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
205914779705SSam Leffler }
206014779705SSam Leffler 
206114779705SSam Leffler /*
206214779705SSam Leffler  * ar5416GetMaxEdgePower
206314779705SSam Leffler  *
206414779705SSam Leffler  * Find the maximum conformance test limit for the given channel and CTL info
206514779705SSam Leffler  */
206618a3a330SAdrian Chadd uint16_t
ar5416GetMaxEdgePower(uint16_t freq,CAL_CTL_EDGES * pRdEdgesPower,HAL_BOOL is2GHz)206712fefae2SRui Paulo ar5416GetMaxEdgePower(uint16_t freq, CAL_CTL_EDGES *pRdEdgesPower, HAL_BOOL is2GHz)
206814779705SSam Leffler {
206914779705SSam Leffler     uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
207012fefae2SRui Paulo     int      i;
207114779705SSam Leffler 
207214779705SSam Leffler     /* Get the edge power */
207312fefae2SRui Paulo     for (i = 0; (i < AR5416_NUM_BAND_EDGES) && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED) ; i++) {
207414779705SSam Leffler         /*
207514779705SSam Leffler          * If there's an exact channel match or an inband flag set
207614779705SSam Leffler          * on the lower channel use the given rdEdgePower
207714779705SSam Leffler          */
207814779705SSam Leffler         if (freq == fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
207914779705SSam Leffler             twiceMaxEdgePower = MS(pRdEdgesPower[i].tPowerFlag, CAL_CTL_EDGES_POWER);
208014779705SSam Leffler             break;
208114779705SSam Leffler         } else if ((i > 0) && (freq < fbin2freq(pRdEdgesPower[i].bChannel, is2GHz))) {
208214779705SSam Leffler             if (fbin2freq(pRdEdgesPower[i - 1].bChannel, is2GHz) < freq && (pRdEdgesPower[i - 1].tPowerFlag & CAL_CTL_EDGES_FLAG) != 0) {
208314779705SSam Leffler                 twiceMaxEdgePower = MS(pRdEdgesPower[i - 1].tPowerFlag, CAL_CTL_EDGES_POWER);
208414779705SSam Leffler             }
208514779705SSam Leffler             /* Leave loop - no more affecting edges possible in this monotonic increasing list */
208614779705SSam Leffler             break;
208714779705SSam Leffler         }
208814779705SSam Leffler     }
208914779705SSam Leffler     HALASSERT(twiceMaxEdgePower > 0);
209014779705SSam Leffler     return twiceMaxEdgePower;
209114779705SSam Leffler }
209214779705SSam Leffler 
209314779705SSam Leffler /**************************************************************
209414779705SSam Leffler  * ar5416GetTargetPowers
209514779705SSam Leffler  *
209614779705SSam Leffler  * Return the rates of target power for the given target power table
209714779705SSam Leffler  * channel, and number of channels
209814779705SSam Leffler  */
20997d4f72b3SRui Paulo void
ar5416GetTargetPowers(struct ath_hal * ah,const struct ieee80211_channel * chan,CAL_TARGET_POWER_HT * powInfo,uint16_t numChannels,CAL_TARGET_POWER_HT * pNewPower,uint16_t numRates,HAL_BOOL isHt40Target)210059efa8b5SSam Leffler ar5416GetTargetPowers(struct ath_hal *ah,  const struct ieee80211_channel *chan,
210114779705SSam Leffler                       CAL_TARGET_POWER_HT *powInfo, uint16_t numChannels,
210214779705SSam Leffler                       CAL_TARGET_POWER_HT *pNewPower, uint16_t numRates,
210314779705SSam Leffler                       HAL_BOOL isHt40Target)
210414779705SSam Leffler {
210514779705SSam Leffler     uint16_t clo, chi;
210614779705SSam Leffler     int i;
210714779705SSam Leffler     int matchIndex = -1, lowIndex = -1;
210814779705SSam Leffler     uint16_t freq;
210914779705SSam Leffler     CHAN_CENTERS centers;
211014779705SSam Leffler 
211114779705SSam Leffler     ar5416GetChannelCenters(ah,  chan, &centers);
211214779705SSam Leffler     freq = isHt40Target ? centers.synth_center : centers.ctl_center;
211314779705SSam Leffler 
211414779705SSam Leffler     /* Copy the target powers into the temp channel list */
211559efa8b5SSam Leffler     if (freq <= fbin2freq(powInfo[0].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) {
211614779705SSam Leffler         matchIndex = 0;
211714779705SSam Leffler     } else {
211814779705SSam Leffler         for (i = 0; (i < numChannels) && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
211959efa8b5SSam Leffler             if (freq == fbin2freq(powInfo[i].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) {
212014779705SSam Leffler                 matchIndex = i;
212114779705SSam Leffler                 break;
212259efa8b5SSam Leffler             } else if ((freq < fbin2freq(powInfo[i].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) &&
212359efa8b5SSam Leffler                        (freq > fbin2freq(powInfo[i - 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))))
212414779705SSam Leffler             {
212514779705SSam Leffler                 lowIndex = i - 1;
212614779705SSam Leffler                 break;
212714779705SSam Leffler             }
212814779705SSam Leffler         }
212914779705SSam Leffler         if ((matchIndex == -1) && (lowIndex == -1)) {
213059efa8b5SSam Leffler             HALASSERT(freq > fbin2freq(powInfo[i - 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan)));
213114779705SSam Leffler             matchIndex = i - 1;
213214779705SSam Leffler         }
213314779705SSam Leffler     }
213414779705SSam Leffler 
213514779705SSam Leffler     if (matchIndex != -1) {
213614779705SSam Leffler         OS_MEMCPY(pNewPower, &powInfo[matchIndex], sizeof(*pNewPower));
213714779705SSam Leffler     } else {
213814779705SSam Leffler         HALASSERT(lowIndex != -1);
213914779705SSam Leffler         /*
214014779705SSam Leffler          * Get the lower and upper channels, target powers,
214114779705SSam Leffler          * and interpolate between them.
214214779705SSam Leffler          */
214359efa8b5SSam Leffler         clo = fbin2freq(powInfo[lowIndex].bChannel, IEEE80211_IS_CHAN_2GHZ(chan));
214459efa8b5SSam Leffler         chi = fbin2freq(powInfo[lowIndex + 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan));
214514779705SSam Leffler 
214614779705SSam Leffler         for (i = 0; i < numRates; i++) {
21476ff1b2bdSAdrian Chadd             pNewPower->tPow2x[i] = (uint8_t)ath_ee_interpolate(freq, clo, chi,
214814779705SSam Leffler                                    powInfo[lowIndex].tPow2x[i], powInfo[lowIndex + 1].tPow2x[i]);
214914779705SSam Leffler         }
215014779705SSam Leffler     }
215114779705SSam Leffler }
215214779705SSam Leffler /**************************************************************
215314779705SSam Leffler  * ar5416GetTargetPowersLeg
215414779705SSam Leffler  *
215514779705SSam Leffler  * Return the four rates of target power for the given target power table
215614779705SSam Leffler  * channel, and number of channels
215714779705SSam Leffler  */
21587d4f72b3SRui Paulo void
ar5416GetTargetPowersLeg(struct ath_hal * ah,const struct ieee80211_channel * chan,CAL_TARGET_POWER_LEG * powInfo,uint16_t numChannels,CAL_TARGET_POWER_LEG * pNewPower,uint16_t numRates,HAL_BOOL isExtTarget)215914779705SSam Leffler ar5416GetTargetPowersLeg(struct ath_hal *ah,
216059efa8b5SSam Leffler                          const struct ieee80211_channel *chan,
216114779705SSam Leffler                          CAL_TARGET_POWER_LEG *powInfo, uint16_t numChannels,
216214779705SSam Leffler                          CAL_TARGET_POWER_LEG *pNewPower, uint16_t numRates,
216314779705SSam Leffler 			 HAL_BOOL isExtTarget)
216414779705SSam Leffler {
216514779705SSam Leffler     uint16_t clo, chi;
216614779705SSam Leffler     int i;
216714779705SSam Leffler     int matchIndex = -1, lowIndex = -1;
216814779705SSam Leffler     uint16_t freq;
216914779705SSam Leffler     CHAN_CENTERS centers;
217014779705SSam Leffler 
217114779705SSam Leffler     ar5416GetChannelCenters(ah,  chan, &centers);
217214779705SSam Leffler     freq = (isExtTarget) ? centers.ext_center :centers.ctl_center;
217314779705SSam Leffler 
217414779705SSam Leffler     /* Copy the target powers into the temp channel list */
217559efa8b5SSam Leffler     if (freq <= fbin2freq(powInfo[0].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) {
217614779705SSam Leffler         matchIndex = 0;
217714779705SSam Leffler     } else {
217814779705SSam Leffler         for (i = 0; (i < numChannels) && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
217959efa8b5SSam Leffler             if (freq == fbin2freq(powInfo[i].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) {
218014779705SSam Leffler                 matchIndex = i;
218114779705SSam Leffler                 break;
218259efa8b5SSam Leffler             } else if ((freq < fbin2freq(powInfo[i].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) &&
218359efa8b5SSam Leffler                        (freq > fbin2freq(powInfo[i - 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))))
218414779705SSam Leffler             {
218514779705SSam Leffler                 lowIndex = i - 1;
218614779705SSam Leffler                 break;
218714779705SSam Leffler             }
218814779705SSam Leffler         }
218914779705SSam Leffler         if ((matchIndex == -1) && (lowIndex == -1)) {
219059efa8b5SSam Leffler             HALASSERT(freq > fbin2freq(powInfo[i - 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan)));
219114779705SSam Leffler             matchIndex = i - 1;
219214779705SSam Leffler         }
219314779705SSam Leffler     }
219414779705SSam Leffler 
219514779705SSam Leffler     if (matchIndex != -1) {
219614779705SSam Leffler         OS_MEMCPY(pNewPower, &powInfo[matchIndex], sizeof(*pNewPower));
219714779705SSam Leffler     } else {
219814779705SSam Leffler         HALASSERT(lowIndex != -1);
219914779705SSam Leffler         /*
220014779705SSam Leffler          * Get the lower and upper channels, target powers,
220114779705SSam Leffler          * and interpolate between them.
220214779705SSam Leffler          */
220359efa8b5SSam Leffler         clo = fbin2freq(powInfo[lowIndex].bChannel, IEEE80211_IS_CHAN_2GHZ(chan));
220459efa8b5SSam Leffler         chi = fbin2freq(powInfo[lowIndex + 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan));
220514779705SSam Leffler 
220614779705SSam Leffler         for (i = 0; i < numRates; i++) {
22076ff1b2bdSAdrian Chadd             pNewPower->tPow2x[i] = (uint8_t)ath_ee_interpolate(freq, clo, chi,
220814779705SSam Leffler                                    powInfo[lowIndex].tPow2x[i], powInfo[lowIndex + 1].tPow2x[i]);
220914779705SSam Leffler         }
221014779705SSam Leffler     }
221114779705SSam Leffler }
221214779705SSam Leffler 
221348c1d364SAdrian Chadd /*
221448c1d364SAdrian Chadd  * Set the gain boundaries for the given radio chain.
221548c1d364SAdrian Chadd  *
221648c1d364SAdrian Chadd  * The gain boundaries tell the hardware at what point in the
221748c1d364SAdrian Chadd  * PDADC array to "switch over" from one PD gain setting
221848c1d364SAdrian Chadd  * to another. There's also a gain overlap between two
221948c1d364SAdrian Chadd  * PDADC array gain curves where there's valid PD values
222048c1d364SAdrian Chadd  * for 2 gain settings.
222148c1d364SAdrian Chadd  *
222248c1d364SAdrian Chadd  * The hardware uses the gain overlap and gain boundaries
222348c1d364SAdrian Chadd  * to determine which gain curve to use for the given
222448c1d364SAdrian Chadd  * target TX power.
222548c1d364SAdrian Chadd  */
222648c1d364SAdrian Chadd void
ar5416SetGainBoundariesClosedLoop(struct ath_hal * ah,int i,uint16_t pdGainOverlap_t2,uint16_t gainBoundaries[])2227b90b8dd2SAdrian Chadd ar5416SetGainBoundariesClosedLoop(struct ath_hal *ah, int i,
222848c1d364SAdrian Chadd     uint16_t pdGainOverlap_t2, uint16_t gainBoundaries[])
222948c1d364SAdrian Chadd {
2230b90b8dd2SAdrian Chadd 	int regChainOffset;
2231b90b8dd2SAdrian Chadd 
2232b90b8dd2SAdrian Chadd 	regChainOffset = ar5416GetRegChainOffset(ah, i);
2233b90b8dd2SAdrian Chadd 
2234b90b8dd2SAdrian Chadd 	HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: chain %d: gainOverlap_t2: %d,"
2235b90b8dd2SAdrian Chadd 	    " gainBoundaries: %d, %d, %d, %d\n", __func__, i, pdGainOverlap_t2,
2236b90b8dd2SAdrian Chadd 	    gainBoundaries[0], gainBoundaries[1], gainBoundaries[2],
2237b90b8dd2SAdrian Chadd 	    gainBoundaries[3]);
223848c1d364SAdrian Chadd 	OS_REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
223948c1d364SAdrian Chadd 	    SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
224048c1d364SAdrian Chadd 	    SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)  |
224148c1d364SAdrian Chadd 	    SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)  |
224248c1d364SAdrian Chadd 	    SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)  |
224348c1d364SAdrian Chadd 	    SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
224448c1d364SAdrian Chadd }
224548c1d364SAdrian Chadd 
224648c1d364SAdrian Chadd /*
224748c1d364SAdrian Chadd  * Get the gain values and the number of gain levels given
224848c1d364SAdrian Chadd  * in xpdMask.
224948c1d364SAdrian Chadd  *
225048c1d364SAdrian Chadd  * The EEPROM xpdMask determines which power detector gain
225148c1d364SAdrian Chadd  * levels were used during calibration. Each of these mask
225248c1d364SAdrian Chadd  * bits maps to a fixed gain level in hardware.
225348c1d364SAdrian Chadd  */
225448c1d364SAdrian Chadd uint16_t
ar5416GetXpdGainValues(struct ath_hal * ah,uint16_t xpdMask,uint16_t xpdGainValues[])225548c1d364SAdrian Chadd ar5416GetXpdGainValues(struct ath_hal *ah, uint16_t xpdMask,
225648c1d364SAdrian Chadd     uint16_t xpdGainValues[])
225748c1d364SAdrian Chadd {
225848c1d364SAdrian Chadd     int i;
225948c1d364SAdrian Chadd     uint16_t numXpdGain = 0;
226048c1d364SAdrian Chadd 
226148c1d364SAdrian Chadd     for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
226248c1d364SAdrian Chadd         if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
226348c1d364SAdrian Chadd             if (numXpdGain >= AR5416_NUM_PD_GAINS) {
226448c1d364SAdrian Chadd                 HALASSERT(0);
226548c1d364SAdrian Chadd                 break;
226648c1d364SAdrian Chadd             }
226748c1d364SAdrian Chadd             xpdGainValues[numXpdGain] = (uint16_t)(AR5416_PD_GAINS_IN_MASK - i);
226848c1d364SAdrian Chadd             numXpdGain++;
226948c1d364SAdrian Chadd         }
227048c1d364SAdrian Chadd     }
227148c1d364SAdrian Chadd     return numXpdGain;
227248c1d364SAdrian Chadd }
227348c1d364SAdrian Chadd 
227448c1d364SAdrian Chadd /*
227548c1d364SAdrian Chadd  * Write the detector gain and biases.
227648c1d364SAdrian Chadd  *
227748c1d364SAdrian Chadd  * There are four power detector gain levels. The xpdMask in the EEPROM
227848c1d364SAdrian Chadd  * determines which power detector gain levels have TX power calibration
227948c1d364SAdrian Chadd  * data associated with them. This function writes the number of
228048c1d364SAdrian Chadd  * PD gain levels and their values into the hardware.
228148c1d364SAdrian Chadd  *
228248c1d364SAdrian Chadd  * This is valid for all TX chains - the calibration data itself however
228348c1d364SAdrian Chadd  * will likely differ per-chain.
228448c1d364SAdrian Chadd  */
228548c1d364SAdrian Chadd void
ar5416WriteDetectorGainBiases(struct ath_hal * ah,uint16_t numXpdGain,uint16_t xpdGainValues[])228648c1d364SAdrian Chadd ar5416WriteDetectorGainBiases(struct ath_hal *ah, uint16_t numXpdGain,
228748c1d364SAdrian Chadd     uint16_t xpdGainValues[])
228848c1d364SAdrian Chadd {
2289b90b8dd2SAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: numXpdGain: %d,"
2290b90b8dd2SAdrian Chadd       " xpdGainValues: %d, %d, %d\n", __func__, numXpdGain,
2291b90b8dd2SAdrian Chadd       xpdGainValues[0], xpdGainValues[1], xpdGainValues[2]);
2292b90b8dd2SAdrian Chadd 
229348c1d364SAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_TPCRG1, (OS_REG_READ(ah, AR_PHY_TPCRG1) &
229448c1d364SAdrian Chadd     	~(AR_PHY_TPCRG1_NUM_PD_GAIN | AR_PHY_TPCRG1_PD_GAIN_1 |
229548c1d364SAdrian Chadd 	AR_PHY_TPCRG1_PD_GAIN_2 | AR_PHY_TPCRG1_PD_GAIN_3)) |
229648c1d364SAdrian Chadd 	SM(numXpdGain - 1, AR_PHY_TPCRG1_NUM_PD_GAIN) |
229748c1d364SAdrian Chadd 	SM(xpdGainValues[0], AR_PHY_TPCRG1_PD_GAIN_1 ) |
229848c1d364SAdrian Chadd 	SM(xpdGainValues[1], AR_PHY_TPCRG1_PD_GAIN_2) |
229948c1d364SAdrian Chadd 	SM(xpdGainValues[2],  AR_PHY_TPCRG1_PD_GAIN_3));
230048c1d364SAdrian Chadd }
230148c1d364SAdrian Chadd 
230248c1d364SAdrian Chadd /*
2303b90b8dd2SAdrian Chadd  * Write the PDADC array to the given radio chain i.
230448c1d364SAdrian Chadd  *
230548c1d364SAdrian Chadd  * The 32 PDADC registers are written without any care about
230648c1d364SAdrian Chadd  * their contents - so if various chips treat values as "special",
230748c1d364SAdrian Chadd  * this routine will not care.
230848c1d364SAdrian Chadd  */
230948c1d364SAdrian Chadd void
ar5416WritePdadcValues(struct ath_hal * ah,int i,uint8_t pdadcValues[])2310b90b8dd2SAdrian Chadd ar5416WritePdadcValues(struct ath_hal *ah, int i, uint8_t pdadcValues[])
231148c1d364SAdrian Chadd {
2312b90b8dd2SAdrian Chadd 	int regOffset, regChainOffset;
231348c1d364SAdrian Chadd 	int j;
231448c1d364SAdrian Chadd 	int reg32;
231548c1d364SAdrian Chadd 
2316b90b8dd2SAdrian Chadd 	regChainOffset = ar5416GetRegChainOffset(ah, i);
231748c1d364SAdrian Chadd 	regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
231848c1d364SAdrian Chadd 
231948c1d364SAdrian Chadd 	for (j = 0; j < 32; j++) {
232048c1d364SAdrian Chadd 		reg32 = ((pdadcValues[4*j + 0] & 0xFF) << 0)  |
232148c1d364SAdrian Chadd 		    ((pdadcValues[4*j + 1] & 0xFF) << 8)  |
232248c1d364SAdrian Chadd 		    ((pdadcValues[4*j + 2] & 0xFF) << 16) |
232348c1d364SAdrian Chadd 		    ((pdadcValues[4*j + 3] & 0xFF) << 24) ;
232448c1d364SAdrian Chadd 		OS_REG_WRITE(ah, regOffset, reg32);
2325b90b8dd2SAdrian Chadd 		HALDEBUG(ah, HAL_DEBUG_EEPROM, "PDADC: Chain %d |"
232648c1d364SAdrian Chadd 		    " PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d"
2327b90b8dd2SAdrian Chadd 		    " Value %3d | PDADC %3d Value %3d |\n",
232848c1d364SAdrian Chadd 		    i,
232948c1d364SAdrian Chadd 		    4*j, pdadcValues[4*j],
233048c1d364SAdrian Chadd 		    4*j+1, pdadcValues[4*j + 1],
233148c1d364SAdrian Chadd 		    4*j+2, pdadcValues[4*j + 2],
233248c1d364SAdrian Chadd 		    4*j+3, pdadcValues[4*j + 3]);
233348c1d364SAdrian Chadd 		regOffset += 4;
233448c1d364SAdrian Chadd 	}
233548c1d364SAdrian Chadd }
233648c1d364SAdrian Chadd 
233714779705SSam Leffler /**************************************************************
233814779705SSam Leffler  * ar5416SetPowerCalTable
233914779705SSam Leffler  *
234014779705SSam Leffler  * Pull the PDADC piers from cal data and interpolate them across the given
234114779705SSam Leffler  * points as well as from the nearest pier(s) to get a power detector
234214779705SSam Leffler  * linear voltage to power level table.
234314779705SSam Leffler  */
234448c1d364SAdrian Chadd HAL_BOOL
ar5416SetPowerCalTable(struct ath_hal * ah,struct ar5416eeprom * pEepData,const struct ieee80211_channel * chan,int16_t * pTxPowerIndexOffset)234559efa8b5SSam Leffler ar5416SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom *pEepData,
234659efa8b5SSam Leffler 	const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset)
234714779705SSam Leffler {
234812fefae2SRui Paulo     CAL_DATA_PER_FREQ *pRawDataset;
234914779705SSam Leffler     uint8_t  *pCalBChans = AH_NULL;
235014779705SSam Leffler     uint16_t pdGainOverlap_t2;
235114779705SSam Leffler     static uint8_t  pdadcValues[AR5416_NUM_PDADC_VALUES];
235214779705SSam Leffler     uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK];
235348c1d364SAdrian Chadd     uint16_t numPiers, i;
235414779705SSam Leffler     int16_t  tMinCalPower;
235514779705SSam Leffler     uint16_t numXpdGain, xpdMask;
235614779705SSam Leffler     uint16_t xpdGainValues[AR5416_NUM_PD_GAINS];
235748c1d364SAdrian Chadd     uint32_t regChainOffset;
235814779705SSam Leffler 
2359b4307a77SSam Leffler     OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues));
236014779705SSam Leffler 
236159efa8b5SSam Leffler     xpdMask = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].xpdGain;
236214779705SSam Leffler 
236314779705SSam Leffler     if (IS_EEP_MINOR_V2(ah)) {
236459efa8b5SSam Leffler         pdGainOverlap_t2 = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pdGainOverlap;
236514779705SSam Leffler     } else {
236614779705SSam Leffler     	pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
236714779705SSam Leffler     }
236814779705SSam Leffler 
236959efa8b5SSam Leffler     if (IEEE80211_IS_CHAN_2GHZ(chan)) {
237014779705SSam Leffler         pCalBChans = pEepData->calFreqPier2G;
237114779705SSam Leffler         numPiers = AR5416_NUM_2G_CAL_PIERS;
237214779705SSam Leffler     } else {
237314779705SSam Leffler         pCalBChans = pEepData->calFreqPier5G;
237414779705SSam Leffler         numPiers = AR5416_NUM_5G_CAL_PIERS;
237514779705SSam Leffler     }
237614779705SSam Leffler 
237714779705SSam Leffler     /* Calculate the value of xpdgains from the xpdGain Mask */
237848c1d364SAdrian Chadd     numXpdGain = ar5416GetXpdGainValues(ah, xpdMask, xpdGainValues);
237914779705SSam Leffler 
238014779705SSam Leffler     /* Write the detector gain biases and their number */
238148c1d364SAdrian Chadd     ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues);
238214779705SSam Leffler 
238314779705SSam Leffler     for (i = 0; i < AR5416_MAX_CHAINS; i++) {
238448c1d364SAdrian Chadd 	regChainOffset = ar5416GetRegChainOffset(ah, i);
238514779705SSam Leffler 
238612fefae2SRui Paulo         if (pEepData->baseEepHeader.txMask & (1 << i)) {
238759efa8b5SSam Leffler             if (IEEE80211_IS_CHAN_2GHZ(chan)) {
238814779705SSam Leffler                 pRawDataset = pEepData->calPierData2G[i];
238914779705SSam Leffler             } else {
239014779705SSam Leffler                 pRawDataset = pEepData->calPierData5G[i];
239114779705SSam Leffler             }
239214779705SSam Leffler 
239348c1d364SAdrian Chadd             /* Fetch the gain boundaries and the PDADC values */
239414779705SSam Leffler 	    ar5416GetGainBoundariesAndPdadcs(ah,  chan, pRawDataset,
239514779705SSam Leffler                                              pCalBChans, numPiers,
239614779705SSam Leffler                                              pdGainOverlap_t2,
239714779705SSam Leffler                                              &tMinCalPower, gainBoundaries,
239814779705SSam Leffler                                              pdadcValues, numXpdGain);
239914779705SSam Leffler 
2400ef1901a3SAdrian Chadd             if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
2401b90b8dd2SAdrian Chadd 		ar5416SetGainBoundariesClosedLoop(ah, i, pdGainOverlap_t2,
2402b90b8dd2SAdrian Chadd 		  gainBoundaries);
240314779705SSam Leffler             }
240414779705SSam Leffler 
240514779705SSam Leffler             /* Write the power values into the baseband power table */
2406b90b8dd2SAdrian Chadd 	    ar5416WritePdadcValues(ah, i, pdadcValues);
240714779705SSam Leffler         }
240814779705SSam Leffler     }
240914779705SSam Leffler     *pTxPowerIndexOffset = 0;
241014779705SSam Leffler 
241114779705SSam Leffler     return AH_TRUE;
241214779705SSam Leffler }
241314779705SSam Leffler 
241414779705SSam Leffler /**************************************************************
241514779705SSam Leffler  * ar5416GetGainBoundariesAndPdadcs
241614779705SSam Leffler  *
241714779705SSam Leffler  * Uses the data points read from EEPROM to reconstruct the pdadc power table
241814779705SSam Leffler  * Called by ar5416SetPowerCalTable only.
241914779705SSam Leffler  */
242048c1d364SAdrian Chadd void
ar5416GetGainBoundariesAndPdadcs(struct ath_hal * ah,const struct ieee80211_channel * chan,CAL_DATA_PER_FREQ * pRawDataSet,uint8_t * bChans,uint16_t availPiers,uint16_t tPdGainOverlap,int16_t * pMinCalPower,uint16_t * pPdGainBoundaries,uint8_t * pPDADCValues,uint16_t numXpdGains)242114779705SSam Leffler ar5416GetGainBoundariesAndPdadcs(struct ath_hal *ah,
242259efa8b5SSam Leffler                                  const struct ieee80211_channel *chan,
242359efa8b5SSam Leffler 				 CAL_DATA_PER_FREQ *pRawDataSet,
242414779705SSam Leffler                                  uint8_t * bChans,  uint16_t availPiers,
242512fefae2SRui Paulo                                  uint16_t tPdGainOverlap, int16_t *pMinCalPower, uint16_t * pPdGainBoundaries,
242614779705SSam Leffler                                  uint8_t * pPDADCValues, uint16_t numXpdGains)
242714779705SSam Leffler {
242814779705SSam Leffler 
242914779705SSam Leffler     int       i, j, k;
243014779705SSam Leffler     int16_t   ss;         /* potentially -ve index for taking care of pdGainOverlap */
243114779705SSam Leffler     uint16_t  idxL, idxR, numPiers; /* Pier indexes */
243214779705SSam Leffler 
243314779705SSam Leffler     /* filled out Vpd table for all pdGains (chanL) */
243414779705SSam Leffler     static uint8_t   vpdTableL[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB];
243514779705SSam Leffler 
243614779705SSam Leffler     /* filled out Vpd table for all pdGains (chanR) */
243714779705SSam Leffler     static uint8_t   vpdTableR[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB];
243814779705SSam Leffler 
243914779705SSam Leffler     /* filled out Vpd table for all pdGains (interpolated) */
244014779705SSam Leffler     static uint8_t   vpdTableI[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB];
244114779705SSam Leffler 
244214779705SSam Leffler     uint8_t   *pVpdL, *pVpdR, *pPwrL, *pPwrR;
244314779705SSam Leffler     uint8_t   minPwrT4[AR5416_NUM_PD_GAINS];
244414779705SSam Leffler     uint8_t   maxPwrT4[AR5416_NUM_PD_GAINS];
244514779705SSam Leffler     int16_t   vpdStep;
244614779705SSam Leffler     int16_t   tmpVal;
244714779705SSam Leffler     uint16_t  sizeCurrVpdTable, maxIndex, tgtIndex;
244814779705SSam Leffler     HAL_BOOL    match;
244914779705SSam Leffler     int16_t  minDelta = 0;
245014779705SSam Leffler     CHAN_CENTERS centers;
245114779705SSam Leffler 
245214779705SSam Leffler     ar5416GetChannelCenters(ah, chan, &centers);
245314779705SSam Leffler 
245414779705SSam Leffler     /* Trim numPiers for the number of populated channel Piers */
245514779705SSam Leffler     for (numPiers = 0; numPiers < availPiers; numPiers++) {
245614779705SSam Leffler         if (bChans[numPiers] == AR5416_BCHAN_UNUSED) {
245714779705SSam Leffler             break;
245814779705SSam Leffler         }
245914779705SSam Leffler     }
246014779705SSam Leffler 
246114779705SSam Leffler     /* Find pier indexes around the current channel */
24626ff1b2bdSAdrian Chadd     match = ath_ee_getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center,
24636ff1b2bdSAdrian Chadd 	IEEE80211_IS_CHAN_2GHZ(chan)), bChans, numPiers, &idxL, &idxR);
246414779705SSam Leffler 
246514779705SSam Leffler     if (match) {
246614779705SSam Leffler         /* Directly fill both vpd tables from the matching index */
246714779705SSam Leffler         for (i = 0; i < numXpdGains; i++) {
246814779705SSam Leffler             minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
246914779705SSam Leffler             maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
24706ff1b2bdSAdrian Chadd             ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pRawDataSet[idxL].pwrPdg[i],
247112fefae2SRui Paulo                                pRawDataSet[idxL].vpdPdg[i], AR5416_PD_GAIN_ICEPTS, vpdTableI[i]);
247214779705SSam Leffler         }
247314779705SSam Leffler     } else {
247414779705SSam Leffler         for (i = 0; i < numXpdGains; i++) {
247514779705SSam Leffler             pVpdL = pRawDataSet[idxL].vpdPdg[i];
247614779705SSam Leffler             pPwrL = pRawDataSet[idxL].pwrPdg[i];
247714779705SSam Leffler             pVpdR = pRawDataSet[idxR].vpdPdg[i];
247814779705SSam Leffler             pPwrR = pRawDataSet[idxR].pwrPdg[i];
247914779705SSam Leffler 
248014779705SSam Leffler             /* Start Vpd interpolation from the max of the minimum powers */
248114779705SSam Leffler             minPwrT4[i] = AH_MAX(pPwrL[0], pPwrR[0]);
248214779705SSam Leffler 
248314779705SSam Leffler             /* End Vpd interpolation from the min of the max powers */
248414779705SSam Leffler             maxPwrT4[i] = AH_MIN(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
248514779705SSam Leffler             HALASSERT(maxPwrT4[i] > minPwrT4[i]);
248614779705SSam Leffler 
248714779705SSam Leffler             /* Fill pier Vpds */
24886ff1b2bdSAdrian Chadd             ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrL, pVpdL, AR5416_PD_GAIN_ICEPTS, vpdTableL[i]);
24896ff1b2bdSAdrian Chadd             ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrR, pVpdR, AR5416_PD_GAIN_ICEPTS, vpdTableR[i]);
249014779705SSam Leffler 
249114779705SSam Leffler             /* Interpolate the final vpd */
249214779705SSam Leffler             for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
24936ff1b2bdSAdrian Chadd                 vpdTableI[i][j] = (uint8_t)(ath_ee_interpolate((uint16_t)FREQ2FBIN(centers.synth_center,
24946ff1b2bdSAdrian Chadd 		    IEEE80211_IS_CHAN_2GHZ(chan)),
249514779705SSam Leffler                     bChans[idxL], bChans[idxR], vpdTableL[i][j], vpdTableR[i][j]));
249614779705SSam Leffler             }
249714779705SSam Leffler         }
249814779705SSam Leffler     }
249914779705SSam Leffler     *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
250014779705SSam Leffler 
250114779705SSam Leffler     k = 0; /* index for the final table */
250214779705SSam Leffler     for (i = 0; i < numXpdGains; i++) {
250314779705SSam Leffler         if (i == (numXpdGains - 1)) {
250414779705SSam Leffler             pPdGainBoundaries[i] = (uint16_t)(maxPwrT4[i] / 2);
250514779705SSam Leffler         } else {
250614779705SSam Leffler             pPdGainBoundaries[i] = (uint16_t)((maxPwrT4[i] + minPwrT4[i+1]) / 4);
250714779705SSam Leffler         }
250814779705SSam Leffler 
250914779705SSam Leffler         pPdGainBoundaries[i] = (uint16_t)AH_MIN(AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
251014779705SSam Leffler 
251114779705SSam Leffler 	/* NB: only applies to owl 1.0 */
2512ef1901a3SAdrian Chadd         if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah) ) {
251314779705SSam Leffler 	    /*
251414779705SSam Leffler              * fix the gain delta, but get a delta that can be applied to min to
251514779705SSam Leffler              * keep the upper power values accurate, don't think max needs to
251614779705SSam Leffler              * be adjusted because should not be at that area of the table?
251714779705SSam Leffler 	     */
251814779705SSam Leffler             minDelta = pPdGainBoundaries[0] - 23;
251914779705SSam Leffler             pPdGainBoundaries[0] = 23;
252014779705SSam Leffler         }
252114779705SSam Leffler         else {
252214779705SSam Leffler             minDelta = 0;
252314779705SSam Leffler         }
252414779705SSam Leffler 
252514779705SSam Leffler         /* Find starting index for this pdGain */
252614779705SSam Leffler         if (i == 0) {
2527b357d576SAdrian Chadd             if (AR_SREV_MERLIN_10_OR_LATER(ah))
2528b2b02919SAdrian Chadd                 ss = (int16_t)(0 - (minPwrT4[i] / 2));
2529b2b02919SAdrian Chadd             else
253014779705SSam Leffler                 ss = 0; /* for the first pdGain, start from index 0 */
253114779705SSam Leffler         } else {
253214779705SSam Leffler 	    /* need overlap entries extrapolated below. */
253314779705SSam Leffler             ss = (int16_t)((pPdGainBoundaries[i-1] - (minPwrT4[i] / 2)) - tPdGainOverlap + 1 + minDelta);
253414779705SSam Leffler         }
253514779705SSam Leffler         vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
253614779705SSam Leffler         vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
253714779705SSam Leffler         /*
253814779705SSam Leffler          *-ve ss indicates need to extrapolate data below for this pdGain
253914779705SSam Leffler          */
254014779705SSam Leffler         while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
254114779705SSam Leffler             tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
254214779705SSam Leffler             pPDADCValues[k++] = (uint8_t)((tmpVal < 0) ? 0 : tmpVal);
254314779705SSam Leffler             ss++;
254414779705SSam Leffler         }
254514779705SSam Leffler 
254614779705SSam Leffler         sizeCurrVpdTable = (uint8_t)((maxPwrT4[i] - minPwrT4[i]) / 2 +1);
254714779705SSam Leffler         tgtIndex = (uint8_t)(pPdGainBoundaries[i] + tPdGainOverlap - (minPwrT4[i] / 2));
254814779705SSam Leffler         maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
254914779705SSam Leffler 
255014779705SSam Leffler         while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
255114779705SSam Leffler             pPDADCValues[k++] = vpdTableI[i][ss++];
255214779705SSam Leffler         }
255314779705SSam Leffler 
255414779705SSam Leffler         vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - vpdTableI[i][sizeCurrVpdTable - 2]);
255514779705SSam Leffler         vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
255614779705SSam Leffler         /*
255714779705SSam Leffler          * for last gain, pdGainBoundary == Pmax_t2, so will
255814779705SSam Leffler          * have to extrapolate
255914779705SSam Leffler          */
256049d2d79bSAdrian Chadd         if (tgtIndex >= maxIndex) {  /* need to extrapolate above */
256114779705SSam Leffler             while ((ss <= tgtIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
256214779705SSam Leffler                 tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
256314779705SSam Leffler                           (ss - maxIndex +1) * vpdStep));
256414779705SSam Leffler                 pPDADCValues[k++] = (uint8_t)((tmpVal > 255) ? 255 : tmpVal);
256514779705SSam Leffler                 ss++;
256614779705SSam Leffler             }
256714779705SSam Leffler         }               /* extrapolated above */
256814779705SSam Leffler     }                   /* for all pdGainUsed */
256914779705SSam Leffler 
257014779705SSam Leffler     /* Fill out pdGainBoundaries - only up to 2 allowed here, but hardware allows up to 4 */
257114779705SSam Leffler     while (i < AR5416_PD_GAINS_IN_MASK) {
257214779705SSam Leffler         pPdGainBoundaries[i] = pPdGainBoundaries[i-1];
257314779705SSam Leffler         i++;
257414779705SSam Leffler     }
257514779705SSam Leffler 
257614779705SSam Leffler     while (k < AR5416_NUM_PDADC_VALUES) {
257714779705SSam Leffler         pPDADCValues[k] = pPDADCValues[k-1];
257814779705SSam Leffler         k++;
257914779705SSam Leffler     }
258014779705SSam Leffler     return;
258114779705SSam Leffler }
258214779705SSam Leffler 
2583d8d0c29dSAdrian Chadd /*
2584d8d0c29dSAdrian Chadd  * The linux ath9k driver and (from what I've been told) the reference
2585d8d0c29dSAdrian Chadd  * Atheros driver enables the 11n PHY by default whether or not it's
2586d8d0c29dSAdrian Chadd  * configured.
2587d8d0c29dSAdrian Chadd  */
258814779705SSam Leffler static void
ar5416Set11nRegs(struct ath_hal * ah,const struct ieee80211_channel * chan)258959efa8b5SSam Leffler ar5416Set11nRegs(struct ath_hal *ah, const struct ieee80211_channel *chan)
259014779705SSam Leffler {
259114779705SSam Leffler 	uint32_t phymode;
2592d8d0c29dSAdrian Chadd 	uint32_t enableDacFifo = 0;
259314779705SSam Leffler 	HAL_HT_MACMODE macmode;		/* MAC - 20/40 mode */
259414779705SSam Leffler 
2595d8d0c29dSAdrian Chadd 	if (AR_SREV_KITE_10_OR_LATER(ah))
2596d8d0c29dSAdrian Chadd 		enableDacFifo = (OS_REG_READ(ah, AR_PHY_TURBO) & AR_PHY_FC_ENABLE_DAC_FIFO);
259714779705SSam Leffler 
259814779705SSam Leffler 	/* Enable 11n HT, 20 MHz */
259914779705SSam Leffler 	phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
2600d8d0c29dSAdrian Chadd 		| AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo;
260114779705SSam Leffler 
260214779705SSam Leffler 	/* Configure baseband for dynamic 20/40 operation */
260359efa8b5SSam Leffler 	if (IEEE80211_IS_CHAN_HT40(chan)) {
2604d8d0c29dSAdrian Chadd 		phymode |= AR_PHY_FC_DYN2040_EN;
260514779705SSam Leffler 
260614779705SSam Leffler 		/* Configure control (primary) channel at +-10MHz */
260759efa8b5SSam Leffler 		if (IEEE80211_IS_CHAN_HT40U(chan))
260814779705SSam Leffler 			phymode |= AR_PHY_FC_DYN2040_PRI_CH;
260914779705SSam Leffler #if 0
261014779705SSam Leffler 		/* Configure 20/25 spacing */
261114779705SSam Leffler 		if (ht->ht_extprotspacing == HAL_HT_EXTPROTSPACING_25)
261214779705SSam Leffler 			phymode |= AR_PHY_FC_DYN2040_EXT_CH;
261314779705SSam Leffler #endif
261414779705SSam Leffler 		macmode = HAL_HT_MACMODE_2040;
261514779705SSam Leffler 	} else
261614779705SSam Leffler 		macmode = HAL_HT_MACMODE_20;
261714779705SSam Leffler 	OS_REG_WRITE(ah, AR_PHY_TURBO, phymode);
261814779705SSam Leffler 
261914779705SSam Leffler 	/* Configure MAC for 20/40 operation */
262014779705SSam Leffler 	ar5416Set11nMac2040(ah, macmode);
262114779705SSam Leffler 
262214779705SSam Leffler 	/* global transmit timeout (25 TUs default)*/
262314779705SSam Leffler 	/* XXX - put this elsewhere??? */
262414779705SSam Leffler 	OS_REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S) ;
262514779705SSam Leffler 
262614779705SSam Leffler 	/* carrier sense timeout */
262714779705SSam Leffler 	OS_REG_SET_BIT(ah, AR_GTTM, AR_GTTM_CST_USEC);
2628b9862659SAdrian Chadd 	OS_REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
262914779705SSam Leffler }
263014779705SSam Leffler 
263114779705SSam Leffler void
ar5416GetChannelCenters(struct ath_hal * ah,const struct ieee80211_channel * chan,CHAN_CENTERS * centers)263214779705SSam Leffler ar5416GetChannelCenters(struct ath_hal *ah,
263359efa8b5SSam Leffler 	const struct ieee80211_channel *chan, CHAN_CENTERS *centers)
263414779705SSam Leffler {
263559efa8b5SSam Leffler 	uint16_t freq = ath_hal_gethwchannel(ah, chan);
263659efa8b5SSam Leffler 
263759efa8b5SSam Leffler 	centers->ctl_center = freq;
263859efa8b5SSam Leffler 	centers->synth_center = freq;
263914779705SSam Leffler 	/*
264014779705SSam Leffler 	 * In 20/40 phy mode, the center frequency is
264114779705SSam Leffler 	 * "between" the control and extension channels.
264214779705SSam Leffler 	 */
264359efa8b5SSam Leffler 	if (IEEE80211_IS_CHAN_HT40U(chan)) {
264414779705SSam Leffler 		centers->synth_center += HT40_CHANNEL_CENTER_SHIFT;
264514779705SSam Leffler 		centers->ext_center =
264614779705SSam Leffler 		    centers->synth_center + HT40_CHANNEL_CENTER_SHIFT;
264759efa8b5SSam Leffler 	} else if (IEEE80211_IS_CHAN_HT40D(chan)) {
264814779705SSam Leffler 		centers->synth_center -= HT40_CHANNEL_CENTER_SHIFT;
264914779705SSam Leffler 		centers->ext_center =
265014779705SSam Leffler 		    centers->synth_center - HT40_CHANNEL_CENTER_SHIFT;
265114779705SSam Leffler 	} else {
265259efa8b5SSam Leffler 		centers->ext_center = freq;
265314779705SSam Leffler 	}
265414779705SSam Leffler }
26559d6de76dSAdrian Chadd 
26569d6de76dSAdrian Chadd /*
26579d6de76dSAdrian Chadd  * Override the INI vals being programmed.
26589d6de76dSAdrian Chadd  */
26599d6de76dSAdrian Chadd static void
ar5416OverrideIni(struct ath_hal * ah,const struct ieee80211_channel * chan)26609d6de76dSAdrian Chadd ar5416OverrideIni(struct ath_hal *ah, const struct ieee80211_channel *chan)
26619d6de76dSAdrian Chadd {
26629d6de76dSAdrian Chadd 	uint32_t val;
26639d6de76dSAdrian Chadd 
26649d6de76dSAdrian Chadd 	/*
26659d6de76dSAdrian Chadd 	 * Set the RX_ABORT and RX_DIS and clear if off only after
26669d6de76dSAdrian Chadd 	 * RXE is set for MAC. This prevents frames with corrupted
26679d6de76dSAdrian Chadd 	 * descriptor status.
26689d6de76dSAdrian Chadd 	 */
26699d6de76dSAdrian Chadd 	OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
26709d6de76dSAdrian Chadd 
267160d38784SAdrian Chadd 	if (AR_SREV_MERLIN_10_OR_LATER(ah)) {
26729d6de76dSAdrian Chadd 		val = OS_REG_READ(ah, AR_PCU_MISC_MODE2);
267360d38784SAdrian Chadd 		val &= (~AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE);
26749d6de76dSAdrian Chadd 		if (!AR_SREV_9271(ah))
26759d6de76dSAdrian Chadd 			val &= ~AR_PCU_MISC_MODE2_HWWAR1;
26769d6de76dSAdrian Chadd 
26773ca6cfa8SAdrian Chadd 		if (AR_SREV_KIWI_10_OR_LATER(ah))
26789d6de76dSAdrian Chadd 			val = val & (~AR_PCU_MISC_MODE2_HWWAR2);
26799d6de76dSAdrian Chadd 
26809d6de76dSAdrian Chadd 		OS_REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
26819d6de76dSAdrian Chadd 	}
26829d6de76dSAdrian Chadd 
26839d6de76dSAdrian Chadd 	/*
26849d6de76dSAdrian Chadd 	 * Disable RIFS search on some chips to avoid baseband
26859d6de76dSAdrian Chadd 	 * hang issues.
26869d6de76dSAdrian Chadd 	 */
2687e7cb5d54SAdrian Chadd 	if (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah))
2688d6415a7cSAdrian Chadd 		(void) ar5416SetRifsDelay(ah, chan, AH_FALSE);
2689ef1901a3SAdrian Chadd 
2690ef1901a3SAdrian Chadd         if (!AR_SREV_5416_V20_OR_LATER(ah) || AR_SREV_MERLIN(ah))
2691ef1901a3SAdrian Chadd 		return;
2692ef1901a3SAdrian Chadd 
2693ef1901a3SAdrian Chadd 	/*
2694ef1901a3SAdrian Chadd 	 * Disable BB clock gating
2695ef1901a3SAdrian Chadd 	 * Necessary to avoid issues on AR5416 2.0
2696ef1901a3SAdrian Chadd 	 */
2697ef1901a3SAdrian Chadd 	OS_REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
26989d6de76dSAdrian Chadd }
2699f6f59583SAdrian Chadd 
2700f6f59583SAdrian Chadd struct ini {
2701f6f59583SAdrian Chadd 	uint32_t        *data;          /* NB: !const */
2702f6f59583SAdrian Chadd 	int             rows, cols;
2703f6f59583SAdrian Chadd };
2704f6f59583SAdrian Chadd 
2705f6f59583SAdrian Chadd /*
2706f6f59583SAdrian Chadd  * Override XPA bias level based on operating frequency.
2707f6f59583SAdrian Chadd  * This is a v14 EEPROM specific thing for the AR9160.
2708f6f59583SAdrian Chadd  */
2709f6f59583SAdrian Chadd void
ar5416EepromSetAddac(struct ath_hal * ah,const struct ieee80211_channel * chan)2710f6f59583SAdrian Chadd ar5416EepromSetAddac(struct ath_hal *ah, const struct ieee80211_channel *chan)
2711f6f59583SAdrian Chadd {
2712f6f59583SAdrian Chadd #define	XPA_LVL_FREQ(cnt)	(pModal->xpaBiasLvlFreq[cnt])
2713f6f59583SAdrian Chadd 	MODAL_EEP_HEADER	*pModal;
2714f6f59583SAdrian Chadd 	HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
2715f6f59583SAdrian Chadd 	struct ar5416eeprom	*eep = &ee->ee_base;
2716f6f59583SAdrian Chadd 	uint8_t biaslevel;
2717f6f59583SAdrian Chadd 
2718f6f59583SAdrian Chadd 	if (! AR_SREV_SOWL(ah))
2719f6f59583SAdrian Chadd 		return;
2720f6f59583SAdrian Chadd 
2721f6f59583SAdrian Chadd         if (EEP_MINOR(ah) < AR5416_EEP_MINOR_VER_7)
2722f6f59583SAdrian Chadd                 return;
2723f6f59583SAdrian Chadd 
2724f6f59583SAdrian Chadd 	pModal = &(eep->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)]);
2725f6f59583SAdrian Chadd 
2726f6f59583SAdrian Chadd 	if (pModal->xpaBiasLvl != 0xff)
2727f6f59583SAdrian Chadd 		biaslevel = pModal->xpaBiasLvl;
2728f6f59583SAdrian Chadd 	else {
2729f6f59583SAdrian Chadd 		uint16_t resetFreqBin, freqBin, freqCount = 0;
2730f6f59583SAdrian Chadd 		CHAN_CENTERS centers;
2731f6f59583SAdrian Chadd 
2732f6f59583SAdrian Chadd 		ar5416GetChannelCenters(ah, chan, &centers);
2733f6f59583SAdrian Chadd 
2734f6f59583SAdrian Chadd 		resetFreqBin = FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan));
2735f6f59583SAdrian Chadd 		freqBin = XPA_LVL_FREQ(0) & 0xff;
2736f6f59583SAdrian Chadd 		biaslevel = (uint8_t) (XPA_LVL_FREQ(0) >> 14);
2737f6f59583SAdrian Chadd 
2738f6f59583SAdrian Chadd 		freqCount++;
2739f6f59583SAdrian Chadd 
2740f6f59583SAdrian Chadd 		while (freqCount < 3) {
2741f6f59583SAdrian Chadd 			if (XPA_LVL_FREQ(freqCount) == 0x0)
2742f6f59583SAdrian Chadd 			break;
2743f6f59583SAdrian Chadd 
2744f6f59583SAdrian Chadd 			freqBin = XPA_LVL_FREQ(freqCount) & 0xff;
2745f6f59583SAdrian Chadd 			if (resetFreqBin >= freqBin)
2746f6f59583SAdrian Chadd 				biaslevel = (uint8_t)(XPA_LVL_FREQ(freqCount) >> 14);
2747f6f59583SAdrian Chadd 			else
2748f6f59583SAdrian Chadd 				break;
2749f6f59583SAdrian Chadd 			freqCount++;
2750f6f59583SAdrian Chadd 		}
2751f6f59583SAdrian Chadd 	}
2752f6f59583SAdrian Chadd 
2753f6f59583SAdrian Chadd 	HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: overriding XPA bias level = %d\n",
2754f6f59583SAdrian Chadd 	    __func__, biaslevel);
2755f6f59583SAdrian Chadd 
2756f6f59583SAdrian Chadd 	/*
2757f6f59583SAdrian Chadd 	 * This is a dirty workaround for the const initval data,
2758f6f59583SAdrian Chadd 	 * which will upset multiple AR9160's on the same board.
2759f6f59583SAdrian Chadd 	 *
2760f6f59583SAdrian Chadd 	 * The HAL should likely just have a private copy of the addac
2761f6f59583SAdrian Chadd 	 * data per instance.
2762f6f59583SAdrian Chadd 	 */
2763f6f59583SAdrian Chadd 	if (IEEE80211_IS_CHAN_2GHZ(chan))
2764f6f59583SAdrian Chadd                 HAL_INI_VAL((struct ini *) &AH5416(ah)->ah_ini_addac, 7, 1) =
2765f6f59583SAdrian Chadd 		    (HAL_INI_VAL(&AH5416(ah)->ah_ini_addac, 7, 1) & (~0x18)) | biaslevel << 3;
2766f6f59583SAdrian Chadd         else
2767f6f59583SAdrian Chadd                 HAL_INI_VAL((struct ini *) &AH5416(ah)->ah_ini_addac, 6, 1) =
2768f6f59583SAdrian Chadd 		    (HAL_INI_VAL(&AH5416(ah)->ah_ini_addac, 6, 1) & (~0xc0)) | biaslevel << 6;
2769f6f59583SAdrian Chadd #undef XPA_LVL_FREQ
2770f6f59583SAdrian Chadd }
2771f6f59583SAdrian Chadd 
2772d10f1cdcSAdrian Chadd static void
ar5416MarkPhyInactive(struct ath_hal * ah)2773d10f1cdcSAdrian Chadd ar5416MarkPhyInactive(struct ath_hal *ah)
2774d10f1cdcSAdrian Chadd {
2775d10f1cdcSAdrian Chadd 	OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
2776d10f1cdcSAdrian Chadd }
2777ce801478SAdrian Chadd 
2778ce801478SAdrian Chadd #define	AR5416_IFS_SLOT_FULL_RATE_40	0x168	/* 9 us half, 40 MHz core clock (9*40) */
2779ce801478SAdrian Chadd #define	AR5416_IFS_SLOT_HALF_RATE_40	0x104	/* 13 us half, 20 MHz core clock (13*20) */
2780ce801478SAdrian Chadd #define	AR5416_IFS_SLOT_QUARTER_RATE_40	0xD2	/* 21 us quarter, 10 MHz core clock (21*10) */
2781ce801478SAdrian Chadd 
2782ce801478SAdrian Chadd #define	AR5416_IFS_EIFS_FULL_RATE_40	0xE60	/* (74 + (2 * 9)) * 40MHz core clock */
2783ce801478SAdrian Chadd #define	AR5416_IFS_EIFS_HALF_RATE_40	0xDAC	/* (149 + (2 * 13)) * 20MHz core clock */
2784ce801478SAdrian Chadd #define	AR5416_IFS_EIFS_QUARTER_RATE_40	0xD48	/* (298 + (2 * 21)) * 10MHz core clock */
2785ce801478SAdrian Chadd 
2786ce801478SAdrian Chadd #define	AR5416_IFS_SLOT_FULL_RATE_44	0x18c	/* 9 us half, 44 MHz core clock (9*44) */
2787ce801478SAdrian Chadd #define	AR5416_IFS_SLOT_HALF_RATE_44	0x11e	/* 13 us half, 22 MHz core clock (13*22) */
2788ce801478SAdrian Chadd #define	AR5416_IFS_SLOT_QUARTER_RATE_44	0xe7	/* 21 us quarter, 11 MHz core clock (21*11) */
2789ce801478SAdrian Chadd 
2790ce801478SAdrian Chadd #define	AR5416_IFS_EIFS_FULL_RATE_44	0xfd0	/* (74 + (2 * 9)) * 44MHz core clock */
2791ce801478SAdrian Chadd #define	AR5416_IFS_EIFS_HALF_RATE_44	0xf0a	/* (149 + (2 * 13)) * 22MHz core clock */
2792ce801478SAdrian Chadd #define	AR5416_IFS_EIFS_QUARTER_RATE_44	0xe9c	/* (298 + (2 * 21)) * 11MHz core clock */
2793ce801478SAdrian Chadd 
2794ce801478SAdrian Chadd #define	AR5416_INIT_USEC_40		40
2795ce801478SAdrian Chadd #define	AR5416_HALF_RATE_USEC_40	19 /* ((40 / 2) - 1 ) */
2796ce801478SAdrian Chadd #define	AR5416_QUARTER_RATE_USEC_40	9  /* ((40 / 4) - 1 ) */
2797ce801478SAdrian Chadd 
2798ce801478SAdrian Chadd #define	AR5416_INIT_USEC_44		44
2799ce801478SAdrian Chadd #define	AR5416_HALF_RATE_USEC_44	21 /* ((44 / 2) - 1 ) */
2800ce801478SAdrian Chadd #define	AR5416_QUARTER_RATE_USEC_44	10  /* ((44 / 4) - 1 ) */
2801ce801478SAdrian Chadd 
2802ce801478SAdrian Chadd /* XXX What should these be for 40/44MHz clocks (and half/quarter) ? */
2803ce801478SAdrian Chadd #define	AR5416_RX_NON_FULL_RATE_LATENCY		63
2804ce801478SAdrian Chadd #define	AR5416_TX_HALF_RATE_LATENCY		108
2805ce801478SAdrian Chadd #define	AR5416_TX_QUARTER_RATE_LATENCY		216
2806ce801478SAdrian Chadd 
2807ce801478SAdrian Chadd /*
2808ce801478SAdrian Chadd  * Adjust various register settings based on half/quarter rate clock setting.
2809ce801478SAdrian Chadd  * This includes:
2810ce801478SAdrian Chadd  *
2811ce801478SAdrian Chadd  * + USEC, TX/RX latency,
2812ce801478SAdrian Chadd  * + IFS params: slot, eifs, misc etc.
2813ce801478SAdrian Chadd  *
2814ce801478SAdrian Chadd  * TODO:
2815ce801478SAdrian Chadd  *
2816ce801478SAdrian Chadd  * + Verify which other registers need to be tweaked;
2817ce801478SAdrian Chadd  * + Verify the behaviour of this for 5GHz fast and non-fast clock mode;
2818ce801478SAdrian Chadd  * + This just plain won't work for long distance links - the coverage class
2819ce801478SAdrian Chadd  *   code isn't aware of the slot/ifs/ACK/RTS timeout values that need to
2820ce801478SAdrian Chadd  *   change;
2821ce801478SAdrian Chadd  * + Verify whether the 32KHz USEC value needs to be kept for the 802.11n
2822ce801478SAdrian Chadd  *   series chips?
2823ce801478SAdrian Chadd  * + Calculate/derive values for 2GHz, 5GHz, 5GHz fast clock
2824ce801478SAdrian Chadd  */
2825ce801478SAdrian Chadd static void
ar5416SetIFSTiming(struct ath_hal * ah,const struct ieee80211_channel * chan)2826ce801478SAdrian Chadd ar5416SetIFSTiming(struct ath_hal *ah, const struct ieee80211_channel *chan)
2827ce801478SAdrian Chadd {
2828ce801478SAdrian Chadd 	uint32_t txLat, rxLat, usec, slot, refClock, eifs, init_usec;
2829ce801478SAdrian Chadd 	int clk_44 = 0;
2830ce801478SAdrian Chadd 
2831ce801478SAdrian Chadd 	HALASSERT(IEEE80211_IS_CHAN_HALF(chan) ||
2832ce801478SAdrian Chadd 	    IEEE80211_IS_CHAN_QUARTER(chan));
2833ce801478SAdrian Chadd 
2834ce801478SAdrian Chadd 	/* 2GHz and 5GHz fast clock - 44MHz; else 40MHz */
2835ce801478SAdrian Chadd 	if (IEEE80211_IS_CHAN_2GHZ(chan))
2836ce801478SAdrian Chadd 		clk_44 = 1;
2837ce801478SAdrian Chadd 	else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
2838ce801478SAdrian Chadd 	    IS_5GHZ_FAST_CLOCK_EN(ah, chan))
2839ce801478SAdrian Chadd 		clk_44 = 1;
2840ce801478SAdrian Chadd 
2841ce801478SAdrian Chadd 	/* XXX does this need save/restoring for the 11n chips? */
284290d3a30aSAdrian Chadd 	/*
284390d3a30aSAdrian Chadd 	 * XXX TODO: should mask out the txlat/rxlat/usec values?
284490d3a30aSAdrian Chadd 	 */
2845ce801478SAdrian Chadd 	refClock = OS_REG_READ(ah, AR_USEC) & AR_USEC_USEC32;
2846ce801478SAdrian Chadd 
2847ce801478SAdrian Chadd 	/*
2848ce801478SAdrian Chadd 	 * XXX This really should calculate things, not use
2849ce801478SAdrian Chadd 	 * hard coded values! Ew.
2850ce801478SAdrian Chadd 	 */
2851ce801478SAdrian Chadd 	if (IEEE80211_IS_CHAN_HALF(chan)) {
2852ce801478SAdrian Chadd 		if (clk_44) {
2853ce801478SAdrian Chadd 			slot = AR5416_IFS_SLOT_HALF_RATE_44;
2854ce801478SAdrian Chadd 			rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<
2855ce801478SAdrian Chadd 			    AR5416_USEC_RX_LAT_S;
2856ce801478SAdrian Chadd 			txLat = AR5416_TX_HALF_RATE_LATENCY <<
2857ce801478SAdrian Chadd 			    AR5416_USEC_TX_LAT_S;
2858ce801478SAdrian Chadd 			usec = AR5416_HALF_RATE_USEC_44;
2859ce801478SAdrian Chadd 			eifs = AR5416_IFS_EIFS_HALF_RATE_44;
2860ce801478SAdrian Chadd 			init_usec = AR5416_INIT_USEC_44 >> 1;
2861ce801478SAdrian Chadd 		} else {
2862ce801478SAdrian Chadd 			slot = AR5416_IFS_SLOT_HALF_RATE_40;
2863ce801478SAdrian Chadd 			rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<
2864ce801478SAdrian Chadd 			    AR5416_USEC_RX_LAT_S;
2865ce801478SAdrian Chadd 			txLat = AR5416_TX_HALF_RATE_LATENCY <<
2866ce801478SAdrian Chadd 			    AR5416_USEC_TX_LAT_S;
2867ce801478SAdrian Chadd 			usec = AR5416_HALF_RATE_USEC_40;
2868ce801478SAdrian Chadd 			eifs = AR5416_IFS_EIFS_HALF_RATE_40;
2869ce801478SAdrian Chadd 			init_usec = AR5416_INIT_USEC_40 >> 1;
2870ce801478SAdrian Chadd 		}
2871ce801478SAdrian Chadd 	} else { /* quarter rate */
2872ce801478SAdrian Chadd 		if (clk_44) {
2873ce801478SAdrian Chadd 			slot = AR5416_IFS_SLOT_QUARTER_RATE_44;
2874ce801478SAdrian Chadd 			rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<
2875ce801478SAdrian Chadd 			    AR5416_USEC_RX_LAT_S;
2876ce801478SAdrian Chadd 			txLat = AR5416_TX_QUARTER_RATE_LATENCY <<
2877ce801478SAdrian Chadd 			    AR5416_USEC_TX_LAT_S;
2878ce801478SAdrian Chadd 			usec = AR5416_QUARTER_RATE_USEC_44;
2879ce801478SAdrian Chadd 			eifs = AR5416_IFS_EIFS_QUARTER_RATE_44;
2880ce801478SAdrian Chadd 			init_usec = AR5416_INIT_USEC_44 >> 2;
2881ce801478SAdrian Chadd 		} else {
2882ce801478SAdrian Chadd 			slot = AR5416_IFS_SLOT_QUARTER_RATE_40;
2883ce801478SAdrian Chadd 			rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<
2884ce801478SAdrian Chadd 			    AR5416_USEC_RX_LAT_S;
2885ce801478SAdrian Chadd 			txLat = AR5416_TX_QUARTER_RATE_LATENCY <<
2886ce801478SAdrian Chadd 			    AR5416_USEC_TX_LAT_S;
2887ce801478SAdrian Chadd 			usec = AR5416_QUARTER_RATE_USEC_40;
2888ce801478SAdrian Chadd 			eifs = AR5416_IFS_EIFS_QUARTER_RATE_40;
2889ce801478SAdrian Chadd 			init_usec = AR5416_INIT_USEC_40 >> 2;
2890ce801478SAdrian Chadd 		}
2891ce801478SAdrian Chadd 	}
2892ce801478SAdrian Chadd 
2893ce801478SAdrian Chadd 	/* XXX verify these! */
2894ce801478SAdrian Chadd 	OS_REG_WRITE(ah, AR_USEC, (usec | refClock | txLat | rxLat));
2895ce801478SAdrian Chadd 	OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot);
2896ce801478SAdrian Chadd 	OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs);
2897ce801478SAdrian Chadd 	OS_REG_RMW_FIELD(ah, AR_D_GBL_IFS_MISC,
2898ce801478SAdrian Chadd 	    AR_D_GBL_IFS_MISC_USEC_DURATION, init_usec);
2899ce801478SAdrian Chadd }
2900