1718cf2ccSPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
448c1d364SAdrian Chadd * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
548c1d364SAdrian Chadd *
648c1d364SAdrian Chadd * Redistribution and use in source and binary forms, with or without
748c1d364SAdrian Chadd * modification, are permitted provided that the following conditions
848c1d364SAdrian Chadd * are met:
948c1d364SAdrian Chadd * 1. Redistributions of source code must retain the above copyright
1048c1d364SAdrian Chadd * notice, this list of conditions and the following disclaimer.
1148c1d364SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright
1248c1d364SAdrian Chadd * notice, this list of conditions and the following disclaimer in the
1348c1d364SAdrian Chadd * documentation and/or other materials provided with the distribution.
1448c1d364SAdrian Chadd *
1548c1d364SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1648c1d364SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1748c1d364SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1848c1d364SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1948c1d364SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2048c1d364SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2148c1d364SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2248c1d364SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2348c1d364SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2448c1d364SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2548c1d364SAdrian Chadd * SUCH DAMAGE.
2648c1d364SAdrian Chadd */
2748c1d364SAdrian Chadd #include "opt_ah.h"
2848c1d364SAdrian Chadd
2948c1d364SAdrian Chadd #include "ah.h"
3048c1d364SAdrian Chadd #include "ah_internal.h"
3148c1d364SAdrian Chadd
3248c1d364SAdrian Chadd #include "ah_eeprom_v14.h"
3348c1d364SAdrian Chadd
3448c1d364SAdrian Chadd #include "ar9002/ar9280.h"
3548c1d364SAdrian Chadd #include "ar5416/ar5416reg.h"
3648c1d364SAdrian Chadd #include "ar5416/ar5416phy.h"
3748c1d364SAdrian Chadd #include "ar9002/ar9002phy.h"
3848c1d364SAdrian Chadd
3948c1d364SAdrian Chadd #include "ar9002/ar9280_olc.h"
4048c1d364SAdrian Chadd
4148c1d364SAdrian Chadd void
ar9280olcInit(struct ath_hal * ah)4248c1d364SAdrian Chadd ar9280olcInit(struct ath_hal *ah)
4348c1d364SAdrian Chadd {
4448c1d364SAdrian Chadd uint32_t i;
4548c1d364SAdrian Chadd
464342b610SAdrian Chadd /* Only do OLC if it's enabled for this chipset */
474342b610SAdrian Chadd if (! ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL))
484342b610SAdrian Chadd return;
494342b610SAdrian Chadd
504342b610SAdrian Chadd HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Setting up TX gain tables.\n", __func__);
514342b610SAdrian Chadd
5248c1d364SAdrian Chadd for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
5348c1d364SAdrian Chadd AH9280(ah)->originalGain[i] = MS(OS_REG_READ(ah,
5448c1d364SAdrian Chadd AR_PHY_TX_GAIN_TBL1 + i * 4), AR_PHY_TX_GAIN);
5548c1d364SAdrian Chadd
5648c1d364SAdrian Chadd AH9280(ah)->PDADCdelta = 0;
5748c1d364SAdrian Chadd }
5848c1d364SAdrian Chadd
5948c1d364SAdrian Chadd void
ar9280olcGetTxGainIndex(struct ath_hal * ah,const struct ieee80211_channel * chan,struct calDataPerFreqOpLoop * rawDatasetOpLoop,uint8_t * calChans,uint16_t availPiers,uint8_t * pwr,uint8_t * pcdacIdx)6048c1d364SAdrian Chadd ar9280olcGetTxGainIndex(struct ath_hal *ah,
6148c1d364SAdrian Chadd const struct ieee80211_channel *chan,
6248c1d364SAdrian Chadd struct calDataPerFreqOpLoop *rawDatasetOpLoop,
6348c1d364SAdrian Chadd uint8_t *calChans, uint16_t availPiers, uint8_t *pwr, uint8_t *pcdacIdx)
6448c1d364SAdrian Chadd {
6548c1d364SAdrian Chadd uint8_t pcdac, i = 0;
6648c1d364SAdrian Chadd uint16_t idxL = 0, idxR = 0, numPiers;
6748c1d364SAdrian Chadd HAL_BOOL match;
6848c1d364SAdrian Chadd CHAN_CENTERS centers;
6948c1d364SAdrian Chadd
7048c1d364SAdrian Chadd ar5416GetChannelCenters(ah, chan, ¢ers);
7148c1d364SAdrian Chadd
7248c1d364SAdrian Chadd for (numPiers = 0; numPiers < availPiers; numPiers++)
7348c1d364SAdrian Chadd if (calChans[numPiers] == AR5416_BCHAN_UNUSED)
7448c1d364SAdrian Chadd break;
7548c1d364SAdrian Chadd
766ff1b2bdSAdrian Chadd match = ath_ee_getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center,
7748c1d364SAdrian Chadd IEEE80211_IS_CHAN_2GHZ(chan)), calChans, numPiers,
7848c1d364SAdrian Chadd &idxL, &idxR);
7948c1d364SAdrian Chadd if (match) {
8048c1d364SAdrian Chadd pcdac = rawDatasetOpLoop[idxL].pcdac[0][0];
8148c1d364SAdrian Chadd *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0];
8248c1d364SAdrian Chadd } else {
8348c1d364SAdrian Chadd pcdac = rawDatasetOpLoop[idxR].pcdac[0][0];
8448c1d364SAdrian Chadd *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] +
8548c1d364SAdrian Chadd rawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
8648c1d364SAdrian Chadd }
8748c1d364SAdrian Chadd while (pcdac > AH9280(ah)->originalGain[i] &&
8848c1d364SAdrian Chadd i < (AR9280_TX_GAIN_TABLE_SIZE - 1))
8948c1d364SAdrian Chadd i++;
9048c1d364SAdrian Chadd
9148c1d364SAdrian Chadd *pcdacIdx = i;
9248c1d364SAdrian Chadd }
9348c1d364SAdrian Chadd
9448c1d364SAdrian Chadd /*
9548c1d364SAdrian Chadd * XXX txPower here is likely not the target txPower in the traditional
9648c1d364SAdrian Chadd * XXX sense, but is set by a call to ar9280olcGetTxGainIndex().
9748c1d364SAdrian Chadd * XXX Thus, be careful if you're trying to use this routine yourself.
9848c1d364SAdrian Chadd */
9948c1d364SAdrian Chadd void
ar9280olcGetPDADCs(struct ath_hal * ah,uint32_t initTxGain,int txPower,uint8_t * pPDADCValues)10048c1d364SAdrian Chadd ar9280olcGetPDADCs(struct ath_hal *ah, uint32_t initTxGain, int txPower,
10148c1d364SAdrian Chadd uint8_t *pPDADCValues)
10248c1d364SAdrian Chadd {
10348c1d364SAdrian Chadd uint32_t i;
10448c1d364SAdrian Chadd uint32_t offset;
10548c1d364SAdrian Chadd
10648c1d364SAdrian Chadd OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
10748c1d364SAdrian Chadd OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
10848c1d364SAdrian Chadd
10948c1d364SAdrian Chadd OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain);
11048c1d364SAdrian Chadd
11148c1d364SAdrian Chadd offset = txPower;
11248c1d364SAdrian Chadd for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++)
11348c1d364SAdrian Chadd if (i < offset)
11448c1d364SAdrian Chadd pPDADCValues[i] = 0x0;
11548c1d364SAdrian Chadd else
11648c1d364SAdrian Chadd pPDADCValues[i] = 0xFF;
11748c1d364SAdrian Chadd }
11848c1d364SAdrian Chadd
11948c1d364SAdrian Chadd /*
12048c1d364SAdrian Chadd * Run temperature compensation calibration.
12148c1d364SAdrian Chadd *
12248c1d364SAdrian Chadd * The TX gain table is adjusted depending upon the difference
12348c1d364SAdrian Chadd * between the initial PDADC value and the currently read
12448c1d364SAdrian Chadd * average TX power sample value. This value is only valid if
12548c1d364SAdrian Chadd * frames have been transmitted, so currPDADC will be 0 if
12648c1d364SAdrian Chadd * no frames have yet been transmitted.
12748c1d364SAdrian Chadd */
12848c1d364SAdrian Chadd void
ar9280olcTemperatureCompensation(struct ath_hal * ah)12948c1d364SAdrian Chadd ar9280olcTemperatureCompensation(struct ath_hal *ah)
13048c1d364SAdrian Chadd {
13148c1d364SAdrian Chadd uint32_t rddata, i;
13248c1d364SAdrian Chadd int delta, currPDADC, regval;
13348c1d364SAdrian Chadd uint8_t hpwr_5g = 0;
13448c1d364SAdrian Chadd
1354342b610SAdrian Chadd if (! ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL))
1364342b610SAdrian Chadd return;
1374342b610SAdrian Chadd
13848c1d364SAdrian Chadd rddata = OS_REG_READ(ah, AR_PHY_TX_PWRCTRL4);
13948c1d364SAdrian Chadd currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
14048c1d364SAdrian Chadd
14148c1d364SAdrian Chadd HALDEBUG(ah, HAL_DEBUG_PERCAL,
14248c1d364SAdrian Chadd "%s: called: initPDADC=%d, currPDADC=%d\n",
14348c1d364SAdrian Chadd __func__, AH5416(ah)->initPDADC, currPDADC);
14448c1d364SAdrian Chadd
14548c1d364SAdrian Chadd if (AH5416(ah)->initPDADC == 0 || currPDADC == 0)
14648c1d364SAdrian Chadd return;
14748c1d364SAdrian Chadd
14848c1d364SAdrian Chadd (void) (ath_hal_eepromGet(ah, AR_EEP_DAC_HPWR_5G, &hpwr_5g));
14948c1d364SAdrian Chadd
15048c1d364SAdrian Chadd if (hpwr_5g)
15148c1d364SAdrian Chadd delta = (currPDADC - AH5416(ah)->initPDADC + 4) / 8;
15248c1d364SAdrian Chadd else
15348c1d364SAdrian Chadd delta = (currPDADC - AH5416(ah)->initPDADC + 5) / 10;
15448c1d364SAdrian Chadd
15548c1d364SAdrian Chadd HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: delta=%d, PDADCdelta=%d\n",
15648c1d364SAdrian Chadd __func__, delta, AH9280(ah)->PDADCdelta);
15748c1d364SAdrian Chadd
15848c1d364SAdrian Chadd if (delta != AH9280(ah)->PDADCdelta) {
15948c1d364SAdrian Chadd AH9280(ah)->PDADCdelta = delta;
16048c1d364SAdrian Chadd for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
16148c1d364SAdrian Chadd regval = AH9280(ah)->originalGain[i] - delta;
16248c1d364SAdrian Chadd if (regval < 0)
16348c1d364SAdrian Chadd regval = 0;
16448c1d364SAdrian Chadd
16548c1d364SAdrian Chadd OS_REG_RMW_FIELD(ah,
16648c1d364SAdrian Chadd AR_PHY_TX_GAIN_TBL1 + i * 4,
16748c1d364SAdrian Chadd AR_PHY_TX_GAIN, regval);
16848c1d364SAdrian Chadd }
16948c1d364SAdrian Chadd }
17048c1d364SAdrian Chadd }
17148c1d364SAdrian Chadd
172cc5c884dSAdrian Chadd static int16_t
ar9280ChangeGainBoundarySettings(struct ath_hal * ah,uint16_t * gb,uint16_t numXpdGain,uint16_t pdGainOverlap_t2,int8_t pwr_table_offset,int16_t * diff)173cc5c884dSAdrian Chadd ar9280ChangeGainBoundarySettings(struct ath_hal *ah, uint16_t *gb,
174cc5c884dSAdrian Chadd uint16_t numXpdGain, uint16_t pdGainOverlap_t2, int8_t pwr_table_offset,
175cc5c884dSAdrian Chadd int16_t *diff)
176cc5c884dSAdrian Chadd {
177cc5c884dSAdrian Chadd uint16_t k;
178cc5c884dSAdrian Chadd
179cc5c884dSAdrian Chadd /* Prior to writing the boundaries or the pdadc vs. power table
180cc5c884dSAdrian Chadd * into the chip registers the default starting point on the pdadc
181cc5c884dSAdrian Chadd * vs. power table needs to be checked and the curve boundaries
182cc5c884dSAdrian Chadd * adjusted accordingly
183cc5c884dSAdrian Chadd */
184cc5c884dSAdrian Chadd if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
185cc5c884dSAdrian Chadd uint16_t gb_limit;
186cc5c884dSAdrian Chadd
187cc5c884dSAdrian Chadd if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
188cc5c884dSAdrian Chadd /* get the difference in dB */
189cc5c884dSAdrian Chadd *diff = (uint16_t)(pwr_table_offset - AR5416_PWR_TABLE_OFFSET_DB);
190cc5c884dSAdrian Chadd /* get the number of half dB steps */
191cc5c884dSAdrian Chadd *diff *= 2;
192cc5c884dSAdrian Chadd /* change the original gain boundary settings
193cc5c884dSAdrian Chadd * by the number of half dB steps
194cc5c884dSAdrian Chadd */
195cc5c884dSAdrian Chadd for (k = 0; k < numXpdGain; k++)
196cc5c884dSAdrian Chadd gb[k] = (uint16_t)(gb[k] - *diff);
197cc5c884dSAdrian Chadd }
198cc5c884dSAdrian Chadd /* Because of a hardware limitation, ensure the gain boundary
199cc5c884dSAdrian Chadd * is not larger than (63 - overlap)
200cc5c884dSAdrian Chadd */
201cc5c884dSAdrian Chadd gb_limit = (uint16_t)(AR5416_MAX_RATE_POWER - pdGainOverlap_t2);
202cc5c884dSAdrian Chadd
203cc5c884dSAdrian Chadd for (k = 0; k < numXpdGain; k++)
204cc5c884dSAdrian Chadd gb[k] = (uint16_t)min(gb_limit, gb[k]);
205cc5c884dSAdrian Chadd }
206cc5c884dSAdrian Chadd
207cc5c884dSAdrian Chadd return *diff;
208cc5c884dSAdrian Chadd }
209cc5c884dSAdrian Chadd
210cc5c884dSAdrian Chadd static void
ar9280AdjustPDADCValues(struct ath_hal * ah,int8_t pwr_table_offset,int16_t diff,uint8_t * pdadcValues)211cc5c884dSAdrian Chadd ar9280AdjustPDADCValues(struct ath_hal *ah, int8_t pwr_table_offset,
212cc5c884dSAdrian Chadd int16_t diff, uint8_t *pdadcValues)
213cc5c884dSAdrian Chadd {
214cc5c884dSAdrian Chadd #define NUM_PDADC(diff) (AR5416_NUM_PDADC_VALUES - diff)
215cc5c884dSAdrian Chadd uint16_t k;
216cc5c884dSAdrian Chadd
217cc5c884dSAdrian Chadd /* If this is a board that has a pwrTableOffset that differs from
218cc5c884dSAdrian Chadd * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the
219cc5c884dSAdrian Chadd * pdadc vs pwr table needs to be adjusted prior to writing to the
220cc5c884dSAdrian Chadd * chip.
221cc5c884dSAdrian Chadd */
222cc5c884dSAdrian Chadd if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
223cc5c884dSAdrian Chadd if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
224cc5c884dSAdrian Chadd /* shift the table to start at the new offset */
225cc5c884dSAdrian Chadd for (k = 0; k < (uint16_t)NUM_PDADC(diff); k++ ) {
226cc5c884dSAdrian Chadd pdadcValues[k] = pdadcValues[k + diff];
227cc5c884dSAdrian Chadd }
228cc5c884dSAdrian Chadd
229cc5c884dSAdrian Chadd /* fill the back of the table */
230cc5c884dSAdrian Chadd for (k = (uint16_t)NUM_PDADC(diff); k < NUM_PDADC(0); k++) {
231cc5c884dSAdrian Chadd pdadcValues[k] = pdadcValues[NUM_PDADC(diff)];
232cc5c884dSAdrian Chadd }
233cc5c884dSAdrian Chadd }
234cc5c884dSAdrian Chadd }
235cc5c884dSAdrian Chadd #undef NUM_PDADC
236cc5c884dSAdrian Chadd }
23748c1d364SAdrian Chadd /*
23848c1d364SAdrian Chadd * This effectively disables the gain boundaries leaving it
23948c1d364SAdrian Chadd * to the open-loop TX power control.
24048c1d364SAdrian Chadd */
24148c1d364SAdrian Chadd static void
ar9280SetGainBoundariesOpenLoop(struct ath_hal * ah,int i,uint16_t pdGainOverlap_t2,uint16_t gainBoundaries[])242b90b8dd2SAdrian Chadd ar9280SetGainBoundariesOpenLoop(struct ath_hal *ah, int i,
24348c1d364SAdrian Chadd uint16_t pdGainOverlap_t2, uint16_t gainBoundaries[])
24448c1d364SAdrian Chadd {
245b90b8dd2SAdrian Chadd int regChainOffset;
246b90b8dd2SAdrian Chadd
247b90b8dd2SAdrian Chadd regChainOffset = ar5416GetRegChainOffset(ah, i);
248b90b8dd2SAdrian Chadd
24948c1d364SAdrian Chadd /* These are unused for OLC */
25048c1d364SAdrian Chadd (void) pdGainOverlap_t2;
25148c1d364SAdrian Chadd (void) gainBoundaries;
25248c1d364SAdrian Chadd
253b90b8dd2SAdrian Chadd HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: chain %d: writing closed loop values\n",
254b90b8dd2SAdrian Chadd __func__, i);
255b90b8dd2SAdrian Chadd
25648c1d364SAdrian Chadd OS_REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
25748c1d364SAdrian Chadd SM(0x6, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
25848c1d364SAdrian Chadd SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) |
25948c1d364SAdrian Chadd SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) |
26048c1d364SAdrian Chadd SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) |
26148c1d364SAdrian Chadd SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
26248c1d364SAdrian Chadd }
26348c1d364SAdrian Chadd
26448c1d364SAdrian Chadd /* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */
26548c1d364SAdrian Chadd /* XXX shouldn't be here! */
26648c1d364SAdrian Chadd #define EEP_MINOR(_ah) \
26748c1d364SAdrian Chadd (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK)
26848c1d364SAdrian Chadd #define IS_EEP_MINOR_V2(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2)
26948c1d364SAdrian Chadd #define IS_EEP_MINOR_V3(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3)
27048c1d364SAdrian Chadd
27148c1d364SAdrian Chadd /**************************************************************
27248c1d364SAdrian Chadd * ar9280SetPowerCalTable
27348c1d364SAdrian Chadd *
27448c1d364SAdrian Chadd * Pull the PDADC piers from cal data and interpolate them across the given
27548c1d364SAdrian Chadd * points as well as from the nearest pier(s) to get a power detector
27648c1d364SAdrian Chadd * linear voltage to power level table.
27748c1d364SAdrian Chadd *
27848c1d364SAdrian Chadd * Handle OLC for Merlin where required.
27948c1d364SAdrian Chadd */
28048c1d364SAdrian Chadd HAL_BOOL
ar9280SetPowerCalTable(struct ath_hal * ah,struct ar5416eeprom * pEepData,const struct ieee80211_channel * chan,int16_t * pTxPowerIndexOffset)28148c1d364SAdrian Chadd ar9280SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom *pEepData,
28248c1d364SAdrian Chadd const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset)
28348c1d364SAdrian Chadd {
28448c1d364SAdrian Chadd CAL_DATA_PER_FREQ *pRawDataset;
28548c1d364SAdrian Chadd uint8_t *pCalBChans = AH_NULL;
28648c1d364SAdrian Chadd uint16_t pdGainOverlap_t2;
28748c1d364SAdrian Chadd static uint8_t pdadcValues[AR5416_NUM_PDADC_VALUES];
28848c1d364SAdrian Chadd uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK];
28948c1d364SAdrian Chadd uint16_t numPiers, i;
29048c1d364SAdrian Chadd int16_t tMinCalPower;
29148c1d364SAdrian Chadd uint16_t numXpdGain, xpdMask;
29248c1d364SAdrian Chadd uint16_t xpdGainValues[AR5416_NUM_PD_GAINS];
29348c1d364SAdrian Chadd uint32_t regChainOffset;
294cc5c884dSAdrian Chadd int8_t pwr_table_offset;
29548c1d364SAdrian Chadd
29648c1d364SAdrian Chadd OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues));
29748c1d364SAdrian Chadd
29848c1d364SAdrian Chadd xpdMask = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].xpdGain;
29948c1d364SAdrian Chadd
300cc5c884dSAdrian Chadd (void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET, &pwr_table_offset);
301cc5c884dSAdrian Chadd
30248c1d364SAdrian Chadd if (IS_EEP_MINOR_V2(ah)) {
30348c1d364SAdrian Chadd pdGainOverlap_t2 = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pdGainOverlap;
30448c1d364SAdrian Chadd } else {
30548c1d364SAdrian Chadd pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
30648c1d364SAdrian Chadd }
30748c1d364SAdrian Chadd
30848c1d364SAdrian Chadd if (IEEE80211_IS_CHAN_2GHZ(chan)) {
30948c1d364SAdrian Chadd pCalBChans = pEepData->calFreqPier2G;
31048c1d364SAdrian Chadd numPiers = AR5416_NUM_2G_CAL_PIERS;
31148c1d364SAdrian Chadd } else {
31248c1d364SAdrian Chadd pCalBChans = pEepData->calFreqPier5G;
31348c1d364SAdrian Chadd numPiers = AR5416_NUM_5G_CAL_PIERS;
31448c1d364SAdrian Chadd }
31548c1d364SAdrian Chadd
31648c1d364SAdrian Chadd /* If OLC is being done, set the init PDADC value appropriately */
31748c1d364SAdrian Chadd if (IEEE80211_IS_CHAN_2GHZ(chan) && AR_SREV_MERLIN_20_OR_LATER(ah) &&
31848c1d364SAdrian Chadd ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
31948c1d364SAdrian Chadd struct calDataPerFreq *pRawDataset = pEepData->calPierData2G[0];
32048c1d364SAdrian Chadd AH5416(ah)->initPDADC = ((struct calDataPerFreqOpLoop *) pRawDataset)->vpdPdg[0][0];
32148c1d364SAdrian Chadd } else {
32248c1d364SAdrian Chadd /*
32348c1d364SAdrian Chadd * XXX ath9k doesn't clear this for 5ghz mode if
32448c1d364SAdrian Chadd * it were set in 2ghz mode before!
32548c1d364SAdrian Chadd * The Merlin OLC temperature compensation code
32648c1d364SAdrian Chadd * uses this to calculate the PDADC delta during
32748c1d364SAdrian Chadd * calibration ; 0 here effectively stops the
32848c1d364SAdrian Chadd * temperature compensation calibration from
329f6b6084bSPedro F. Giffuni * occurring.
33048c1d364SAdrian Chadd */
33148c1d364SAdrian Chadd AH5416(ah)->initPDADC = 0;
33248c1d364SAdrian Chadd }
33348c1d364SAdrian Chadd
33448c1d364SAdrian Chadd /* Calculate the value of xpdgains from the xpdGain Mask */
33548c1d364SAdrian Chadd numXpdGain = ar5416GetXpdGainValues(ah, xpdMask, xpdGainValues);
33648c1d364SAdrian Chadd
33748c1d364SAdrian Chadd /* Write the detector gain biases and their number */
33848c1d364SAdrian Chadd ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues);
33948c1d364SAdrian Chadd
34048c1d364SAdrian Chadd for (i = 0; i < AR5416_MAX_CHAINS; i++) {
34148c1d364SAdrian Chadd regChainOffset = ar5416GetRegChainOffset(ah, i);
34248c1d364SAdrian Chadd if (pEepData->baseEepHeader.txMask & (1 << i)) {
343cc5c884dSAdrian Chadd uint16_t diff;
344cc5c884dSAdrian Chadd
34548c1d364SAdrian Chadd if (IEEE80211_IS_CHAN_2GHZ(chan)) {
34648c1d364SAdrian Chadd pRawDataset = pEepData->calPierData2G[i];
34748c1d364SAdrian Chadd } else {
34848c1d364SAdrian Chadd pRawDataset = pEepData->calPierData5G[i];
34948c1d364SAdrian Chadd }
35048c1d364SAdrian Chadd
35148c1d364SAdrian Chadd /* Fetch the gain boundaries and the PDADC values */
35248c1d364SAdrian Chadd if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
35348c1d364SAdrian Chadd ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
35448c1d364SAdrian Chadd uint8_t pcdacIdx;
35548c1d364SAdrian Chadd uint8_t txPower;
35648c1d364SAdrian Chadd
35748c1d364SAdrian Chadd ar9280olcGetTxGainIndex(ah, chan,
35848c1d364SAdrian Chadd (struct calDataPerFreqOpLoop *) pRawDataset,
35948c1d364SAdrian Chadd pCalBChans, numPiers, &txPower, &pcdacIdx);
36048c1d364SAdrian Chadd ar9280olcGetPDADCs(ah, pcdacIdx, txPower / 2, pdadcValues);
36148c1d364SAdrian Chadd } else {
36248c1d364SAdrian Chadd ar5416GetGainBoundariesAndPdadcs(ah, chan,
36348c1d364SAdrian Chadd pRawDataset, pCalBChans, numPiers,
36448c1d364SAdrian Chadd pdGainOverlap_t2, &tMinCalPower,
36548c1d364SAdrian Chadd gainBoundaries, pdadcValues, numXpdGain);
36648c1d364SAdrian Chadd }
36748c1d364SAdrian Chadd
36848c1d364SAdrian Chadd /*
36948c1d364SAdrian Chadd * Prior to writing the boundaries or the pdadc vs. power table
37048c1d364SAdrian Chadd * into the chip registers the default starting point on the pdadc
37148c1d364SAdrian Chadd * vs. power table needs to be checked and the curve boundaries
37248c1d364SAdrian Chadd * adjusted accordingly
37348c1d364SAdrian Chadd */
374cc5c884dSAdrian Chadd diff = ar9280ChangeGainBoundarySettings(ah,
375cc5c884dSAdrian Chadd gainBoundaries, numXpdGain, pdGainOverlap_t2,
376cc5c884dSAdrian Chadd pwr_table_offset, &diff);
37748c1d364SAdrian Chadd
378ef1901a3SAdrian Chadd if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
37948c1d364SAdrian Chadd /* Set gain boundaries for either open- or closed-loop TPC */
38048c1d364SAdrian Chadd if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
38148c1d364SAdrian Chadd ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL))
38248c1d364SAdrian Chadd ar9280SetGainBoundariesOpenLoop(ah,
383b90b8dd2SAdrian Chadd i, pdGainOverlap_t2,
38448c1d364SAdrian Chadd gainBoundaries);
38548c1d364SAdrian Chadd else
38648c1d364SAdrian Chadd ar5416SetGainBoundariesClosedLoop(ah,
387b90b8dd2SAdrian Chadd i, pdGainOverlap_t2,
38848c1d364SAdrian Chadd gainBoundaries);
38948c1d364SAdrian Chadd }
39048c1d364SAdrian Chadd
39148c1d364SAdrian Chadd /*
39248c1d364SAdrian Chadd * If this is a board that has a pwrTableOffset that differs from
39348c1d364SAdrian Chadd * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the
39448c1d364SAdrian Chadd * pdadc vs pwr table needs to be adjusted prior to writing to the
39548c1d364SAdrian Chadd * chip.
39648c1d364SAdrian Chadd */
397cc5c884dSAdrian Chadd ar9280AdjustPDADCValues(ah, pwr_table_offset, diff, pdadcValues);
39848c1d364SAdrian Chadd
39948c1d364SAdrian Chadd /* Write the power values into the baseband power table */
400b90b8dd2SAdrian Chadd ar5416WritePdadcValues(ah, i, pdadcValues);
40148c1d364SAdrian Chadd }
40248c1d364SAdrian Chadd }
40348c1d364SAdrian Chadd *pTxPowerIndexOffset = 0;
40448c1d364SAdrian Chadd
40548c1d364SAdrian Chadd return AH_TRUE;
40648c1d364SAdrian Chadd }
407