1219393Sadrian/*
2219393Sadrian * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
3219393Sadrian *
4219393Sadrian * Redistribution and use in source and binary forms, with or without
5219393Sadrian * modification, are permitted provided that the following conditions
6219393Sadrian * are met:
7219393Sadrian * 1. Redistributions of source code must retain the above copyright
8219393Sadrian *    notice, this list of conditions and the following disclaimer.
9219393Sadrian * 2. Redistributions in binary form must reproduce the above copyright
10219393Sadrian *    notice, this list of conditions and the following disclaimer in the
11219393Sadrian *    documentation and/or other materials provided with the distribution.
12219393Sadrian *
13219393Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14219393Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15219393Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16219393Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17219393Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18219393Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19219393Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20219393Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21219393Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22219393Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23219393Sadrian * SUCH DAMAGE.
24219393Sadrian *
25219393Sadrian * $FreeBSD$
26219393Sadrian */
27219393Sadrian#include "opt_ah.h"
28219393Sadrian
29219393Sadrian#include "ah.h"
30219393Sadrian#include "ah_internal.h"
31219393Sadrian
32219393Sadrian#include "ah_eeprom_v14.h"
33219393Sadrian
34219393Sadrian#include "ar9002/ar9280.h"
35219393Sadrian#include "ar5416/ar5416reg.h"
36219393Sadrian#include "ar5416/ar5416phy.h"
37219393Sadrian#include "ar9002/ar9002phy.h"
38219393Sadrian
39219393Sadrian#include "ar9002/ar9280_olc.h"
40219393Sadrian
41219393Sadrianvoid
42219393Sadrianar9280olcInit(struct ath_hal *ah)
43219393Sadrian{
44219393Sadrian	uint32_t i;
45219393Sadrian
46221837Sadrian	/* Only do OLC if it's enabled for this chipset */
47221837Sadrian	if (! ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL))
48221837Sadrian		return;
49221837Sadrian
50221837Sadrian	HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Setting up TX gain tables.\n", __func__);
51221837Sadrian
52219393Sadrian	for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
53219393Sadrian		AH9280(ah)->originalGain[i] = MS(OS_REG_READ(ah,
54219393Sadrian		    AR_PHY_TX_GAIN_TBL1 + i * 4), AR_PHY_TX_GAIN);
55219393Sadrian
56219393Sadrian	AH9280(ah)->PDADCdelta = 0;
57219393Sadrian}
58219393Sadrian
59219393Sadrianvoid
60219393Sadrianar9280olcGetTxGainIndex(struct ath_hal *ah,
61219393Sadrian    const struct ieee80211_channel *chan,
62219393Sadrian    struct calDataPerFreqOpLoop *rawDatasetOpLoop,
63219393Sadrian    uint8_t *calChans, uint16_t availPiers, uint8_t *pwr, uint8_t *pcdacIdx)
64219393Sadrian{
65219393Sadrian	uint8_t pcdac, i = 0;
66219393Sadrian	uint16_t idxL = 0, idxR = 0, numPiers;
67219393Sadrian	HAL_BOOL match;
68219393Sadrian	CHAN_CENTERS centers;
69219393Sadrian
70219393Sadrian	ar5416GetChannelCenters(ah, chan, &centers);
71219393Sadrian
72219393Sadrian	for (numPiers = 0; numPiers < availPiers; numPiers++)
73219393Sadrian		if (calChans[numPiers] == AR5416_BCHAN_UNUSED)
74219393Sadrian			break;
75219393Sadrian
76219586Sadrian	match = ath_ee_getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center,
77219393Sadrian		    IEEE80211_IS_CHAN_2GHZ(chan)), calChans, numPiers,
78219393Sadrian		    &idxL, &idxR);
79219393Sadrian	if (match) {
80219393Sadrian		pcdac = rawDatasetOpLoop[idxL].pcdac[0][0];
81219393Sadrian		*pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0];
82219393Sadrian	} else {
83219393Sadrian		pcdac = rawDatasetOpLoop[idxR].pcdac[0][0];
84219393Sadrian		*pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] +
85219393Sadrian				rawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
86219393Sadrian	}
87219393Sadrian	while (pcdac > AH9280(ah)->originalGain[i] &&
88219393Sadrian			i < (AR9280_TX_GAIN_TABLE_SIZE - 1))
89219393Sadrian		i++;
90219393Sadrian
91219393Sadrian	*pcdacIdx = i;
92219393Sadrian}
93219393Sadrian
94219393Sadrian/*
95219393Sadrian * XXX txPower here is likely not the target txPower in the traditional
96219393Sadrian * XXX sense, but is set by a call to ar9280olcGetTxGainIndex().
97219393Sadrian * XXX Thus, be careful if you're trying to use this routine yourself.
98219393Sadrian */
99219393Sadrianvoid
100219393Sadrianar9280olcGetPDADCs(struct ath_hal *ah, uint32_t initTxGain, int txPower,
101219393Sadrian    uint8_t *pPDADCValues)
102219393Sadrian{
103219393Sadrian	uint32_t i;
104219393Sadrian	uint32_t offset;
105219393Sadrian
106219393Sadrian	OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
107219393Sadrian	OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
108219393Sadrian
109219393Sadrian	OS_REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain);
110219393Sadrian
111219393Sadrian	offset = txPower;
112219393Sadrian	for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++)
113219393Sadrian		if (i < offset)
114219393Sadrian			pPDADCValues[i] = 0x0;
115219393Sadrian		else
116219393Sadrian			pPDADCValues[i] = 0xFF;
117219393Sadrian}
118219393Sadrian
119219393Sadrian/*
120219393Sadrian * Run temperature compensation calibration.
121219393Sadrian *
122219393Sadrian * The TX gain table is adjusted depending upon the difference
123219393Sadrian * between the initial PDADC value and the currently read
124219393Sadrian * average TX power sample value. This value is only valid if
125219393Sadrian * frames have been transmitted, so currPDADC will be 0 if
126219393Sadrian * no frames have yet been transmitted.
127219393Sadrian */
128219393Sadrianvoid
129219393Sadrianar9280olcTemperatureCompensation(struct ath_hal *ah)
130219393Sadrian{
131219393Sadrian	uint32_t rddata, i;
132219393Sadrian	int delta, currPDADC, regval;
133219393Sadrian	uint8_t hpwr_5g = 0;
134219393Sadrian
135221837Sadrian	if (! ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL))
136221837Sadrian		return;
137221837Sadrian
138219393Sadrian	rddata = OS_REG_READ(ah, AR_PHY_TX_PWRCTRL4);
139219393Sadrian	currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
140219393Sadrian
141219393Sadrian	HALDEBUG(ah, HAL_DEBUG_PERCAL,
142219393Sadrian	    "%s: called: initPDADC=%d, currPDADC=%d\n",
143219393Sadrian	    __func__, AH5416(ah)->initPDADC, currPDADC);
144219393Sadrian
145219393Sadrian	if (AH5416(ah)->initPDADC == 0 || currPDADC == 0)
146219393Sadrian		return;
147219393Sadrian
148219393Sadrian	(void) (ath_hal_eepromGet(ah, AR_EEP_DAC_HPWR_5G, &hpwr_5g));
149219393Sadrian
150219393Sadrian	if (hpwr_5g)
151219393Sadrian		delta = (currPDADC - AH5416(ah)->initPDADC + 4) / 8;
152219393Sadrian	else
153219393Sadrian		delta = (currPDADC - AH5416(ah)->initPDADC + 5) / 10;
154219393Sadrian
155219393Sadrian	HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: delta=%d, PDADCdelta=%d\n",
156219393Sadrian	    __func__, delta, AH9280(ah)->PDADCdelta);
157219393Sadrian
158219393Sadrian	if (delta != AH9280(ah)->PDADCdelta) {
159219393Sadrian		AH9280(ah)->PDADCdelta = delta;
160219393Sadrian		for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
161219393Sadrian			regval = AH9280(ah)->originalGain[i] - delta;
162219393Sadrian			if (regval < 0)
163219393Sadrian				regval = 0;
164219393Sadrian
165219393Sadrian			OS_REG_RMW_FIELD(ah,
166219393Sadrian				      AR_PHY_TX_GAIN_TBL1 + i * 4,
167219393Sadrian				      AR_PHY_TX_GAIN, regval);
168219393Sadrian		}
169219393Sadrian	}
170219393Sadrian}
171219393Sadrian
172219444Sadrian
173219444Sadrianstatic int16_t
174219444Sadrianar9280ChangeGainBoundarySettings(struct ath_hal *ah, uint16_t *gb,
175219444Sadrian    uint16_t numXpdGain, uint16_t pdGainOverlap_t2, int8_t pwr_table_offset,
176219444Sadrian    int16_t *diff)
177219444Sadrian{
178219444Sadrian	uint16_t k;
179219444Sadrian
180219444Sadrian	/* Prior to writing the boundaries or the pdadc vs. power table
181219444Sadrian	 * into the chip registers the default starting point on the pdadc
182219444Sadrian	 * vs. power table needs to be checked and the curve boundaries
183219444Sadrian	 * adjusted accordingly
184219444Sadrian	 */
185219444Sadrian	if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
186219444Sadrian		uint16_t gb_limit;
187219444Sadrian
188219444Sadrian		if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
189219444Sadrian			/* get the difference in dB */
190219444Sadrian			*diff = (uint16_t)(pwr_table_offset - AR5416_PWR_TABLE_OFFSET_DB);
191219444Sadrian			/* get the number of half dB steps */
192219444Sadrian			*diff *= 2;
193219444Sadrian			/* change the original gain boundary settings
194219444Sadrian			 * by the number of half dB steps
195219444Sadrian			 */
196219444Sadrian			for (k = 0; k < numXpdGain; k++)
197219444Sadrian				gb[k] = (uint16_t)(gb[k] - *diff);
198219444Sadrian		}
199219444Sadrian		/* Because of a hardware limitation, ensure the gain boundary
200219444Sadrian		 * is not larger than (63 - overlap)
201219444Sadrian		 */
202219444Sadrian		gb_limit = (uint16_t)(AR5416_MAX_RATE_POWER - pdGainOverlap_t2);
203219444Sadrian
204219444Sadrian		for (k = 0; k < numXpdGain; k++)
205219444Sadrian			gb[k] = (uint16_t)min(gb_limit, gb[k]);
206219444Sadrian	}
207219444Sadrian
208219444Sadrian	return *diff;
209219444Sadrian}
210219444Sadrian
211219444Sadrianstatic void
212219444Sadrianar9280AdjustPDADCValues(struct ath_hal *ah, int8_t pwr_table_offset,
213219444Sadrian    int16_t diff, uint8_t *pdadcValues)
214219444Sadrian{
215219444Sadrian#define NUM_PDADC(diff) (AR5416_NUM_PDADC_VALUES - diff)
216219444Sadrian	uint16_t k;
217219444Sadrian
218219444Sadrian	/* If this is a board that has a pwrTableOffset that differs from
219219444Sadrian	 * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the
220219444Sadrian	 * pdadc vs pwr table needs to be adjusted prior to writing to the
221219444Sadrian	 * chip.
222219444Sadrian	 */
223219444Sadrian	if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
224219444Sadrian		if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
225219444Sadrian			/* shift the table to start at the new offset */
226219444Sadrian			for (k = 0; k < (uint16_t)NUM_PDADC(diff); k++ ) {
227219444Sadrian				pdadcValues[k] = pdadcValues[k + diff];
228219444Sadrian			}
229219444Sadrian
230219444Sadrian			/* fill the back of the table */
231219444Sadrian			for (k = (uint16_t)NUM_PDADC(diff); k < NUM_PDADC(0); k++) {
232219444Sadrian				pdadcValues[k] = pdadcValues[NUM_PDADC(diff)];
233219444Sadrian			}
234219444Sadrian		}
235219444Sadrian	}
236219444Sadrian#undef NUM_PDADC
237219444Sadrian}
238219393Sadrian/*
239219393Sadrian * This effectively disables the gain boundaries leaving it
240219393Sadrian * to the open-loop TX power control.
241219393Sadrian */
242219393Sadrianstatic void
243219585Sadrianar9280SetGainBoundariesOpenLoop(struct ath_hal *ah, int i,
244219393Sadrian    uint16_t pdGainOverlap_t2, uint16_t gainBoundaries[])
245219393Sadrian{
246219585Sadrian	int regChainOffset;
247219585Sadrian
248219585Sadrian	regChainOffset = ar5416GetRegChainOffset(ah, i);
249219585Sadrian
250219393Sadrian	/* These are unused for OLC */
251219393Sadrian	(void) pdGainOverlap_t2;
252219393Sadrian	(void) gainBoundaries;
253219393Sadrian
254219585Sadrian	HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: chain %d: writing closed loop values\n",
255219585Sadrian	    __func__, i);
256219585Sadrian
257219393Sadrian	OS_REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
258219393Sadrian	    SM(0x6, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
259219393Sadrian	    SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)  |
260219393Sadrian	    SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)  |
261219393Sadrian	    SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)  |
262219393Sadrian	    SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
263219393Sadrian}
264219393Sadrian
265219393Sadrian/* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */
266219393Sadrian/* XXX shouldn't be here! */
267219393Sadrian#define EEP_MINOR(_ah) \
268219393Sadrian        (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK)
269219393Sadrian#define IS_EEP_MINOR_V2(_ah)    (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2)
270219393Sadrian#define IS_EEP_MINOR_V3(_ah)    (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3)
271219393Sadrian
272219393Sadrian/**************************************************************
273219393Sadrian * ar9280SetPowerCalTable
274219393Sadrian *
275219393Sadrian * Pull the PDADC piers from cal data and interpolate them across the given
276219393Sadrian * points as well as from the nearest pier(s) to get a power detector
277219393Sadrian * linear voltage to power level table.
278219393Sadrian *
279219393Sadrian * Handle OLC for Merlin where required.
280219393Sadrian */
281219393SadrianHAL_BOOL
282219393Sadrianar9280SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom *pEepData,
283219393Sadrian	const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset)
284219393Sadrian{
285219393Sadrian	CAL_DATA_PER_FREQ *pRawDataset;
286219393Sadrian	uint8_t  *pCalBChans = AH_NULL;
287219393Sadrian	uint16_t pdGainOverlap_t2;
288219393Sadrian	static uint8_t  pdadcValues[AR5416_NUM_PDADC_VALUES];
289219393Sadrian	uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK];
290219393Sadrian	uint16_t numPiers, i;
291219393Sadrian	int16_t  tMinCalPower;
292219393Sadrian	uint16_t numXpdGain, xpdMask;
293219393Sadrian	uint16_t xpdGainValues[AR5416_NUM_PD_GAINS];
294219393Sadrian	uint32_t regChainOffset;
295219444Sadrian	int8_t pwr_table_offset;
296219393Sadrian
297219393Sadrian	OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues));
298219393Sadrian
299219393Sadrian	xpdMask = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].xpdGain;
300219393Sadrian
301219444Sadrian	(void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET, &pwr_table_offset);
302219444Sadrian
303219444Sadrian
304219393Sadrian	if (IS_EEP_MINOR_V2(ah)) {
305219393Sadrian		pdGainOverlap_t2 = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pdGainOverlap;
306219393Sadrian	} else {
307219393Sadrian		pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
308219393Sadrian	}
309219393Sadrian
310219393Sadrian	if (IEEE80211_IS_CHAN_2GHZ(chan)) {
311219393Sadrian		pCalBChans = pEepData->calFreqPier2G;
312219393Sadrian		numPiers = AR5416_NUM_2G_CAL_PIERS;
313219393Sadrian	} else {
314219393Sadrian		pCalBChans = pEepData->calFreqPier5G;
315219393Sadrian		numPiers = AR5416_NUM_5G_CAL_PIERS;
316219393Sadrian	}
317219393Sadrian
318219393Sadrian	/* If OLC is being done, set the init PDADC value appropriately */
319219393Sadrian	if (IEEE80211_IS_CHAN_2GHZ(chan) && AR_SREV_MERLIN_20_OR_LATER(ah) &&
320219393Sadrian	    ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
321219393Sadrian		struct calDataPerFreq *pRawDataset = pEepData->calPierData2G[0];
322219393Sadrian		AH5416(ah)->initPDADC = ((struct calDataPerFreqOpLoop *) pRawDataset)->vpdPdg[0][0];
323219393Sadrian	} else {
324219393Sadrian		/*
325219393Sadrian		 * XXX ath9k doesn't clear this for 5ghz mode if
326219393Sadrian		 * it were set in 2ghz mode before!
327219393Sadrian		 * The Merlin OLC temperature compensation code
328219393Sadrian		 * uses this to calculate the PDADC delta during
329219393Sadrian		 * calibration ; 0 here effectively stops the
330219393Sadrian		 * temperature compensation calibration from
331219393Sadrian		 * occuring.
332219393Sadrian		 */
333219393Sadrian		AH5416(ah)->initPDADC = 0;
334219393Sadrian	}
335219393Sadrian
336219393Sadrian	/* Calculate the value of xpdgains from the xpdGain Mask */
337219393Sadrian	numXpdGain = ar5416GetXpdGainValues(ah, xpdMask, xpdGainValues);
338219393Sadrian
339219393Sadrian	/* Write the detector gain biases and their number */
340219393Sadrian	ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues);
341219393Sadrian
342219393Sadrian	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
343219393Sadrian		regChainOffset = ar5416GetRegChainOffset(ah, i);
344219393Sadrian		if (pEepData->baseEepHeader.txMask & (1 << i)) {
345219444Sadrian			uint16_t diff;
346219444Sadrian
347219393Sadrian			if (IEEE80211_IS_CHAN_2GHZ(chan)) {
348219393Sadrian				pRawDataset = pEepData->calPierData2G[i];
349219393Sadrian			} else {
350219393Sadrian				pRawDataset = pEepData->calPierData5G[i];
351219393Sadrian			}
352219393Sadrian
353219393Sadrian			/* Fetch the gain boundaries and the PDADC values */
354219393Sadrian			if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
355219393Sadrian			    ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
356219393Sadrian				uint8_t pcdacIdx;
357219393Sadrian				uint8_t txPower;
358219393Sadrian
359219393Sadrian				ar9280olcGetTxGainIndex(ah, chan,
360219393Sadrian				    (struct calDataPerFreqOpLoop *) pRawDataset,
361219393Sadrian				    pCalBChans, numPiers, &txPower, &pcdacIdx);
362219393Sadrian				ar9280olcGetPDADCs(ah, pcdacIdx, txPower / 2, pdadcValues);
363219393Sadrian			} else {
364219393Sadrian				ar5416GetGainBoundariesAndPdadcs(ah,  chan,
365219393Sadrian				    pRawDataset, pCalBChans, numPiers,
366219393Sadrian				    pdGainOverlap_t2, &tMinCalPower,
367219393Sadrian				    gainBoundaries, pdadcValues, numXpdGain);
368219393Sadrian			}
369219393Sadrian
370219393Sadrian			/*
371219393Sadrian			 * Prior to writing the boundaries or the pdadc vs. power table
372219393Sadrian			 * into the chip registers the default starting point on the pdadc
373219393Sadrian			 * vs. power table needs to be checked and the curve boundaries
374219393Sadrian			 * adjusted accordingly
375219393Sadrian			 */
376219444Sadrian			diff = ar9280ChangeGainBoundarySettings(ah,
377219444Sadrian			    gainBoundaries, numXpdGain, pdGainOverlap_t2,
378219444Sadrian			    pwr_table_offset, &diff);
379219393Sadrian
380221574Sadrian			if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
381219393Sadrian				/* Set gain boundaries for either open- or closed-loop TPC */
382219393Sadrian				if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
383219393Sadrian				    ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL))
384219393Sadrian					ar9280SetGainBoundariesOpenLoop(ah,
385219585Sadrian					    i, pdGainOverlap_t2,
386219393Sadrian					    gainBoundaries);
387219393Sadrian				else
388219393Sadrian					ar5416SetGainBoundariesClosedLoop(ah,
389219585Sadrian					    i, pdGainOverlap_t2,
390219393Sadrian					    gainBoundaries);
391219393Sadrian			}
392219393Sadrian
393219393Sadrian			/*
394219393Sadrian			 * If this is a board that has a pwrTableOffset that differs from
395219393Sadrian			 * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the
396219393Sadrian			 * pdadc vs pwr table needs to be adjusted prior to writing to the
397219393Sadrian			 * chip.
398219393Sadrian			 */
399219444Sadrian			ar9280AdjustPDADCValues(ah, pwr_table_offset, diff, pdadcValues);
400219393Sadrian
401219393Sadrian			/* Write the power values into the baseband power table */
402219585Sadrian			ar5416WritePdadcValues(ah, i, pdadcValues);
403219393Sadrian		}
404219393Sadrian	}
405219393Sadrian	*pTxPowerIndexOffset = 0;
406219393Sadrian
407219393Sadrian	return AH_TRUE;
408219393Sadrian}
409