Path: blob/main/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2008 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"22#include "ah_devid.h"2324#include "ah_eeprom_v14.h"2526#include "ar5416/ar5416.h"27#include "ar5416/ar5416reg.h"28#include "ar5416/ar5416phy.h"2930/* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */31#define EEP_MINOR(_ah) \32(AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK)33#define IS_EEP_MINOR_V2(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2)34#define IS_EEP_MINOR_V3(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3)3536/* Additional Time delay to wait after activiting the Base band */37#define BASE_ACTIVATE_DELAY 100 /* 100 usec */38#define PLL_SETTLE_DELAY 300 /* 300 usec */39#define RTC_PLL_SETTLE_DELAY 1000 /* 1 ms */4041static void ar5416InitDMA(struct ath_hal *ah);42static void ar5416InitBB(struct ath_hal *ah, const struct ieee80211_channel *);43static void ar5416InitIMR(struct ath_hal *ah, HAL_OPMODE opmode);44static void ar5416InitQoS(struct ath_hal *ah);45static void ar5416InitUserSettings(struct ath_hal *ah);46static void ar5416OverrideIni(struct ath_hal *ah, const struct ieee80211_channel *);4748#if 049static HAL_BOOL ar5416ChannelChange(struct ath_hal *, const struct ieee80211_channel *);50#endif51static void ar5416SetDeltaSlope(struct ath_hal *, const struct ieee80211_channel *);5253static HAL_BOOL ar5416SetResetPowerOn(struct ath_hal *ah);54static HAL_BOOL ar5416SetReset(struct ath_hal *ah, int type);55static HAL_BOOL ar5416SetPowerPerRateTable(struct ath_hal *ah,56struct ar5416eeprom *pEepData,57const struct ieee80211_channel *chan, int16_t *ratesArray,58uint16_t cfgCtl, uint16_t AntennaReduction,59uint16_t twiceMaxRegulatoryPower,60uint16_t powerLimit);61static void ar5416Set11nRegs(struct ath_hal *ah, const struct ieee80211_channel *chan);62static void ar5416MarkPhyInactive(struct ath_hal *ah);63static void ar5416SetIFSTiming(struct ath_hal *ah,64const struct ieee80211_channel *chan);6566/*67* Places the device in and out of reset and then places sane68* values in the registers based on EEPROM config, initialization69* vectors (as determined by the mode), and station configuration70*71* bChannelChange is used to preserve DMA/PCU registers across72* a HW Reset during channel change.73*/74HAL_BOOL75ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode,76struct ieee80211_channel *chan,77HAL_BOOL bChannelChange,78HAL_RESET_TYPE resetType,79HAL_STATUS *status)80{81#define N(a) (sizeof (a) / sizeof (a[0]))82#define FAIL(_code) do { ecode = _code; goto bad; } while (0)83struct ath_hal_5212 *ahp = AH5212(ah);84HAL_CHANNEL_INTERNAL *ichan;85uint32_t saveDefAntenna, saveLedState;86uint32_t macStaId1;87uint16_t rfXpdGain[2];88HAL_STATUS ecode;89uint32_t powerVal, rssiThrReg;90uint32_t ackTpcPow, ctsTpcPow, chirpTpcPow;91int i;92uint64_t tsf = 0;9394OS_MARK(ah, AH_MARK_RESET, bChannelChange);9596/* Bring out of sleep mode */97if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {98HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip did not wakeup\n",99__func__);100FAIL(HAL_EIO);101}102103/*104* Map public channel to private.105*/106ichan = ath_hal_checkchannel(ah, chan);107if (ichan == AH_NULL)108FAIL(HAL_EINVAL);109switch (opmode) {110case HAL_M_STA:111case HAL_M_IBSS:112case HAL_M_HOSTAP:113case HAL_M_MONITOR:114break;115default:116HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n",117__func__, opmode);118FAIL(HAL_EINVAL);119break;120}121HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);122123/* Blank the channel survey statistics */124ath_hal_survey_clear(ah);125126/* XXX Turn on fast channel change for 5416 */127128/*129* Preserve the bmiss rssi threshold and count threshold130* across resets131*/132rssiThrReg = OS_REG_READ(ah, AR_RSSI_THR);133/* If reg is zero, first time thru set to default val */134if (rssiThrReg == 0)135rssiThrReg = INIT_RSSI_THR;136137/*138* Preserve the antenna on a channel change139*/140saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA);141142/*143* Don't do this for the AR9285 - it breaks RX for single144* antenna designs when diversity is disabled.145*146* I'm not sure what this was working around; it may be147* something to do with the AR5416. Certainly this register148* isn't supposed to be used by the MIMO chips for anything149* except for defining the default antenna when an external150* phase array / smart antenna is connected.151*152* See PR: kern/179269 .153*/154if ((! AR_SREV_KITE(ah)) && saveDefAntenna == 0) /* XXX magic constants */155saveDefAntenna = 1;156157/* Save hardware flag before chip reset clears the register */158macStaId1 = OS_REG_READ(ah, AR_STA_ID1) &159(AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT);160161/* Save led state from pci config register */162saveLedState = OS_REG_READ(ah, AR_MAC_LED) &163(AR_MAC_LED_ASSOC | AR_MAC_LED_MODE |164AR_MAC_LED_BLINK_THRESH_SEL | AR_MAC_LED_BLINK_SLOW);165166/* For chips on which the RTC reset is done, save TSF before it gets cleared */167if (AR_SREV_HOWL(ah) ||168(AR_SREV_MERLIN(ah) &&169ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) ||170(resetType == HAL_RESET_FORCE_COLD) ||171(resetType == HAL_RESET_BBPANIC) ||172(ah->ah_config.ah_force_full_reset))173tsf = ar5416GetTsf64(ah);174175/* Mark PHY as inactive; marked active in ar5416InitBB() */176ar5416MarkPhyInactive(ah);177178if (!ar5416ChipReset(ah, chan, resetType)) {179HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);180FAIL(HAL_EIO);181}182183/* Restore TSF */184if (tsf)185ar5416SetTsf64(ah, tsf);186187OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);188if (AR_SREV_MERLIN_10_OR_LATER(ah))189OS_REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);190191AH5416(ah)->ah_writeIni(ah, chan);192193if(AR_SREV_KIWI_13_OR_LATER(ah) ) {194/* Enable ASYNC FIFO */195OS_REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,196AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);197OS_REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);198OS_REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,199AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);200OS_REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,201AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);202}203204/* Override ini values (that can be overridden in this fashion) */205ar5416OverrideIni(ah, chan);206207/* Setup 11n MAC/Phy mode registers */208ar5416Set11nRegs(ah, chan);209210OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);211212/*213* Some AR91xx SoC devices frequently fail to accept TSF writes214* right after the chip reset. When that happens, write a new215* value after the initvals have been applied, with an offset216* based on measured time difference217*/218if (AR_SREV_HOWL(ah) && (ar5416GetTsf64(ah) < tsf)) {219tsf += 1500;220ar5416SetTsf64(ah, tsf);221}222223HALDEBUG(ah, HAL_DEBUG_RESET, ">>>2 %s: AR_PHY_DAG_CTRLCCK=0x%x\n",224__func__, OS_REG_READ(ah,AR_PHY_DAG_CTRLCCK));225HALDEBUG(ah, HAL_DEBUG_RESET, ">>>2 %s: AR_PHY_ADC_CTL=0x%x\n",226__func__, OS_REG_READ(ah,AR_PHY_ADC_CTL));227228/*229* This routine swaps the analog chains - it should be done230* before any radio register twiddling is done.231*/232ar5416InitChainMasks(ah);233234/* Setup the open-loop power calibration if required */235if (ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {236AH5416(ah)->ah_olcInit(ah);237AH5416(ah)->ah_olcTempCompensation(ah);238}239240/* Setup the transmit power values. */241if (!ah->ah_setTxPower(ah, chan, rfXpdGain)) {242HALDEBUG(ah, HAL_DEBUG_ANY,243"%s: error init'ing transmit power\n", __func__);244FAIL(HAL_EIO);245}246247/* Write the analog registers */248if (!ahp->ah_rfHal->setRfRegs(ah, chan,249IEEE80211_IS_CHAN_2GHZ(chan) ? 2: 1, rfXpdGain)) {250HALDEBUG(ah, HAL_DEBUG_ANY,251"%s: ar5212SetRfRegs failed\n", __func__);252FAIL(HAL_EIO);253}254255/* Write delta slope for OFDM enabled modes (A, G, Turbo) */256if (IEEE80211_IS_CHAN_OFDM(chan)|| IEEE80211_IS_CHAN_HT(chan))257ar5416SetDeltaSlope(ah, chan);258259AH5416(ah)->ah_spurMitigate(ah, chan);260261/* Setup board specific options for EEPROM version 3 */262if (!ah->ah_setBoardValues(ah, chan)) {263HALDEBUG(ah, HAL_DEBUG_ANY,264"%s: error setting board options\n", __func__);265FAIL(HAL_EIO);266}267268OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);269270OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));271OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)272| macStaId1273| AR_STA_ID1_RTS_USE_DEF274| ahp->ah_staId1Defaults275);276ar5212SetOperatingMode(ah, opmode);277278/* Set Venice BSSID mask according to current state */279OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));280OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));281282/* Restore previous led state */283if (AR_SREV_HOWL(ah))284OS_REG_WRITE(ah, AR_MAC_LED,285AR_MAC_LED_ASSOC_ACTIVE | AR_CFG_SCLK_32KHZ);286else287OS_REG_WRITE(ah, AR_MAC_LED, OS_REG_READ(ah, AR_MAC_LED) |288saveLedState);289290/* Start TSF2 for generic timer 8-15 */291#ifdef NOTYET292if (AR_SREV_KIWI(ah))293ar5416StartTsf2(ah);294#endif295296/*297* Enable Bluetooth Coexistence if it's enabled.298*/299if (AH5416(ah)->ah_btCoexConfigType != HAL_BT_COEX_CFG_NONE)300ar5416InitBTCoex(ah);301302/* Restore previous antenna */303OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);304305/* then our BSSID and associate id */306OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));307OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4) |308(ahp->ah_assocId & 0x3fff) << AR_BSS_ID1_AID_S);309310/* Restore bmiss rssi & count thresholds */311OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);312313OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */314315/* Restore bmiss rssi & count thresholds */316OS_REG_WRITE(ah, AR_RSSI_THR, rssiThrReg);317318if (!ar5212SetChannel(ah, chan))319FAIL(HAL_EIO);320321OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);322323/* Set 1:1 QCU to DCU mapping for all queues */324for (i = 0; i < AR_NUM_DCU; i++)325OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);326327ahp->ah_intrTxqs = 0;328for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++)329ah->ah_resetTxQueue(ah, i);330331ar5416InitIMR(ah, opmode);332ar5416SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1);333ar5416InitQoS(ah);334/* This may override the AR_DIAG_SW register */335ar5416InitUserSettings(ah);336337/* XXX this won't work for AR9287! */338if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) {339ar5416SetIFSTiming(ah, chan);340#if 0341/*342* AR5413?343* Force window_length for 1/2 and 1/4 rate channels,344* the ini file sets this to zero otherwise.345*/346OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,347AR_PHY_FRAME_CTL_WINLEN, 3);348}349#endif350}351352if (AR_SREV_KIWI_13_OR_LATER(ah)) {353/*354* Enable ASYNC FIFO355*356* If Async FIFO is enabled, the following counters change357* as MAC now runs at 117 Mhz instead of 88/44MHz when358* async FIFO is disabled.359*360* Overwrite the delay/timeouts initialized in ProcessIni()361* above.362*/363OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS,364AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);365OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT,366AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);367OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS,368AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);369370OS_REG_WRITE(ah, AR_TIME_OUT,371AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);372OS_REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);373374OS_REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,375AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);376OS_REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,377AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);378}379380if (AR_SREV_KIWI_13_OR_LATER(ah)) {381/* Enable AGGWEP to accelerate encryption engine */382OS_REG_SET_BIT(ah, AR_PCU_MISC_MODE2,383AR_PCU_MISC_MODE2_ENABLE_AGGWEP);384}385386/*387* disable seq number generation in hw388*/389OS_REG_WRITE(ah, AR_STA_ID1,390OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);391392ar5416InitDMA(ah);393394/*395* program OBS bus to see MAC interrupts396*/397OS_REG_WRITE(ah, AR_OBS, 8);398399/*400* Disable the "general" TX/RX mitigation timers.401*/402OS_REG_WRITE(ah, AR_MIRT, 0);403404#ifdef AH_AR5416_INTERRUPT_MITIGATION405/*406* This initialises the RX interrupt mitigation timers.407*408* The mitigation timers begin at idle and are triggered409* upon the RXOK of a single frame (or sub-frame, for A-MPDU.)410* Then, the RX mitigation interrupt will fire:411*412* + 250uS after the last RX'ed frame, or413* + 700uS after the first RX'ed frame414*415* Thus, the LAST field dictates the extra latency416* induced by the RX mitigation method and the FIRST417* field dictates how long to delay before firing an418* RX mitigation interrupt.419*420* Please note this only seems to be for RXOK frames;421* not CRC or PHY error frames.422*423*/424OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 250);425OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 700);426#endif427ar5416InitBB(ah, chan);428429/* Setup compression registers */430ar5212SetCompRegs(ah); /* XXX not needed? */431432/*433* 5416 baseband will check the per rate power table434* and select the lower of the two435*/436ackTpcPow = 63;437ctsTpcPow = 63;438chirpTpcPow = 63;439powerVal = SM(ackTpcPow, AR_TPC_ACK) |440SM(ctsTpcPow, AR_TPC_CTS) |441SM(chirpTpcPow, AR_TPC_CHIRP);442OS_REG_WRITE(ah, AR_TPC, powerVal);443444if (!ar5416InitCal(ah, chan))445FAIL(HAL_ESELFTEST);446447ar5416RestoreChainMask(ah);448449AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */450451if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan))452chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;453454if (AR_SREV_HOWL(ah)) {455/*456* Enable the MBSSID block-ack fix for HOWL.457* This feature is only supported on Howl 1.4, but it is safe to458* set bit 22 of STA_ID1 on other Howl revisions (1.1, 1.2, 1.3),459* since bit 22 is unused in those Howl revisions.460*/461unsigned int reg;462reg = (OS_REG_READ(ah, AR_STA_ID1) | (1<<22));463OS_REG_WRITE(ah,AR_STA_ID1, reg);464ath_hal_printf(ah, "MBSSID Set bit 22 of AR_STA_ID 0x%x\n", reg);465}466467HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__);468469OS_MARK(ah, AH_MARK_RESET_DONE, 0);470471return AH_TRUE;472bad:473OS_MARK(ah, AH_MARK_RESET_DONE, ecode);474if (status != AH_NULL)475*status = ecode;476return AH_FALSE;477#undef FAIL478#undef N479}480481#if 0482/*483* This channel change evaluates whether the selected hardware can484* perform a synthesizer-only channel change (no reset). If the485* TX is not stopped, or the RFBus cannot be granted in the given486* time, the function returns false as a reset is necessary487*/488HAL_BOOL489ar5416ChannelChange(struct ath_hal *ah, const structu ieee80211_channel *chan)490{491uint32_t ulCount;492uint32_t data, synthDelay, qnum;493uint16_t rfXpdGain[4];494struct ath_hal_5212 *ahp = AH5212(ah);495HAL_CHANNEL_INTERNAL *ichan;496497/*498* Map public channel to private.499*/500ichan = ath_hal_checkchannel(ah, chan);501502/* TX must be stopped or RF Bus grant will not work */503for (qnum = 0; qnum < AH_PRIVATE(ah)->ah_caps.halTotalQueues; qnum++) {504if (ar5212NumTxPending(ah, qnum)) {505HALDEBUG(ah, HAL_DEBUG_ANY,506"%s: frames pending on queue %d\n", __func__, qnum);507return AH_FALSE;508}509}510511/*512* Kill last Baseband Rx Frame - Request analog bus grant513*/514OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_REQUEST);515if (!ath_hal_wait(ah, AR_PHY_RFBUS_GNT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN)) {516HALDEBUG(ah, HAL_DEBUG_ANY, "%s: could not kill baseband rx\n",517__func__);518return AH_FALSE;519}520521ar5416Set11nRegs(ah, chan); /* NB: setup 5416-specific regs */522523/* Change the synth */524if (!ar5212SetChannel(ah, chan))525return AH_FALSE;526527/* Setup the transmit power values. */528if (!ah->ah_setTxPower(ah, chan, rfXpdGain)) {529HALDEBUG(ah, HAL_DEBUG_ANY,530"%s: error init'ing transmit power\n", __func__);531return AH_FALSE;532}533534/*535* Wait for the frequency synth to settle (synth goes on536* via PHY_ACTIVE_EN). Read the phy active delay register.537* Value is in 100ns increments.538*/539data = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;540if (IS_CHAN_CCK(ichan)) {541synthDelay = (4 * data) / 22;542} else {543synthDelay = data / 10;544}545546OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY);547548/* Release the RFBus Grant */549OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);550551/* Write delta slope for OFDM enabled modes (A, G, Turbo) */552if (IEEE80211_IS_CHAN_OFDM(ichan)|| IEEE80211_IS_CHAN_HT(chan)) {553HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3);554ar5212SetSpurMitigation(ah, chan);555ar5416SetDeltaSlope(ah, chan);556}557558/* XXX spur mitigation for Melin */559560if (!IEEE80211_IS_CHAN_DFS(chan))561chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;562563ichan->channel_time = 0;564ichan->tsf_last = ar5416GetTsf64(ah);565ar5212TxEnable(ah, AH_TRUE);566return AH_TRUE;567}568#endif569570static void571ar5416InitDMA(struct ath_hal *ah)572{573struct ath_hal_5212 *ahp = AH5212(ah);574575/*576* set AHB_MODE not to do cacheline prefetches577*/578OS_REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN);579580/*581* let mac dma reads be in 128 byte chunks582*/583OS_REG_WRITE(ah, AR_TXCFG,584(OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK) | AR_TXCFG_DMASZ_128B);585586/*587* let mac dma writes be in 128 byte chunks588*/589/*590* XXX If you change this, you must change the headroom591* assigned in ah_maxTxTrigLev - see ar5416InitState().592*/593OS_REG_WRITE(ah, AR_RXCFG,594(OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK) | AR_RXCFG_DMASZ_128B);595596/* restore TX trigger level */597OS_REG_WRITE(ah, AR_TXCFG,598(OS_REG_READ(ah, AR_TXCFG) &~ AR_FTRIG) |599SM(ahp->ah_txTrigLev, AR_FTRIG));600601/*602* Setup receive FIFO threshold to hold off TX activities603*/604OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);605606/*607* reduce the number of usable entries in PCU TXBUF to avoid608* wrap around.609*/610if (AR_SREV_KITE(ah))611/*612* For AR9285 the number of Fifos are reduced to half.613* So set the usable tx buf size also to half to614* avoid data/delimiter underruns615*/616OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);617else618OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE);619}620621static void622ar5416InitBB(struct ath_hal *ah, const struct ieee80211_channel *chan)623{624uint32_t synthDelay;625626/*627* Wait for the frequency synth to settle (synth goes on628* via AR_PHY_ACTIVE_EN). Read the phy active delay register.629* Value is in 100ns increments.630*/631synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;632if (IEEE80211_IS_CHAN_CCK(chan)) {633synthDelay = (4 * synthDelay) / 22;634} else {635synthDelay /= 10;636}637638/* Turn on PLL on 5416 */639HALDEBUG(ah, HAL_DEBUG_RESET, "%s %s channel\n",640__func__, IEEE80211_IS_CHAN_5GHZ(chan) ? "5GHz" : "2GHz");641642/* Activate the PHY (includes baseband activate and synthesizer on) */643OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);644645/*646* If the AP starts the calibration before the base band timeout647* completes we could get rx_clear false triggering. Add an648* extra BASE_ACTIVATE_DELAY usecs to ensure this condition649* does not happen.650*/651if (IEEE80211_IS_CHAN_HALF(chan)) {652OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY);653} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {654OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY);655} else {656OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY);657}658}659660static void661ar5416InitIMR(struct ath_hal *ah, HAL_OPMODE opmode)662{663struct ath_hal_5212 *ahp = AH5212(ah);664665/*666* Setup interrupt handling. Note that ar5212ResetTxQueue667* manipulates the secondary IMR's as queues are enabled668* and disabled. This is done with RMW ops to insure the669* settings we make here are preserved.670*/671ahp->ah_maskReg = AR_IMR_TXERR | AR_IMR_TXURN672| AR_IMR_RXERR | AR_IMR_RXORN673| AR_IMR_BCNMISC;674675#ifdef AH_AR5416_INTERRUPT_MITIGATION676ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;677#else678ahp->ah_maskReg |= AR_IMR_RXOK;679#endif680ahp->ah_maskReg |= AR_IMR_TXOK;681682if (opmode == HAL_M_HOSTAP)683ahp->ah_maskReg |= AR_IMR_MIB;684OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);685686#ifdef ADRIAN_NOTYET687/* This is straight from ath9k */688if (! AR_SREV_HOWL(ah)) {689OS_REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);690OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);691OS_REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);692}693#endif694695/* Enable bus errors that are OR'd to set the HIUERR bit */696#if 0697OS_REG_WRITE(ah, AR_IMR_S2,698OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT | AR_IMR_S2_CST);699#endif700}701702static void703ar5416InitQoS(struct ath_hal *ah)704{705/* QoS support */706OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */707OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */708709/* Turn on NOACK Support for QoS packets */710OS_REG_WRITE(ah, AR_NOACK,711SM(2, AR_NOACK_2BIT_VALUE) |712SM(5, AR_NOACK_BIT_OFFSET) |713SM(0, AR_NOACK_BYTE_OFFSET));714715/*716* initialize TXOP for all TIDs717*/718OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);719OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);720OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);721OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);722OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);723}724725static void726ar5416InitUserSettings(struct ath_hal *ah)727{728struct ath_hal_5212 *ahp = AH5212(ah);729730/* Restore user-specified settings */731if (ahp->ah_miscMode != 0)732OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE)733| ahp->ah_miscMode);734if (ahp->ah_sifstime != (u_int) -1)735ar5212SetSifsTime(ah, ahp->ah_sifstime);736if (ahp->ah_slottime != (u_int) -1)737ar5212SetSlotTime(ah, ahp->ah_slottime);738if (ahp->ah_acktimeout != (u_int) -1)739ar5212SetAckTimeout(ah, ahp->ah_acktimeout);740if (ahp->ah_ctstimeout != (u_int) -1)741ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout);742if (AH_PRIVATE(ah)->ah_diagreg != 0)743OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);744if (AH5416(ah)->ah_globaltxtimeout != (u_int) -1)745ar5416SetGlobalTxTimeout(ah, AH5416(ah)->ah_globaltxtimeout);746}747748static void749ar5416SetRfMode(struct ath_hal *ah, const struct ieee80211_channel *chan)750{751uint32_t rfMode;752753if (chan == AH_NULL)754return;755756/* treat channel B as channel G , no B mode suport in owl */757rfMode = IEEE80211_IS_CHAN_CCK(chan) ?758AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;759760if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {761/* phy mode bits for 5GHz channels require Fast Clock */762rfMode |= AR_PHY_MODE_DYNAMIC763| AR_PHY_MODE_DYN_CCK_DISABLE;764} else if (!AR_SREV_MERLIN_10_OR_LATER(ah)) {765rfMode |= IEEE80211_IS_CHAN_5GHZ(chan) ?766AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;767}768769OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);770}771772/*773* Places the hardware into reset and then pulls it out of reset774*/775HAL_BOOL776ar5416ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan,777HAL_RESET_TYPE resetType)778{779OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);780/*781* Warm reset is optimistic for open-loop TX power control.782*/783if (AR_SREV_MERLIN(ah) &&784ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {785if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))786return AH_FALSE;787} else if (ah->ah_config.ah_force_full_reset) {788if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))789return AH_FALSE;790} else if ((resetType == HAL_RESET_FORCE_COLD) ||791(resetType == HAL_RESET_BBPANIC)) {792HALDEBUG(ah, HAL_DEBUG_RESET,793"%s: full reset; resetType=%d\n",794__func__, resetType);795if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))796return AH_FALSE;797} else {798if (!ar5416SetResetReg(ah, HAL_RESET_WARM))799return AH_FALSE;800}801802/* Bring out of sleep mode (AGAIN) */803if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))804return AH_FALSE;805806#ifdef notyet807ahp->ah_chipFullSleep = AH_FALSE;808#endif809810AH5416(ah)->ah_initPLL(ah, chan);811812/*813* Perform warm reset before the mode/PLL/turbo registers814* are changed in order to deactivate the radio. Mode changes815* with an active radio can result in corrupted shifts to the816* radio device.817*/818ar5416SetRfMode(ah, chan);819820return AH_TRUE;821}822823/*824* Delta slope coefficient computation.825* Required for OFDM operation.826*/827static void828ar5416GetDeltaSlopeValues(struct ath_hal *ah, uint32_t coef_scaled,829uint32_t *coef_mantissa, uint32_t *coef_exponent)830{831#define COEF_SCALE_S 24832uint32_t coef_exp, coef_man;833/*834* ALGO -> coef_exp = 14-floor(log2(coef));835* floor(log2(x)) is the highest set bit position836*/837for (coef_exp = 31; coef_exp > 0; coef_exp--)838if ((coef_scaled >> coef_exp) & 0x1)839break;840/* A coef_exp of 0 is a legal bit position but an unexpected coef_exp */841HALASSERT(coef_exp);842coef_exp = 14 - (coef_exp - COEF_SCALE_S);843844/*845* ALGO -> coef_man = floor(coef* 2^coef_exp+0.5);846* The coefficient is already shifted up for scaling847*/848coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1));849850*coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp);851*coef_exponent = coef_exp - 16;852853#undef COEF_SCALE_S854}855856void857ar5416SetDeltaSlope(struct ath_hal *ah, const struct ieee80211_channel *chan)858{859#define INIT_CLOCKMHZSCALED 0x64000000860uint32_t coef_scaled, ds_coef_exp, ds_coef_man;861uint32_t clockMhzScaled;862863CHAN_CENTERS centers;864865/* half and quarter rate can divide the scaled clock by 2 or 4 respectively */866/* scale for selected channel bandwidth */867clockMhzScaled = INIT_CLOCKMHZSCALED;868if (IEEE80211_IS_CHAN_TURBO(chan))869clockMhzScaled <<= 1;870else if (IEEE80211_IS_CHAN_HALF(chan))871clockMhzScaled >>= 1;872else if (IEEE80211_IS_CHAN_QUARTER(chan))873clockMhzScaled >>= 2;874875/*876* ALGO -> coef = 1e8/fcarrier*fclock/40;877* scaled coef to provide precision for this floating calculation878*/879ar5416GetChannelCenters(ah, chan, ¢ers);880coef_scaled = clockMhzScaled / centers.synth_center;881882ar5416GetDeltaSlopeValues(ah, coef_scaled, &ds_coef_man, &ds_coef_exp);883884OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3,885AR_PHY_TIMING3_DSC_MAN, ds_coef_man);886OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3,887AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);888889/*890* For Short GI,891* scaled coeff is 9/10 that of normal coeff892*/893coef_scaled = (9 * coef_scaled)/10;894895ar5416GetDeltaSlopeValues(ah, coef_scaled, &ds_coef_man, &ds_coef_exp);896897/* for short gi */898OS_REG_RMW_FIELD(ah, AR_PHY_HALFGI,899AR_PHY_HALFGI_DSC_MAN, ds_coef_man);900OS_REG_RMW_FIELD(ah, AR_PHY_HALFGI,901AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);902#undef INIT_CLOCKMHZSCALED903}904905/*906* Set a limit on the overall output power. Used for dynamic907* transmit power control and the like.908*909* NB: limit is in units of 0.5 dbM.910*/911HAL_BOOL912ar5416SetTxPowerLimit(struct ath_hal *ah, uint32_t limit)913{914uint16_t dummyXpdGains[2];915916AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER);917return ah->ah_setTxPower(ah, AH_PRIVATE(ah)->ah_curchan,918dummyXpdGains);919}920921HAL_BOOL922ar5416GetChipPowerLimits(struct ath_hal *ah,923struct ieee80211_channel *chan)924{925struct ath_hal_5212 *ahp = AH5212(ah);926int16_t minPower, maxPower;927928/*929* Get Pier table max and min powers.930*/931if (ahp->ah_rfHal->getChannelMaxMinPower(ah, chan, &maxPower, &minPower)) {932/* NB: rf code returns 1/4 dBm units, convert */933chan->ic_maxpower = maxPower / 2;934chan->ic_minpower = minPower / 2;935} else {936HALDEBUG(ah, HAL_DEBUG_ANY,937"%s: no min/max power for %u/0x%x\n",938__func__, chan->ic_freq, chan->ic_flags);939chan->ic_maxpower = AR5416_MAX_RATE_POWER;940chan->ic_minpower = 0;941}942HALDEBUG(ah, HAL_DEBUG_RESET,943"Chan %d: MaxPow = %d MinPow = %d\n",944chan->ic_freq, chan->ic_maxpower, chan->ic_minpower);945return AH_TRUE;946}947948/**************************************************************949* ar5416WriteTxPowerRateRegisters950*951* Write the TX power rate registers from the raw values given952* in ratesArray[].953*954* The CCK and HT40 rate registers are only written if needed.955* HT20 and 11g/11a OFDM rate registers are always written.956*957* The values written are raw values which should be written958* to the registers - so it's up to the caller to pre-adjust959* them (eg CCK power offset value, or Merlin TX power offset,960* etc.)961*/962void963ar5416WriteTxPowerRateRegisters(struct ath_hal *ah,964const struct ieee80211_channel *chan, const int16_t ratesArray[])965{966#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s))967968/* Write the OFDM power per rate set */969OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,970POW_SM(ratesArray[rate18mb], 24)971| POW_SM(ratesArray[rate12mb], 16)972| POW_SM(ratesArray[rate9mb], 8)973| POW_SM(ratesArray[rate6mb], 0)974);975OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,976POW_SM(ratesArray[rate54mb], 24)977| POW_SM(ratesArray[rate48mb], 16)978| POW_SM(ratesArray[rate36mb], 8)979| POW_SM(ratesArray[rate24mb], 0)980);981982if (IEEE80211_IS_CHAN_2GHZ(chan)) {983/* Write the CCK power per rate set */984OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,985POW_SM(ratesArray[rate2s], 24)986| POW_SM(ratesArray[rate2l], 16)987| POW_SM(ratesArray[rateXr], 8) /* XR target power */988| POW_SM(ratesArray[rate1l], 0)989);990OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,991POW_SM(ratesArray[rate11s], 24)992| POW_SM(ratesArray[rate11l], 16)993| POW_SM(ratesArray[rate5_5s], 8)994| POW_SM(ratesArray[rate5_5l], 0)995);996HALDEBUG(ah, HAL_DEBUG_RESET,997"%s AR_PHY_POWER_TX_RATE3=0x%x AR_PHY_POWER_TX_RATE4=0x%x\n",998__func__, OS_REG_READ(ah,AR_PHY_POWER_TX_RATE3),999OS_REG_READ(ah,AR_PHY_POWER_TX_RATE4));1000}10011002/* Write the HT20 power per rate set */1003OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,1004POW_SM(ratesArray[rateHt20_3], 24)1005| POW_SM(ratesArray[rateHt20_2], 16)1006| POW_SM(ratesArray[rateHt20_1], 8)1007| POW_SM(ratesArray[rateHt20_0], 0)1008);1009OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,1010POW_SM(ratesArray[rateHt20_7], 24)1011| POW_SM(ratesArray[rateHt20_6], 16)1012| POW_SM(ratesArray[rateHt20_5], 8)1013| POW_SM(ratesArray[rateHt20_4], 0)1014);10151016if (IEEE80211_IS_CHAN_HT40(chan)) {1017/* Write the HT40 power per rate set */1018OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,1019POW_SM(ratesArray[rateHt40_3], 24)1020| POW_SM(ratesArray[rateHt40_2], 16)1021| POW_SM(ratesArray[rateHt40_1], 8)1022| POW_SM(ratesArray[rateHt40_0], 0)1023);1024OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,1025POW_SM(ratesArray[rateHt40_7], 24)1026| POW_SM(ratesArray[rateHt40_6], 16)1027| POW_SM(ratesArray[rateHt40_5], 8)1028| POW_SM(ratesArray[rateHt40_4], 0)1029);1030/* Write the Dup/Ext 40 power per rate set */1031OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,1032POW_SM(ratesArray[rateExtOfdm], 24)1033| POW_SM(ratesArray[rateExtCck], 16)1034| POW_SM(ratesArray[rateDupOfdm], 8)1035| POW_SM(ratesArray[rateDupCck], 0)1036);1037}10381039/*1040* Set max power to 30 dBm and, optionally,1041* enable TPC in tx descriptors.1042*/1043OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER |1044(AH5212(ah)->ah_tpcEnabled ? AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE : 0));1045#undef POW_SM1046}10471048/**************************************************************1049* ar5416SetTransmitPower1050*1051* Set the transmit power in the baseband for the given1052* operating channel and mode.1053*/1054HAL_BOOL1055ar5416SetTransmitPower(struct ath_hal *ah,1056const struct ieee80211_channel *chan, uint16_t *rfXpdGain)1057{1058#define N(a) (sizeof (a) / sizeof (a[0]))1059#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s))10601061MODAL_EEP_HEADER *pModal;1062struct ath_hal_5212 *ahp = AH5212(ah);1063int16_t txPowerIndexOffset = 0;1064int i;10651066uint16_t cfgCtl;1067uint16_t powerLimit;1068uint16_t twiceAntennaReduction;1069uint16_t twiceMaxRegulatoryPower;1070int16_t maxPower;1071HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;1072struct ar5416eeprom *pEepData = &ee->ee_base;10731074HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);10751076/*1077* Default to 2, is overridden based on the EEPROM version / value.1078*/1079AH5416(ah)->ah_ht40PowerIncForPdadc = 2;10801081/* Setup info for the actual eeprom */1082OS_MEMZERO(AH5416(ah)->ah_ratesArray, sizeof(AH5416(ah)->ah_ratesArray));1083cfgCtl = ath_hal_getctl(ah, chan);1084powerLimit = chan->ic_maxregpower * 2;1085twiceAntennaReduction = chan->ic_maxantgain;1086twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit);1087pModal = &pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)];1088HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n",1089__func__,chan->ic_freq, cfgCtl );10901091if (IS_EEP_MINOR_V2(ah)) {1092AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;1093}10941095if (!ar5416SetPowerPerRateTable(ah, pEepData, chan,1096&AH5416(ah)->ah_ratesArray[0],1097cfgCtl,1098twiceAntennaReduction,1099twiceMaxRegulatoryPower, powerLimit)) {1100HALDEBUG(ah, HAL_DEBUG_ANY,1101"%s: unable to set tx power per rate table\n", __func__);1102return AH_FALSE;1103}11041105if (!AH5416(ah)->ah_setPowerCalTable(ah, pEepData, chan, &txPowerIndexOffset)) {1106HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set power table\n",1107__func__);1108return AH_FALSE;1109}11101111maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb],1112AH5416(ah)->ah_ratesArray[rateHt20_0]);11131114if (IEEE80211_IS_CHAN_2GHZ(chan)) {1115maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rate1l]);1116}11171118if (IEEE80211_IS_CHAN_HT40(chan)) {1119maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rateHt40_0]);1120}11211122ahp->ah_tx6PowerInHalfDbm = maxPower;1123AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower;1124ahp->ah_txPowerIndexOffset = txPowerIndexOffset;11251126/*1127* txPowerIndexOffset is set by the SetPowerTable() call -1128* adjust the rate table (0 offset if rates EEPROM not loaded)1129*/1130for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {1131AH5416(ah)->ah_ratesArray[i] =1132(int16_t)(txPowerIndexOffset + AH5416(ah)->ah_ratesArray[i]);1133if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)1134AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;1135}11361137#ifdef AH_EEPROM_DUMP1138/*1139* Dump the rate array whilst it represents the intended dBm*21140* values versus what's being adjusted before being programmed1141* in. Keep this in mind if you code up this function and enable1142* this debugging; the values won't necessarily be what's being1143* programmed into the hardware.1144*/1145ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray);1146#endif11471148/*1149* Merlin and later have a power offset, so subtract1150* pwr_table_offset * 2 from each value. The default1151* power offset is -5 dBm - ie, a register value of 01152* equates to a TX power of -5 dBm.1153*/1154if (AR_SREV_MERLIN_20_OR_LATER(ah)) {1155int8_t pwr_table_offset;11561157(void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET,1158&pwr_table_offset);1159/* Underflow power gets clamped at raw value 0 */1160/* Overflow power gets camped at AR5416_MAX_RATE_POWER */1161for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {1162/*1163* + pwr_table_offset is in dBm1164* + ratesArray is in 1/2 dBm1165*/1166AH5416(ah)->ah_ratesArray[i] -= (pwr_table_offset * 2);1167if (AH5416(ah)->ah_ratesArray[i] < 0)1168AH5416(ah)->ah_ratesArray[i] = 0;1169else if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)1170AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;1171}1172}11731174/*1175* Adjust rates for OLC where needed1176*1177* The following CCK rates need adjusting when doing 2.4ghz1178* CCK transmission.1179*1180* + rate2s, rate2l, rate1l, rate11s, rate11l, rate5_5s, rate5_5l1181* + rateExtCck, rateDupCck1182*1183* They're adjusted here regardless. The hardware then gets1184* programmed as needed. 5GHz operation doesn't program in CCK1185* rates for legacy mode but they seem to be initialised for1186* HT40 regardless of channel type.1187*/1188if (AR_SREV_MERLIN_20_OR_LATER(ah) &&1189ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {1190int adj[] = {1191rate2s, rate2l, rate1l, rate11s, rate11l,1192rate5_5s, rate5_5l, rateExtCck, rateDupCck1193};1194int cck_ofdm_delta = 2;1195int i;1196for (i = 0; i < N(adj); i++) {1197AH5416(ah)->ah_ratesArray[adj[i]] -= cck_ofdm_delta;1198if (AH5416(ah)->ah_ratesArray[adj[i]] < 0)1199AH5416(ah)->ah_ratesArray[adj[i]] = 0;1200}1201}12021203/*1204* Adjust the HT40 power to meet the correct target TX power1205* for 40MHz mode, based on TX power curves that are established1206* for 20MHz mode.1207*1208* XXX handle overflow/too high power level?1209*/1210if (IEEE80211_IS_CHAN_HT40(chan)) {1211AH5416(ah)->ah_ratesArray[rateHt40_0] +=1212AH5416(ah)->ah_ht40PowerIncForPdadc;1213AH5416(ah)->ah_ratesArray[rateHt40_1] +=1214AH5416(ah)->ah_ht40PowerIncForPdadc;1215AH5416(ah)->ah_ratesArray[rateHt40_2] += AH5416(ah)->ah_ht40PowerIncForPdadc;1216AH5416(ah)->ah_ratesArray[rateHt40_3] += AH5416(ah)->ah_ht40PowerIncForPdadc;1217AH5416(ah)->ah_ratesArray[rateHt40_4] += AH5416(ah)->ah_ht40PowerIncForPdadc;1218AH5416(ah)->ah_ratesArray[rateHt40_5] += AH5416(ah)->ah_ht40PowerIncForPdadc;1219AH5416(ah)->ah_ratesArray[rateHt40_6] += AH5416(ah)->ah_ht40PowerIncForPdadc;1220AH5416(ah)->ah_ratesArray[rateHt40_7] += AH5416(ah)->ah_ht40PowerIncForPdadc;1221}12221223/* Write the TX power rate registers */1224ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray);12251226/* Write the Power subtraction for dynamic chain changing, for per-packet powertx */1227OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB,1228POW_SM(pModal->pwrDecreaseFor3Chain, 6)1229| POW_SM(pModal->pwrDecreaseFor2Chain, 0)1230);1231return AH_TRUE;1232#undef POW_SM1233#undef N1234}12351236/*1237* Exported call to check for a recent gain reading and return1238* the current state of the thermal calibration gain engine.1239*/1240HAL_RFGAIN1241ar5416GetRfgain(struct ath_hal *ah)1242{12431244return (HAL_RFGAIN_INACTIVE);1245}12461247/*1248* Places all of hardware into reset1249*/1250HAL_BOOL1251ar5416Disable(struct ath_hal *ah)1252{12531254if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))1255return AH_FALSE;1256if (! ar5416SetResetReg(ah, HAL_RESET_COLD))1257return AH_FALSE;12581259AH5416(ah)->ah_initPLL(ah, AH_NULL);1260return (AH_TRUE);1261}12621263/*1264* Places the PHY and Radio chips into reset. A full reset1265* must be called to leave this state. The PCI/MAC/PCU are1266* not placed into reset as we must receive interrupt to1267* re-enable the hardware.1268*/1269HAL_BOOL1270ar5416PhyDisable(struct ath_hal *ah)1271{12721273if (! ar5416SetResetReg(ah, HAL_RESET_WARM))1274return AH_FALSE;12751276AH5416(ah)->ah_initPLL(ah, AH_NULL);1277return (AH_TRUE);1278}12791280/*1281* Write the given reset bit mask into the reset register1282*/1283HAL_BOOL1284ar5416SetResetReg(struct ath_hal *ah, uint32_t type)1285{1286/*1287* Set force wake1288*/1289OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,1290AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);12911292switch (type) {1293case HAL_RESET_POWER_ON:1294return ar5416SetResetPowerOn(ah);1295case HAL_RESET_WARM:1296case HAL_RESET_COLD:1297return ar5416SetReset(ah, type);1298default:1299HALASSERT(AH_FALSE);1300return AH_FALSE;1301}1302}13031304static HAL_BOOL1305ar5416SetResetPowerOn(struct ath_hal *ah)1306{1307/* Power On Reset (Hard Reset) */13081309/*1310* Set force wake1311*1312* If the MAC was running, previously calling1313* reset will wake up the MAC but it may go back to sleep1314* before we can start polling.1315* Set force wake stops that1316* This must be called before initiating a hard reset.1317*/1318OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,1319AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);13201321/*1322* PowerOn reset can be used in open loop power control or failure recovery.1323* If we do RTC reset while DMA is still running, hardware may corrupt memory.1324* Therefore, we need to reset AHB first to stop DMA.1325*/1326if (! AR_SREV_HOWL(ah))1327OS_REG_WRITE(ah, AR_RC, AR_RC_AHB);1328/*1329* RTC reset and clear1330*/1331OS_REG_WRITE(ah, AR_RTC_RESET, 0);1332OS_DELAY(20);13331334if (! AR_SREV_HOWL(ah))1335OS_REG_WRITE(ah, AR_RC, 0);13361337OS_REG_WRITE(ah, AR_RTC_RESET, 1);13381339/*1340* Poll till RTC is ON1341*/1342if (!ath_hal_wait(ah, AR_RTC_STATUS, AR_RTC_PM_STATUS_M, AR_RTC_STATUS_ON)) {1343HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RTC not waking up\n", __func__);1344return AH_FALSE;1345}13461347return ar5416SetReset(ah, HAL_RESET_COLD);1348}13491350static HAL_BOOL1351ar5416SetReset(struct ath_hal *ah, int type)1352{1353uint32_t tmpReg, mask;1354uint32_t rst_flags;13551356#ifdef AH_SUPPORT_AR9130 /* Because of the AR9130 specific registers */1357if (AR_SREV_HOWL(ah)) {1358HALDEBUG(ah, HAL_DEBUG_ANY, "[ath] HOWL: Fiddling with derived clk!\n");1359uint32_t val = OS_REG_READ(ah, AR_RTC_DERIVED_CLK);1360val &= ~AR_RTC_DERIVED_CLK_PERIOD;1361val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD);1362OS_REG_WRITE(ah, AR_RTC_DERIVED_CLK, val);1363(void) OS_REG_READ(ah, AR_RTC_DERIVED_CLK);1364}1365#endif /* AH_SUPPORT_AR9130 */13661367/*1368* Force wake1369*/1370OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,1371AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);13721373#ifdef AH_SUPPORT_AR91301374if (AR_SREV_HOWL(ah)) {1375rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |1376AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;1377} else {1378#endif /* AH_SUPPORT_AR9130 */1379/*1380* Reset AHB1381*1382* (In case the last interrupt source was a bus timeout.)1383* XXX TODO: this is not the way to do it! It should be recorded1384* XXX by the interrupt handler and passed _into_ the1385* XXX reset path routine so this occurs.1386*/1387tmpReg = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE);1388if (tmpReg & (AR_INTR_SYNC_LOCAL_TIMEOUT|AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {1389OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);1390OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF);1391} else {1392OS_REG_WRITE(ah, AR_RC, AR_RC_AHB);1393}1394rst_flags = AR_RTC_RC_MAC_WARM;1395if (type == HAL_RESET_COLD)1396rst_flags |= AR_RTC_RC_MAC_COLD;1397#ifdef AH_SUPPORT_AR91301398}1399#endif /* AH_SUPPORT_AR9130 */14001401OS_REG_WRITE(ah, AR_RTC_RC, rst_flags);14021403if (AR_SREV_HOWL(ah))1404OS_DELAY(10000);1405else1406OS_DELAY(100);14071408/*1409* Clear resets and force wakeup1410*/1411OS_REG_WRITE(ah, AR_RTC_RC, 0);1412if (!ath_hal_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) {1413HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RTC stuck in MAC reset\n", __func__);1414return AH_FALSE;1415}14161417/* Clear AHB reset */1418if (! AR_SREV_HOWL(ah))1419OS_REG_WRITE(ah, AR_RC, 0);14201421if (AR_SREV_HOWL(ah))1422OS_DELAY(50);14231424if (AR_SREV_HOWL(ah)) {1425uint32_t mask;1426mask = OS_REG_READ(ah, AR_CFG);1427if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {1428HALDEBUG(ah, HAL_DEBUG_RESET,1429"CFG Byte Swap Set 0x%x\n", mask);1430} else {1431mask =1432INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;1433OS_REG_WRITE(ah, AR_CFG, mask);1434HALDEBUG(ah, HAL_DEBUG_RESET,1435"Setting CFG 0x%x\n", OS_REG_READ(ah, AR_CFG));1436}1437} else {1438if (type == HAL_RESET_COLD) {1439if (isBigEndian()) {1440/*1441* Set CFG, little-endian for descriptor accesses.1442*/1443mask = INIT_CONFIG_STATUS | AR_CFG_SWRD;1444#ifndef AH_NEED_DESC_SWAP1445mask |= AR_CFG_SWTD;1446#endif1447HALDEBUG(ah, HAL_DEBUG_RESET,1448"%s Applying descriptor swap\n", __func__);1449OS_REG_WRITE(ah, AR_CFG, mask);1450} else1451OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);1452}1453}14541455return AH_TRUE;1456}14571458void1459ar5416InitChainMasks(struct ath_hal *ah)1460{1461int rx_chainmask = AH5416(ah)->ah_rx_chainmask;14621463/* Flip this for this chainmask regardless of chip */1464if (rx_chainmask == 0x5)1465OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN);14661467/*1468* Workaround for OWL 1.0 calibration failure; enable multi-chain;1469* then set true mask after calibration.1470*/1471if (IS_5416V1(ah) && (rx_chainmask == 0x5 || rx_chainmask == 0x3)) {1472OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);1473OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);1474} else {1475OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, AH5416(ah)->ah_rx_chainmask);1476OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, AH5416(ah)->ah_rx_chainmask);1477}1478OS_REG_WRITE(ah, AR_SELFGEN_MASK, AH5416(ah)->ah_tx_chainmask);14791480if (AH5416(ah)->ah_tx_chainmask == 0x5)1481OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN);14821483if (AR_SREV_HOWL(ah)) {1484OS_REG_WRITE(ah, AR_PHY_ANALOG_SWAP,1485OS_REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);1486}1487}14881489/*1490* Work-around for Owl 1.0 calibration failure.1491*1492* ar5416InitChainMasks sets the RX chainmask to 0x7 if it's Owl 1.01493* due to init calibration failures. ar5416RestoreChainMask restores1494* these registers to the correct setting.1495*/1496void1497ar5416RestoreChainMask(struct ath_hal *ah)1498{1499int rx_chainmask = AH5416(ah)->ah_rx_chainmask;15001501if (IS_5416V1(ah) && (rx_chainmask == 0x5 || rx_chainmask == 0x3)) {1502OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);1503OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);1504}1505}15061507void1508ar5416InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan)1509{1510uint32_t pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;1511if (chan != AH_NULL) {1512if (IEEE80211_IS_CHAN_HALF(chan))1513pll |= SM(0x1, AR_RTC_PLL_CLKSEL);1514else if (IEEE80211_IS_CHAN_QUARTER(chan))1515pll |= SM(0x2, AR_RTC_PLL_CLKSEL);15161517if (IEEE80211_IS_CHAN_5GHZ(chan))1518pll |= SM(0xa, AR_RTC_PLL_DIV);1519else1520pll |= SM(0xb, AR_RTC_PLL_DIV);1521} else1522pll |= SM(0xb, AR_RTC_PLL_DIV);15231524OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);15251526/* TODO:1527* For multi-band owl, switch between bands by reiniting the PLL.1528*/15291530OS_DELAY(RTC_PLL_SETTLE_DELAY);15311532OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_SLEEP_DERIVED_CLK);1533}15341535static void1536ar5416SetDefGainValues(struct ath_hal *ah,1537const MODAL_EEP_HEADER *pModal,1538const struct ar5416eeprom *eep,1539uint8_t txRxAttenLocal, int regChainOffset, int i)1540{15411542if (IS_EEP_MINOR_V3(ah)) {1543txRxAttenLocal = pModal->txRxAttenCh[i];15441545if (AR_SREV_MERLIN_10_OR_LATER(ah)) {1546OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,1547AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,1548pModal->bswMargin[i]);1549OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,1550AR_PHY_GAIN_2GHZ_XATTEN1_DB,1551pModal->bswAtten[i]);1552OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,1553AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,1554pModal->xatten2Margin[i]);1555OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,1556AR_PHY_GAIN_2GHZ_XATTEN2_DB,1557pModal->xatten2Db[i]);1558} else {1559OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,1560AR_PHY_GAIN_2GHZ_BSW_MARGIN,1561pModal->bswMargin[i]);1562OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,1563AR_PHY_GAIN_2GHZ_BSW_ATTEN,1564pModal->bswAtten[i]);1565}1566}15671568if (AR_SREV_MERLIN_10_OR_LATER(ah)) {1569OS_REG_RMW_FIELD(ah,1570AR_PHY_RXGAIN + regChainOffset,1571AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);1572OS_REG_RMW_FIELD(ah,1573AR_PHY_RXGAIN + regChainOffset,1574AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]);1575} else {1576OS_REG_RMW_FIELD(ah,1577AR_PHY_RXGAIN + regChainOffset,1578AR_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);1579OS_REG_RMW_FIELD(ah,1580AR_PHY_GAIN_2GHZ + regChainOffset,1581AR_PHY_GAIN_2GHZ_RXTX_MARGIN, pModal->rxTxMarginCh[i]);1582}1583}15841585/*1586* Get the register chain offset for the given chain.1587*1588* Take into account the register chain swapping with AR5416 v2.0.1589*1590* XXX make sure that the reg chain swapping is only done for1591* XXX AR5416 v2.0 or greater, and not later chips?1592*/1593int1594ar5416GetRegChainOffset(struct ath_hal *ah, int i)1595{1596int regChainOffset;15971598if (AR_SREV_5416_V20_OR_LATER(ah) &&1599(AH5416(ah)->ah_rx_chainmask == 0x5 ||1600AH5416(ah)->ah_tx_chainmask == 0x5) && (i != 0)) {1601/* Regs are swapped from chain 2 to 1 for 5416 2_0 with1602* only chains 0 and 2 populated1603*/1604regChainOffset = (i == 1) ? 0x2000 : 0x1000;1605} else {1606regChainOffset = i * 0x1000;1607}16081609return regChainOffset;1610}16111612/*1613* Read EEPROM header info and program the device for correct operation1614* given the channel value.1615*/1616HAL_BOOL1617ar5416SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan)1618{1619const HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;1620const struct ar5416eeprom *eep = &ee->ee_base;1621const MODAL_EEP_HEADER *pModal;1622int i, regChainOffset;1623uint8_t txRxAttenLocal; /* workaround for eeprom versions <= 14.2 */16241625HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);1626pModal = &eep->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)];16271628/* NB: workaround for eeprom versions <= 14.2 */1629txRxAttenLocal = IEEE80211_IS_CHAN_2GHZ(chan) ? 23 : 44;16301631OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);1632for (i = 0; i < AR5416_MAX_CHAINS; i++) {1633if (AR_SREV_MERLIN(ah)) {1634if (i >= 2) break;1635}1636regChainOffset = ar5416GetRegChainOffset(ah, i);16371638OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, pModal->antCtrlChain[i]);16391640OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4 + regChainOffset,1641(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4 + regChainOffset) &1642~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |1643SM(pModal->iqCalICh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |1644SM(pModal->iqCalQCh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));16451646/*1647* Large signal upgrade,1648* If 14.3 or later EEPROM, use1649* txRxAttenLocal = pModal->txRxAttenCh[i]1650* else txRxAttenLocal is fixed value above.1651*/16521653if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah))1654ar5416SetDefGainValues(ah, pModal, eep, txRxAttenLocal, regChainOffset, i);1655}16561657if (AR_SREV_MERLIN_10_OR_LATER(ah)) {1658if (IEEE80211_IS_CHAN_2GHZ(chan)) {1659OS_A_REG_RMW_FIELD(ah, AR_AN_RF2G1_CH0, AR_AN_RF2G1_CH0_OB, pModal->ob);1660OS_A_REG_RMW_FIELD(ah, AR_AN_RF2G1_CH0, AR_AN_RF2G1_CH0_DB, pModal->db);1661OS_A_REG_RMW_FIELD(ah, AR_AN_RF2G1_CH1, AR_AN_RF2G1_CH1_OB, pModal->ob_ch1);1662OS_A_REG_RMW_FIELD(ah, AR_AN_RF2G1_CH1, AR_AN_RF2G1_CH1_DB, pModal->db_ch1);1663} else {1664OS_A_REG_RMW_FIELD(ah, AR_AN_RF5G1_CH0, AR_AN_RF5G1_CH0_OB5, pModal->ob);1665OS_A_REG_RMW_FIELD(ah, AR_AN_RF5G1_CH0, AR_AN_RF5G1_CH0_DB5, pModal->db);1666OS_A_REG_RMW_FIELD(ah, AR_AN_RF5G1_CH1, AR_AN_RF5G1_CH1_OB5, pModal->ob_ch1);1667OS_A_REG_RMW_FIELD(ah, AR_AN_RF5G1_CH1, AR_AN_RF5G1_CH1_DB5, pModal->db_ch1);1668}1669OS_A_REG_RMW_FIELD(ah, AR_AN_TOP2, AR_AN_TOP2_XPABIAS_LVL, pModal->xpaBiasLvl);1670OS_A_REG_RMW_FIELD(ah, AR_AN_TOP2, AR_AN_TOP2_LOCALBIAS,1671!!(pModal->flagBits & AR5416_EEP_FLAG_LOCALBIAS));1672OS_A_REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,1673!!(pModal->flagBits & AR5416_EEP_FLAG_FORCEXPAON));1674}16751676OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->switchSettling);1677OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize);16781679if (! AR_SREV_MERLIN_10_OR_LATER(ah))1680OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_PGA, pModal->pgaDesiredSize);16811682OS_REG_WRITE(ah, AR_PHY_RF_CTL4,1683SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)1684| SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF)1685| SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)1686| SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));16871688OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,1689pModal->txEndToRxOn);16901691if (AR_SREV_MERLIN_10_OR_LATER(ah)) {1692OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,1693pModal->thresh62);1694OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62,1695pModal->thresh62);1696} else {1697OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,1698pModal->thresh62);1699OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CCA_THRESH62,1700pModal->thresh62);1701}17021703/* Minor Version Specific application */1704if (IS_EEP_MINOR_V2(ah)) {1705OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_DATA_START,1706pModal->txFrameToDataStart);1707OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_PA_ON,1708pModal->txFrameToPaOn);1709}17101711if (IS_EEP_MINOR_V3(ah) && IEEE80211_IS_CHAN_HT40(chan))1712/* Overwrite switch settling with HT40 value */1713OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,1714pModal->swSettleHt40);17151716if (AR_SREV_MERLIN_20_OR_LATER(ah) && EEP_MINOR(ah) >= AR5416_EEP_MINOR_VER_19)1717OS_REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, pModal->miscBits);17181719if (AR_SREV_MERLIN_20(ah) && EEP_MINOR(ah) >= AR5416_EEP_MINOR_VER_20) {1720if (IEEE80211_IS_CHAN_2GHZ(chan))1721OS_A_REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,1722eep->baseEepHeader.dacLpMode);1723else if (eep->baseEepHeader.dacHiPwrMode_5G)1724OS_A_REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0);1725else1726OS_A_REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,1727eep->baseEepHeader.dacLpMode);17281729OS_DELAY(100);17301731OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP,1732pModal->miscBits >> 2);1733OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, AR_PHY_TX_DESIRED_SCALE_CCK,1734eep->baseEepHeader.desiredScaleCCK);1735}17361737return (AH_TRUE);1738}17391740/*1741* Helper functions common for AP/CB/XB1742*/17431744/*1745* Set the target power array "ratesArray" from the1746* given set of target powers.1747*1748* This is used by the various chipset/EEPROM TX power1749* setup routines.1750*/1751void1752ar5416SetRatesArrayFromTargetPower(struct ath_hal *ah,1753const struct ieee80211_channel *chan,1754int16_t *ratesArray,1755const CAL_TARGET_POWER_LEG *targetPowerCck,1756const CAL_TARGET_POWER_LEG *targetPowerCckExt,1757const CAL_TARGET_POWER_LEG *targetPowerOfdm,1758const CAL_TARGET_POWER_LEG *targetPowerOfdmExt,1759const CAL_TARGET_POWER_HT *targetPowerHt20,1760const CAL_TARGET_POWER_HT *targetPowerHt40)1761{1762#define N(a) (sizeof(a)/sizeof(a[0]))1763int i;17641765/* Blank the rates array, to be consistent */1766for (i = 0; i < Ar5416RateSize; i++)1767ratesArray[i] = 0;17681769/* Set rates Array from collected data */1770ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =1771ratesArray[rate18mb] = ratesArray[rate24mb] =1772targetPowerOfdm->tPow2x[0];1773ratesArray[rate36mb] = targetPowerOfdm->tPow2x[1];1774ratesArray[rate48mb] = targetPowerOfdm->tPow2x[2];1775ratesArray[rate54mb] = targetPowerOfdm->tPow2x[3];1776ratesArray[rateXr] = targetPowerOfdm->tPow2x[0];17771778for (i = 0; i < N(targetPowerHt20->tPow2x); i++) {1779ratesArray[rateHt20_0 + i] = targetPowerHt20->tPow2x[i];1780}17811782if (IEEE80211_IS_CHAN_2GHZ(chan)) {1783ratesArray[rate1l] = targetPowerCck->tPow2x[0];1784ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck->tPow2x[1];1785ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck->tPow2x[2];1786ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck->tPow2x[3];1787}1788if (IEEE80211_IS_CHAN_HT40(chan)) {1789for (i = 0; i < N(targetPowerHt40->tPow2x); i++) {1790ratesArray[rateHt40_0 + i] = targetPowerHt40->tPow2x[i];1791}1792ratesArray[rateDupOfdm] = targetPowerHt40->tPow2x[0];1793ratesArray[rateDupCck] = targetPowerHt40->tPow2x[0];1794ratesArray[rateExtOfdm] = targetPowerOfdmExt->tPow2x[0];1795if (IEEE80211_IS_CHAN_2GHZ(chan)) {1796ratesArray[rateExtCck] = targetPowerCckExt->tPow2x[0];1797}1798}1799#undef N1800}18011802/*1803* ar5416SetPowerPerRateTable1804*1805* Sets the transmit power in the baseband for the given1806* operating channel and mode.1807*/1808static HAL_BOOL1809ar5416SetPowerPerRateTable(struct ath_hal *ah, struct ar5416eeprom *pEepData,1810const struct ieee80211_channel *chan,1811int16_t *ratesArray, uint16_t cfgCtl,1812uint16_t AntennaReduction,1813uint16_t twiceMaxRegulatoryPower,1814uint16_t powerLimit)1815{1816#define N(a) (sizeof(a)/sizeof(a[0]))1817/* Local defines to distinguish between extension and control CTL's */1818#define EXT_ADDITIVE (0x8000)1819#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)1820#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)1821#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)18221823uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER;1824int i;1825int16_t twiceLargestAntenna;1826CAL_CTL_DATA *rep;1827CAL_TARGET_POWER_LEG targetPowerOfdm, targetPowerCck = {0, {0, 0, 0, 0}};1828CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}, targetPowerCckExt = {0, {0, 0, 0, 0}};1829CAL_TARGET_POWER_HT targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0}};1830int16_t scaledPower, minCtlPower;18311832#define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */1833#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */1834static const uint16_t ctlModesFor11a[] = {1835CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT401836};1837static const uint16_t ctlModesFor11g[] = {1838CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT401839};1840const uint16_t *pCtlMode;1841uint16_t numCtlModes, ctlMode, freq;1842CHAN_CENTERS centers;18431844ar5416GetChannelCenters(ah, chan, ¢ers);18451846/* Compute TxPower reduction due to Antenna Gain */18471848twiceLargestAntenna = AH_MAX(AH_MAX(1849pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[0],1850pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[1]),1851pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[2]);1852#if 01853/* Turn it back on if we need to calculate per chain antenna gain reduction */1854/* Use only if the expected gain > 6dbi */1855/* Chain 0 is always used */1856twiceLargestAntenna = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[0];18571858/* Look at antenna gains of Chains 1 and 2 if the TX mask is set */1859if (ahp->ah_tx_chainmask & 0x2)1860twiceLargestAntenna = AH_MAX(twiceLargestAntenna,1861pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[1]);18621863if (ahp->ah_tx_chainmask & 0x4)1864twiceLargestAntenna = AH_MAX(twiceLargestAntenna,1865pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].antennaGainCh[2]);1866#endif1867twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0);18681869/* XXX setup for 5212 use (really used?) */1870ath_hal_eepromSet(ah,1871IEEE80211_IS_CHAN_2GHZ(chan) ? AR_EEP_ANTGAINMAX_2 : AR_EEP_ANTGAINMAX_5,1872twiceLargestAntenna);18731874/*1875* scaledPower is the minimum of the user input power level and1876* the regulatory allowed power level1877*/1878scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna);18791880/* Reduce scaled Power by number of chains active to get to per chain tx power level */1881/* TODO: better value than these? */1882switch (owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask)) {1883case 1:1884break;1885case 2:1886scaledPower -= pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pwrDecreaseFor2Chain;1887break;1888case 3:1889scaledPower -= pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pwrDecreaseFor3Chain;1890break;1891default:1892return AH_FALSE; /* Unsupported number of chains */1893}18941895scaledPower = AH_MAX(0, scaledPower);18961897/* Get target powers from EEPROM - our baseline for TX Power */1898if (IEEE80211_IS_CHAN_2GHZ(chan)) {1899/* Setup for CTL modes */1900numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */1901pCtlMode = ctlModesFor11g;19021903ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck,1904AR5416_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE);1905ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G,1906AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE);1907ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT20,1908AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE);19091910if (IEEE80211_IS_CHAN_HT40(chan)) {1911numCtlModes = N(ctlModesFor11g); /* All 2G CTL's */19121913ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT40,1914AR5416_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE);1915/* Get target powers for extension channels */1916ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck,1917AR5416_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE);1918ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G,1919AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE);1920}1921} else {1922/* Setup for CTL modes */1923numCtlModes = N(ctlModesFor11a) - SUB_NUM_CTL_MODES_AT_5G_40; /* CTL_11A, CTL_5GHT20 */1924pCtlMode = ctlModesFor11a;19251926ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower5G,1927AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE);1928ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower5GHT20,1929AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE);19301931if (IEEE80211_IS_CHAN_HT40(chan)) {1932numCtlModes = N(ctlModesFor11a); /* All 5G CTL's */19331934ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower5GHT40,1935AR5416_NUM_5G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE);1936ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower5G,1937AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE);1938}1939}19401941/*1942* For MIMO, need to apply regulatory caps individually across dynamically1943* running modes: CCK, OFDM, HT20, HT401944*1945* The outer loop walks through each possible applicable runtime mode.1946* The inner loop walks through each ctlIndex entry in EEPROM.1947* The ctl value is encoded as [7:4] == test group, [3:0] == test mode.1948*1949*/1950for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {1951HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||1952(pCtlMode[ctlMode] == CTL_2GHT40);1953if (isHt40CtlMode) {1954freq = centers.ctl_center;1955} else if (pCtlMode[ctlMode] & EXT_ADDITIVE) {1956freq = centers.ext_center;1957} else {1958freq = centers.ctl_center;1959}19601961/* walk through each CTL index stored in EEPROM */1962for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {1963uint16_t twiceMinEdgePower;19641965/* compare test group from regulatory channel list with test mode from pCtlMode list */1966if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) ||1967(((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) ==1968((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {1969rep = &(pEepData->ctlData[i]);1970twiceMinEdgePower = ar5416GetMaxEdgePower(freq,1971rep->ctlEdges[owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1],1972IEEE80211_IS_CHAN_2GHZ(chan));1973if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {1974/* Find the minimum of all CTL edge powers that apply to this channel */1975twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower);1976} else {1977/* specific */1978twiceMaxEdgePower = twiceMinEdgePower;1979break;1980}1981}1982}1983minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower);1984/* Apply ctl mode to correct target power set */1985switch(pCtlMode[ctlMode]) {1986case CTL_11B:1987for (i = 0; i < N(targetPowerCck.tPow2x); i++) {1988targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower);1989}1990break;1991case CTL_11A:1992case CTL_11G:1993for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) {1994targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower);1995}1996break;1997case CTL_5GHT20:1998case CTL_2GHT20:1999for (i = 0; i < N(targetPowerHt20.tPow2x); i++) {2000targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower);2001}2002break;2003case CTL_11B_EXT:2004targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower);2005break;2006case CTL_11A_EXT:2007case CTL_11G_EXT:2008targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower);2009break;2010case CTL_5GHT40:2011case CTL_2GHT40:2012for (i = 0; i < N(targetPowerHt40.tPow2x); i++) {2013targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower);2014}2015break;2016default:2017return AH_FALSE;2018break;2019}2020} /* end ctl mode checking */20212022/* Set rates Array from collected data */2023ar5416SetRatesArrayFromTargetPower(ah, chan, ratesArray,2024&targetPowerCck,2025&targetPowerCckExt,2026&targetPowerOfdm,2027&targetPowerOfdmExt,2028&targetPowerHt20,2029&targetPowerHt40);2030return AH_TRUE;2031#undef EXT_ADDITIVE2032#undef CTL_11A_EXT2033#undef CTL_11G_EXT2034#undef CTL_11B_EXT2035#undef SUB_NUM_CTL_MODES_AT_5G_402036#undef SUB_NUM_CTL_MODES_AT_2G_402037#undef N2038}20392040/**************************************************************************2041* fbin2freq2042*2043* Get channel value from binary representation held in eeprom2044* RETURNS: the frequency in MHz2045*/2046static uint16_t2047fbin2freq(uint8_t fbin, HAL_BOOL is2GHz)2048{2049/*2050* Reserved value 0xFF provides an empty definition both as2051* an fbin and as a frequency - do not convert2052*/2053if (fbin == AR5416_BCHAN_UNUSED) {2054return fbin;2055}20562057return (uint16_t)((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));2058}20592060/*2061* ar5416GetMaxEdgePower2062*2063* Find the maximum conformance test limit for the given channel and CTL info2064*/2065uint16_t2066ar5416GetMaxEdgePower(uint16_t freq, CAL_CTL_EDGES *pRdEdgesPower, HAL_BOOL is2GHz)2067{2068uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER;2069int i;20702071/* Get the edge power */2072for (i = 0; (i < AR5416_NUM_BAND_EDGES) && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED) ; i++) {2073/*2074* If there's an exact channel match or an inband flag set2075* on the lower channel use the given rdEdgePower2076*/2077if (freq == fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {2078twiceMaxEdgePower = MS(pRdEdgesPower[i].tPowerFlag, CAL_CTL_EDGES_POWER);2079break;2080} else if ((i > 0) && (freq < fbin2freq(pRdEdgesPower[i].bChannel, is2GHz))) {2081if (fbin2freq(pRdEdgesPower[i - 1].bChannel, is2GHz) < freq && (pRdEdgesPower[i - 1].tPowerFlag & CAL_CTL_EDGES_FLAG) != 0) {2082twiceMaxEdgePower = MS(pRdEdgesPower[i - 1].tPowerFlag, CAL_CTL_EDGES_POWER);2083}2084/* Leave loop - no more affecting edges possible in this monotonic increasing list */2085break;2086}2087}2088HALASSERT(twiceMaxEdgePower > 0);2089return twiceMaxEdgePower;2090}20912092/**************************************************************2093* ar5416GetTargetPowers2094*2095* Return the rates of target power for the given target power table2096* channel, and number of channels2097*/2098void2099ar5416GetTargetPowers(struct ath_hal *ah, const struct ieee80211_channel *chan,2100CAL_TARGET_POWER_HT *powInfo, uint16_t numChannels,2101CAL_TARGET_POWER_HT *pNewPower, uint16_t numRates,2102HAL_BOOL isHt40Target)2103{2104uint16_t clo, chi;2105int i;2106int matchIndex = -1, lowIndex = -1;2107uint16_t freq;2108CHAN_CENTERS centers;21092110ar5416GetChannelCenters(ah, chan, ¢ers);2111freq = isHt40Target ? centers.synth_center : centers.ctl_center;21122113/* Copy the target powers into the temp channel list */2114if (freq <= fbin2freq(powInfo[0].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) {2115matchIndex = 0;2116} else {2117for (i = 0; (i < numChannels) && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {2118if (freq == fbin2freq(powInfo[i].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) {2119matchIndex = i;2120break;2121} else if ((freq < fbin2freq(powInfo[i].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) &&2122(freq > fbin2freq(powInfo[i - 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))))2123{2124lowIndex = i - 1;2125break;2126}2127}2128if ((matchIndex == -1) && (lowIndex == -1)) {2129HALASSERT(freq > fbin2freq(powInfo[i - 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan)));2130matchIndex = i - 1;2131}2132}21332134if (matchIndex != -1) {2135OS_MEMCPY(pNewPower, &powInfo[matchIndex], sizeof(*pNewPower));2136} else {2137HALASSERT(lowIndex != -1);2138/*2139* Get the lower and upper channels, target powers,2140* and interpolate between them.2141*/2142clo = fbin2freq(powInfo[lowIndex].bChannel, IEEE80211_IS_CHAN_2GHZ(chan));2143chi = fbin2freq(powInfo[lowIndex + 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan));21442145for (i = 0; i < numRates; i++) {2146pNewPower->tPow2x[i] = (uint8_t)ath_ee_interpolate(freq, clo, chi,2147powInfo[lowIndex].tPow2x[i], powInfo[lowIndex + 1].tPow2x[i]);2148}2149}2150}2151/**************************************************************2152* ar5416GetTargetPowersLeg2153*2154* Return the four rates of target power for the given target power table2155* channel, and number of channels2156*/2157void2158ar5416GetTargetPowersLeg(struct ath_hal *ah,2159const struct ieee80211_channel *chan,2160CAL_TARGET_POWER_LEG *powInfo, uint16_t numChannels,2161CAL_TARGET_POWER_LEG *pNewPower, uint16_t numRates,2162HAL_BOOL isExtTarget)2163{2164uint16_t clo, chi;2165int i;2166int matchIndex = -1, lowIndex = -1;2167uint16_t freq;2168CHAN_CENTERS centers;21692170ar5416GetChannelCenters(ah, chan, ¢ers);2171freq = (isExtTarget) ? centers.ext_center :centers.ctl_center;21722173/* Copy the target powers into the temp channel list */2174if (freq <= fbin2freq(powInfo[0].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) {2175matchIndex = 0;2176} else {2177for (i = 0; (i < numChannels) && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {2178if (freq == fbin2freq(powInfo[i].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) {2179matchIndex = i;2180break;2181} else if ((freq < fbin2freq(powInfo[i].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))) &&2182(freq > fbin2freq(powInfo[i - 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan))))2183{2184lowIndex = i - 1;2185break;2186}2187}2188if ((matchIndex == -1) && (lowIndex == -1)) {2189HALASSERT(freq > fbin2freq(powInfo[i - 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan)));2190matchIndex = i - 1;2191}2192}21932194if (matchIndex != -1) {2195OS_MEMCPY(pNewPower, &powInfo[matchIndex], sizeof(*pNewPower));2196} else {2197HALASSERT(lowIndex != -1);2198/*2199* Get the lower and upper channels, target powers,2200* and interpolate between them.2201*/2202clo = fbin2freq(powInfo[lowIndex].bChannel, IEEE80211_IS_CHAN_2GHZ(chan));2203chi = fbin2freq(powInfo[lowIndex + 1].bChannel, IEEE80211_IS_CHAN_2GHZ(chan));22042205for (i = 0; i < numRates; i++) {2206pNewPower->tPow2x[i] = (uint8_t)ath_ee_interpolate(freq, clo, chi,2207powInfo[lowIndex].tPow2x[i], powInfo[lowIndex + 1].tPow2x[i]);2208}2209}2210}22112212/*2213* Set the gain boundaries for the given radio chain.2214*2215* The gain boundaries tell the hardware at what point in the2216* PDADC array to "switch over" from one PD gain setting2217* to another. There's also a gain overlap between two2218* PDADC array gain curves where there's valid PD values2219* for 2 gain settings.2220*2221* The hardware uses the gain overlap and gain boundaries2222* to determine which gain curve to use for the given2223* target TX power.2224*/2225void2226ar5416SetGainBoundariesClosedLoop(struct ath_hal *ah, int i,2227uint16_t pdGainOverlap_t2, uint16_t gainBoundaries[])2228{2229int regChainOffset;22302231regChainOffset = ar5416GetRegChainOffset(ah, i);22322233HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: chain %d: gainOverlap_t2: %d,"2234" gainBoundaries: %d, %d, %d, %d\n", __func__, i, pdGainOverlap_t2,2235gainBoundaries[0], gainBoundaries[1], gainBoundaries[2],2236gainBoundaries[3]);2237OS_REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,2238SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |2239SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) |2240SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) |2241SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) |2242SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));2243}22442245/*2246* Get the gain values and the number of gain levels given2247* in xpdMask.2248*2249* The EEPROM xpdMask determines which power detector gain2250* levels were used during calibration. Each of these mask2251* bits maps to a fixed gain level in hardware.2252*/2253uint16_t2254ar5416GetXpdGainValues(struct ath_hal *ah, uint16_t xpdMask,2255uint16_t xpdGainValues[])2256{2257int i;2258uint16_t numXpdGain = 0;22592260for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {2261if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {2262if (numXpdGain >= AR5416_NUM_PD_GAINS) {2263HALASSERT(0);2264break;2265}2266xpdGainValues[numXpdGain] = (uint16_t)(AR5416_PD_GAINS_IN_MASK - i);2267numXpdGain++;2268}2269}2270return numXpdGain;2271}22722273/*2274* Write the detector gain and biases.2275*2276* There are four power detector gain levels. The xpdMask in the EEPROM2277* determines which power detector gain levels have TX power calibration2278* data associated with them. This function writes the number of2279* PD gain levels and their values into the hardware.2280*2281* This is valid for all TX chains - the calibration data itself however2282* will likely differ per-chain.2283*/2284void2285ar5416WriteDetectorGainBiases(struct ath_hal *ah, uint16_t numXpdGain,2286uint16_t xpdGainValues[])2287{2288HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: numXpdGain: %d,"2289" xpdGainValues: %d, %d, %d\n", __func__, numXpdGain,2290xpdGainValues[0], xpdGainValues[1], xpdGainValues[2]);22912292OS_REG_WRITE(ah, AR_PHY_TPCRG1, (OS_REG_READ(ah, AR_PHY_TPCRG1) &2293~(AR_PHY_TPCRG1_NUM_PD_GAIN | AR_PHY_TPCRG1_PD_GAIN_1 |2294AR_PHY_TPCRG1_PD_GAIN_2 | AR_PHY_TPCRG1_PD_GAIN_3)) |2295SM(numXpdGain - 1, AR_PHY_TPCRG1_NUM_PD_GAIN) |2296SM(xpdGainValues[0], AR_PHY_TPCRG1_PD_GAIN_1 ) |2297SM(xpdGainValues[1], AR_PHY_TPCRG1_PD_GAIN_2) |2298SM(xpdGainValues[2], AR_PHY_TPCRG1_PD_GAIN_3));2299}23002301/*2302* Write the PDADC array to the given radio chain i.2303*2304* The 32 PDADC registers are written without any care about2305* their contents - so if various chips treat values as "special",2306* this routine will not care.2307*/2308void2309ar5416WritePdadcValues(struct ath_hal *ah, int i, uint8_t pdadcValues[])2310{2311int regOffset, regChainOffset;2312int j;2313int reg32;23142315regChainOffset = ar5416GetRegChainOffset(ah, i);2316regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;23172318for (j = 0; j < 32; j++) {2319reg32 = ((pdadcValues[4*j + 0] & 0xFF) << 0) |2320((pdadcValues[4*j + 1] & 0xFF) << 8) |2321((pdadcValues[4*j + 2] & 0xFF) << 16) |2322((pdadcValues[4*j + 3] & 0xFF) << 24) ;2323OS_REG_WRITE(ah, regOffset, reg32);2324HALDEBUG(ah, HAL_DEBUG_EEPROM, "PDADC: Chain %d |"2325" PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d"2326" Value %3d | PDADC %3d Value %3d |\n",2327i,23284*j, pdadcValues[4*j],23294*j+1, pdadcValues[4*j + 1],23304*j+2, pdadcValues[4*j + 2],23314*j+3, pdadcValues[4*j + 3]);2332regOffset += 4;2333}2334}23352336/**************************************************************2337* ar5416SetPowerCalTable2338*2339* Pull the PDADC piers from cal data and interpolate them across the given2340* points as well as from the nearest pier(s) to get a power detector2341* linear voltage to power level table.2342*/2343HAL_BOOL2344ar5416SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom *pEepData,2345const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset)2346{2347CAL_DATA_PER_FREQ *pRawDataset;2348uint8_t *pCalBChans = AH_NULL;2349uint16_t pdGainOverlap_t2;2350static uint8_t pdadcValues[AR5416_NUM_PDADC_VALUES];2351uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK];2352uint16_t numPiers, i;2353int16_t tMinCalPower;2354uint16_t numXpdGain, xpdMask;2355uint16_t xpdGainValues[AR5416_NUM_PD_GAINS];2356uint32_t regChainOffset;23572358OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues));23592360xpdMask = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].xpdGain;23612362if (IS_EEP_MINOR_V2(ah)) {2363pdGainOverlap_t2 = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pdGainOverlap;2364} else {2365pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP));2366}23672368if (IEEE80211_IS_CHAN_2GHZ(chan)) {2369pCalBChans = pEepData->calFreqPier2G;2370numPiers = AR5416_NUM_2G_CAL_PIERS;2371} else {2372pCalBChans = pEepData->calFreqPier5G;2373numPiers = AR5416_NUM_5G_CAL_PIERS;2374}23752376/* Calculate the value of xpdgains from the xpdGain Mask */2377numXpdGain = ar5416GetXpdGainValues(ah, xpdMask, xpdGainValues);23782379/* Write the detector gain biases and their number */2380ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues);23812382for (i = 0; i < AR5416_MAX_CHAINS; i++) {2383regChainOffset = ar5416GetRegChainOffset(ah, i);23842385if (pEepData->baseEepHeader.txMask & (1 << i)) {2386if (IEEE80211_IS_CHAN_2GHZ(chan)) {2387pRawDataset = pEepData->calPierData2G[i];2388} else {2389pRawDataset = pEepData->calPierData5G[i];2390}23912392/* Fetch the gain boundaries and the PDADC values */2393ar5416GetGainBoundariesAndPdadcs(ah, chan, pRawDataset,2394pCalBChans, numPiers,2395pdGainOverlap_t2,2396&tMinCalPower, gainBoundaries,2397pdadcValues, numXpdGain);23982399if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {2400ar5416SetGainBoundariesClosedLoop(ah, i, pdGainOverlap_t2,2401gainBoundaries);2402}24032404/* Write the power values into the baseband power table */2405ar5416WritePdadcValues(ah, i, pdadcValues);2406}2407}2408*pTxPowerIndexOffset = 0;24092410return AH_TRUE;2411}24122413/**************************************************************2414* ar5416GetGainBoundariesAndPdadcs2415*2416* Uses the data points read from EEPROM to reconstruct the pdadc power table2417* Called by ar5416SetPowerCalTable only.2418*/2419void2420ar5416GetGainBoundariesAndPdadcs(struct ath_hal *ah,2421const struct ieee80211_channel *chan,2422CAL_DATA_PER_FREQ *pRawDataSet,2423uint8_t * bChans, uint16_t availPiers,2424uint16_t tPdGainOverlap, int16_t *pMinCalPower, uint16_t * pPdGainBoundaries,2425uint8_t * pPDADCValues, uint16_t numXpdGains)2426{24272428int i, j, k;2429int16_t ss; /* potentially -ve index for taking care of pdGainOverlap */2430uint16_t idxL, idxR, numPiers; /* Pier indexes */24312432/* filled out Vpd table for all pdGains (chanL) */2433static uint8_t vpdTableL[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB];24342435/* filled out Vpd table for all pdGains (chanR) */2436static uint8_t vpdTableR[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB];24372438/* filled out Vpd table for all pdGains (interpolated) */2439static uint8_t vpdTableI[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB];24402441uint8_t *pVpdL, *pVpdR, *pPwrL, *pPwrR;2442uint8_t minPwrT4[AR5416_NUM_PD_GAINS];2443uint8_t maxPwrT4[AR5416_NUM_PD_GAINS];2444int16_t vpdStep;2445int16_t tmpVal;2446uint16_t sizeCurrVpdTable, maxIndex, tgtIndex;2447HAL_BOOL match;2448int16_t minDelta = 0;2449CHAN_CENTERS centers;24502451ar5416GetChannelCenters(ah, chan, ¢ers);24522453/* Trim numPiers for the number of populated channel Piers */2454for (numPiers = 0; numPiers < availPiers; numPiers++) {2455if (bChans[numPiers] == AR5416_BCHAN_UNUSED) {2456break;2457}2458}24592460/* Find pier indexes around the current channel */2461match = ath_ee_getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center,2462IEEE80211_IS_CHAN_2GHZ(chan)), bChans, numPiers, &idxL, &idxR);24632464if (match) {2465/* Directly fill both vpd tables from the matching index */2466for (i = 0; i < numXpdGains; i++) {2467minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];2468maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];2469ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pRawDataSet[idxL].pwrPdg[i],2470pRawDataSet[idxL].vpdPdg[i], AR5416_PD_GAIN_ICEPTS, vpdTableI[i]);2471}2472} else {2473for (i = 0; i < numXpdGains; i++) {2474pVpdL = pRawDataSet[idxL].vpdPdg[i];2475pPwrL = pRawDataSet[idxL].pwrPdg[i];2476pVpdR = pRawDataSet[idxR].vpdPdg[i];2477pPwrR = pRawDataSet[idxR].pwrPdg[i];24782479/* Start Vpd interpolation from the max of the minimum powers */2480minPwrT4[i] = AH_MAX(pPwrL[0], pPwrR[0]);24812482/* End Vpd interpolation from the min of the max powers */2483maxPwrT4[i] = AH_MIN(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);2484HALASSERT(maxPwrT4[i] > minPwrT4[i]);24852486/* Fill pier Vpds */2487ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrL, pVpdL, AR5416_PD_GAIN_ICEPTS, vpdTableL[i]);2488ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrR, pVpdR, AR5416_PD_GAIN_ICEPTS, vpdTableR[i]);24892490/* Interpolate the final vpd */2491for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {2492vpdTableI[i][j] = (uint8_t)(ath_ee_interpolate((uint16_t)FREQ2FBIN(centers.synth_center,2493IEEE80211_IS_CHAN_2GHZ(chan)),2494bChans[idxL], bChans[idxR], vpdTableL[i][j], vpdTableR[i][j]));2495}2496}2497}2498*pMinCalPower = (int16_t)(minPwrT4[0] / 2);24992500k = 0; /* index for the final table */2501for (i = 0; i < numXpdGains; i++) {2502if (i == (numXpdGains - 1)) {2503pPdGainBoundaries[i] = (uint16_t)(maxPwrT4[i] / 2);2504} else {2505pPdGainBoundaries[i] = (uint16_t)((maxPwrT4[i] + minPwrT4[i+1]) / 4);2506}25072508pPdGainBoundaries[i] = (uint16_t)AH_MIN(AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);25092510/* NB: only applies to owl 1.0 */2511if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah) ) {2512/*2513* fix the gain delta, but get a delta that can be applied to min to2514* keep the upper power values accurate, don't think max needs to2515* be adjusted because should not be at that area of the table?2516*/2517minDelta = pPdGainBoundaries[0] - 23;2518pPdGainBoundaries[0] = 23;2519}2520else {2521minDelta = 0;2522}25232524/* Find starting index for this pdGain */2525if (i == 0) {2526if (AR_SREV_MERLIN_10_OR_LATER(ah))2527ss = (int16_t)(0 - (minPwrT4[i] / 2));2528else2529ss = 0; /* for the first pdGain, start from index 0 */2530} else {2531/* need overlap entries extrapolated below. */2532ss = (int16_t)((pPdGainBoundaries[i-1] - (minPwrT4[i] / 2)) - tPdGainOverlap + 1 + minDelta);2533}2534vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);2535vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);2536/*2537*-ve ss indicates need to extrapolate data below for this pdGain2538*/2539while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {2540tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);2541pPDADCValues[k++] = (uint8_t)((tmpVal < 0) ? 0 : tmpVal);2542ss++;2543}25442545sizeCurrVpdTable = (uint8_t)((maxPwrT4[i] - minPwrT4[i]) / 2 +1);2546tgtIndex = (uint8_t)(pPdGainBoundaries[i] + tPdGainOverlap - (minPwrT4[i] / 2));2547maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;25482549while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {2550pPDADCValues[k++] = vpdTableI[i][ss++];2551}25522553vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - vpdTableI[i][sizeCurrVpdTable - 2]);2554vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);2555/*2556* for last gain, pdGainBoundary == Pmax_t2, so will2557* have to extrapolate2558*/2559if (tgtIndex >= maxIndex) { /* need to extrapolate above */2560while ((ss <= tgtIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {2561tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +2562(ss - maxIndex +1) * vpdStep));2563pPDADCValues[k++] = (uint8_t)((tmpVal > 255) ? 255 : tmpVal);2564ss++;2565}2566} /* extrapolated above */2567} /* for all pdGainUsed */25682569/* Fill out pdGainBoundaries - only up to 2 allowed here, but hardware allows up to 4 */2570while (i < AR5416_PD_GAINS_IN_MASK) {2571pPdGainBoundaries[i] = pPdGainBoundaries[i-1];2572i++;2573}25742575while (k < AR5416_NUM_PDADC_VALUES) {2576pPDADCValues[k] = pPDADCValues[k-1];2577k++;2578}2579return;2580}25812582/*2583* The linux ath9k driver and (from what I've been told) the reference2584* Atheros driver enables the 11n PHY by default whether or not it's2585* configured.2586*/2587static void2588ar5416Set11nRegs(struct ath_hal *ah, const struct ieee80211_channel *chan)2589{2590uint32_t phymode;2591uint32_t enableDacFifo = 0;2592HAL_HT_MACMODE macmode; /* MAC - 20/40 mode */25932594if (AR_SREV_KITE_10_OR_LATER(ah))2595enableDacFifo = (OS_REG_READ(ah, AR_PHY_TURBO) & AR_PHY_FC_ENABLE_DAC_FIFO);25962597/* Enable 11n HT, 20 MHz */2598phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_402599| AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo;26002601/* Configure baseband for dynamic 20/40 operation */2602if (IEEE80211_IS_CHAN_HT40(chan)) {2603phymode |= AR_PHY_FC_DYN2040_EN;26042605/* Configure control (primary) channel at +-10MHz */2606if (IEEE80211_IS_CHAN_HT40U(chan))2607phymode |= AR_PHY_FC_DYN2040_PRI_CH;2608#if 02609/* Configure 20/25 spacing */2610if (ht->ht_extprotspacing == HAL_HT_EXTPROTSPACING_25)2611phymode |= AR_PHY_FC_DYN2040_EXT_CH;2612#endif2613macmode = HAL_HT_MACMODE_2040;2614} else2615macmode = HAL_HT_MACMODE_20;2616OS_REG_WRITE(ah, AR_PHY_TURBO, phymode);26172618/* Configure MAC for 20/40 operation */2619ar5416Set11nMac2040(ah, macmode);26202621/* global transmit timeout (25 TUs default)*/2622/* XXX - put this elsewhere??? */2623OS_REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S) ;26242625/* carrier sense timeout */2626OS_REG_SET_BIT(ah, AR_GTTM, AR_GTTM_CST_USEC);2627OS_REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);2628}26292630void2631ar5416GetChannelCenters(struct ath_hal *ah,2632const struct ieee80211_channel *chan, CHAN_CENTERS *centers)2633{2634uint16_t freq = ath_hal_gethwchannel(ah, chan);26352636centers->ctl_center = freq;2637centers->synth_center = freq;2638/*2639* In 20/40 phy mode, the center frequency is2640* "between" the control and extension channels.2641*/2642if (IEEE80211_IS_CHAN_HT40U(chan)) {2643centers->synth_center += HT40_CHANNEL_CENTER_SHIFT;2644centers->ext_center =2645centers->synth_center + HT40_CHANNEL_CENTER_SHIFT;2646} else if (IEEE80211_IS_CHAN_HT40D(chan)) {2647centers->synth_center -= HT40_CHANNEL_CENTER_SHIFT;2648centers->ext_center =2649centers->synth_center - HT40_CHANNEL_CENTER_SHIFT;2650} else {2651centers->ext_center = freq;2652}2653}26542655/*2656* Override the INI vals being programmed.2657*/2658static void2659ar5416OverrideIni(struct ath_hal *ah, const struct ieee80211_channel *chan)2660{2661uint32_t val;26622663/*2664* Set the RX_ABORT and RX_DIS and clear if off only after2665* RXE is set for MAC. This prevents frames with corrupted2666* descriptor status.2667*/2668OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));26692670if (AR_SREV_MERLIN_10_OR_LATER(ah)) {2671val = OS_REG_READ(ah, AR_PCU_MISC_MODE2);2672val &= (~AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE);2673if (!AR_SREV_9271(ah))2674val &= ~AR_PCU_MISC_MODE2_HWWAR1;26752676if (AR_SREV_KIWI_10_OR_LATER(ah))2677val = val & (~AR_PCU_MISC_MODE2_HWWAR2);26782679OS_REG_WRITE(ah, AR_PCU_MISC_MODE2, val);2680}26812682/*2683* Disable RIFS search on some chips to avoid baseband2684* hang issues.2685*/2686if (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah))2687(void) ar5416SetRifsDelay(ah, chan, AH_FALSE);26882689if (!AR_SREV_5416_V20_OR_LATER(ah) || AR_SREV_MERLIN(ah))2690return;26912692/*2693* Disable BB clock gating2694* Necessary to avoid issues on AR5416 2.02695*/2696OS_REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);2697}26982699struct ini {2700uint32_t *data; /* NB: !const */2701int rows, cols;2702};27032704/*2705* Override XPA bias level based on operating frequency.2706* This is a v14 EEPROM specific thing for the AR9160.2707*/2708void2709ar5416EepromSetAddac(struct ath_hal *ah, const struct ieee80211_channel *chan)2710{2711#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt])2712MODAL_EEP_HEADER *pModal;2713HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;2714struct ar5416eeprom *eep = &ee->ee_base;2715uint8_t biaslevel;27162717if (! AR_SREV_SOWL(ah))2718return;27192720if (EEP_MINOR(ah) < AR5416_EEP_MINOR_VER_7)2721return;27222723pModal = &(eep->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)]);27242725if (pModal->xpaBiasLvl != 0xff)2726biaslevel = pModal->xpaBiasLvl;2727else {2728uint16_t resetFreqBin, freqBin, freqCount = 0;2729CHAN_CENTERS centers;27302731ar5416GetChannelCenters(ah, chan, ¢ers);27322733resetFreqBin = FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan));2734freqBin = XPA_LVL_FREQ(0) & 0xff;2735biaslevel = (uint8_t) (XPA_LVL_FREQ(0) >> 14);27362737freqCount++;27382739while (freqCount < 3) {2740if (XPA_LVL_FREQ(freqCount) == 0x0)2741break;27422743freqBin = XPA_LVL_FREQ(freqCount) & 0xff;2744if (resetFreqBin >= freqBin)2745biaslevel = (uint8_t)(XPA_LVL_FREQ(freqCount) >> 14);2746else2747break;2748freqCount++;2749}2750}27512752HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: overriding XPA bias level = %d\n",2753__func__, biaslevel);27542755/*2756* This is a dirty workaround for the const initval data,2757* which will upset multiple AR9160's on the same board.2758*2759* The HAL should likely just have a private copy of the addac2760* data per instance.2761*/2762if (IEEE80211_IS_CHAN_2GHZ(chan))2763HAL_INI_VAL((struct ini *) &AH5416(ah)->ah_ini_addac, 7, 1) =2764(HAL_INI_VAL(&AH5416(ah)->ah_ini_addac, 7, 1) & (~0x18)) | biaslevel << 3;2765else2766HAL_INI_VAL((struct ini *) &AH5416(ah)->ah_ini_addac, 6, 1) =2767(HAL_INI_VAL(&AH5416(ah)->ah_ini_addac, 6, 1) & (~0xc0)) | biaslevel << 6;2768#undef XPA_LVL_FREQ2769}27702771static void2772ar5416MarkPhyInactive(struct ath_hal *ah)2773{2774OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);2775}27762777#define AR5416_IFS_SLOT_FULL_RATE_40 0x168 /* 9 us half, 40 MHz core clock (9*40) */2778#define AR5416_IFS_SLOT_HALF_RATE_40 0x104 /* 13 us half, 20 MHz core clock (13*20) */2779#define AR5416_IFS_SLOT_QUARTER_RATE_40 0xD2 /* 21 us quarter, 10 MHz core clock (21*10) */27802781#define AR5416_IFS_EIFS_FULL_RATE_40 0xE60 /* (74 + (2 * 9)) * 40MHz core clock */2782#define AR5416_IFS_EIFS_HALF_RATE_40 0xDAC /* (149 + (2 * 13)) * 20MHz core clock */2783#define AR5416_IFS_EIFS_QUARTER_RATE_40 0xD48 /* (298 + (2 * 21)) * 10MHz core clock */27842785#define AR5416_IFS_SLOT_FULL_RATE_44 0x18c /* 9 us half, 44 MHz core clock (9*44) */2786#define AR5416_IFS_SLOT_HALF_RATE_44 0x11e /* 13 us half, 22 MHz core clock (13*22) */2787#define AR5416_IFS_SLOT_QUARTER_RATE_44 0xe7 /* 21 us quarter, 11 MHz core clock (21*11) */27882789#define AR5416_IFS_EIFS_FULL_RATE_44 0xfd0 /* (74 + (2 * 9)) * 44MHz core clock */2790#define AR5416_IFS_EIFS_HALF_RATE_44 0xf0a /* (149 + (2 * 13)) * 22MHz core clock */2791#define AR5416_IFS_EIFS_QUARTER_RATE_44 0xe9c /* (298 + (2 * 21)) * 11MHz core clock */27922793#define AR5416_INIT_USEC_40 402794#define AR5416_HALF_RATE_USEC_40 19 /* ((40 / 2) - 1 ) */2795#define AR5416_QUARTER_RATE_USEC_40 9 /* ((40 / 4) - 1 ) */27962797#define AR5416_INIT_USEC_44 442798#define AR5416_HALF_RATE_USEC_44 21 /* ((44 / 2) - 1 ) */2799#define AR5416_QUARTER_RATE_USEC_44 10 /* ((44 / 4) - 1 ) */28002801/* XXX What should these be for 40/44MHz clocks (and half/quarter) ? */2802#define AR5416_RX_NON_FULL_RATE_LATENCY 632803#define AR5416_TX_HALF_RATE_LATENCY 1082804#define AR5416_TX_QUARTER_RATE_LATENCY 21628052806/*2807* Adjust various register settings based on half/quarter rate clock setting.2808* This includes:2809*2810* + USEC, TX/RX latency,2811* + IFS params: slot, eifs, misc etc.2812*2813* TODO:2814*2815* + Verify which other registers need to be tweaked;2816* + Verify the behaviour of this for 5GHz fast and non-fast clock mode;2817* + This just plain won't work for long distance links - the coverage class2818* code isn't aware of the slot/ifs/ACK/RTS timeout values that need to2819* change;2820* + Verify whether the 32KHz USEC value needs to be kept for the 802.11n2821* series chips?2822* + Calculate/derive values for 2GHz, 5GHz, 5GHz fast clock2823*/2824static void2825ar5416SetIFSTiming(struct ath_hal *ah, const struct ieee80211_channel *chan)2826{2827uint32_t txLat, rxLat, usec, slot, refClock, eifs, init_usec;2828int clk_44 = 0;28292830HALASSERT(IEEE80211_IS_CHAN_HALF(chan) ||2831IEEE80211_IS_CHAN_QUARTER(chan));28322833/* 2GHz and 5GHz fast clock - 44MHz; else 40MHz */2834if (IEEE80211_IS_CHAN_2GHZ(chan))2835clk_44 = 1;2836else if (IEEE80211_IS_CHAN_5GHZ(chan) &&2837IS_5GHZ_FAST_CLOCK_EN(ah, chan))2838clk_44 = 1;28392840/* XXX does this need save/restoring for the 11n chips? */2841/*2842* XXX TODO: should mask out the txlat/rxlat/usec values?2843*/2844refClock = OS_REG_READ(ah, AR_USEC) & AR_USEC_USEC32;28452846/*2847* XXX This really should calculate things, not use2848* hard coded values! Ew.2849*/2850if (IEEE80211_IS_CHAN_HALF(chan)) {2851if (clk_44) {2852slot = AR5416_IFS_SLOT_HALF_RATE_44;2853rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<2854AR5416_USEC_RX_LAT_S;2855txLat = AR5416_TX_HALF_RATE_LATENCY <<2856AR5416_USEC_TX_LAT_S;2857usec = AR5416_HALF_RATE_USEC_44;2858eifs = AR5416_IFS_EIFS_HALF_RATE_44;2859init_usec = AR5416_INIT_USEC_44 >> 1;2860} else {2861slot = AR5416_IFS_SLOT_HALF_RATE_40;2862rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<2863AR5416_USEC_RX_LAT_S;2864txLat = AR5416_TX_HALF_RATE_LATENCY <<2865AR5416_USEC_TX_LAT_S;2866usec = AR5416_HALF_RATE_USEC_40;2867eifs = AR5416_IFS_EIFS_HALF_RATE_40;2868init_usec = AR5416_INIT_USEC_40 >> 1;2869}2870} else { /* quarter rate */2871if (clk_44) {2872slot = AR5416_IFS_SLOT_QUARTER_RATE_44;2873rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<2874AR5416_USEC_RX_LAT_S;2875txLat = AR5416_TX_QUARTER_RATE_LATENCY <<2876AR5416_USEC_TX_LAT_S;2877usec = AR5416_QUARTER_RATE_USEC_44;2878eifs = AR5416_IFS_EIFS_QUARTER_RATE_44;2879init_usec = AR5416_INIT_USEC_44 >> 2;2880} else {2881slot = AR5416_IFS_SLOT_QUARTER_RATE_40;2882rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<2883AR5416_USEC_RX_LAT_S;2884txLat = AR5416_TX_QUARTER_RATE_LATENCY <<2885AR5416_USEC_TX_LAT_S;2886usec = AR5416_QUARTER_RATE_USEC_40;2887eifs = AR5416_IFS_EIFS_QUARTER_RATE_40;2888init_usec = AR5416_INIT_USEC_40 >> 2;2889}2890}28912892/* XXX verify these! */2893OS_REG_WRITE(ah, AR_USEC, (usec | refClock | txLat | rxLat));2894OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot);2895OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs);2896OS_REG_RMW_FIELD(ah, AR_D_GBL_IFS_MISC,2897AR_D_GBL_IFS_MISC_USEC_DURATION, init_usec);2898}289929002901