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, ¢ers);
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, ¢ers);
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, ¢ers);
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, ¢ers);
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, ¢ers);
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, ¢ers);
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