diff options
author | Sujith <Sujith.Manoharan@atheros.com> | 2009-08-07 00:15:15 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-14 09:13:34 -0400 |
commit | b5aec950eeb433d4850c1e5fcf14b666048e647d (patch) | |
tree | 4d38f9f64c0ff9bbededed207a5c92c1646ebdd6 /drivers/net/wireless/ath/ath9k/eeprom_9287.c | |
parent | 6780ccf5652a04493f72fafd9af0d9964ee977ad (diff) |
ath9k: Split eeprom.c into manageable pieces
Add eeprom_def.c, eeprom_4k.c and eeprom_9287.c
This improves maintainability.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/eeprom_9287.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/eeprom_9287.c | 1183 |
1 files changed, 1183 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c new file mode 100644 index 000000000000..aeb7f484b6e1 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c | |||
@@ -0,0 +1,1183 @@ | |||
1 | /* | ||
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 | |||
17 | #include "ath9k.h" | ||
18 | |||
19 | static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) | ||
20 | { | ||
21 | return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; | ||
22 | } | ||
23 | |||
24 | static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) | ||
25 | { | ||
26 | return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; | ||
27 | } | ||
28 | |||
29 | static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) | ||
30 | { | ||
31 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
32 | u16 *eep_data; | ||
33 | int addr, eep_start_loc = AR9287_EEP_START_LOC; | ||
34 | eep_data = (u16 *)eep; | ||
35 | |||
36 | if (!ath9k_hw_use_flash(ah)) { | ||
37 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
38 | "Reading from EEPROM, not flash\n"); | ||
39 | } | ||
40 | |||
41 | for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); | ||
42 | addr++) { | ||
43 | if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { | ||
44 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
45 | "Unable to read eeprom region \n"); | ||
46 | return false; | ||
47 | } | ||
48 | eep_data++; | ||
49 | } | ||
50 | return true; | ||
51 | } | ||
52 | |||
53 | static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) | ||
54 | { | ||
55 | u32 sum = 0, el, integer; | ||
56 | u16 temp, word, magic, magic2, *eepdata; | ||
57 | int i, addr; | ||
58 | bool need_swap = false; | ||
59 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
60 | |||
61 | if (!ath9k_hw_use_flash(ah)) { | ||
62 | if (!ath9k_hw_nvram_read | ||
63 | (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { | ||
64 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
65 | "Reading Magic # failed\n"); | ||
66 | return false; | ||
67 | } | ||
68 | |||
69 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
70 | "Read Magic = 0x%04X\n", magic); | ||
71 | if (magic != AR5416_EEPROM_MAGIC) { | ||
72 | magic2 = swab16(magic); | ||
73 | |||
74 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
75 | need_swap = true; | ||
76 | eepdata = (u16 *)(&ah->eeprom); | ||
77 | |||
78 | for (addr = 0; | ||
79 | addr < sizeof(struct ar9287_eeprom) / sizeof(u16); | ||
80 | addr++) { | ||
81 | temp = swab16(*eepdata); | ||
82 | *eepdata = temp; | ||
83 | eepdata++; | ||
84 | } | ||
85 | } else { | ||
86 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
87 | "Invalid EEPROM Magic. " | ||
88 | "endianness mismatch.\n"); | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? | ||
94 | "True" : "False"); | ||
95 | |||
96 | if (need_swap) | ||
97 | el = swab16(ah->eeprom.map9287.baseEepHeader.length); | ||
98 | else | ||
99 | el = ah->eeprom.map9287.baseEepHeader.length; | ||
100 | |||
101 | if (el > sizeof(struct ar9287_eeprom)) | ||
102 | el = sizeof(struct ar9287_eeprom) / sizeof(u16); | ||
103 | else | ||
104 | el = el / sizeof(u16); | ||
105 | |||
106 | eepdata = (u16 *)(&ah->eeprom); | ||
107 | for (i = 0; i < el; i++) | ||
108 | sum ^= *eepdata++; | ||
109 | |||
110 | if (need_swap) { | ||
111 | word = swab16(eep->baseEepHeader.length); | ||
112 | eep->baseEepHeader.length = word; | ||
113 | |||
114 | word = swab16(eep->baseEepHeader.checksum); | ||
115 | eep->baseEepHeader.checksum = word; | ||
116 | |||
117 | word = swab16(eep->baseEepHeader.version); | ||
118 | eep->baseEepHeader.version = word; | ||
119 | |||
120 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
121 | eep->baseEepHeader.regDmn[0] = word; | ||
122 | |||
123 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
124 | eep->baseEepHeader.regDmn[1] = word; | ||
125 | |||
126 | word = swab16(eep->baseEepHeader.rfSilent); | ||
127 | eep->baseEepHeader.rfSilent = word; | ||
128 | |||
129 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
130 | eep->baseEepHeader.blueToothOptions = word; | ||
131 | |||
132 | word = swab16(eep->baseEepHeader.deviceCap); | ||
133 | eep->baseEepHeader.deviceCap = word; | ||
134 | |||
135 | integer = swab32(eep->modalHeader.antCtrlCommon); | ||
136 | eep->modalHeader.antCtrlCommon = integer; | ||
137 | |||
138 | for (i = 0; i < AR9287_MAX_CHAINS; i++) { | ||
139 | integer = swab32(eep->modalHeader.antCtrlChain[i]); | ||
140 | eep->modalHeader.antCtrlChain[i] = integer; | ||
141 | } | ||
142 | |||
143 | for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) { | ||
144 | word = swab16(eep->modalHeader.spurChans[i].spurChan); | ||
145 | eep->modalHeader.spurChans[i].spurChan = word; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER | ||
150 | || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | ||
151 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
152 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
153 | sum, ah->eep_ops->get_eeprom_ver(ah)); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, | ||
161 | enum eeprom_param param) | ||
162 | { | ||
163 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
164 | struct modal_eep_ar9287_header *pModal = &eep->modalHeader; | ||
165 | struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; | ||
166 | u16 ver_minor; | ||
167 | |||
168 | ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; | ||
169 | switch (param) { | ||
170 | case EEP_NFTHRESH_2: | ||
171 | return pModal->noiseFloorThreshCh[0]; | ||
172 | case AR_EEPROM_MAC(0): | ||
173 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
174 | case AR_EEPROM_MAC(1): | ||
175 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
176 | case AR_EEPROM_MAC(2): | ||
177 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
178 | case EEP_REG_0: | ||
179 | return pBase->regDmn[0]; | ||
180 | case EEP_REG_1: | ||
181 | return pBase->regDmn[1]; | ||
182 | case EEP_OP_CAP: | ||
183 | return pBase->deviceCap; | ||
184 | case EEP_OP_MODE: | ||
185 | return pBase->opCapFlags; | ||
186 | case EEP_RF_SILENT: | ||
187 | return pBase->rfSilent; | ||
188 | case EEP_MINOR_REV: | ||
189 | return ver_minor; | ||
190 | case EEP_TX_MASK: | ||
191 | return pBase->txMask; | ||
192 | case EEP_RX_MASK: | ||
193 | return pBase->rxMask; | ||
194 | case EEP_DEV_TYPE: | ||
195 | return pBase->deviceType; | ||
196 | case EEP_OL_PWRCTRL: | ||
197 | return pBase->openLoopPwrCntl; | ||
198 | case EEP_TEMPSENSE_SLOPE: | ||
199 | if (ver_minor >= AR9287_EEP_MINOR_VER_2) | ||
200 | return pBase->tempSensSlope; | ||
201 | else | ||
202 | return 0; | ||
203 | case EEP_TEMPSENSE_SLOPE_PAL_ON: | ||
204 | if (ver_minor >= AR9287_EEP_MINOR_VER_3) | ||
205 | return pBase->tempSensSlopePalOn; | ||
206 | else | ||
207 | return 0; | ||
208 | default: | ||
209 | return 0; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | |||
214 | static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, | ||
215 | struct ath9k_channel *chan, | ||
216 | struct cal_data_per_freq_ar9287 *pRawDataSet, | ||
217 | u8 *bChans, u16 availPiers, | ||
218 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
219 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
220 | u16 numXpdGains) | ||
221 | { | ||
222 | #define TMP_VAL_VPD_TABLE \ | ||
223 | ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); | ||
224 | |||
225 | int i, j, k; | ||
226 | int16_t ss; | ||
227 | u16 idxL = 0, idxR = 0, numPiers; | ||
228 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
229 | u8 minPwrT4[AR9287_NUM_PD_GAINS]; | ||
230 | u8 maxPwrT4[AR9287_NUM_PD_GAINS]; | ||
231 | int16_t vpdStep; | ||
232 | int16_t tmpVal; | ||
233 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
234 | bool match; | ||
235 | int16_t minDelta = 0; | ||
236 | struct chan_centers centers; | ||
237 | static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] | ||
238 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
239 | static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] | ||
240 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
241 | static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] | ||
242 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
243 | |||
244 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
245 | |||
246 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
247 | if (bChans[numPiers] == AR9287_BCHAN_UNUSED) | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | match = ath9k_hw_get_lower_upper_index( | ||
252 | (u8)FREQ2FBIN(centers.synth_center, | ||
253 | IS_CHAN_2GHZ(chan)), bChans, numPiers, | ||
254 | &idxL, &idxR); | ||
255 | |||
256 | if (match) { | ||
257 | for (i = 0; i < numXpdGains; i++) { | ||
258 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
259 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
260 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
261 | pRawDataSet[idxL].pwrPdg[i], | ||
262 | pRawDataSet[idxL].vpdPdg[i], | ||
263 | AR9287_PD_GAIN_ICEPTS, vpdTableI[i]); | ||
264 | } | ||
265 | } else { | ||
266 | for (i = 0; i < numXpdGains; i++) { | ||
267 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
268 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
269 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
270 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
271 | |||
272 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
273 | |||
274 | maxPwrT4[i] = | ||
275 | min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1], | ||
276 | pPwrR[AR9287_PD_GAIN_ICEPTS - 1]); | ||
277 | |||
278 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
279 | pPwrL, pVpdL, | ||
280 | AR9287_PD_GAIN_ICEPTS, | ||
281 | vpdTableL[i]); | ||
282 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
283 | pPwrR, pVpdR, | ||
284 | AR9287_PD_GAIN_ICEPTS, | ||
285 | vpdTableR[i]); | ||
286 | |||
287 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
288 | vpdTableI[i][j] = | ||
289 | (u8)(ath9k_hw_interpolate((u16) | ||
290 | FREQ2FBIN(centers. synth_center, | ||
291 | IS_CHAN_2GHZ(chan)), | ||
292 | bChans[idxL], bChans[idxR], | ||
293 | vpdTableL[i][j], vpdTableR[i][j])); | ||
294 | } | ||
295 | } | ||
296 | } | ||
297 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
298 | |||
299 | k = 0; | ||
300 | for (i = 0; i < numXpdGains; i++) { | ||
301 | if (i == (numXpdGains - 1)) | ||
302 | pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2); | ||
303 | else | ||
304 | pPdGainBoundaries[i] = (u16)((maxPwrT4[i] + | ||
305 | minPwrT4[i+1]) / 4); | ||
306 | |||
307 | pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER, | ||
308 | pPdGainBoundaries[i]); | ||
309 | |||
310 | |||
311 | if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { | ||
312 | minDelta = pPdGainBoundaries[0] - 23; | ||
313 | pPdGainBoundaries[0] = 23; | ||
314 | } else | ||
315 | minDelta = 0; | ||
316 | |||
317 | if (i == 0) { | ||
318 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
319 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
320 | else | ||
321 | ss = 0; | ||
322 | } else | ||
323 | ss = (int16_t)((pPdGainBoundaries[i-1] - | ||
324 | (minPwrT4[i] / 2)) - | ||
325 | tPdGainOverlap + 1 + minDelta); | ||
326 | |||
327 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
328 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
329 | while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) { | ||
330 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
331 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
332 | ss++; | ||
333 | } | ||
334 | |||
335 | sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
336 | tgtIndex = (u8)(pPdGainBoundaries[i] + | ||
337 | tPdGainOverlap - (minPwrT4[i] / 2)); | ||
338 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
339 | tgtIndex : sizeCurrVpdTable; | ||
340 | |||
341 | while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1))) | ||
342 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
343 | |||
344 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
345 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
346 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
347 | if (tgtIndex > maxIndex) { | ||
348 | while ((ss <= tgtIndex) && | ||
349 | (k < (AR9287_NUM_PDADC_VALUES - 1))) { | ||
350 | tmpVal = (int16_t) TMP_VAL_VPD_TABLE; | ||
351 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
352 | 255 : tmpVal); | ||
353 | ss++; | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | |||
358 | while (i < AR9287_PD_GAINS_IN_MASK) { | ||
359 | pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; | ||
360 | i++; | ||
361 | } | ||
362 | |||
363 | while (k < AR9287_NUM_PDADC_VALUES) { | ||
364 | pPDADCValues[k] = pPDADCValues[k-1]; | ||
365 | k++; | ||
366 | } | ||
367 | |||
368 | #undef TMP_VAL_VPD_TABLE | ||
369 | } | ||
370 | |||
371 | static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, | ||
372 | struct ath9k_channel *chan, | ||
373 | struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, | ||
374 | u8 *pCalChans, u16 availPiers, | ||
375 | int8_t *pPwr) | ||
376 | { | ||
377 | u8 pcdac, i = 0; | ||
378 | u16 idxL = 0, idxR = 0, numPiers; | ||
379 | bool match; | ||
380 | struct chan_centers centers; | ||
381 | |||
382 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
383 | |||
384 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
385 | if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) | ||
386 | break; | ||
387 | } | ||
388 | |||
389 | match = ath9k_hw_get_lower_upper_index( | ||
390 | (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), | ||
391 | pCalChans, numPiers, | ||
392 | &idxL, &idxR); | ||
393 | |||
394 | if (match) { | ||
395 | pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; | ||
396 | *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; | ||
397 | } else { | ||
398 | pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; | ||
399 | *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + | ||
400 | pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; | ||
401 | } | ||
402 | |||
403 | while ((pcdac > ah->originalGain[i]) && | ||
404 | (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) | ||
405 | i++; | ||
406 | } | ||
407 | |||
408 | static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, | ||
409 | int32_t txPower, u16 chain) | ||
410 | { | ||
411 | u32 tmpVal; | ||
412 | u32 a; | ||
413 | |||
414 | tmpVal = REG_READ(ah, 0xa270); | ||
415 | tmpVal = tmpVal & 0xFCFFFFFF; | ||
416 | tmpVal = tmpVal | (0x3 << 24); | ||
417 | REG_WRITE(ah, 0xa270, tmpVal); | ||
418 | |||
419 | tmpVal = REG_READ(ah, 0xb270); | ||
420 | tmpVal = tmpVal & 0xFCFFFFFF; | ||
421 | tmpVal = tmpVal | (0x3 << 24); | ||
422 | REG_WRITE(ah, 0xb270, tmpVal); | ||
423 | |||
424 | if (chain == 0) { | ||
425 | tmpVal = REG_READ(ah, 0xa398); | ||
426 | tmpVal = tmpVal & 0xff00ffff; | ||
427 | a = (txPower)&0xff; | ||
428 | tmpVal = tmpVal | (a << 16); | ||
429 | REG_WRITE(ah, 0xa398, tmpVal); | ||
430 | } | ||
431 | |||
432 | if (chain == 1) { | ||
433 | tmpVal = REG_READ(ah, 0xb398); | ||
434 | tmpVal = tmpVal & 0xff00ffff; | ||
435 | a = (txPower)&0xff; | ||
436 | tmpVal = tmpVal | (a << 16); | ||
437 | REG_WRITE(ah, 0xb398, tmpVal); | ||
438 | } | ||
439 | } | ||
440 | |||
441 | static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, | ||
442 | struct ath9k_channel *chan, | ||
443 | int16_t *pTxPowerIndexOffset) | ||
444 | { | ||
445 | struct cal_data_per_freq_ar9287 *pRawDataset; | ||
446 | struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; | ||
447 | u8 *pCalBChans = NULL; | ||
448 | u16 pdGainOverlap_t2; | ||
449 | u8 pdadcValues[AR9287_NUM_PDADC_VALUES]; | ||
450 | u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK]; | ||
451 | u16 numPiers = 0, i, j; | ||
452 | int16_t tMinCalPower; | ||
453 | u16 numXpdGain, xpdMask; | ||
454 | u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; | ||
455 | u32 reg32, regOffset, regChainOffset; | ||
456 | int16_t modalIdx, diff = 0; | ||
457 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; | ||
458 | modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; | ||
459 | xpdMask = pEepData->modalHeader.xpdGain; | ||
460 | if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= | ||
461 | AR9287_EEP_MINOR_VER_2) | ||
462 | pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; | ||
463 | else | ||
464 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
465 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
466 | |||
467 | if (IS_CHAN_2GHZ(chan)) { | ||
468 | pCalBChans = pEepData->calFreqPier2G; | ||
469 | numPiers = AR9287_NUM_2G_CAL_PIERS; | ||
470 | if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
471 | pRawDatasetOpenLoop = | ||
472 | (struct cal_data_op_loop_ar9287 *) | ||
473 | pEepData->calPierData2G[0]; | ||
474 | ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | numXpdGain = 0; | ||
479 | for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) { | ||
480 | if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) { | ||
481 | if (numXpdGain >= AR9287_NUM_PD_GAINS) | ||
482 | break; | ||
483 | xpdGainValues[numXpdGain] = | ||
484 | (u16)(AR9287_PD_GAINS_IN_MASK-i); | ||
485 | numXpdGain++; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
490 | (numXpdGain - 1) & 0x3); | ||
491 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
492 | xpdGainValues[0]); | ||
493 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
494 | xpdGainValues[1]); | ||
495 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, | ||
496 | xpdGainValues[2]); | ||
497 | |||
498 | for (i = 0; i < AR9287_MAX_CHAINS; i++) { | ||
499 | regChainOffset = i * 0x1000; | ||
500 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
501 | pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *) | ||
502 | pEepData->calPierData2G[i]; | ||
503 | if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
504 | int8_t txPower; | ||
505 | ar9287_eeprom_get_tx_gain_index(ah, chan, | ||
506 | pRawDatasetOpenLoop, | ||
507 | pCalBChans, numPiers, | ||
508 | &txPower); | ||
509 | ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); | ||
510 | } else { | ||
511 | pRawDataset = | ||
512 | (struct cal_data_per_freq_ar9287 *) | ||
513 | pEepData->calPierData2G[i]; | ||
514 | ath9k_hw_get_AR9287_gain_boundaries_pdadcs( | ||
515 | ah, chan, pRawDataset, | ||
516 | pCalBChans, numPiers, | ||
517 | pdGainOverlap_t2, | ||
518 | &tMinCalPower, gainBoundaries, | ||
519 | pdadcValues, numXpdGain); | ||
520 | } | ||
521 | |||
522 | if (i == 0) { | ||
523 | if (!ath9k_hw_AR9287_get_eeprom( | ||
524 | ah, EEP_OL_PWRCTRL)) { | ||
525 | REG_WRITE(ah, AR_PHY_TPCRG5 + | ||
526 | regChainOffset, | ||
527 | SM(pdGainOverlap_t2, | ||
528 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | | ||
529 | SM(gainBoundaries[0], | ||
530 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | ||
531 | | SM(gainBoundaries[1], | ||
532 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | ||
533 | | SM(gainBoundaries[2], | ||
534 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | ||
535 | | SM(gainBoundaries[3], | ||
536 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); | ||
537 | } | ||
538 | } | ||
539 | |||
540 | if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != | ||
541 | pEepData->baseEepHeader.pwrTableOffset) { | ||
542 | diff = (u16) | ||
543 | (pEepData->baseEepHeader.pwrTableOffset | ||
544 | - (int32_t)AR9287_PWR_TABLE_OFFSET_DB); | ||
545 | diff *= 2; | ||
546 | |||
547 | for (j = 0; | ||
548 | j < ((u16)AR9287_NUM_PDADC_VALUES-diff); | ||
549 | j++) | ||
550 | pdadcValues[j] = pdadcValues[j+diff]; | ||
551 | |||
552 | for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff); | ||
553 | j < AR9287_NUM_PDADC_VALUES; j++) | ||
554 | pdadcValues[j] = | ||
555 | pdadcValues[ | ||
556 | AR9287_NUM_PDADC_VALUES-diff]; | ||
557 | } | ||
558 | |||
559 | if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
560 | regOffset = AR_PHY_BASE + (672 << 2) + | ||
561 | regChainOffset; | ||
562 | for (j = 0; j < 32; j++) { | ||
563 | reg32 = ((pdadcValues[4*j + 0] | ||
564 | & 0xFF) << 0) | | ||
565 | ((pdadcValues[4*j + 1] | ||
566 | & 0xFF) << 8) | | ||
567 | ((pdadcValues[4*j + 2] | ||
568 | & 0xFF) << 16) | | ||
569 | ((pdadcValues[4*j + 3] | ||
570 | & 0xFF) << 24) ; | ||
571 | REG_WRITE(ah, regOffset, reg32); | ||
572 | |||
573 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
574 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
575 | i, regChainOffset, regOffset, | ||
576 | reg32); | ||
577 | |||
578 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
579 | "PDADC: Chain %d | " | ||
580 | "PDADC %3d Value %3d | " | ||
581 | "PDADC %3d Value %3d | " | ||
582 | "PDADC %3d Value %3d | " | ||
583 | "PDADC %3d Value %3d |\n", | ||
584 | i, 4 * j, pdadcValues[4 * j], | ||
585 | 4 * j + 1, | ||
586 | pdadcValues[4 * j + 1], | ||
587 | 4 * j + 2, | ||
588 | pdadcValues[4 * j + 2], | ||
589 | 4 * j + 3, | ||
590 | pdadcValues[4 * j + 3]); | ||
591 | |||
592 | regOffset += 4; | ||
593 | } | ||
594 | } | ||
595 | } | ||
596 | } | ||
597 | |||
598 | *pTxPowerIndexOffset = 0; | ||
599 | } | ||
600 | |||
601 | static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, | ||
602 | struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, | ||
603 | u16 AntennaReduction, u16 twiceMaxRegulatoryPower, | ||
604 | u16 powerLimit) | ||
605 | { | ||
606 | #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 | ||
607 | #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 | ||
608 | |||
609 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
610 | static const u16 tpScaleReductionTable[5] = | ||
611 | { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; | ||
612 | int i; | ||
613 | int16_t twiceLargestAntenna; | ||
614 | struct cal_ctl_data_ar9287 *rep; | ||
615 | struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, | ||
616 | targetPowerCck = {0, {0, 0, 0, 0} }; | ||
617 | struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, | ||
618 | targetPowerCckExt = {0, {0, 0, 0, 0} }; | ||
619 | struct cal_target_power_ht targetPowerHt20, | ||
620 | targetPowerHt40 = {0, {0, 0, 0, 0} }; | ||
621 | u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
622 | u16 ctlModesFor11g[] = | ||
623 | {CTL_11B, CTL_11G, CTL_2GHT20, | ||
624 | CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40}; | ||
625 | u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; | ||
626 | struct chan_centers centers; | ||
627 | int tx_chainmask; | ||
628 | u16 twiceMinEdgePower; | ||
629 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; | ||
630 | tx_chainmask = ah->txchainmask; | ||
631 | |||
632 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
633 | |||
634 | twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], | ||
635 | pEepData->modalHeader.antennaGainCh[1]); | ||
636 | |||
637 | twiceLargestAntenna = (int16_t)min((AntennaReduction) - | ||
638 | twiceLargestAntenna, 0); | ||
639 | |||
640 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
641 | if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) | ||
642 | maxRegAllowedPower -= | ||
643 | (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); | ||
644 | |||
645 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
646 | |||
647 | switch (ar5416_get_ntxchains(tx_chainmask)) { | ||
648 | case 1: | ||
649 | break; | ||
650 | case 2: | ||
651 | scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; | ||
652 | break; | ||
653 | case 3: | ||
654 | scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; | ||
655 | break; | ||
656 | } | ||
657 | scaledPower = max((u16)0, scaledPower); | ||
658 | |||
659 | if (IS_CHAN_2GHZ(chan)) { | ||
660 | numCtlModes = | ||
661 | ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; | ||
662 | pCtlMode = ctlModesFor11g; | ||
663 | |||
664 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
665 | pEepData->calTargetPowerCck, | ||
666 | AR9287_NUM_2G_CCK_TARGET_POWERS, | ||
667 | &targetPowerCck, 4, false); | ||
668 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
669 | pEepData->calTargetPower2G, | ||
670 | AR9287_NUM_2G_20_TARGET_POWERS, | ||
671 | &targetPowerOfdm, 4, false); | ||
672 | ath9k_hw_get_target_powers(ah, chan, | ||
673 | pEepData->calTargetPower2GHT20, | ||
674 | AR9287_NUM_2G_20_TARGET_POWERS, | ||
675 | &targetPowerHt20, 8, false); | ||
676 | |||
677 | if (IS_CHAN_HT40(chan)) { | ||
678 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
679 | ath9k_hw_get_target_powers(ah, chan, | ||
680 | pEepData->calTargetPower2GHT40, | ||
681 | AR9287_NUM_2G_40_TARGET_POWERS, | ||
682 | &targetPowerHt40, 8, true); | ||
683 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
684 | pEepData->calTargetPowerCck, | ||
685 | AR9287_NUM_2G_CCK_TARGET_POWERS, | ||
686 | &targetPowerCckExt, 4, true); | ||
687 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
688 | pEepData->calTargetPower2G, | ||
689 | AR9287_NUM_2G_20_TARGET_POWERS, | ||
690 | &targetPowerOfdmExt, 4, true); | ||
691 | } | ||
692 | } | ||
693 | |||
694 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
695 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
696 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
697 | if (isHt40CtlMode) | ||
698 | freq = centers.synth_center; | ||
699 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
700 | freq = centers.ext_center; | ||
701 | else | ||
702 | freq = centers.ctl_center; | ||
703 | |||
704 | if (ah->eep_ops->get_eeprom_ver(ah) == 14 && | ||
705 | ah->eep_ops->get_eeprom_rev(ah) <= 2) | ||
706 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
707 | |||
708 | for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { | ||
709 | if ((((cfgCtl & ~CTL_MODE_M) | | ||
710 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
711 | pEepData->ctlIndex[i]) || | ||
712 | (((cfgCtl & ~CTL_MODE_M) | | ||
713 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
714 | ((pEepData->ctlIndex[i] & | ||
715 | CTL_MODE_M) | SD_NO_CTL))) { | ||
716 | |||
717 | rep = &(pEepData->ctlData[i]); | ||
718 | twiceMinEdgePower = ath9k_hw_get_max_edge_power( | ||
719 | freq, | ||
720 | rep->ctlEdges[ar5416_get_ntxchains( | ||
721 | tx_chainmask) - 1], | ||
722 | IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); | ||
723 | |||
724 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) | ||
725 | twiceMaxEdgePower = min( | ||
726 | twiceMaxEdgePower, | ||
727 | twiceMinEdgePower); | ||
728 | else { | ||
729 | twiceMaxEdgePower = twiceMinEdgePower; | ||
730 | break; | ||
731 | } | ||
732 | } | ||
733 | } | ||
734 | |||
735 | minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); | ||
736 | |||
737 | switch (pCtlMode[ctlMode]) { | ||
738 | case CTL_11B: | ||
739 | for (i = 0; | ||
740 | i < ARRAY_SIZE(targetPowerCck.tPow2x); | ||
741 | i++) { | ||
742 | targetPowerCck.tPow2x[i] = (u8)min( | ||
743 | (u16)targetPowerCck.tPow2x[i], | ||
744 | minCtlPower); | ||
745 | } | ||
746 | break; | ||
747 | case CTL_11A: | ||
748 | case CTL_11G: | ||
749 | for (i = 0; | ||
750 | i < ARRAY_SIZE(targetPowerOfdm.tPow2x); | ||
751 | i++) { | ||
752 | targetPowerOfdm.tPow2x[i] = (u8)min( | ||
753 | (u16)targetPowerOfdm.tPow2x[i], | ||
754 | minCtlPower); | ||
755 | } | ||
756 | break; | ||
757 | case CTL_5GHT20: | ||
758 | case CTL_2GHT20: | ||
759 | for (i = 0; | ||
760 | i < ARRAY_SIZE(targetPowerHt20.tPow2x); | ||
761 | i++) { | ||
762 | targetPowerHt20.tPow2x[i] = (u8)min( | ||
763 | (u16)targetPowerHt20.tPow2x[i], | ||
764 | minCtlPower); | ||
765 | } | ||
766 | break; | ||
767 | case CTL_11B_EXT: | ||
768 | targetPowerCckExt.tPow2x[0] = (u8)min( | ||
769 | (u16)targetPowerCckExt.tPow2x[0], | ||
770 | minCtlPower); | ||
771 | break; | ||
772 | case CTL_11A_EXT: | ||
773 | case CTL_11G_EXT: | ||
774 | targetPowerOfdmExt.tPow2x[0] = (u8)min( | ||
775 | (u16)targetPowerOfdmExt.tPow2x[0], | ||
776 | minCtlPower); | ||
777 | break; | ||
778 | case CTL_5GHT40: | ||
779 | case CTL_2GHT40: | ||
780 | for (i = 0; | ||
781 | i < ARRAY_SIZE(targetPowerHt40.tPow2x); | ||
782 | i++) { | ||
783 | targetPowerHt40.tPow2x[i] = (u8)min( | ||
784 | (u16)targetPowerHt40.tPow2x[i], | ||
785 | minCtlPower); | ||
786 | } | ||
787 | break; | ||
788 | default: | ||
789 | break; | ||
790 | } | ||
791 | } | ||
792 | |||
793 | ratesArray[rate6mb] = | ||
794 | ratesArray[rate9mb] = | ||
795 | ratesArray[rate12mb] = | ||
796 | ratesArray[rate18mb] = | ||
797 | ratesArray[rate24mb] = | ||
798 | targetPowerOfdm.tPow2x[0]; | ||
799 | |||
800 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
801 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
802 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
803 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
804 | |||
805 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
806 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
807 | |||
808 | if (IS_CHAN_2GHZ(chan)) { | ||
809 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
810 | ratesArray[rate2s] = ratesArray[rate2l] = | ||
811 | targetPowerCck.tPow2x[1]; | ||
812 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = | ||
813 | targetPowerCck.tPow2x[2]; | ||
814 | ratesArray[rate11s] = ratesArray[rate11l] = | ||
815 | targetPowerCck.tPow2x[3]; | ||
816 | } | ||
817 | if (IS_CHAN_HT40(chan)) { | ||
818 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) | ||
819 | ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; | ||
820 | |||
821 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
822 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
823 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
824 | if (IS_CHAN_2GHZ(chan)) | ||
825 | ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; | ||
826 | } | ||
827 | |||
828 | #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN | ||
829 | #undef REDUCE_SCALED_POWER_BY_THREE_CHAIN | ||
830 | } | ||
831 | |||
832 | static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, | ||
833 | struct ath9k_channel *chan, u16 cfgCtl, | ||
834 | u8 twiceAntennaReduction, | ||
835 | u8 twiceMaxRegulatoryPower, | ||
836 | u8 powerLimit) | ||
837 | { | ||
838 | #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 | ||
839 | #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 | ||
840 | |||
841 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; | ||
842 | struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; | ||
843 | int16_t ratesArray[Ar5416RateSize]; | ||
844 | int16_t txPowerIndexOffset = 0; | ||
845 | u8 ht40PowerIncForPdadc = 2; | ||
846 | int i; | ||
847 | |||
848 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
849 | |||
850 | if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= | ||
851 | AR9287_EEP_MINOR_VER_2) | ||
852 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
853 | |||
854 | ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, | ||
855 | &ratesArray[0], cfgCtl, | ||
856 | twiceAntennaReduction, | ||
857 | twiceMaxRegulatoryPower, | ||
858 | powerLimit); | ||
859 | |||
860 | ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); | ||
861 | |||
862 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
863 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
864 | if (ratesArray[i] > AR9287_MAX_RATE_POWER) | ||
865 | ratesArray[i] = AR9287_MAX_RATE_POWER; | ||
866 | } | ||
867 | |||
868 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
869 | for (i = 0; i < Ar5416RateSize; i++) | ||
870 | ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; | ||
871 | } | ||
872 | |||
873 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
874 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
875 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
876 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
877 | | ATH9K_POW_SM(ratesArray[rate6mb], 0)); | ||
878 | |||
879 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
880 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
881 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
882 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
883 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | ||
884 | |||
885 | if (IS_CHAN_2GHZ(chan)) { | ||
886 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
887 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
888 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
889 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
890 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
891 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
892 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
893 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
894 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
895 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
896 | } | ||
897 | |||
898 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
899 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
900 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
901 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
902 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); | ||
903 | |||
904 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
905 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
906 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
907 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
908 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); | ||
909 | |||
910 | if (IS_CHAN_HT40(chan)) { | ||
911 | if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
912 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
913 | ATH9K_POW_SM(ratesArray[rateHt40_3], 24) | ||
914 | | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) | ||
915 | | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) | ||
916 | | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)); | ||
917 | |||
918 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
919 | ATH9K_POW_SM(ratesArray[rateHt40_7], 24) | ||
920 | | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) | ||
921 | | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) | ||
922 | | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)); | ||
923 | } else { | ||
924 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
925 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
926 | ht40PowerIncForPdadc, 24) | ||
927 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
928 | ht40PowerIncForPdadc, 16) | ||
929 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
930 | ht40PowerIncForPdadc, 8) | ||
931 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
932 | ht40PowerIncForPdadc, 0)); | ||
933 | |||
934 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
935 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
936 | ht40PowerIncForPdadc, 24) | ||
937 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
938 | ht40PowerIncForPdadc, 16) | ||
939 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
940 | ht40PowerIncForPdadc, 8) | ||
941 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
942 | ht40PowerIncForPdadc, 0)); | ||
943 | } | ||
944 | |||
945 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
946 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
947 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
948 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
949 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
950 | } | ||
951 | |||
952 | if (IS_CHAN_2GHZ(chan)) | ||
953 | i = rate1l; | ||
954 | else | ||
955 | i = rate6mb; | ||
956 | |||
957 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
958 | ah->regulatory.max_power_level = | ||
959 | ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; | ||
960 | else | ||
961 | ah->regulatory.max_power_level = ratesArray[i]; | ||
962 | |||
963 | switch (ar5416_get_ntxchains(ah->txchainmask)) { | ||
964 | case 1: | ||
965 | break; | ||
966 | case 2: | ||
967 | ah->regulatory.max_power_level += | ||
968 | INCREASE_MAXPOW_BY_TWO_CHAIN; | ||
969 | break; | ||
970 | case 3: | ||
971 | ah->regulatory.max_power_level += | ||
972 | INCREASE_MAXPOW_BY_THREE_CHAIN; | ||
973 | break; | ||
974 | default: | ||
975 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
976 | "Invalid chainmask configuration\n"); | ||
977 | break; | ||
978 | } | ||
979 | } | ||
980 | |||
981 | static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, | ||
982 | struct ath9k_channel *chan) | ||
983 | { | ||
984 | } | ||
985 | |||
986 | static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, | ||
987 | struct ath9k_channel *chan) | ||
988 | { | ||
989 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
990 | struct modal_eep_ar9287_header *pModal = &eep->modalHeader; | ||
991 | u16 antWrites[AR9287_ANT_16S]; | ||
992 | u32 regChainOffset; | ||
993 | u8 txRxAttenLocal; | ||
994 | int i, j, offset_num; | ||
995 | |||
996 | pModal = &eep->modalHeader; | ||
997 | |||
998 | antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); | ||
999 | antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); | ||
1000 | antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); | ||
1001 | antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); | ||
1002 | antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); | ||
1003 | antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); | ||
1004 | antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); | ||
1005 | antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); | ||
1006 | |||
1007 | offset_num = 8; | ||
1008 | |||
1009 | for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { | ||
1010 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); | ||
1011 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); | ||
1012 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); | ||
1013 | antWrites[j++] = 0; | ||
1014 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); | ||
1015 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); | ||
1016 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); | ||
1017 | antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); | ||
1018 | } | ||
1019 | |||
1020 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
1021 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
1022 | |||
1023 | for (i = 0; i < AR9287_MAX_CHAINS; i++) { | ||
1024 | regChainOffset = i * 0x1000; | ||
1025 | |||
1026 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, | ||
1027 | pModal->antCtrlChain[i]); | ||
1028 | |||
1029 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | ||
1030 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) | ||
1031 | & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
1032 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
1033 | SM(pModal->iqCalICh[i], | ||
1034 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
1035 | SM(pModal->iqCalQCh[i], | ||
1036 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
1037 | |||
1038 | txRxAttenLocal = pModal->txRxAttenCh[i]; | ||
1039 | |||
1040 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1041 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
1042 | pModal->bswMargin[i]); | ||
1043 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1044 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, | ||
1045 | pModal->bswAtten[i]); | ||
1046 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | ||
1047 | AR9280_PHY_RXGAIN_TXRX_ATTEN, | ||
1048 | txRxAttenLocal); | ||
1049 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | ||
1050 | AR9280_PHY_RXGAIN_TXRX_MARGIN, | ||
1051 | pModal->rxTxMarginCh[i]); | ||
1052 | } | ||
1053 | |||
1054 | |||
1055 | if (IS_CHAN_HT40(chan)) | ||
1056 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1057 | AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); | ||
1058 | else | ||
1059 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1060 | AR_PHY_SETTLING_SWITCH, pModal->switchSettling); | ||
1061 | |||
1062 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, | ||
1063 | AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); | ||
1064 | |||
1065 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
1066 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | ||
1067 | | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | ||
1068 | | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | ||
1069 | | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
1070 | |||
1071 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, | ||
1072 | AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); | ||
1073 | |||
1074 | REG_RMW_FIELD(ah, AR_PHY_CCA, | ||
1075 | AR9280_PHY_CCA_THRESH62, pModal->thresh62); | ||
1076 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, | ||
1077 | AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); | ||
1078 | |||
1079 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1, | ||
1080 | AR9287_AN_RF2G3_DB1_S, pModal->db1); | ||
1081 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2, | ||
1082 | AR9287_AN_RF2G3_DB2_S, pModal->db2); | ||
1083 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
1084 | AR9287_AN_RF2G3_OB_CCK, | ||
1085 | AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); | ||
1086 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
1087 | AR9287_AN_RF2G3_OB_PSK, | ||
1088 | AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); | ||
1089 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
1090 | AR9287_AN_RF2G3_OB_QAM, | ||
1091 | AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); | ||
1092 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
1093 | AR9287_AN_RF2G3_OB_PAL_OFF, | ||
1094 | AR9287_AN_RF2G3_OB_PAL_OFF_S, | ||
1095 | pModal->ob_pal_off); | ||
1096 | |||
1097 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
1098 | AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S, | ||
1099 | pModal->db1); | ||
1100 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2, | ||
1101 | AR9287_AN_RF2G3_DB2_S, pModal->db2); | ||
1102 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
1103 | AR9287_AN_RF2G3_OB_CCK, | ||
1104 | AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); | ||
1105 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
1106 | AR9287_AN_RF2G3_OB_PSK, | ||
1107 | AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); | ||
1108 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
1109 | AR9287_AN_RF2G3_OB_QAM, | ||
1110 | AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); | ||
1111 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
1112 | AR9287_AN_RF2G3_OB_PAL_OFF, | ||
1113 | AR9287_AN_RF2G3_OB_PAL_OFF_S, | ||
1114 | pModal->ob_pal_off); | ||
1115 | |||
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 | |||
1127 | static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, | ||
1128 | enum ieee80211_band freq_band) | ||
1129 | { | ||
1130 | return 1; | ||
1131 | } | ||
1132 | |||
1133 | static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, | ||
1134 | struct ath9k_channel *chan) | ||
1135 | { | ||
1136 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
1137 | struct modal_eep_ar9287_header *pModal = &eep->modalHeader; | ||
1138 | |||
1139 | return pModal->antCtrlCommon & 0xFFFF; | ||
1140 | } | ||
1141 | |||
1142 | static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, | ||
1143 | u16 i, bool is2GHz) | ||
1144 | { | ||
1145 | #define EEP_MAP9287_SPURCHAN \ | ||
1146 | (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) | ||
1147 | u16 spur_val = AR_NO_SPUR; | ||
1148 | |||
1149 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1150 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
1151 | i, is2GHz, ah->config.spurchans[i][is2GHz]); | ||
1152 | |||
1153 | switch (ah->config.spurmode) { | ||
1154 | case SPUR_DISABLE: | ||
1155 | break; | ||
1156 | case SPUR_ENABLE_IOCTL: | ||
1157 | spur_val = ah->config.spurchans[i][is2GHz]; | ||
1158 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1159 | "Getting spur val from new loc. %d\n", spur_val); | ||
1160 | break; | ||
1161 | case SPUR_ENABLE_EEPROM: | ||
1162 | spur_val = EEP_MAP9287_SPURCHAN; | ||
1163 | break; | ||
1164 | } | ||
1165 | |||
1166 | return spur_val; | ||
1167 | |||
1168 | #undef EEP_MAP9287_SPURCHAN | ||
1169 | } | ||
1170 | |||
1171 | const struct eeprom_ops eep_AR9287_ops = { | ||
1172 | .check_eeprom = ath9k_hw_AR9287_check_eeprom, | ||
1173 | .get_eeprom = ath9k_hw_AR9287_get_eeprom, | ||
1174 | .fill_eeprom = ath9k_hw_AR9287_fill_eeprom, | ||
1175 | .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver, | ||
1176 | .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev, | ||
1177 | .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config, | ||
1178 | .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg, | ||
1179 | .set_board_values = ath9k_hw_AR9287_set_board_values, | ||
1180 | .set_addac = ath9k_hw_AR9287_set_addac, | ||
1181 | .set_txpower = ath9k_hw_AR9287_set_txpower, | ||
1182 | .get_spur_channel = ath9k_hw_AR9287_get_spur_channel | ||
1183 | }; | ||