blob: 37207dfd1799a76916f8a22aa95d9fd8610991ac [file] [log] [blame]
Sujithb5aec952009-08-07 09:45:15 +05301/*
2 * Copyright (c) 2008-2009 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070017#include "hw.h"
Luis R. Rodriguez8fe65362010-04-15 17:38:14 -040018#include "ar9002_phy.h"
Sujithb5aec952009-08-07 09:45:15 +053019
Sujith16c94ac2010-06-01 15:14:04 +053020#define NUM_EEP_WORDS (sizeof(struct ar9287_eeprom) / sizeof(u16))
21
22static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
Sujithb5aec952009-08-07 09:45:15 +053023{
24 return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF;
25}
26
Sujith16c94ac2010-06-01 15:14:04 +053027static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
Sujithb5aec952009-08-07 09:45:15 +053028{
29 return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF;
30}
31
Sujith16c94ac2010-06-01 15:14:04 +053032static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
Sujithb5aec952009-08-07 09:45:15 +053033{
34 struct ar9287_eeprom *eep = &ah->eeprom.map9287;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070035 struct ath_common *common = ath9k_hw_common(ah);
Sujithb5aec952009-08-07 09:45:15 +053036 u16 *eep_data;
37 int addr, eep_start_loc = AR9287_EEP_START_LOC;
38 eep_data = (u16 *)eep;
39
40 if (!ath9k_hw_use_flash(ah)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070041 ath_print(common, ATH_DBG_EEPROM,
42 "Reading from EEPROM, not flash\n");
Sujithb5aec952009-08-07 09:45:15 +053043 }
44
Sujith16c94ac2010-06-01 15:14:04 +053045 for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
46 if (!ath9k_hw_nvram_read(common, addr + eep_start_loc,
47 eep_data)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070048 ath_print(common, ATH_DBG_EEPROM,
Frans Pop60ece402010-03-24 19:46:30 +010049 "Unable to read eeprom region\n");
Sujithb5aec952009-08-07 09:45:15 +053050 return false;
51 }
52 eep_data++;
53 }
Sujith16c94ac2010-06-01 15:14:04 +053054
Sujithb5aec952009-08-07 09:45:15 +053055 return true;
56}
57
Sujith16c94ac2010-06-01 15:14:04 +053058static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
Sujithb5aec952009-08-07 09:45:15 +053059{
60 u32 sum = 0, el, integer;
61 u16 temp, word, magic, magic2, *eepdata;
62 int i, addr;
63 bool need_swap = false;
64 struct ar9287_eeprom *eep = &ah->eeprom.map9287;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070065 struct ath_common *common = ath9k_hw_common(ah);
Sujithb5aec952009-08-07 09:45:15 +053066
67 if (!ath9k_hw_use_flash(ah)) {
Sujith16c94ac2010-06-01 15:14:04 +053068 if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
69 &magic)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070070 ath_print(common, ATH_DBG_FATAL,
71 "Reading Magic # failed\n");
Sujithb5aec952009-08-07 09:45:15 +053072 return false;
73 }
74
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070075 ath_print(common, ATH_DBG_EEPROM,
76 "Read Magic = 0x%04X\n", magic);
Sujith16c94ac2010-06-01 15:14:04 +053077
Sujithb5aec952009-08-07 09:45:15 +053078 if (magic != AR5416_EEPROM_MAGIC) {
79 magic2 = swab16(magic);
80
81 if (magic2 == AR5416_EEPROM_MAGIC) {
82 need_swap = true;
83 eepdata = (u16 *)(&ah->eeprom);
84
Sujith16c94ac2010-06-01 15:14:04 +053085 for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
Sujithb5aec952009-08-07 09:45:15 +053086 temp = swab16(*eepdata);
87 *eepdata = temp;
88 eepdata++;
89 }
90 } else {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070091 ath_print(common, ATH_DBG_FATAL,
92 "Invalid EEPROM Magic. "
Sujith16c94ac2010-06-01 15:14:04 +053093 "Endianness mismatch.\n");
Sujithb5aec952009-08-07 09:45:15 +053094 return -EINVAL;
95 }
96 }
97 }
Sujith16c94ac2010-06-01 15:14:04 +053098
99 ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
100 need_swap ? "True" : "False");
Sujithb5aec952009-08-07 09:45:15 +0530101
102 if (need_swap)
103 el = swab16(ah->eeprom.map9287.baseEepHeader.length);
104 else
105 el = ah->eeprom.map9287.baseEepHeader.length;
106
107 if (el > sizeof(struct ar9287_eeprom))
108 el = sizeof(struct ar9287_eeprom) / sizeof(u16);
109 else
110 el = el / sizeof(u16);
111
112 eepdata = (u16 *)(&ah->eeprom);
Sujith16c94ac2010-06-01 15:14:04 +0530113
Sujithb5aec952009-08-07 09:45:15 +0530114 for (i = 0; i < el; i++)
115 sum ^= *eepdata++;
116
117 if (need_swap) {
118 word = swab16(eep->baseEepHeader.length);
119 eep->baseEepHeader.length = word;
120
121 word = swab16(eep->baseEepHeader.checksum);
122 eep->baseEepHeader.checksum = word;
123
124 word = swab16(eep->baseEepHeader.version);
125 eep->baseEepHeader.version = word;
126
127 word = swab16(eep->baseEepHeader.regDmn[0]);
128 eep->baseEepHeader.regDmn[0] = word;
129
130 word = swab16(eep->baseEepHeader.regDmn[1]);
131 eep->baseEepHeader.regDmn[1] = word;
132
133 word = swab16(eep->baseEepHeader.rfSilent);
134 eep->baseEepHeader.rfSilent = word;
135
136 word = swab16(eep->baseEepHeader.blueToothOptions);
137 eep->baseEepHeader.blueToothOptions = word;
138
139 word = swab16(eep->baseEepHeader.deviceCap);
140 eep->baseEepHeader.deviceCap = word;
141
142 integer = swab32(eep->modalHeader.antCtrlCommon);
143 eep->modalHeader.antCtrlCommon = integer;
144
145 for (i = 0; i < AR9287_MAX_CHAINS; i++) {
146 integer = swab32(eep->modalHeader.antCtrlChain[i]);
147 eep->modalHeader.antCtrlChain[i] = integer;
148 }
149
150 for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) {
151 word = swab16(eep->modalHeader.spurChans[i].spurChan);
152 eep->modalHeader.spurChans[i].spurChan = word;
153 }
154 }
155
156 if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER
157 || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700158 ath_print(common, ATH_DBG_FATAL,
159 "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
160 sum, ah->eep_ops->get_eeprom_ver(ah));
Sujithb5aec952009-08-07 09:45:15 +0530161 return -EINVAL;
162 }
163
164 return 0;
165}
166
Sujith16c94ac2010-06-01 15:14:04 +0530167static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
Sujithb5aec952009-08-07 09:45:15 +0530168 enum eeprom_param param)
169{
170 struct ar9287_eeprom *eep = &ah->eeprom.map9287;
171 struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
172 struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
173 u16 ver_minor;
174
175 ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK;
Sujith16c94ac2010-06-01 15:14:04 +0530176
Sujithb5aec952009-08-07 09:45:15 +0530177 switch (param) {
178 case EEP_NFTHRESH_2:
179 return pModal->noiseFloorThreshCh[0];
Luis R. Rodriguez49101672010-04-15 17:39:13 -0400180 case EEP_MAC_LSW:
Sujithb5aec952009-08-07 09:45:15 +0530181 return pBase->macAddr[0] << 8 | pBase->macAddr[1];
Luis R. Rodriguez49101672010-04-15 17:39:13 -0400182 case EEP_MAC_MID:
Sujithb5aec952009-08-07 09:45:15 +0530183 return pBase->macAddr[2] << 8 | pBase->macAddr[3];
Luis R. Rodriguez49101672010-04-15 17:39:13 -0400184 case EEP_MAC_MSW:
Sujithb5aec952009-08-07 09:45:15 +0530185 return pBase->macAddr[4] << 8 | pBase->macAddr[5];
186 case EEP_REG_0:
187 return pBase->regDmn[0];
188 case EEP_REG_1:
189 return pBase->regDmn[1];
190 case EEP_OP_CAP:
191 return pBase->deviceCap;
192 case EEP_OP_MODE:
193 return pBase->opCapFlags;
194 case EEP_RF_SILENT:
195 return pBase->rfSilent;
196 case EEP_MINOR_REV:
197 return ver_minor;
198 case EEP_TX_MASK:
199 return pBase->txMask;
200 case EEP_RX_MASK:
201 return pBase->rxMask;
202 case EEP_DEV_TYPE:
203 return pBase->deviceType;
204 case EEP_OL_PWRCTRL:
205 return pBase->openLoopPwrCntl;
206 case EEP_TEMPSENSE_SLOPE:
207 if (ver_minor >= AR9287_EEP_MINOR_VER_2)
208 return pBase->tempSensSlope;
209 else
210 return 0;
211 case EEP_TEMPSENSE_SLOPE_PAL_ON:
212 if (ver_minor >= AR9287_EEP_MINOR_VER_3)
213 return pBase->tempSensSlopePalOn;
214 else
215 return 0;
216 default:
217 return 0;
218 }
219}
220
Sujith16c94ac2010-06-01 15:14:04 +0530221static void ath9k_hw_get_ar9287_gain_boundaries_pdadcs(struct ath_hw *ah,
222 struct ath9k_channel *chan,
223 struct cal_data_per_freq_ar9287 *pRawDataSet,
224 u8 *bChans, u16 availPiers,
225 u16 tPdGainOverlap,
226 int16_t *pMinCalPower,
227 u16 *pPdGainBoundaries,
228 u8 *pPDADCValues,
229 u16 numXpdGains)
Sujithb5aec952009-08-07 09:45:15 +0530230{
Sujith16c94ac2010-06-01 15:14:04 +0530231#define TMP_VAL_VPD_TABLE \
Sujithb5aec952009-08-07 09:45:15 +0530232 ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
233
Sujith16c94ac2010-06-01 15:14:04 +0530234 int i, j, k;
235 int16_t ss;
236 u16 idxL = 0, idxR = 0, numPiers;
237 u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
238 u8 minPwrT4[AR9287_NUM_PD_GAINS];
239 u8 maxPwrT4[AR9287_NUM_PD_GAINS];
240 int16_t vpdStep;
241 int16_t tmpVal;
242 u16 sizeCurrVpdTable, maxIndex, tgtIndex;
243 bool match;
244 int16_t minDelta = 0;
Sujithb5aec952009-08-07 09:45:15 +0530245 struct chan_centers centers;
246 static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
247 [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
248 static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS]
249 [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
250 static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
251 [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
252
Prarit Bhargavaa5fdbca2010-05-27 14:14:54 -0400253 memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
Sujithb5aec952009-08-07 09:45:15 +0530254 ath9k_hw_get_channel_centers(ah, chan, &centers);
255
256 for (numPiers = 0; numPiers < availPiers; numPiers++) {
257 if (bChans[numPiers] == AR9287_BCHAN_UNUSED)
258 break;
259 }
260
261 match = ath9k_hw_get_lower_upper_index(
Sujith16c94ac2010-06-01 15:14:04 +0530262 (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
263 bChans, numPiers, &idxL, &idxR);
Sujithb5aec952009-08-07 09:45:15 +0530264
265 if (match) {
266 for (i = 0; i < numXpdGains; i++) {
267 minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
268 maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
269 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
Sujith16c94ac2010-06-01 15:14:04 +0530270 pRawDataSet[idxL].pwrPdg[i],
271 pRawDataSet[idxL].vpdPdg[i],
272 AR9287_PD_GAIN_ICEPTS,
273 vpdTableI[i]);
Sujithb5aec952009-08-07 09:45:15 +0530274 }
275 } else {
276 for (i = 0; i < numXpdGains; i++) {
277 pVpdL = pRawDataSet[idxL].vpdPdg[i];
278 pPwrL = pRawDataSet[idxL].pwrPdg[i];
279 pVpdR = pRawDataSet[idxR].vpdPdg[i];
280 pPwrR = pRawDataSet[idxR].pwrPdg[i];
281
282 minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
283
Sujith16c94ac2010-06-01 15:14:04 +0530284 maxPwrT4[i] = min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1],
285 pPwrR[AR9287_PD_GAIN_ICEPTS - 1]);
Sujithb5aec952009-08-07 09:45:15 +0530286
287 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
Sujith16c94ac2010-06-01 15:14:04 +0530288 pPwrL, pVpdL,
289 AR9287_PD_GAIN_ICEPTS,
290 vpdTableL[i]);
Sujithb5aec952009-08-07 09:45:15 +0530291 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
Sujith16c94ac2010-06-01 15:14:04 +0530292 pPwrR, pVpdR,
293 AR9287_PD_GAIN_ICEPTS,
294 vpdTableR[i]);
Sujithb5aec952009-08-07 09:45:15 +0530295
296 for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
Sujith16c94ac2010-06-01 15:14:04 +0530297 vpdTableI[i][j] = (u8)(ath9k_hw_interpolate(
298 (u16)FREQ2FBIN(centers. synth_center,
299 IS_CHAN_2GHZ(chan)),
300 bChans[idxL], bChans[idxR],
301 vpdTableL[i][j], vpdTableR[i][j]));
Sujithb5aec952009-08-07 09:45:15 +0530302 }
303 }
304 }
Sujithb5aec952009-08-07 09:45:15 +0530305
Sujith16c94ac2010-06-01 15:14:04 +0530306 *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
Sujithb5aec952009-08-07 09:45:15 +0530307 k = 0;
Sujith16c94ac2010-06-01 15:14:04 +0530308
Sujithb5aec952009-08-07 09:45:15 +0530309 for (i = 0; i < numXpdGains; i++) {
310 if (i == (numXpdGains - 1))
Sujith16c94ac2010-06-01 15:14:04 +0530311 pPdGainBoundaries[i] =
312 (u16)(maxPwrT4[i] / 2);
Sujithb5aec952009-08-07 09:45:15 +0530313 else
Sujith16c94ac2010-06-01 15:14:04 +0530314 pPdGainBoundaries[i] =
315 (u16)((maxPwrT4[i] + minPwrT4[i+1]) / 4);
Sujithb5aec952009-08-07 09:45:15 +0530316
317 pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER,
Sujith16c94ac2010-06-01 15:14:04 +0530318 pPdGainBoundaries[i]);
Sujithb5aec952009-08-07 09:45:15 +0530319
320
Sujitha55f8582010-06-01 15:14:07 +0530321 minDelta = 0;
Sujithb5aec952009-08-07 09:45:15 +0530322
323 if (i == 0) {
324 if (AR_SREV_9280_10_OR_LATER(ah))
325 ss = (int16_t)(0 - (minPwrT4[i] / 2));
326 else
327 ss = 0;
Sujitha55f8582010-06-01 15:14:07 +0530328 } else {
Sujithb5aec952009-08-07 09:45:15 +0530329 ss = (int16_t)((pPdGainBoundaries[i-1] -
Sujith16c94ac2010-06-01 15:14:04 +0530330 (minPwrT4[i] / 2)) -
Sujithb5aec952009-08-07 09:45:15 +0530331 tPdGainOverlap + 1 + minDelta);
Sujitha55f8582010-06-01 15:14:07 +0530332 }
Sujithb5aec952009-08-07 09:45:15 +0530333
334 vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
335 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
Sujith16c94ac2010-06-01 15:14:04 +0530336
Sujithb5aec952009-08-07 09:45:15 +0530337 while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) {
338 tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
339 pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
340 ss++;
341 }
342
343 sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
344 tgtIndex = (u8)(pPdGainBoundaries[i] +
345 tPdGainOverlap - (minPwrT4[i] / 2));
346 maxIndex = (tgtIndex < sizeCurrVpdTable) ?
347 tgtIndex : sizeCurrVpdTable;
348
349 while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1)))
350 pPDADCValues[k++] = vpdTableI[i][ss++];
351
352 vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
353 vpdTableI[i][sizeCurrVpdTable - 2]);
354 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
Sujith16c94ac2010-06-01 15:14:04 +0530355
Sujithb5aec952009-08-07 09:45:15 +0530356 if (tgtIndex > maxIndex) {
357 while ((ss <= tgtIndex) &&
358 (k < (AR9287_NUM_PDADC_VALUES - 1))) {
359 tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
Sujith16c94ac2010-06-01 15:14:04 +0530360 pPDADCValues[k++] =
361 (u8)((tmpVal > 255) ? 255 : tmpVal);
Sujithb5aec952009-08-07 09:45:15 +0530362 ss++;
363 }
364 }
365 }
366
367 while (i < AR9287_PD_GAINS_IN_MASK) {
368 pPdGainBoundaries[i] = pPdGainBoundaries[i-1];
369 i++;
370 }
371
372 while (k < AR9287_NUM_PDADC_VALUES) {
373 pPDADCValues[k] = pPDADCValues[k-1];
374 k++;
375 }
376
377#undef TMP_VAL_VPD_TABLE
378}
379
380static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
381 struct ath9k_channel *chan,
382 struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
Sujith16c94ac2010-06-01 15:14:04 +0530383 u8 *pCalChans, u16 availPiers, int8_t *pPwr)
Sujithb5aec952009-08-07 09:45:15 +0530384{
Sujith16c94ac2010-06-01 15:14:04 +0530385 u16 idxL = 0, idxR = 0, numPiers;
Sujithb5aec952009-08-07 09:45:15 +0530386 bool match;
387 struct chan_centers centers;
388
389 ath9k_hw_get_channel_centers(ah, chan, &centers);
390
391 for (numPiers = 0; numPiers < availPiers; numPiers++) {
392 if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED)
393 break;
394 }
395
396 match = ath9k_hw_get_lower_upper_index(
Sujitha55f8582010-06-01 15:14:07 +0530397 (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
398 pCalChans, numPiers, &idxL, &idxR);
Sujithb5aec952009-08-07 09:45:15 +0530399
400 if (match) {
Vivek Natarajand4fe5af2009-08-14 11:32:04 +0530401 *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
Sujithb5aec952009-08-07 09:45:15 +0530402 } else {
Vivek Natarajand4fe5af2009-08-14 11:32:04 +0530403 *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
Sujith16c94ac2010-06-01 15:14:04 +0530404 (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
Sujithb5aec952009-08-07 09:45:15 +0530405 }
406
Sujithb5aec952009-08-07 09:45:15 +0530407}
408
409static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
410 int32_t txPower, u16 chain)
411{
412 u32 tmpVal;
413 u32 a;
414
Sujith16c94ac2010-06-01 15:14:04 +0530415 /* Enable OLPC for chain 0 */
416
Sujithb5aec952009-08-07 09:45:15 +0530417 tmpVal = REG_READ(ah, 0xa270);
418 tmpVal = tmpVal & 0xFCFFFFFF;
419 tmpVal = tmpVal | (0x3 << 24);
420 REG_WRITE(ah, 0xa270, tmpVal);
421
Sujith16c94ac2010-06-01 15:14:04 +0530422 /* Enable OLPC for chain 1 */
423
Sujithb5aec952009-08-07 09:45:15 +0530424 tmpVal = REG_READ(ah, 0xb270);
425 tmpVal = tmpVal & 0xFCFFFFFF;
426 tmpVal = tmpVal | (0x3 << 24);
427 REG_WRITE(ah, 0xb270, tmpVal);
428
Sujith16c94ac2010-06-01 15:14:04 +0530429 /* Write the OLPC ref power for chain 0 */
430
Sujithb5aec952009-08-07 09:45:15 +0530431 if (chain == 0) {
432 tmpVal = REG_READ(ah, 0xa398);
433 tmpVal = tmpVal & 0xff00ffff;
434 a = (txPower)&0xff;
435 tmpVal = tmpVal | (a << 16);
436 REG_WRITE(ah, 0xa398, tmpVal);
437 }
438
Sujith16c94ac2010-06-01 15:14:04 +0530439 /* Write the OLPC ref power for chain 1 */
440
Sujithb5aec952009-08-07 09:45:15 +0530441 if (chain == 1) {
442 tmpVal = REG_READ(ah, 0xb398);
443 tmpVal = tmpVal & 0xff00ffff;
444 a = (txPower)&0xff;
445 tmpVal = tmpVal | (a << 16);
446 REG_WRITE(ah, 0xb398, tmpVal);
447 }
448}
449
Sujith16c94ac2010-06-01 15:14:04 +0530450static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
Sujithb5aec952009-08-07 09:45:15 +0530451 struct ath9k_channel *chan,
452 int16_t *pTxPowerIndexOffset)
453{
454 struct cal_data_per_freq_ar9287 *pRawDataset;
455 struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
Sujith16c94ac2010-06-01 15:14:04 +0530456 u8 *pCalBChans = NULL;
Sujithb5aec952009-08-07 09:45:15 +0530457 u16 pdGainOverlap_t2;
Sujith16c94ac2010-06-01 15:14:04 +0530458 u8 pdadcValues[AR9287_NUM_PDADC_VALUES];
Sujithb5aec952009-08-07 09:45:15 +0530459 u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK];
460 u16 numPiers = 0, i, j;
Sujith16c94ac2010-06-01 15:14:04 +0530461 int16_t tMinCalPower;
Sujithb5aec952009-08-07 09:45:15 +0530462 u16 numXpdGain, xpdMask;
463 u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0};
Sujitha55f8582010-06-01 15:14:07 +0530464 u32 reg32, regOffset, regChainOffset, regval;
Sujith16c94ac2010-06-01 15:14:04 +0530465 int16_t modalIdx, diff = 0;
Sujithb5aec952009-08-07 09:45:15 +0530466 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
Sujith16c94ac2010-06-01 15:14:04 +0530467
Sujithb5aec952009-08-07 09:45:15 +0530468 modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
469 xpdMask = pEepData->modalHeader.xpdGain;
Sujith16c94ac2010-06-01 15:14:04 +0530470
Sujithb5aec952009-08-07 09:45:15 +0530471 if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
Sujitha55f8582010-06-01 15:14:07 +0530472 AR9287_EEP_MINOR_VER_2)
Sujithb5aec952009-08-07 09:45:15 +0530473 pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
474 else
475 pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
476 AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
477
478 if (IS_CHAN_2GHZ(chan)) {
479 pCalBChans = pEepData->calFreqPier2G;
480 numPiers = AR9287_NUM_2G_CAL_PIERS;
Sujith16c94ac2010-06-01 15:14:04 +0530481 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
Sujithb5aec952009-08-07 09:45:15 +0530482 pRawDatasetOpenLoop =
Sujitha55f8582010-06-01 15:14:07 +0530483 (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
Sujithb5aec952009-08-07 09:45:15 +0530484 ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
485 }
486 }
487
488 numXpdGain = 0;
Sujith16c94ac2010-06-01 15:14:04 +0530489
Sujitha55f8582010-06-01 15:14:07 +0530490 /* Calculate the value of xpdgains from the xpdGain Mask */
Sujithb5aec952009-08-07 09:45:15 +0530491 for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) {
492 if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) {
493 if (numXpdGain >= AR9287_NUM_PD_GAINS)
494 break;
495 xpdGainValues[numXpdGain] =
496 (u16)(AR9287_PD_GAINS_IN_MASK-i);
497 numXpdGain++;
498 }
499 }
500
501 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
502 (numXpdGain - 1) & 0x3);
503 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
504 xpdGainValues[0]);
505 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
506 xpdGainValues[1]);
507 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
508 xpdGainValues[2]);
509
510 for (i = 0; i < AR9287_MAX_CHAINS; i++) {
511 regChainOffset = i * 0x1000;
Sujitha55f8582010-06-01 15:14:07 +0530512
Sujithb5aec952009-08-07 09:45:15 +0530513 if (pEepData->baseEepHeader.txMask & (1 << i)) {
Sujitha55f8582010-06-01 15:14:07 +0530514 pRawDatasetOpenLoop =
515 (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
516
Sujith16c94ac2010-06-01 15:14:04 +0530517 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
Sujithb5aec952009-08-07 09:45:15 +0530518 int8_t txPower;
519 ar9287_eeprom_get_tx_gain_index(ah, chan,
Sujitha55f8582010-06-01 15:14:07 +0530520 pRawDatasetOpenLoop,
521 pCalBChans, numPiers,
522 &txPower);
Sujithb5aec952009-08-07 09:45:15 +0530523 ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i);
524 } else {
525 pRawDataset =
526 (struct cal_data_per_freq_ar9287 *)
527 pEepData->calPierData2G[i];
Sujitha55f8582010-06-01 15:14:07 +0530528
529 ath9k_hw_get_ar9287_gain_boundaries_pdadcs(ah, chan,
530 pRawDataset,
531 pCalBChans, numPiers,
532 pdGainOverlap_t2,
533 &tMinCalPower,
534 gainBoundaries,
535 pdadcValues,
536 numXpdGain);
Sujithb5aec952009-08-07 09:45:15 +0530537 }
538
539 if (i == 0) {
Sujitha55f8582010-06-01 15:14:07 +0530540 if (!ath9k_hw_ar9287_get_eeprom(ah,
541 EEP_OL_PWRCTRL)) {
542
543 regval = SM(pdGainOverlap_t2,
544 AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
545 | SM(gainBoundaries[0],
546 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
547 | SM(gainBoundaries[1],
548 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
549 | SM(gainBoundaries[2],
550 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
551 | SM(gainBoundaries[3],
552 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4);
553
554 REG_WRITE(ah,
555 AR_PHY_TPCRG5 + regChainOffset,
556 regval);
Sujithb5aec952009-08-07 09:45:15 +0530557 }
558 }
559
560 if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB !=
Sujitha55f8582010-06-01 15:14:07 +0530561 pEepData->baseEepHeader.pwrTableOffset) {
562 diff = (u16)(pEepData->baseEepHeader.pwrTableOffset -
563 (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
Sujithb5aec952009-08-07 09:45:15 +0530564 diff *= 2;
565
Sujitha55f8582010-06-01 15:14:07 +0530566 for (j = 0; j < ((u16)AR9287_NUM_PDADC_VALUES-diff); j++)
Sujithb5aec952009-08-07 09:45:15 +0530567 pdadcValues[j] = pdadcValues[j+diff];
568
569 for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff);
570 j < AR9287_NUM_PDADC_VALUES; j++)
571 pdadcValues[j] =
Sujitha55f8582010-06-01 15:14:07 +0530572 pdadcValues[AR9287_NUM_PDADC_VALUES-diff];
Sujithb5aec952009-08-07 09:45:15 +0530573 }
574
Sujith16c94ac2010-06-01 15:14:04 +0530575 if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
Sujitha55f8582010-06-01 15:14:07 +0530576 regOffset = AR_PHY_BASE +
577 (672 << 2) + regChainOffset;
578
Sujithb5aec952009-08-07 09:45:15 +0530579 for (j = 0; j < 32; j++) {
Sujitha55f8582010-06-01 15:14:07 +0530580 reg32 = ((pdadcValues[4*j + 0] & 0xFF) << 0)
581 | ((pdadcValues[4*j + 1] & 0xFF) << 8)
582 | ((pdadcValues[4*j + 2] & 0xFF) << 16)
583 | ((pdadcValues[4*j + 3] & 0xFF) << 24);
584
Sujithb5aec952009-08-07 09:45:15 +0530585 REG_WRITE(ah, regOffset, reg32);
Sujithb5aec952009-08-07 09:45:15 +0530586 regOffset += 4;
587 }
588 }
589 }
590 }
591
592 *pTxPowerIndexOffset = 0;
593}
594
Sujith16c94ac2010-06-01 15:14:04 +0530595static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
596 struct ath9k_channel *chan,
597 int16_t *ratesArray,
598 u16 cfgCtl,
599 u16 AntennaReduction,
600 u16 twiceMaxRegulatoryPower,
601 u16 powerLimit)
Sujithb5aec952009-08-07 09:45:15 +0530602{
Sujitha55f8582010-06-01 15:14:07 +0530603#define CMP_CTL \
604 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
605 pEepData->ctlIndex[i])
606
607#define CMP_NO_CTL \
608 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
609 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
610
Sujithb5aec952009-08-07 09:45:15 +0530611#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6
612#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10
Sujith16c94ac2010-06-01 15:14:04 +0530613
Luis R. Rodriguez608b88c2009-08-17 18:07:23 -0700614 struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
Sujithb5aec952009-08-07 09:45:15 +0530615 u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
616 static const u16 tpScaleReductionTable[5] =
617 { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
618 int i;
Sujith16c94ac2010-06-01 15:14:04 +0530619 int16_t twiceLargestAntenna;
Sujithb5aec952009-08-07 09:45:15 +0530620 struct cal_ctl_data_ar9287 *rep;
621 struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
622 targetPowerCck = {0, {0, 0, 0, 0} };
623 struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} },
624 targetPowerCckExt = {0, {0, 0, 0, 0} };
Sujith16c94ac2010-06-01 15:14:04 +0530625 struct cal_target_power_ht targetPowerHt20,
Sujithb5aec952009-08-07 09:45:15 +0530626 targetPowerHt40 = {0, {0, 0, 0, 0} };
627 u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
Sujitha55f8582010-06-01 15:14:07 +0530628 u16 ctlModesFor11g[] = {CTL_11B,
629 CTL_11G,
630 CTL_2GHT20,
631 CTL_11B_EXT,
632 CTL_11G_EXT,
633 CTL_2GHT40};
Sujithb5aec952009-08-07 09:45:15 +0530634 u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq;
635 struct chan_centers centers;
636 int tx_chainmask;
637 u16 twiceMinEdgePower;
638 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
639 tx_chainmask = ah->txchainmask;
640
641 ath9k_hw_get_channel_centers(ah, chan, &centers);
642
Sujitha55f8582010-06-01 15:14:07 +0530643 /* Compute TxPower reduction due to Antenna Gain */
Sujithb5aec952009-08-07 09:45:15 +0530644 twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0],
645 pEepData->modalHeader.antennaGainCh[1]);
Sujith16c94ac2010-06-01 15:14:04 +0530646 twiceLargestAntenna = (int16_t)min((AntennaReduction) -
647 twiceLargestAntenna, 0);
Sujithb5aec952009-08-07 09:45:15 +0530648
Sujitha55f8582010-06-01 15:14:07 +0530649 /*
650 * scaledPower is the minimum of the user input power level
651 * and the regulatory allowed power level.
652 */
Sujithb5aec952009-08-07 09:45:15 +0530653 maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
Sujitha55f8582010-06-01 15:14:07 +0530654
Luis R. Rodriguez608b88c2009-08-17 18:07:23 -0700655 if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX)
Sujithb5aec952009-08-07 09:45:15 +0530656 maxRegAllowedPower -=
Luis R. Rodriguez608b88c2009-08-17 18:07:23 -0700657 (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
Sujithb5aec952009-08-07 09:45:15 +0530658
659 scaledPower = min(powerLimit, maxRegAllowedPower);
660
Sujitha55f8582010-06-01 15:14:07 +0530661 /*
662 * Reduce scaled Power by number of chains active
663 * to get the per chain tx power level.
664 */
Sujithb5aec952009-08-07 09:45:15 +0530665 switch (ar5416_get_ntxchains(tx_chainmask)) {
666 case 1:
667 break;
668 case 2:
669 scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
670 break;
671 case 3:
672 scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
673 break;
674 }
675 scaledPower = max((u16)0, scaledPower);
676
Sujitha55f8582010-06-01 15:14:07 +0530677 /*
678 * Get TX power from EEPROM.
679 */
Sujithb5aec952009-08-07 09:45:15 +0530680 if (IS_CHAN_2GHZ(chan)) {
Sujitha55f8582010-06-01 15:14:07 +0530681 /* CTL_11B, CTL_11G, CTL_2GHT20 */
Sujithb5aec952009-08-07 09:45:15 +0530682 numCtlModes =
683 ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
Sujith16c94ac2010-06-01 15:14:04 +0530684
Sujithb5aec952009-08-07 09:45:15 +0530685 pCtlMode = ctlModesFor11g;
686
687 ath9k_hw_get_legacy_target_powers(ah, chan,
688 pEepData->calTargetPowerCck,
689 AR9287_NUM_2G_CCK_TARGET_POWERS,
690 &targetPowerCck, 4, false);
691 ath9k_hw_get_legacy_target_powers(ah, chan,
692 pEepData->calTargetPower2G,
693 AR9287_NUM_2G_20_TARGET_POWERS,
694 &targetPowerOfdm, 4, false);
695 ath9k_hw_get_target_powers(ah, chan,
696 pEepData->calTargetPower2GHT20,
697 AR9287_NUM_2G_20_TARGET_POWERS,
698 &targetPowerHt20, 8, false);
699
700 if (IS_CHAN_HT40(chan)) {
Sujitha55f8582010-06-01 15:14:07 +0530701 /* All 2G CTLs */
Sujithb5aec952009-08-07 09:45:15 +0530702 numCtlModes = ARRAY_SIZE(ctlModesFor11g);
703 ath9k_hw_get_target_powers(ah, chan,
704 pEepData->calTargetPower2GHT40,
705 AR9287_NUM_2G_40_TARGET_POWERS,
706 &targetPowerHt40, 8, true);
707 ath9k_hw_get_legacy_target_powers(ah, chan,
708 pEepData->calTargetPowerCck,
709 AR9287_NUM_2G_CCK_TARGET_POWERS,
710 &targetPowerCckExt, 4, true);
711 ath9k_hw_get_legacy_target_powers(ah, chan,
712 pEepData->calTargetPower2G,
713 AR9287_NUM_2G_20_TARGET_POWERS,
714 &targetPowerOfdmExt, 4, true);
715 }
716 }
717
718 for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
Sujitha55f8582010-06-01 15:14:07 +0530719 bool isHt40CtlMode =
720 (pCtlMode[ctlMode] == CTL_2GHT40) ? true : false;
721
Sujithb5aec952009-08-07 09:45:15 +0530722 if (isHt40CtlMode)
723 freq = centers.synth_center;
724 else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
725 freq = centers.ext_center;
726 else
727 freq = centers.ctl_center;
728
Sujitha55f8582010-06-01 15:14:07 +0530729 /* Walk through the CTL indices stored in EEPROM */
Sujithb5aec952009-08-07 09:45:15 +0530730 for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
Sujitha55f8582010-06-01 15:14:07 +0530731 struct cal_ctl_edges *pRdEdgesPower;
Sujithb5aec952009-08-07 09:45:15 +0530732
Sujitha55f8582010-06-01 15:14:07 +0530733 /*
734 * Compare test group from regulatory channel list
735 * with test mode from pCtlMode list
736 */
737 if (CMP_CTL || CMP_NO_CTL) {
Sujithb5aec952009-08-07 09:45:15 +0530738 rep = &(pEepData->ctlData[i]);
Sujitha55f8582010-06-01 15:14:07 +0530739 pRdEdgesPower =
740 rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1];
Sujithb5aec952009-08-07 09:45:15 +0530741
Sujitha55f8582010-06-01 15:14:07 +0530742 twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
743 pRdEdgesPower,
744 IS_CHAN_2GHZ(chan),
745 AR5416_NUM_BAND_EDGES);
746
747 if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
748 twiceMaxEdgePower = min(twiceMaxEdgePower,
749 twiceMinEdgePower);
750 } else {
Sujithb5aec952009-08-07 09:45:15 +0530751 twiceMaxEdgePower = twiceMinEdgePower;
752 break;
753 }
754 }
755 }
756
757 minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
758
Sujitha55f8582010-06-01 15:14:07 +0530759 /* Apply ctl mode to correct target power set */
Sujithb5aec952009-08-07 09:45:15 +0530760 switch (pCtlMode[ctlMode]) {
761 case CTL_11B:
Sujitha55f8582010-06-01 15:14:07 +0530762 for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
763 targetPowerCck.tPow2x[i] =
764 (u8)min((u16)targetPowerCck.tPow2x[i],
765 minCtlPower);
Sujithb5aec952009-08-07 09:45:15 +0530766 }
767 break;
768 case CTL_11A:
769 case CTL_11G:
Sujitha55f8582010-06-01 15:14:07 +0530770 for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
771 targetPowerOfdm.tPow2x[i] =
772 (u8)min((u16)targetPowerOfdm.tPow2x[i],
773 minCtlPower);
Sujithb5aec952009-08-07 09:45:15 +0530774 }
775 break;
776 case CTL_5GHT20:
777 case CTL_2GHT20:
Sujitha55f8582010-06-01 15:14:07 +0530778 for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
779 targetPowerHt20.tPow2x[i] =
780 (u8)min((u16)targetPowerHt20.tPow2x[i],
781 minCtlPower);
Sujithb5aec952009-08-07 09:45:15 +0530782 }
783 break;
784 case CTL_11B_EXT:
Sujitha55f8582010-06-01 15:14:07 +0530785 targetPowerCckExt.tPow2x[0] =
786 (u8)min((u16)targetPowerCckExt.tPow2x[0],
787 minCtlPower);
Sujithb5aec952009-08-07 09:45:15 +0530788 break;
789 case CTL_11A_EXT:
790 case CTL_11G_EXT:
Sujitha55f8582010-06-01 15:14:07 +0530791 targetPowerOfdmExt.tPow2x[0] =
792 (u8)min((u16)targetPowerOfdmExt.tPow2x[0],
793 minCtlPower);
Sujithb5aec952009-08-07 09:45:15 +0530794 break;
795 case CTL_5GHT40:
796 case CTL_2GHT40:
Sujitha55f8582010-06-01 15:14:07 +0530797 for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
798 targetPowerHt40.tPow2x[i] =
799 (u8)min((u16)targetPowerHt40.tPow2x[i],
800 minCtlPower);
Sujithb5aec952009-08-07 09:45:15 +0530801 }
802 break;
803 default:
804 break;
805 }
806 }
807
Sujitha55f8582010-06-01 15:14:07 +0530808 /* Now set the rates array */
809
Sujithb5aec952009-08-07 09:45:15 +0530810 ratesArray[rate6mb] =
811 ratesArray[rate9mb] =
812 ratesArray[rate12mb] =
813 ratesArray[rate18mb] =
Sujitha55f8582010-06-01 15:14:07 +0530814 ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0];
Sujithb5aec952009-08-07 09:45:15 +0530815
816 ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
817 ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
818 ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
819 ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
820
821 for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
822 ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
823
824 if (IS_CHAN_2GHZ(chan)) {
825 ratesArray[rate1l] = targetPowerCck.tPow2x[0];
Sujitha55f8582010-06-01 15:14:07 +0530826 ratesArray[rate2s] =
827 ratesArray[rate2l] = targetPowerCck.tPow2x[1];
828 ratesArray[rate5_5s] =
829 ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
830 ratesArray[rate11s] =
831 ratesArray[rate11l] = targetPowerCck.tPow2x[3];
Sujithb5aec952009-08-07 09:45:15 +0530832 }
833 if (IS_CHAN_HT40(chan)) {
834 for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++)
835 ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i];
836
837 ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
838 ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
839 ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
Sujitha55f8582010-06-01 15:14:07 +0530840
Sujithb5aec952009-08-07 09:45:15 +0530841 if (IS_CHAN_2GHZ(chan))
842 ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
843 }
844
Sujitha55f8582010-06-01 15:14:07 +0530845#undef CMP_CTL
846#undef CMP_NO_CTL
Sujithb5aec952009-08-07 09:45:15 +0530847#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
848#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
849}
850
Sujith16c94ac2010-06-01 15:14:04 +0530851static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
Sujithb5aec952009-08-07 09:45:15 +0530852 struct ath9k_channel *chan, u16 cfgCtl,
853 u8 twiceAntennaReduction,
854 u8 twiceMaxRegulatoryPower,
855 u8 powerLimit)
856{
Luis R. Rodriguez608b88c2009-08-17 18:07:23 -0700857 struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
Sujithb5aec952009-08-07 09:45:15 +0530858 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
859 struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
860 int16_t ratesArray[Ar5416RateSize];
Sujith16c94ac2010-06-01 15:14:04 +0530861 int16_t txPowerIndexOffset = 0;
Sujithb5aec952009-08-07 09:45:15 +0530862 u8 ht40PowerIncForPdadc = 2;
863 int i;
864
865 memset(ratesArray, 0, sizeof(ratesArray));
866
867 if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
868 AR9287_EEP_MINOR_VER_2)
869 ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
870
Sujith16c94ac2010-06-01 15:14:04 +0530871 ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
Sujithb5aec952009-08-07 09:45:15 +0530872 &ratesArray[0], cfgCtl,
873 twiceAntennaReduction,
874 twiceMaxRegulatoryPower,
875 powerLimit);
876
Sujith16c94ac2010-06-01 15:14:04 +0530877 ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset);
Sujithb5aec952009-08-07 09:45:15 +0530878
879 for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
880 ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
881 if (ratesArray[i] > AR9287_MAX_RATE_POWER)
882 ratesArray[i] = AR9287_MAX_RATE_POWER;
883 }
884
885 if (AR_SREV_9280_10_OR_LATER(ah)) {
886 for (i = 0; i < Ar5416RateSize; i++)
887 ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
888 }
889
Sujitha55f8582010-06-01 15:14:07 +0530890 /* OFDM power per rate */
Sujithb5aec952009-08-07 09:45:15 +0530891 REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
892 ATH9K_POW_SM(ratesArray[rate18mb], 24)
893 | ATH9K_POW_SM(ratesArray[rate12mb], 16)
894 | ATH9K_POW_SM(ratesArray[rate9mb], 8)
895 | ATH9K_POW_SM(ratesArray[rate6mb], 0));
896
897 REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
898 ATH9K_POW_SM(ratesArray[rate54mb], 24)
899 | ATH9K_POW_SM(ratesArray[rate48mb], 16)
900 | ATH9K_POW_SM(ratesArray[rate36mb], 8)
901 | ATH9K_POW_SM(ratesArray[rate24mb], 0));
902
Sujitha55f8582010-06-01 15:14:07 +0530903 /* CCK power per rate */
Sujithb5aec952009-08-07 09:45:15 +0530904 if (IS_CHAN_2GHZ(chan)) {
905 REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
906 ATH9K_POW_SM(ratesArray[rate2s], 24)
907 | ATH9K_POW_SM(ratesArray[rate2l], 16)
908 | ATH9K_POW_SM(ratesArray[rateXr], 8)
909 | ATH9K_POW_SM(ratesArray[rate1l], 0));
910 REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
911 ATH9K_POW_SM(ratesArray[rate11s], 24)
912 | ATH9K_POW_SM(ratesArray[rate11l], 16)
913 | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
914 | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
915 }
916
Sujitha55f8582010-06-01 15:14:07 +0530917 /* HT20 power per rate */
Sujithb5aec952009-08-07 09:45:15 +0530918 REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
919 ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
920 | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
921 | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
922 | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
923
924 REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
925 ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
926 | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
927 | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
928 | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
929
Sujitha55f8582010-06-01 15:14:07 +0530930 /* HT40 power per rate */
Sujithb5aec952009-08-07 09:45:15 +0530931 if (IS_CHAN_HT40(chan)) {
Sujith16c94ac2010-06-01 15:14:04 +0530932 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
Sujithb5aec952009-08-07 09:45:15 +0530933 REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
934 ATH9K_POW_SM(ratesArray[rateHt40_3], 24)
935 | ATH9K_POW_SM(ratesArray[rateHt40_2], 16)
936 | ATH9K_POW_SM(ratesArray[rateHt40_1], 8)
937 | ATH9K_POW_SM(ratesArray[rateHt40_0], 0));
938
939 REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
940 ATH9K_POW_SM(ratesArray[rateHt40_7], 24)
941 | ATH9K_POW_SM(ratesArray[rateHt40_6], 16)
942 | ATH9K_POW_SM(ratesArray[rateHt40_5], 8)
943 | ATH9K_POW_SM(ratesArray[rateHt40_4], 0));
944 } else {
945 REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
946 ATH9K_POW_SM(ratesArray[rateHt40_3] +
947 ht40PowerIncForPdadc, 24)
948 | ATH9K_POW_SM(ratesArray[rateHt40_2] +
949 ht40PowerIncForPdadc, 16)
950 | ATH9K_POW_SM(ratesArray[rateHt40_1] +
951 ht40PowerIncForPdadc, 8)
952 | ATH9K_POW_SM(ratesArray[rateHt40_0] +
953 ht40PowerIncForPdadc, 0));
954
955 REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
956 ATH9K_POW_SM(ratesArray[rateHt40_7] +
957 ht40PowerIncForPdadc, 24)
958 | ATH9K_POW_SM(ratesArray[rateHt40_6] +
959 ht40PowerIncForPdadc, 16)
960 | ATH9K_POW_SM(ratesArray[rateHt40_5] +
961 ht40PowerIncForPdadc, 8)
962 | ATH9K_POW_SM(ratesArray[rateHt40_4] +
963 ht40PowerIncForPdadc, 0));
964 }
965
Sujitha55f8582010-06-01 15:14:07 +0530966 /* Dup/Ext power per rate */
Sujithb5aec952009-08-07 09:45:15 +0530967 REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
968 ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
969 | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
970 | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
971 | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
972 }
973
974 if (IS_CHAN_2GHZ(chan))
975 i = rate1l;
976 else
977 i = rate6mb;
978
979 if (AR_SREV_9280_10_OR_LATER(ah))
Luis R. Rodriguez608b88c2009-08-17 18:07:23 -0700980 regulatory->max_power_level =
Sujithb5aec952009-08-07 09:45:15 +0530981 ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2;
982 else
Luis R. Rodriguez608b88c2009-08-17 18:07:23 -0700983 regulatory->max_power_level = ratesArray[i];
Sujithb5aec952009-08-07 09:45:15 +0530984}
985
Sujith16c94ac2010-06-01 15:14:04 +0530986static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah,
Sujithb5aec952009-08-07 09:45:15 +0530987 struct ath9k_channel *chan)
988{
989}
990
Sujith16c94ac2010-06-01 15:14:04 +0530991static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
Sujithb5aec952009-08-07 09:45:15 +0530992 struct ath9k_channel *chan)
993{
994 struct ar9287_eeprom *eep = &ah->eeprom.map9287;
995 struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
996 u16 antWrites[AR9287_ANT_16S];
Sujith79d7f4b2010-06-01 15:14:06 +0530997 u32 regChainOffset, regval;
Sujithb5aec952009-08-07 09:45:15 +0530998 u8 txRxAttenLocal;
999 int i, j, offset_num;
1000
1001 pModal = &eep->modalHeader;
1002
1003 antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF);
1004 antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF);
1005 antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF);
1006 antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF);
1007 antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF);
1008 antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF);
1009 antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF);
1010 antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF);
1011
1012 offset_num = 8;
1013
1014 for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) {
1015 antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf);
1016 antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3);
1017 antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3);
1018 antWrites[j++] = 0;
1019 antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3);
1020 antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3);
1021 antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3);
1022 antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3);
1023 }
1024
1025 REG_WRITE(ah, AR_PHY_SWITCH_COM,
1026 ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
1027
1028 for (i = 0; i < AR9287_MAX_CHAINS; i++) {
1029 regChainOffset = i * 0x1000;
1030
1031 REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
1032 pModal->antCtrlChain[i]);
1033
1034 REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
1035 (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset)
1036 & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
1037 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
1038 SM(pModal->iqCalICh[i],
1039 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
1040 SM(pModal->iqCalQCh[i],
1041 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
1042
1043 txRxAttenLocal = pModal->txRxAttenCh[i];
1044
1045 REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
1046 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
1047 pModal->bswMargin[i]);
1048 REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
1049 AR_PHY_GAIN_2GHZ_XATTEN1_DB,
1050 pModal->bswAtten[i]);
1051 REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
1052 AR9280_PHY_RXGAIN_TXRX_ATTEN,
1053 txRxAttenLocal);
1054 REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
1055 AR9280_PHY_RXGAIN_TXRX_MARGIN,
1056 pModal->rxTxMarginCh[i]);
1057 }
1058
1059
1060 if (IS_CHAN_HT40(chan))
1061 REG_RMW_FIELD(ah, AR_PHY_SETTLING,
1062 AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40);
1063 else
1064 REG_RMW_FIELD(ah, AR_PHY_SETTLING,
1065 AR_PHY_SETTLING_SWITCH, pModal->switchSettling);
1066
1067 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
1068 AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize);
1069
1070 REG_WRITE(ah, AR_PHY_RF_CTL4,
1071 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
1072 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
1073 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)
1074 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
1075
1076 REG_RMW_FIELD(ah, AR_PHY_RF_CTL3,
1077 AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn);
1078
1079 REG_RMW_FIELD(ah, AR_PHY_CCA,
1080 AR9280_PHY_CCA_THRESH62, pModal->thresh62);
1081 REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
1082 AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62);
1083
Sujith79d7f4b2010-06-01 15:14:06 +05301084 regval = REG_READ(ah, AR9287_AN_RF2G3_CH0);
1085 regval &= ~(AR9287_AN_RF2G3_DB1 |
1086 AR9287_AN_RF2G3_DB2 |
1087 AR9287_AN_RF2G3_OB_CCK |
1088 AR9287_AN_RF2G3_OB_PSK |
1089 AR9287_AN_RF2G3_OB_QAM |
1090 AR9287_AN_RF2G3_OB_PAL_OFF);
1091 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
1092 SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
1093 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
1094 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
1095 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
1096 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
Sujithb5aec952009-08-07 09:45:15 +05301097
Sujith79d7f4b2010-06-01 15:14:06 +05301098 ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH0, regval);
1099
1100 regval = REG_READ(ah, AR9287_AN_RF2G3_CH1);
1101 regval &= ~(AR9287_AN_RF2G3_DB1 |
1102 AR9287_AN_RF2G3_DB2 |
1103 AR9287_AN_RF2G3_OB_CCK |
1104 AR9287_AN_RF2G3_OB_PSK |
1105 AR9287_AN_RF2G3_OB_QAM |
1106 AR9287_AN_RF2G3_OB_PAL_OFF);
1107 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
1108 SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
1109 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
1110 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
1111 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
1112 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
1113
1114 ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH1, regval);
Sujithb5aec952009-08-07 09:45:15 +05301115
1116 REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
1117 AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart);
1118 REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
1119 AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn);
1120
1121 ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2,
1122 AR9287_AN_TOP2_XPABIAS_LVL,
1123 AR9287_AN_TOP2_XPABIAS_LVL_S,
1124 pModal->xpaBiasLvl);
1125}
1126
Sujith16c94ac2010-06-01 15:14:04 +05301127static u8 ath9k_hw_ar9287_get_num_ant_config(struct ath_hw *ah,
Sujithb5aec952009-08-07 09:45:15 +05301128 enum ieee80211_band freq_band)
1129{
1130 return 1;
1131}
1132
Felix Fietkau601e0cb2010-07-11 12:48:39 +02001133static u32 ath9k_hw_ar9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
Sujithb5aec952009-08-07 09:45:15 +05301134 struct ath9k_channel *chan)
1135{
1136 struct ar9287_eeprom *eep = &ah->eeprom.map9287;
1137 struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
1138
Felix Fietkau601e0cb2010-07-11 12:48:39 +02001139 return pModal->antCtrlCommon;
Sujithb5aec952009-08-07 09:45:15 +05301140}
1141
Sujith16c94ac2010-06-01 15:14:04 +05301142static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
Sujithb5aec952009-08-07 09:45:15 +05301143 u16 i, bool is2GHz)
1144{
1145#define EEP_MAP9287_SPURCHAN \
1146 (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
Sujith16c94ac2010-06-01 15:14:04 +05301147
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001148 struct ath_common *common = ath9k_hw_common(ah);
Sujithb5aec952009-08-07 09:45:15 +05301149 u16 spur_val = AR_NO_SPUR;
1150
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001151 ath_print(common, ATH_DBG_ANI,
1152 "Getting spur idx %d is2Ghz. %d val %x\n",
1153 i, is2GHz, ah->config.spurchans[i][is2GHz]);
Sujithb5aec952009-08-07 09:45:15 +05301154
1155 switch (ah->config.spurmode) {
1156 case SPUR_DISABLE:
1157 break;
1158 case SPUR_ENABLE_IOCTL:
1159 spur_val = ah->config.spurchans[i][is2GHz];
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001160 ath_print(common, ATH_DBG_ANI,
1161 "Getting spur val from new loc. %d\n", spur_val);
Sujithb5aec952009-08-07 09:45:15 +05301162 break;
1163 case SPUR_ENABLE_EEPROM:
1164 spur_val = EEP_MAP9287_SPURCHAN;
1165 break;
1166 }
1167
1168 return spur_val;
1169
1170#undef EEP_MAP9287_SPURCHAN
1171}
1172
Luis R. Rodriguez0b8f6f2b12010-04-15 17:39:12 -04001173const struct eeprom_ops eep_ar9287_ops = {
Sujith16c94ac2010-06-01 15:14:04 +05301174 .check_eeprom = ath9k_hw_ar9287_check_eeprom,
1175 .get_eeprom = ath9k_hw_ar9287_get_eeprom,
1176 .fill_eeprom = ath9k_hw_ar9287_fill_eeprom,
1177 .get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver,
1178 .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev,
1179 .get_num_ant_config = ath9k_hw_ar9287_get_num_ant_config,
1180 .get_eeprom_antenna_cfg = ath9k_hw_ar9287_get_eeprom_antenna_cfg,
1181 .set_board_values = ath9k_hw_ar9287_set_board_values,
1182 .set_addac = ath9k_hw_ar9287_set_addac,
1183 .set_txpower = ath9k_hw_ar9287_set_txpower,
1184 .get_spur_channel = ath9k_hw_ar9287_get_spur_channel
Sujithb5aec952009-08-07 09:45:15 +05301185};