ar9280_olc.c revision 219586
11541Srgrimes/*
21541Srgrimes * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
31541Srgrimes *
41541Srgrimes * Redistribution and use in source and binary forms, with or without
51541Srgrimes * modification, are permitted provided that the following conditions
61541Srgrimes * are met:
71541Srgrimes * 1. Redistributions of source code must retain the above copyright
81541Srgrimes *    notice, this list of conditions and the following disclaimer.
91541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
101541Srgrimes *    notice, this list of conditions and the following disclaimer in the
111541Srgrimes *    documentation and/or other materials provided with the distribution.
121541Srgrimes *
131541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
141541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
151541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
161541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
171541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
181541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
191541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
201541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
211541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
221541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
231541Srgrimes * SUCH DAMAGE.
241541Srgrimes *
251541Srgrimes * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c 219586 2011-03-13 05:54:05Z adrian $
261541Srgrimes */
271541Srgrimes#include "opt_ah.h"
281541Srgrimes
291541Srgrimes#include "ah.h"
301541Srgrimes#include "ah_internal.h"
311541Srgrimes
321541Srgrimes#include "ah_eeprom_v14.h"
331541Srgrimes
341541Srgrimes#include "ar9002/ar9280.h"
351541Srgrimes#include "ar5416/ar5416reg.h"
3622521Sdyson#include "ar5416/ar5416phy.h"
371541Srgrimes#include "ar9002/ar9002phy.h"
3822521Sdyson
3922521Sdyson#include "ar9002/ar9280_olc.h"
4030431Sphk
4122521Sdysonvoid
4222521Sdysonar9280olcInit(struct ath_hal *ah)
4322521Sdyson{
4430431Sphk	uint32_t i;
451541Srgrimes
461541Srgrimes	for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
471541Srgrimes		AH9280(ah)->originalGain[i] = MS(OS_REG_READ(ah,
481541Srgrimes		    AR_PHY_TX_GAIN_TBL1 + i * 4), AR_PHY_TX_GAIN);
491541Srgrimes
501541Srgrimes	AH9280(ah)->PDADCdelta = 0;
511541Srgrimes}
521541Srgrimes
531541Srgrimesvoid
541541Srgrimesar9280olcGetTxGainIndex(struct ath_hal *ah,
551541Srgrimes    const struct ieee80211_channel *chan,
561541Srgrimes    struct calDataPerFreqOpLoop *rawDatasetOpLoop,
571541Srgrimes    uint8_t *calChans, uint16_t availPiers, uint8_t *pwr, uint8_t *pcdacIdx)
581541Srgrimes{
591541Srgrimes	uint8_t pcdac, i = 0;
601541Srgrimes	uint16_t idxL = 0, idxR = 0, numPiers;
611541Srgrimes	HAL_BOOL match;
621541Srgrimes	CHAN_CENTERS centers;
631541Srgrimes
641541Srgrimes	ar5416GetChannelCenters(ah, chan, &centers);
651541Srgrimes
661541Srgrimes	for (numPiers = 0; numPiers < availPiers; numPiers++)
671541Srgrimes		if (calChans[numPiers] == AR5416_BCHAN_UNUSED)
681541Srgrimes			break;
691541Srgrimes
701541Srgrimes	match = ath_ee_getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center,
711541Srgrimes		    IEEE80211_IS_CHAN_2GHZ(chan)), calChans, numPiers,
721541Srgrimes		    &idxL, &idxR);
731541Srgrimes	if (match) {
741541Srgrimes		pcdac = rawDatasetOpLoop[idxL].pcdac[0][0];
751541Srgrimes		*pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0];
761541Srgrimes	} else {
771541Srgrimes		pcdac = rawDatasetOpLoop[idxR].pcdac[0][0];
781541Srgrimes		*pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] +
791541Srgrimes				rawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
801541Srgrimes	}
811541Srgrimes	while (pcdac > AH9280(ah)->originalGain[i] &&
821541Srgrimes			i < (AR9280_TX_GAIN_TABLE_SIZE - 1))
831541Srgrimes		i++;
841541Srgrimes
851541Srgrimes	*pcdacIdx = i;
8626963Salex}
871541Srgrimes
881541Srgrimes/*
891541Srgrimes * XXX txPower here is likely not the target txPower in the traditional
901541Srgrimes * XXX sense, but is set by a call to ar9280olcGetTxGainIndex().
911541Srgrimes * XXX Thus, be careful if you're trying to use this routine yourself.
921541Srgrimes */
931541Srgrimesvoid
941541Srgrimesar9280olcGetPDADCs(struct ath_hal *ah, uint32_t initTxGain, int txPower,
951541Srgrimes    uint8_t *pPDADCValues)
961541Srgrimes{
9722521Sdyson	uint32_t i;
9822521Sdyson	uint32_t offset;
9922521Sdyson
10022521Sdyson	OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
10122521Sdyson	OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
1021541Srgrimes
10322521Sdyson	OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain);
10422521Sdyson
10522521Sdyson	offset = txPower;
10622521Sdyson	for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++)
10722521Sdyson		if (i < offset)
10822521Sdyson			pPDADCValues[i] = 0x0;
10922521Sdyson		else
11022521Sdyson			pPDADCValues[i] = 0xFF;
11122521Sdyson}
1121541Srgrimes
1131541Srgrimes/*
1141541Srgrimes * Run temperature compensation calibration.
1151541Srgrimes *
1161541Srgrimes * The TX gain table is adjusted depending upon the difference
1171541Srgrimes * between the initial PDADC value and the currently read
1181541Srgrimes * average TX power sample value. This value is only valid if
1191541Srgrimes * frames have been transmitted, so currPDADC will be 0 if
1201541Srgrimes * no frames have yet been transmitted.
1211541Srgrimes */
1221541Srgrimesvoid
1231541Srgrimesar9280olcTemperatureCompensation(struct ath_hal *ah)
1241541Srgrimes{
1251541Srgrimes	uint32_t rddata, i;
1268876Srgrimes	int delta, currPDADC, regval;
1271541Srgrimes	uint8_t hpwr_5g = 0;
1281541Srgrimes
1291541Srgrimes	rddata = OS_REG_READ(ah, AR_PHY_TX_PWRCTRL4);
1301541Srgrimes	currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
1311541Srgrimes
1321541Srgrimes	HALDEBUG(ah, HAL_DEBUG_PERCAL,
1331541Srgrimes	    "%s: called: initPDADC=%d, currPDADC=%d\n",
1341541Srgrimes	    __func__, AH5416(ah)->initPDADC, currPDADC);
1351541Srgrimes
1368876Srgrimes	if (AH5416(ah)->initPDADC == 0 || currPDADC == 0)
1371541Srgrimes		return;
1381541Srgrimes
1391541Srgrimes	(void) (ath_hal_eepromGet(ah, AR_EEP_DAC_HPWR_5G, &hpwr_5g));
1401541Srgrimes
1411541Srgrimes	if (hpwr_5g)
1421541Srgrimes		delta = (currPDADC - AH5416(ah)->initPDADC + 4) / 8;
1431541Srgrimes	else
1441541Srgrimes		delta = (currPDADC - AH5416(ah)->initPDADC + 5) / 10;
1451541Srgrimes
1461541Srgrimes	HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: delta=%d, PDADCdelta=%d\n",
1471541Srgrimes	    __func__, delta, AH9280(ah)->PDADCdelta);
1481541Srgrimes
1491541Srgrimes	if (delta != AH9280(ah)->PDADCdelta) {
1508876Srgrimes		AH9280(ah)->PDADCdelta = delta;
1511541Srgrimes		for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
1521541Srgrimes			regval = AH9280(ah)->originalGain[i] - delta;
1531541Srgrimes			if (regval < 0)
1541541Srgrimes				regval = 0;
1551541Srgrimes
1568876Srgrimes			OS_REG_RMW_FIELD(ah,
1571541Srgrimes				      AR_PHY_TX_GAIN_TBL1 + i * 4,
1581541Srgrimes				      AR_PHY_TX_GAIN, regval);
1591541Srgrimes		}
1601541Srgrimes	}
1611541Srgrimes}
1621541Srgrimes
1631541Srgrimes
1641541Srgrimesstatic int16_t
16526964Salexar9280ChangeGainBoundarySettings(struct ath_hal *ah, uint16_t *gb,
1661541Srgrimes    uint16_t numXpdGain, uint16_t pdGainOverlap_t2, int8_t pwr_table_offset,
1671541Srgrimes    int16_t *diff)
1681541Srgrimes{
16926964Salex	uint16_t k;
1701541Srgrimes
1711541Srgrimes	/* Prior to writing the boundaries or the pdadc vs. power table
1721541Srgrimes	 * into the chip registers the default starting point on the pdadc
17326964Salex	 * vs. power table needs to be checked and the curve boundaries
1741541Srgrimes	 * adjusted accordingly
1751541Srgrimes	 */
1761541Srgrimes	if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
1771541Srgrimes		uint16_t gb_limit;
1781541Srgrimes
1792960Swollman		if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
18012769Sphk			/* get the difference in dB */
1811541Srgrimes			*diff = (uint16_t)(pwr_table_offset - AR5416_PWR_TABLE_OFFSET_DB);
1821541Srgrimes			/* get the number of half dB steps */
1831541Srgrimes			*diff *= 2;
1841541Srgrimes			/* change the original gain boundary settings
1851541Srgrimes			 * by the number of half dB steps
1861541Srgrimes			 */
1871541Srgrimes			for (k = 0; k < numXpdGain; k++)
18812769Sphk				gb[k] = (uint16_t)(gb[k] - *diff);
18912769Sphk		}
19012769Sphk		/* Because of a hardware limitation, ensure the gain boundary
1911541Srgrimes		 * is not larger than (63 - overlap)
19222597Smpp		 */
19312769Sphk		gb_limit = (uint16_t)(AR5416_MAX_RATE_POWER - pdGainOverlap_t2);
19412769Sphk
19512769Sphk		for (k = 0; k < numXpdGain; k++)
19622597Smpp			gb[k] = (uint16_t)min(gb_limit, gb[k]);
19722597Smpp	}
19812769Sphk
19912769Sphk	return *diff;
20022597Smpp}
20112769Sphk
20222597Smppstatic void
20312595Sbdear9280AdjustPDADCValues(struct ath_hal *ah, int8_t pwr_table_offset,
2041541Srgrimes    int16_t diff, uint8_t *pdadcValues)
2051541Srgrimes{
2061541Srgrimes#define NUM_PDADC(diff) (AR5416_NUM_PDADC_VALUES - diff)
2071541Srgrimes	uint16_t k;
2081541Srgrimes
2091541Srgrimes	/* If this is a board that has a pwrTableOffset that differs from
2101541Srgrimes	 * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the
2111541Srgrimes	 * pdadc vs pwr table needs to be adjusted prior to writing to the
2121541Srgrimes	 * chip.
2131541Srgrimes	 */
2141541Srgrimes	if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
2151541Srgrimes		if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
2161541Srgrimes			/* shift the table to start at the new offset */
2171541Srgrimes			for (k = 0; k < (uint16_t)NUM_PDADC(diff); k++ ) {
2181541Srgrimes				pdadcValues[k] = pdadcValues[k + diff];
2191541Srgrimes			}
2201541Srgrimes
2211541Srgrimes			/* fill the back of the table */
2221541Srgrimes			for (k = (uint16_t)NUM_PDADC(diff); k < NUM_PDADC(0); k++) {
2231541Srgrimes				pdadcValues[k] = pdadcValues[NUM_PDADC(diff)];
2241541Srgrimes			}
2251541Srgrimes		}
2261541Srgrimes	}
2271541Srgrimes#undef NUM_PDADC
2288876Srgrimes}
22922521Sdyson/*
2301541Srgrimes * This effectively disables the gain boundaries leaving it
2311541Srgrimes * to the open-loop TX power control.
2321541Srgrimes */
2331541Srgrimesstatic void
2341541Srgrimesar9280SetGainBoundariesOpenLoop(struct ath_hal *ah, int i,
2351541Srgrimes    uint16_t pdGainOverlap_t2, uint16_t gainBoundaries[])
2361541Srgrimes{
2371541Srgrimes	int regChainOffset;
2381541Srgrimes
2391541Srgrimes	regChainOffset = ar5416GetRegChainOffset(ah, i);
2401541Srgrimes
2411541Srgrimes	/* These are unused for OLC */
2421541Srgrimes	(void) pdGainOverlap_t2;
2431541Srgrimes	(void) gainBoundaries;
2441541Srgrimes
2451541Srgrimes	HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: chain %d: writing closed loop values\n",
2461541Srgrimes	    __func__, i);
2471541Srgrimes
2481541Srgrimes	OS_REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
2491541Srgrimes	    SM(0x6, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
2501541Srgrimes	    SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)  |
2511541Srgrimes	    SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)  |
2521541Srgrimes	    SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)  |
2537170Sdg	    SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
2541541Srgrimes}
2551541Srgrimes
2561541Srgrimes/* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */
2571541Srgrimes/* XXX shouldn't be here! */
2581541Srgrimes#define EEP_MINOR(_ah) \
2591541Srgrimes        (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK)
2601541Srgrimes#define IS_EEP_MINOR_V2(_ah)    (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2)
2611541Srgrimes#define IS_EEP_MINOR_V3(_ah)    (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3)
2621541Srgrimes
2631541Srgrimes/**************************************************************
2641541Srgrimes * ar9280SetPowerCalTable
2658876Srgrimes *
2661541Srgrimes * Pull the PDADC piers from cal data and interpolate them across the given
2671541Srgrimes * points as well as from the nearest pier(s) to get a power detector
2681541Srgrimes * linear voltage to power level table.
2691541Srgrimes *
2701541Srgrimes * Handle OLC for Merlin where required.
2711541Srgrimes */
27224987SkatoHAL_BOOL
27322521Sdysonar9280SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom *pEepData,
27424987Skato	const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset)
2751541Srgrimes{
2761541Srgrimes	CAL_DATA_PER_FREQ *pRawDataset;
2771541Srgrimes	uint8_t  *pCalBChans = AH_NULL;
2781541Srgrimes	uint16_t pdGainOverlap_t2;
2791541Srgrimes	static uint8_t  pdadcValues[AR5416_NUM_PDADC_VALUES];
2801541Srgrimes	uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK];
2811541Srgrimes	uint16_t numPiers, i;
2821541Srgrimes	int16_t  tMinCalPower;
2831541Srgrimes	uint16_t numXpdGain, xpdMask;
2841541Srgrimes	uint16_t xpdGainValues[AR5416_NUM_PD_GAINS];
2851541Srgrimes	uint32_t regChainOffset;
2868876Srgrimes	int8_t pwr_table_offset;
2871541Srgrimes
2881541Srgrimes	OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues));
2891541Srgrimes
2901541Srgrimes	xpdMask = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].xpdGain;
2911541Srgrimes
2921541Srgrimes	(void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET, &pwr_table_offset);
2931541Srgrimes
2941541Srgrimes
2951541Srgrimes	if (IS_EEP_MINOR_V2(ah)) {
2961541Srgrimes		pdGainOverlap_t2 = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pdGainOverlap;
2971541Srgrimes	} else {
2981541Srgrimes		pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
2991541Srgrimes	}
3001541Srgrimes
3011541Srgrimes	if (IEEE80211_IS_CHAN_2GHZ(chan)) {
3021541Srgrimes		pCalBChans = pEepData->calFreqPier2G;
3031541Srgrimes		numPiers = AR5416_NUM_2G_CAL_PIERS;
3041541Srgrimes	} else {
3051541Srgrimes		pCalBChans = pEepData->calFreqPier5G;
3061541Srgrimes		numPiers = AR5416_NUM_5G_CAL_PIERS;
3071541Srgrimes	}
3081541Srgrimes
3091541Srgrimes	/* If OLC is being done, set the init PDADC value appropriately */
3101541Srgrimes	if (IEEE80211_IS_CHAN_2GHZ(chan) && AR_SREV_MERLIN_20_OR_LATER(ah) &&
3111541Srgrimes	    ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
3121541Srgrimes		struct calDataPerFreq *pRawDataset = pEepData->calPierData2G[0];
3131541Srgrimes		AH5416(ah)->initPDADC = ((struct calDataPerFreqOpLoop *) pRawDataset)->vpdPdg[0][0];
3141541Srgrimes	} else {
3151541Srgrimes		/*
3161541Srgrimes		 * XXX ath9k doesn't clear this for 5ghz mode if
3171541Srgrimes		 * it were set in 2ghz mode before!
3181541Srgrimes		 * The Merlin OLC temperature compensation code
3191541Srgrimes		 * uses this to calculate the PDADC delta during
3201541Srgrimes		 * calibration ; 0 here effectively stops the
3211541Srgrimes		 * temperature compensation calibration from
3221541Srgrimes		 * occuring.
3231541Srgrimes		 */
3241541Srgrimes		AH5416(ah)->initPDADC = 0;
3251541Srgrimes	}
3261541Srgrimes
3271541Srgrimes	/* Calculate the value of xpdgains from the xpdGain Mask */
3281541Srgrimes	numXpdGain = ar5416GetXpdGainValues(ah, xpdMask, xpdGainValues);
32929584Sphk
33029584Sphk	/* Write the detector gain biases and their number */
3311541Srgrimes	ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues);
3321541Srgrimes
3331541Srgrimes	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
3341541Srgrimes		regChainOffset = ar5416GetRegChainOffset(ah, i);
3351541Srgrimes		if (pEepData->baseEepHeader.txMask & (1 << i)) {
3361541Srgrimes			uint16_t diff;
33722521Sdyson
33822521Sdyson			if (IEEE80211_IS_CHAN_2GHZ(chan)) {
33922521Sdyson				pRawDataset = pEepData->calPierData2G[i];
34022521Sdyson			} else {
34122521Sdyson				pRawDataset = pEepData->calPierData5G[i];
34222521Sdyson			}
34322521Sdyson
34422521Sdyson			/* Fetch the gain boundaries and the PDADC values */
34522521Sdyson			if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
34622521Sdyson			    ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
34722521Sdyson				uint8_t pcdacIdx;
34822521Sdyson				uint8_t txPower;
34922521Sdyson
35022521Sdyson				ar9280olcGetTxGainIndex(ah, chan,
35122521Sdyson				    (struct calDataPerFreqOpLoop *) pRawDataset,
35222521Sdyson				    pCalBChans, numPiers, &txPower, &pcdacIdx);
35322521Sdyson				ar9280olcGetPDADCs(ah, pcdacIdx, txPower / 2, pdadcValues);
35422521Sdyson			} else {
35522521Sdyson				ar5416GetGainBoundariesAndPdadcs(ah,  chan,
35622521Sdyson				    pRawDataset, pCalBChans, numPiers,
3571541Srgrimes				    pdGainOverlap_t2, &tMinCalPower,
35822521Sdyson				    gainBoundaries, pdadcValues, numXpdGain);
35922521Sdyson			}
36022521Sdyson
36122607Smpp			/*
36222521Sdyson			 * Prior to writing the boundaries or the pdadc vs. power table
36322521Sdyson			 * into the chip registers the default starting point on the pdadc
36422521Sdyson			 * vs. power table needs to be checked and the curve boundaries
36522521Sdyson			 * adjusted accordingly
36622521Sdyson			 */
36722521Sdyson			diff = ar9280ChangeGainBoundarySettings(ah,
36822521Sdyson			    gainBoundaries, numXpdGain, pdGainOverlap_t2,
36922521Sdyson			    pwr_table_offset, &diff);
37022521Sdyson
37122521Sdyson			if ((i == 0) || AR_SREV_OWL_20_OR_LATER(ah)) {
37222521Sdyson				/* Set gain boundaries for either open- or closed-loop TPC */
37322521Sdyson				if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
37422521Sdyson				    ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL))
37522521Sdyson					ar9280SetGainBoundariesOpenLoop(ah,
37622521Sdyson					    i, pdGainOverlap_t2,
37722521Sdyson					    gainBoundaries);
37822521Sdyson				else
37922521Sdyson					ar5416SetGainBoundariesClosedLoop(ah,
38022521Sdyson					    i, pdGainOverlap_t2,
38122521Sdyson					    gainBoundaries);
38222521Sdyson			}
38322521Sdyson
38424987Skato			/*
38522521Sdyson			 * If this is a board that has a pwrTableOffset that differs from
38622521Sdyson			 * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the
38722521Sdyson			 * pdadc vs pwr table needs to be adjusted prior to writing to the
38822521Sdyson			 * chip.
38922521Sdyson			 */
39022521Sdyson			ar9280AdjustPDADCValues(ah, pwr_table_offset, diff, pdadcValues);
39122521Sdyson
39222521Sdyson			/* Write the power values into the baseband power table */
3931541Srgrimes			ar5416WritePdadcValues(ah, i, pdadcValues);
39422521Sdyson		}
39522521Sdyson	}
39622521Sdyson	*pTxPowerIndexOffset = 0;
39722521Sdyson
39822521Sdyson	return AH_TRUE;
39922521Sdyson}
40022521Sdyson