diff options
author | Sujith <Sujith.Manoharan@atheros.com> | 2008-10-29 00:46:30 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-11-10 15:16:05 -0500 |
commit | f1dc56003b23d2d5bb5a756de6b1633a76c9e697 (patch) | |
tree | f530aa716620322192bb0e7e083c903bf0e55544 /drivers/net/wireless/ath9k/eeprom.c | |
parent | 5640b08ef7e88b606c740e746cb77bc97d78508e (diff) |
ath9k: Refactor hw.c
Split hw.c into more manageable files:
ani.c
calib.c
eeprom.c
mac.c
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k/eeprom.c')
-rw-r--r-- | drivers/net/wireless/ath9k/eeprom.c | 1605 |
1 files changed, 1605 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c new file mode 100644 index 000000000000..f5fd03c0edd7 --- /dev/null +++ b/drivers/net/wireless/ath9k/eeprom.c | |||
@@ -0,0 +1,1605 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 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 "core.h" | ||
18 | #include "hw.h" | ||
19 | #include "reg.h" | ||
20 | #include "phy.h" | ||
21 | |||
22 | static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah, | ||
23 | u32 reg, u32 mask, | ||
24 | u32 shift, u32 val) | ||
25 | { | ||
26 | u32 regVal; | ||
27 | |||
28 | regVal = REG_READ(ah, reg) & ~mask; | ||
29 | regVal |= (val << shift) & mask; | ||
30 | |||
31 | REG_WRITE(ah, reg, regVal); | ||
32 | |||
33 | if (ah->ah_config.analog_shiftreg) | ||
34 | udelay(100); | ||
35 | |||
36 | return; | ||
37 | } | ||
38 | |||
39 | static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) | ||
40 | { | ||
41 | |||
42 | if (fbin == AR5416_BCHAN_UNUSED) | ||
43 | return fbin; | ||
44 | |||
45 | return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); | ||
46 | } | ||
47 | |||
48 | static inline int16_t ath9k_hw_interpolate(u16 target, | ||
49 | u16 srcLeft, u16 srcRight, | ||
50 | int16_t targetLeft, | ||
51 | int16_t targetRight) | ||
52 | { | ||
53 | int16_t rv; | ||
54 | |||
55 | if (srcRight == srcLeft) { | ||
56 | rv = targetLeft; | ||
57 | } else { | ||
58 | rv = (int16_t) (((target - srcLeft) * targetRight + | ||
59 | (srcRight - target) * targetLeft) / | ||
60 | (srcRight - srcLeft)); | ||
61 | } | ||
62 | return rv; | ||
63 | } | ||
64 | |||
65 | static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, | ||
66 | u16 listSize, u16 *indexL, | ||
67 | u16 *indexR) | ||
68 | { | ||
69 | u16 i; | ||
70 | |||
71 | if (target <= pList[0]) { | ||
72 | *indexL = *indexR = 0; | ||
73 | return true; | ||
74 | } | ||
75 | if (target >= pList[listSize - 1]) { | ||
76 | *indexL = *indexR = (u16) (listSize - 1); | ||
77 | return true; | ||
78 | } | ||
79 | |||
80 | for (i = 0; i < listSize - 1; i++) { | ||
81 | if (pList[i] == target) { | ||
82 | *indexL = *indexR = i; | ||
83 | return true; | ||
84 | } | ||
85 | if (target < pList[i + 1]) { | ||
86 | *indexL = i; | ||
87 | *indexR = (u16) (i + 1); | ||
88 | return false; | ||
89 | } | ||
90 | } | ||
91 | return false; | ||
92 | } | ||
93 | |||
94 | static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, u16 *data) | ||
95 | { | ||
96 | (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); | ||
97 | |||
98 | if (!ath9k_hw_wait(ah, | ||
99 | AR_EEPROM_STATUS_DATA, | ||
100 | AR_EEPROM_STATUS_DATA_BUSY | | ||
101 | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) { | ||
102 | return false; | ||
103 | } | ||
104 | |||
105 | *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), | ||
106 | AR_EEPROM_STATUS_DATA_VAL); | ||
107 | |||
108 | return true; | ||
109 | } | ||
110 | |||
111 | static int ath9k_hw_flash_map(struct ath_hal *ah) | ||
112 | { | ||
113 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
114 | |||
115 | ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX); | ||
116 | |||
117 | if (!ahp->ah_cal_mem) { | ||
118 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
119 | "%s: cannot remap eeprom region \n", __func__); | ||
120 | return -EIO; | ||
121 | } | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, u16 *data) | ||
127 | { | ||
128 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
129 | |||
130 | *data = ioread16(ahp->ah_cal_mem + off); | ||
131 | |||
132 | return true; | ||
133 | } | ||
134 | |||
135 | static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data) | ||
136 | { | ||
137 | if (ath9k_hw_use_flash(ah)) | ||
138 | return ath9k_hw_flash_read(ah, off, data); | ||
139 | else | ||
140 | return ath9k_hw_eeprom_read(ah, off, data); | ||
141 | } | ||
142 | |||
143 | static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) | ||
144 | { | ||
145 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
146 | struct ar5416_eeprom *eep = &ahp->ah_eeprom; | ||
147 | u16 *eep_data; | ||
148 | int addr, ar5416_eep_start_loc = 0; | ||
149 | |||
150 | if (!ath9k_hw_use_flash(ah)) { | ||
151 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
152 | "%s: Reading from EEPROM, not flash\n", __func__); | ||
153 | ar5416_eep_start_loc = 256; | ||
154 | } | ||
155 | |||
156 | if (AR_SREV_9100(ah)) | ||
157 | ar5416_eep_start_loc = 256; | ||
158 | |||
159 | eep_data = (u16 *)eep; | ||
160 | |||
161 | for (addr = 0; addr < sizeof(struct ar5416_eeprom) / sizeof(u16); addr++) { | ||
162 | if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, | ||
163 | eep_data)) { | ||
164 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
165 | "%s: Unable to read eeprom region \n", | ||
166 | __func__); | ||
167 | return false; | ||
168 | } | ||
169 | eep_data++; | ||
170 | } | ||
171 | return true; | ||
172 | } | ||
173 | |||
174 | static int ath9k_hw_check_eeprom(struct ath_hal *ah) | ||
175 | { | ||
176 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
177 | struct ar5416_eeprom *eep = | ||
178 | (struct ar5416_eeprom *) &ahp->ah_eeprom; | ||
179 | u16 *eepdata, temp, magic, magic2; | ||
180 | u32 sum = 0, el; | ||
181 | bool need_swap = false; | ||
182 | int i, addr, size; | ||
183 | |||
184 | if (!ath9k_hw_use_flash(ah)) { | ||
185 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, | ||
186 | &magic)) { | ||
187 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
188 | "%s: Reading Magic # failed\n", __func__); | ||
189 | return false; | ||
190 | } | ||
191 | |||
192 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n", | ||
193 | __func__, magic); | ||
194 | |||
195 | if (magic != AR5416_EEPROM_MAGIC) { | ||
196 | magic2 = swab16(magic); | ||
197 | |||
198 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
199 | size = sizeof(struct ar5416_eeprom); | ||
200 | need_swap = true; | ||
201 | eepdata = (u16 *) (&ahp->ah_eeprom); | ||
202 | |||
203 | for (addr = 0; addr < size / sizeof(u16); addr++) { | ||
204 | temp = swab16(*eepdata); | ||
205 | *eepdata = temp; | ||
206 | eepdata++; | ||
207 | |||
208 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
209 | "0x%04X ", *eepdata); | ||
210 | |||
211 | if (((addr + 1) % 6) == 0) | ||
212 | DPRINTF(ah->ah_sc, | ||
213 | ATH_DBG_EEPROM, "\n"); | ||
214 | } | ||
215 | } else { | ||
216 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
217 | "Invalid EEPROM Magic. " | ||
218 | "endianness mismatch.\n"); | ||
219 | return -EINVAL; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", | ||
225 | need_swap ? "True" : "False"); | ||
226 | |||
227 | if (need_swap) | ||
228 | el = swab16(ahp->ah_eeprom.baseEepHeader.length); | ||
229 | else | ||
230 | el = ahp->ah_eeprom.baseEepHeader.length; | ||
231 | |||
232 | if (el > sizeof(struct ar5416_eeprom)) | ||
233 | el = sizeof(struct ar5416_eeprom) / sizeof(u16); | ||
234 | else | ||
235 | el = el / sizeof(u16); | ||
236 | |||
237 | eepdata = (u16 *)(&ahp->ah_eeprom); | ||
238 | |||
239 | for (i = 0; i < el; i++) | ||
240 | sum ^= *eepdata++; | ||
241 | |||
242 | if (need_swap) { | ||
243 | u32 integer, j; | ||
244 | u16 word; | ||
245 | |||
246 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
247 | "EEPROM Endianness is not native.. Changing \n"); | ||
248 | |||
249 | word = swab16(eep->baseEepHeader.length); | ||
250 | eep->baseEepHeader.length = word; | ||
251 | |||
252 | word = swab16(eep->baseEepHeader.checksum); | ||
253 | eep->baseEepHeader.checksum = word; | ||
254 | |||
255 | word = swab16(eep->baseEepHeader.version); | ||
256 | eep->baseEepHeader.version = word; | ||
257 | |||
258 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
259 | eep->baseEepHeader.regDmn[0] = word; | ||
260 | |||
261 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
262 | eep->baseEepHeader.regDmn[1] = word; | ||
263 | |||
264 | word = swab16(eep->baseEepHeader.rfSilent); | ||
265 | eep->baseEepHeader.rfSilent = word; | ||
266 | |||
267 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
268 | eep->baseEepHeader.blueToothOptions = word; | ||
269 | |||
270 | word = swab16(eep->baseEepHeader.deviceCap); | ||
271 | eep->baseEepHeader.deviceCap = word; | ||
272 | |||
273 | for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { | ||
274 | struct modal_eep_header *pModal = | ||
275 | &eep->modalHeader[j]; | ||
276 | integer = swab32(pModal->antCtrlCommon); | ||
277 | pModal->antCtrlCommon = integer; | ||
278 | |||
279 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
280 | integer = swab32(pModal->antCtrlChain[i]); | ||
281 | pModal->antCtrlChain[i] = integer; | ||
282 | } | ||
283 | |||
284 | for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { | ||
285 | word = swab16(pModal->spurChans[i].spurChan); | ||
286 | pModal->spurChans[i].spurChan = word; | ||
287 | } | ||
288 | } | ||
289 | } | ||
290 | |||
291 | if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER || | ||
292 | ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) { | ||
293 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
294 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
295 | sum, ar5416_get_eep_ver(ahp)); | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, | ||
303 | u8 *pVpdList, u16 numIntercepts, | ||
304 | u8 *pRetVpdList) | ||
305 | { | ||
306 | u16 i, k; | ||
307 | u8 currPwr = pwrMin; | ||
308 | u16 idxL = 0, idxR = 0; | ||
309 | |||
310 | for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { | ||
311 | ath9k_hw_get_lower_upper_index(currPwr, pPwrList, | ||
312 | numIntercepts, &(idxL), | ||
313 | &(idxR)); | ||
314 | if (idxR < 1) | ||
315 | idxR = 1; | ||
316 | if (idxL == numIntercepts - 1) | ||
317 | idxL = (u16) (numIntercepts - 2); | ||
318 | if (pPwrList[idxL] == pPwrList[idxR]) | ||
319 | k = pVpdList[idxL]; | ||
320 | else | ||
321 | k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + | ||
322 | (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / | ||
323 | (pPwrList[idxR] - pPwrList[idxL])); | ||
324 | pRetVpdList[i] = (u8) k; | ||
325 | currPwr += 2; | ||
326 | } | ||
327 | |||
328 | return true; | ||
329 | } | ||
330 | |||
331 | static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, | ||
332 | struct ath9k_channel *chan, | ||
333 | struct cal_data_per_freq *pRawDataSet, | ||
334 | u8 *bChans, u16 availPiers, | ||
335 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
336 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
337 | u16 numXpdGains) | ||
338 | { | ||
339 | int i, j, k; | ||
340 | int16_t ss; | ||
341 | u16 idxL = 0, idxR = 0, numPiers; | ||
342 | static u8 vpdTableL[AR5416_NUM_PD_GAINS] | ||
343 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
344 | static u8 vpdTableR[AR5416_NUM_PD_GAINS] | ||
345 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
346 | static u8 vpdTableI[AR5416_NUM_PD_GAINS] | ||
347 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
348 | |||
349 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
350 | u8 minPwrT4[AR5416_NUM_PD_GAINS]; | ||
351 | u8 maxPwrT4[AR5416_NUM_PD_GAINS]; | ||
352 | int16_t vpdStep; | ||
353 | int16_t tmpVal; | ||
354 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
355 | bool match; | ||
356 | int16_t minDelta = 0; | ||
357 | struct chan_centers centers; | ||
358 | |||
359 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
360 | |||
361 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
362 | if (bChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
363 | break; | ||
364 | } | ||
365 | |||
366 | match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, | ||
367 | IS_CHAN_2GHZ(chan)), | ||
368 | bChans, numPiers, &idxL, &idxR); | ||
369 | |||
370 | if (match) { | ||
371 | for (i = 0; i < numXpdGains; i++) { | ||
372 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
373 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
374 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
375 | pRawDataSet[idxL].pwrPdg[i], | ||
376 | pRawDataSet[idxL].vpdPdg[i], | ||
377 | AR5416_PD_GAIN_ICEPTS, | ||
378 | vpdTableI[i]); | ||
379 | } | ||
380 | } else { | ||
381 | for (i = 0; i < numXpdGains; i++) { | ||
382 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
383 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
384 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
385 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
386 | |||
387 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
388 | |||
389 | maxPwrT4[i] = | ||
390 | min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], | ||
391 | pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); | ||
392 | |||
393 | |||
394 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
395 | pPwrL, pVpdL, | ||
396 | AR5416_PD_GAIN_ICEPTS, | ||
397 | vpdTableL[i]); | ||
398 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
399 | pPwrR, pVpdR, | ||
400 | AR5416_PD_GAIN_ICEPTS, | ||
401 | vpdTableR[i]); | ||
402 | |||
403 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
404 | vpdTableI[i][j] = | ||
405 | (u8)(ath9k_hw_interpolate((u16) | ||
406 | FREQ2FBIN(centers. | ||
407 | synth_center, | ||
408 | IS_CHAN_2GHZ | ||
409 | (chan)), | ||
410 | bChans[idxL], bChans[idxR], | ||
411 | vpdTableL[i][j], vpdTableR[i][j])); | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | |||
416 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
417 | |||
418 | k = 0; | ||
419 | |||
420 | for (i = 0; i < numXpdGains; i++) { | ||
421 | if (i == (numXpdGains - 1)) | ||
422 | pPdGainBoundaries[i] = | ||
423 | (u16)(maxPwrT4[i] / 2); | ||
424 | else | ||
425 | pPdGainBoundaries[i] = | ||
426 | (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); | ||
427 | |||
428 | pPdGainBoundaries[i] = | ||
429 | min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); | ||
430 | |||
431 | if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { | ||
432 | minDelta = pPdGainBoundaries[0] - 23; | ||
433 | pPdGainBoundaries[0] = 23; | ||
434 | } else { | ||
435 | minDelta = 0; | ||
436 | } | ||
437 | |||
438 | if (i == 0) { | ||
439 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
440 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
441 | else | ||
442 | ss = 0; | ||
443 | } else { | ||
444 | ss = (int16_t)((pPdGainBoundaries[i - 1] - | ||
445 | (minPwrT4[i] / 2)) - | ||
446 | tPdGainOverlap + 1 + minDelta); | ||
447 | } | ||
448 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
449 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
450 | |||
451 | while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
452 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
453 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
454 | ss++; | ||
455 | } | ||
456 | |||
457 | sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
458 | tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - | ||
459 | (minPwrT4[i] / 2)); | ||
460 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
461 | tgtIndex : sizeCurrVpdTable; | ||
462 | |||
463 | while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
464 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
465 | } | ||
466 | |||
467 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
468 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
469 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
470 | |||
471 | if (tgtIndex > maxIndex) { | ||
472 | while ((ss <= tgtIndex) && | ||
473 | (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
474 | tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + | ||
475 | (ss - maxIndex + 1) * vpdStep)); | ||
476 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
477 | 255 : tmpVal); | ||
478 | ss++; | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | |||
483 | while (i < AR5416_PD_GAINS_IN_MASK) { | ||
484 | pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; | ||
485 | i++; | ||
486 | } | ||
487 | |||
488 | while (k < AR5416_NUM_PDADC_VALUES) { | ||
489 | pPDADCValues[k] = pPDADCValues[k - 1]; | ||
490 | k++; | ||
491 | } | ||
492 | |||
493 | return; | ||
494 | } | ||
495 | |||
496 | static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, | ||
497 | struct ath9k_channel *chan, | ||
498 | struct cal_target_power_leg *powInfo, | ||
499 | u16 numChannels, | ||
500 | struct cal_target_power_leg *pNewPower, | ||
501 | u16 numRates, bool isExtTarget) | ||
502 | { | ||
503 | struct chan_centers centers; | ||
504 | u16 clo, chi; | ||
505 | int i; | ||
506 | int matchIndex = -1, lowIndex = -1; | ||
507 | u16 freq; | ||
508 | |||
509 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
510 | freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; | ||
511 | |||
512 | if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, | ||
513 | IS_CHAN_2GHZ(chan))) { | ||
514 | matchIndex = 0; | ||
515 | } else { | ||
516 | for (i = 0; (i < numChannels) && | ||
517 | (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { | ||
518 | if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, | ||
519 | IS_CHAN_2GHZ(chan))) { | ||
520 | matchIndex = i; | ||
521 | break; | ||
522 | } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, | ||
523 | IS_CHAN_2GHZ(chan))) && | ||
524 | (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, | ||
525 | IS_CHAN_2GHZ(chan)))) { | ||
526 | lowIndex = i - 1; | ||
527 | break; | ||
528 | } | ||
529 | } | ||
530 | if ((matchIndex == -1) && (lowIndex == -1)) | ||
531 | matchIndex = i - 1; | ||
532 | } | ||
533 | |||
534 | if (matchIndex != -1) { | ||
535 | *pNewPower = powInfo[matchIndex]; | ||
536 | } else { | ||
537 | clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, | ||
538 | IS_CHAN_2GHZ(chan)); | ||
539 | chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, | ||
540 | IS_CHAN_2GHZ(chan)); | ||
541 | |||
542 | for (i = 0; i < numRates; i++) { | ||
543 | pNewPower->tPow2x[i] = | ||
544 | (u8)ath9k_hw_interpolate(freq, clo, chi, | ||
545 | powInfo[lowIndex].tPow2x[i], | ||
546 | powInfo[lowIndex + 1].tPow2x[i]); | ||
547 | } | ||
548 | } | ||
549 | } | ||
550 | |||
551 | static void ath9k_hw_get_target_powers(struct ath_hal *ah, | ||
552 | struct ath9k_channel *chan, | ||
553 | struct cal_target_power_ht *powInfo, | ||
554 | u16 numChannels, | ||
555 | struct cal_target_power_ht *pNewPower, | ||
556 | u16 numRates, bool isHt40Target) | ||
557 | { | ||
558 | struct chan_centers centers; | ||
559 | u16 clo, chi; | ||
560 | int i; | ||
561 | int matchIndex = -1, lowIndex = -1; | ||
562 | u16 freq; | ||
563 | |||
564 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
565 | freq = isHt40Target ? centers.synth_center : centers.ctl_center; | ||
566 | |||
567 | if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { | ||
568 | matchIndex = 0; | ||
569 | } else { | ||
570 | for (i = 0; (i < numChannels) && | ||
571 | (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { | ||
572 | if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, | ||
573 | IS_CHAN_2GHZ(chan))) { | ||
574 | matchIndex = i; | ||
575 | break; | ||
576 | } else | ||
577 | if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, | ||
578 | IS_CHAN_2GHZ(chan))) && | ||
579 | (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, | ||
580 | IS_CHAN_2GHZ(chan)))) { | ||
581 | lowIndex = i - 1; | ||
582 | break; | ||
583 | } | ||
584 | } | ||
585 | if ((matchIndex == -1) && (lowIndex == -1)) | ||
586 | matchIndex = i - 1; | ||
587 | } | ||
588 | |||
589 | if (matchIndex != -1) { | ||
590 | *pNewPower = powInfo[matchIndex]; | ||
591 | } else { | ||
592 | clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, | ||
593 | IS_CHAN_2GHZ(chan)); | ||
594 | chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, | ||
595 | IS_CHAN_2GHZ(chan)); | ||
596 | |||
597 | for (i = 0; i < numRates; i++) { | ||
598 | pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, | ||
599 | clo, chi, | ||
600 | powInfo[lowIndex].tPow2x[i], | ||
601 | powInfo[lowIndex + 1].tPow2x[i]); | ||
602 | } | ||
603 | } | ||
604 | } | ||
605 | |||
606 | static u16 ath9k_hw_get_max_edge_power(u16 freq, | ||
607 | struct cal_ctl_edges *pRdEdgesPower, | ||
608 | bool is2GHz) | ||
609 | { | ||
610 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
611 | int i; | ||
612 | |||
613 | for (i = 0; (i < AR5416_NUM_BAND_EDGES) && | ||
614 | (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { | ||
615 | if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { | ||
616 | twiceMaxEdgePower = pRdEdgesPower[i].tPower; | ||
617 | break; | ||
618 | } else if ((i > 0) && | ||
619 | (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, | ||
620 | is2GHz))) { | ||
621 | if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, | ||
622 | is2GHz) < freq && | ||
623 | pRdEdgesPower[i - 1].flag) { | ||
624 | twiceMaxEdgePower = | ||
625 | pRdEdgesPower[i - 1].tPower; | ||
626 | } | ||
627 | break; | ||
628 | } | ||
629 | } | ||
630 | |||
631 | return twiceMaxEdgePower; | ||
632 | } | ||
633 | |||
634 | int ath9k_hw_set_txpower(struct ath_hal *ah, | ||
635 | struct ath9k_channel *chan, | ||
636 | u16 cfgCtl, | ||
637 | u8 twiceAntennaReduction, | ||
638 | u8 twiceMaxRegulatoryPower, | ||
639 | u8 powerLimit) | ||
640 | { | ||
641 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
642 | struct ar5416_eeprom *pEepData = &ahp->ah_eeprom; | ||
643 | struct modal_eep_header *pModal = | ||
644 | &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
645 | int16_t ratesArray[Ar5416RateSize]; | ||
646 | int16_t txPowerIndexOffset = 0; | ||
647 | u8 ht40PowerIncForPdadc = 2; | ||
648 | int i; | ||
649 | |||
650 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
651 | |||
652 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
653 | AR5416_EEP_MINOR_VER_2) { | ||
654 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
655 | } | ||
656 | |||
657 | if (!ath9k_hw_set_power_per_rate_table(ah, chan, | ||
658 | &ratesArray[0], cfgCtl, | ||
659 | twiceAntennaReduction, | ||
660 | twiceMaxRegulatoryPower, | ||
661 | powerLimit)) { | ||
662 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
663 | "ath9k_hw_set_txpower: unable to set " | ||
664 | "tx power per rate table\n"); | ||
665 | return -EIO; | ||
666 | } | ||
667 | |||
668 | if (!ath9k_hw_set_power_cal_table(ah, chan, &txPowerIndexOffset)) { | ||
669 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
670 | "ath9k_hw_set_txpower: unable to set power table\n"); | ||
671 | return -EIO; | ||
672 | } | ||
673 | |||
674 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
675 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
676 | if (ratesArray[i] > AR5416_MAX_RATE_POWER) | ||
677 | ratesArray[i] = AR5416_MAX_RATE_POWER; | ||
678 | } | ||
679 | |||
680 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
681 | for (i = 0; i < Ar5416RateSize; i++) | ||
682 | ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; | ||
683 | } | ||
684 | |||
685 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
686 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
687 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
688 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
689 | | ATH9K_POW_SM(ratesArray[rate6mb], 0)); | ||
690 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
691 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
692 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
693 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
694 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | ||
695 | |||
696 | if (IS_CHAN_2GHZ(chan)) { | ||
697 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
698 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
699 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
700 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
701 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
702 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
703 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
704 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
705 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
706 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
707 | } | ||
708 | |||
709 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
710 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
711 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
712 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
713 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); | ||
714 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
715 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
716 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
717 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
718 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); | ||
719 | |||
720 | if (IS_CHAN_HT40(chan)) { | ||
721 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
722 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
723 | ht40PowerIncForPdadc, 24) | ||
724 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
725 | ht40PowerIncForPdadc, 16) | ||
726 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
727 | ht40PowerIncForPdadc, 8) | ||
728 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
729 | ht40PowerIncForPdadc, 0)); | ||
730 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
731 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
732 | ht40PowerIncForPdadc, 24) | ||
733 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
734 | ht40PowerIncForPdadc, 16) | ||
735 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
736 | ht40PowerIncForPdadc, 8) | ||
737 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
738 | ht40PowerIncForPdadc, 0)); | ||
739 | |||
740 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
741 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
742 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
743 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
744 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
745 | } | ||
746 | |||
747 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, | ||
748 | ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ||
749 | | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); | ||
750 | |||
751 | i = rate6mb; | ||
752 | |||
753 | if (IS_CHAN_HT40(chan)) | ||
754 | i = rateHt40_0; | ||
755 | else if (IS_CHAN_HT20(chan)) | ||
756 | i = rateHt20_0; | ||
757 | |||
758 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
759 | ah->ah_maxPowerLevel = | ||
760 | ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; | ||
761 | else | ||
762 | ah->ah_maxPowerLevel = ratesArray[i]; | ||
763 | |||
764 | return 0; | ||
765 | } | ||
766 | |||
767 | void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan) | ||
768 | { | ||
769 | struct modal_eep_header *pModal; | ||
770 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
771 | struct ar5416_eeprom *eep = &ahp->ah_eeprom; | ||
772 | u8 biaslevel; | ||
773 | |||
774 | if (ah->ah_macVersion != AR_SREV_VERSION_9160) | ||
775 | return; | ||
776 | |||
777 | if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) | ||
778 | return; | ||
779 | |||
780 | pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
781 | |||
782 | if (pModal->xpaBiasLvl != 0xff) { | ||
783 | biaslevel = pModal->xpaBiasLvl; | ||
784 | } else { | ||
785 | u16 resetFreqBin, freqBin, freqCount = 0; | ||
786 | struct chan_centers centers; | ||
787 | |||
788 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
789 | |||
790 | resetFreqBin = FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)); | ||
791 | freqBin = pModal->xpaBiasLvlFreq[0] & 0xff; | ||
792 | biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14); | ||
793 | |||
794 | freqCount++; | ||
795 | |||
796 | while (freqCount < 3) { | ||
797 | if (pModal->xpaBiasLvlFreq[freqCount] == 0x0) | ||
798 | break; | ||
799 | |||
800 | freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff; | ||
801 | if (resetFreqBin >= freqBin) { | ||
802 | biaslevel = (u8)(pModal->xpaBiasLvlFreq[freqCount] >> 14); | ||
803 | } else { | ||
804 | break; | ||
805 | } | ||
806 | freqCount++; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | if (IS_CHAN_2GHZ(chan)) { | ||
811 | INI_RA(&ahp->ah_iniAddac, 7, 1) = | ||
812 | (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; | ||
813 | } else { | ||
814 | INI_RA(&ahp->ah_iniAddac, 6, 1) = | ||
815 | (INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel << 6; | ||
816 | } | ||
817 | } | ||
818 | |||
819 | bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, | ||
820 | struct ath9k_channel *chan, | ||
821 | int16_t *ratesArray, | ||
822 | u16 cfgCtl, | ||
823 | u8 AntennaReduction, | ||
824 | u8 twiceMaxRegulatoryPower, | ||
825 | u8 powerLimit) | ||
826 | { | ||
827 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
828 | struct ar5416_eeprom *pEepData = &ahp->ah_eeprom; | ||
829 | u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
830 | static const u16 tpScaleReductionTable[5] = | ||
831 | { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; | ||
832 | |||
833 | int i; | ||
834 | int8_t twiceLargestAntenna; | ||
835 | struct cal_ctl_data *rep; | ||
836 | struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { | ||
837 | 0, { 0, 0, 0, 0} | ||
838 | }; | ||
839 | struct cal_target_power_leg targetPowerOfdmExt = { | ||
840 | 0, { 0, 0, 0, 0} }, targetPowerCckExt = { | ||
841 | 0, { 0, 0, 0, 0 } | ||
842 | }; | ||
843 | struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { | ||
844 | 0, {0, 0, 0, 0} | ||
845 | }; | ||
846 | u8 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
847 | u16 ctlModesFor11a[] = | ||
848 | { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; | ||
849 | u16 ctlModesFor11g[] = | ||
850 | { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, | ||
851 | CTL_2GHT40 | ||
852 | }; | ||
853 | u16 numCtlModes, *pCtlMode, ctlMode, freq; | ||
854 | struct chan_centers centers; | ||
855 | int tx_chainmask; | ||
856 | u8 twiceMinEdgePower; | ||
857 | |||
858 | tx_chainmask = ahp->ah_txchainmask; | ||
859 | |||
860 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
861 | |||
862 | twiceLargestAntenna = max( | ||
863 | pEepData->modalHeader | ||
864 | [IS_CHAN_2GHZ(chan)].antennaGainCh[0], | ||
865 | pEepData->modalHeader | ||
866 | [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); | ||
867 | |||
868 | twiceLargestAntenna = max((u8)twiceLargestAntenna, | ||
869 | pEepData->modalHeader | ||
870 | [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); | ||
871 | |||
872 | twiceLargestAntenna = (int8_t)min(AntennaReduction - twiceLargestAntenna, 0); | ||
873 | |||
874 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
875 | |||
876 | if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { | ||
877 | maxRegAllowedPower -= | ||
878 | (tpScaleReductionTable[(ah->ah_tpScale)] * 2); | ||
879 | } | ||
880 | |||
881 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
882 | |||
883 | switch (ar5416_get_ntxchains(tx_chainmask)) { | ||
884 | case 1: | ||
885 | break; | ||
886 | case 2: | ||
887 | scaledPower -= | ||
888 | pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor2Chain; | ||
889 | break; | ||
890 | case 3: | ||
891 | scaledPower -= | ||
892 | pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor3Chain; | ||
893 | break; | ||
894 | } | ||
895 | |||
896 | scaledPower = max(0, (int32_t) scaledPower); | ||
897 | |||
898 | if (IS_CHAN_2GHZ(chan)) { | ||
899 | numCtlModes = ARRAY_SIZE(ctlModesFor11g) - | ||
900 | SUB_NUM_CTL_MODES_AT_2G_40; | ||
901 | pCtlMode = ctlModesFor11g; | ||
902 | |||
903 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
904 | pEepData->calTargetPowerCck, | ||
905 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
906 | &targetPowerCck, 4, false); | ||
907 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
908 | pEepData->calTargetPower2G, | ||
909 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
910 | &targetPowerOfdm, 4, false); | ||
911 | ath9k_hw_get_target_powers(ah, chan, | ||
912 | pEepData->calTargetPower2GHT20, | ||
913 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
914 | &targetPowerHt20, 8, false); | ||
915 | |||
916 | if (IS_CHAN_HT40(chan)) { | ||
917 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
918 | ath9k_hw_get_target_powers(ah, chan, | ||
919 | pEepData->calTargetPower2GHT40, | ||
920 | AR5416_NUM_2G_40_TARGET_POWERS, | ||
921 | &targetPowerHt40, 8, true); | ||
922 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
923 | pEepData->calTargetPowerCck, | ||
924 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
925 | &targetPowerCckExt, 4, true); | ||
926 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
927 | pEepData->calTargetPower2G, | ||
928 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
929 | &targetPowerOfdmExt, 4, true); | ||
930 | } | ||
931 | } else { | ||
932 | numCtlModes = ARRAY_SIZE(ctlModesFor11a) - | ||
933 | SUB_NUM_CTL_MODES_AT_5G_40; | ||
934 | pCtlMode = ctlModesFor11a; | ||
935 | |||
936 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
937 | pEepData->calTargetPower5G, | ||
938 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
939 | &targetPowerOfdm, 4, false); | ||
940 | ath9k_hw_get_target_powers(ah, chan, | ||
941 | pEepData->calTargetPower5GHT20, | ||
942 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
943 | &targetPowerHt20, 8, false); | ||
944 | |||
945 | if (IS_CHAN_HT40(chan)) { | ||
946 | numCtlModes = ARRAY_SIZE(ctlModesFor11a); | ||
947 | ath9k_hw_get_target_powers(ah, chan, | ||
948 | pEepData->calTargetPower5GHT40, | ||
949 | AR5416_NUM_5G_40_TARGET_POWERS, | ||
950 | &targetPowerHt40, 8, true); | ||
951 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
952 | pEepData->calTargetPower5G, | ||
953 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
954 | &targetPowerOfdmExt, 4, true); | ||
955 | } | ||
956 | } | ||
957 | |||
958 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
959 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
960 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
961 | if (isHt40CtlMode) | ||
962 | freq = centers.synth_center; | ||
963 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
964 | freq = centers.ext_center; | ||
965 | else | ||
966 | freq = centers.ctl_center; | ||
967 | |||
968 | if (ar5416_get_eep_ver(ahp) == 14 && ar5416_get_eep_rev(ahp) <= 2) | ||
969 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
970 | |||
971 | DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, | ||
972 | "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " | ||
973 | "EXT_ADDITIVE %d\n", | ||
974 | ctlMode, numCtlModes, isHt40CtlMode, | ||
975 | (pCtlMode[ctlMode] & EXT_ADDITIVE)); | ||
976 | |||
977 | for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { | ||
978 | DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, | ||
979 | " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " | ||
980 | "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " | ||
981 | "chan %d\n", | ||
982 | i, cfgCtl, pCtlMode[ctlMode], | ||
983 | pEepData->ctlIndex[i], chan->channel); | ||
984 | |||
985 | if ((((cfgCtl & ~CTL_MODE_M) | | ||
986 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
987 | pEepData->ctlIndex[i]) || | ||
988 | (((cfgCtl & ~CTL_MODE_M) | | ||
989 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
990 | ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { | ||
991 | rep = &(pEepData->ctlData[i]); | ||
992 | |||
993 | twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, | ||
994 | rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], | ||
995 | IS_CHAN_2GHZ(chan)); | ||
996 | |||
997 | DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, | ||
998 | " MATCH-EE_IDX %d: ch %d is2 %d " | ||
999 | "2xMinEdge %d chainmask %d chains %d\n", | ||
1000 | i, freq, IS_CHAN_2GHZ(chan), | ||
1001 | twiceMinEdgePower, tx_chainmask, | ||
1002 | ar5416_get_ntxchains | ||
1003 | (tx_chainmask)); | ||
1004 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { | ||
1005 | twiceMaxEdgePower = min(twiceMaxEdgePower, | ||
1006 | twiceMinEdgePower); | ||
1007 | } else { | ||
1008 | twiceMaxEdgePower = twiceMinEdgePower; | ||
1009 | break; | ||
1010 | } | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | minCtlPower = min(twiceMaxEdgePower, scaledPower); | ||
1015 | |||
1016 | DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, | ||
1017 | " SEL-Min ctlMode %d pCtlMode %d " | ||
1018 | "2xMaxEdge %d sP %d minCtlPwr %d\n", | ||
1019 | ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, | ||
1020 | scaledPower, minCtlPower); | ||
1021 | |||
1022 | switch (pCtlMode[ctlMode]) { | ||
1023 | case CTL_11B: | ||
1024 | for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { | ||
1025 | targetPowerCck.tPow2x[i] = | ||
1026 | min(targetPowerCck.tPow2x[i], | ||
1027 | minCtlPower); | ||
1028 | } | ||
1029 | break; | ||
1030 | case CTL_11A: | ||
1031 | case CTL_11G: | ||
1032 | for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { | ||
1033 | targetPowerOfdm.tPow2x[i] = | ||
1034 | min(targetPowerOfdm.tPow2x[i], | ||
1035 | minCtlPower); | ||
1036 | } | ||
1037 | break; | ||
1038 | case CTL_5GHT20: | ||
1039 | case CTL_2GHT20: | ||
1040 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { | ||
1041 | targetPowerHt20.tPow2x[i] = | ||
1042 | min(targetPowerHt20.tPow2x[i], | ||
1043 | minCtlPower); | ||
1044 | } | ||
1045 | break; | ||
1046 | case CTL_11B_EXT: | ||
1047 | targetPowerCckExt.tPow2x[0] = | ||
1048 | min(targetPowerCckExt.tPow2x[0], minCtlPower); | ||
1049 | break; | ||
1050 | case CTL_11A_EXT: | ||
1051 | case CTL_11G_EXT: | ||
1052 | targetPowerOfdmExt.tPow2x[0] = | ||
1053 | min(targetPowerOfdmExt.tPow2x[0], minCtlPower); | ||
1054 | break; | ||
1055 | case CTL_5GHT40: | ||
1056 | case CTL_2GHT40: | ||
1057 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
1058 | targetPowerHt40.tPow2x[i] = | ||
1059 | min(targetPowerHt40.tPow2x[i], | ||
1060 | minCtlPower); | ||
1061 | } | ||
1062 | break; | ||
1063 | default: | ||
1064 | break; | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = | ||
1069 | ratesArray[rate18mb] = ratesArray[rate24mb] = | ||
1070 | targetPowerOfdm.tPow2x[0]; | ||
1071 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
1072 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
1073 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
1074 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
1075 | |||
1076 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
1077 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
1078 | |||
1079 | if (IS_CHAN_2GHZ(chan)) { | ||
1080 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
1081 | ratesArray[rate2s] = ratesArray[rate2l] = | ||
1082 | targetPowerCck.tPow2x[1]; | ||
1083 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = | ||
1084 | targetPowerCck.tPow2x[2]; | ||
1085 | ; | ||
1086 | ratesArray[rate11s] = ratesArray[rate11l] = | ||
1087 | targetPowerCck.tPow2x[3]; | ||
1088 | ; | ||
1089 | } | ||
1090 | if (IS_CHAN_HT40(chan)) { | ||
1091 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
1092 | ratesArray[rateHt40_0 + i] = | ||
1093 | targetPowerHt40.tPow2x[i]; | ||
1094 | } | ||
1095 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
1096 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
1097 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
1098 | if (IS_CHAN_2GHZ(chan)) { | ||
1099 | ratesArray[rateExtCck] = | ||
1100 | targetPowerCckExt.tPow2x[0]; | ||
1101 | } | ||
1102 | } | ||
1103 | return true; | ||
1104 | } | ||
1105 | |||
1106 | bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, | ||
1107 | struct ath9k_channel *chan, | ||
1108 | int16_t *pTxPowerIndexOffset) | ||
1109 | { | ||
1110 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
1111 | struct ar5416_eeprom *pEepData = &ahp->ah_eeprom; | ||
1112 | struct cal_data_per_freq *pRawDataset; | ||
1113 | u8 *pCalBChans = NULL; | ||
1114 | u16 pdGainOverlap_t2; | ||
1115 | static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; | ||
1116 | u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; | ||
1117 | u16 numPiers, i, j; | ||
1118 | int16_t tMinCalPower; | ||
1119 | u16 numXpdGain, xpdMask; | ||
1120 | u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; | ||
1121 | u32 reg32, regOffset, regChainOffset; | ||
1122 | int16_t modalIdx; | ||
1123 | |||
1124 | modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; | ||
1125 | xpdMask = pEepData->modalHeader[modalIdx].xpdGain; | ||
1126 | |||
1127 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1128 | AR5416_EEP_MINOR_VER_2) { | ||
1129 | pdGainOverlap_t2 = | ||
1130 | pEepData->modalHeader[modalIdx].pdGainOverlap; | ||
1131 | } else { | ||
1132 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
1133 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
1134 | } | ||
1135 | |||
1136 | if (IS_CHAN_2GHZ(chan)) { | ||
1137 | pCalBChans = pEepData->calFreqPier2G; | ||
1138 | numPiers = AR5416_NUM_2G_CAL_PIERS; | ||
1139 | } else { | ||
1140 | pCalBChans = pEepData->calFreqPier5G; | ||
1141 | numPiers = AR5416_NUM_5G_CAL_PIERS; | ||
1142 | } | ||
1143 | |||
1144 | numXpdGain = 0; | ||
1145 | |||
1146 | for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { | ||
1147 | if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { | ||
1148 | if (numXpdGain >= AR5416_NUM_PD_GAINS) | ||
1149 | break; | ||
1150 | xpdGainValues[numXpdGain] = | ||
1151 | (u16)(AR5416_PD_GAINS_IN_MASK - i); | ||
1152 | numXpdGain++; | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1156 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
1157 | (numXpdGain - 1) & 0x3); | ||
1158 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
1159 | xpdGainValues[0]); | ||
1160 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
1161 | xpdGainValues[1]); | ||
1162 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, | ||
1163 | xpdGainValues[2]); | ||
1164 | |||
1165 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
1166 | if (AR_SREV_5416_V20_OR_LATER(ah) && | ||
1167 | (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && | ||
1168 | (i != 0)) { | ||
1169 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
1170 | } else | ||
1171 | regChainOffset = i * 0x1000; | ||
1172 | |||
1173 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
1174 | if (IS_CHAN_2GHZ(chan)) | ||
1175 | pRawDataset = pEepData->calPierData2G[i]; | ||
1176 | else | ||
1177 | pRawDataset = pEepData->calPierData5G[i]; | ||
1178 | |||
1179 | ath9k_hw_get_gain_boundaries_pdadcs(ah, chan, | ||
1180 | pRawDataset, pCalBChans, | ||
1181 | numPiers, pdGainOverlap_t2, | ||
1182 | &tMinCalPower, gainBoundaries, | ||
1183 | pdadcValues, numXpdGain); | ||
1184 | |||
1185 | if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { | ||
1186 | REG_WRITE(ah, | ||
1187 | AR_PHY_TPCRG5 + regChainOffset, | ||
1188 | SM(pdGainOverlap_t2, | ||
1189 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | ||
1190 | | SM(gainBoundaries[0], | ||
1191 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | ||
1192 | | SM(gainBoundaries[1], | ||
1193 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | ||
1194 | | SM(gainBoundaries[2], | ||
1195 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | ||
1196 | | SM(gainBoundaries[3], | ||
1197 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); | ||
1198 | } | ||
1199 | |||
1200 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; | ||
1201 | for (j = 0; j < 32; j++) { | ||
1202 | reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | | ||
1203 | ((pdadcValues[4 * j + 1] & 0xFF) << 8) | | ||
1204 | ((pdadcValues[4 * j + 2] & 0xFF) << 16) | | ||
1205 | ((pdadcValues[4 * j + 3] & 0xFF) << 24); | ||
1206 | REG_WRITE(ah, regOffset, reg32); | ||
1207 | |||
1208 | DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, | ||
1209 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
1210 | i, regChainOffset, regOffset, | ||
1211 | reg32); | ||
1212 | DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, | ||
1213 | "PDADC: Chain %d | PDADC %3d Value %3d | " | ||
1214 | "PDADC %3d Value %3d | PDADC %3d Value %3d | " | ||
1215 | "PDADC %3d Value %3d |\n", | ||
1216 | i, 4 * j, pdadcValues[4 * j], | ||
1217 | 4 * j + 1, pdadcValues[4 * j + 1], | ||
1218 | 4 * j + 2, pdadcValues[4 * j + 2], | ||
1219 | 4 * j + 3, | ||
1220 | pdadcValues[4 * j + 3]); | ||
1221 | |||
1222 | regOffset += 4; | ||
1223 | } | ||
1224 | } | ||
1225 | } | ||
1226 | |||
1227 | *pTxPowerIndexOffset = 0; | ||
1228 | |||
1229 | return true; | ||
1230 | } | ||
1231 | |||
1232 | /* XXX: Clean me up, make me more legible */ | ||
1233 | bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, | ||
1234 | struct ath9k_channel *chan) | ||
1235 | { | ||
1236 | struct modal_eep_header *pModal; | ||
1237 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
1238 | struct ar5416_eeprom *eep = &ahp->ah_eeprom; | ||
1239 | int i, regChainOffset; | ||
1240 | u8 txRxAttenLocal; | ||
1241 | u16 ant_config; | ||
1242 | |||
1243 | pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
1244 | |||
1245 | txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; | ||
1246 | |||
1247 | ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 1, &ant_config); | ||
1248 | REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); | ||
1249 | |||
1250 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
1251 | if (AR_SREV_9280(ah)) { | ||
1252 | if (i >= 2) | ||
1253 | break; | ||
1254 | } | ||
1255 | |||
1256 | if (AR_SREV_5416_V20_OR_LATER(ah) && | ||
1257 | (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) | ||
1258 | && (i != 0)) | ||
1259 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
1260 | else | ||
1261 | regChainOffset = i * 0x1000; | ||
1262 | |||
1263 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, | ||
1264 | pModal->antCtrlChain[i]); | ||
1265 | |||
1266 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | ||
1267 | (REG_READ(ah, | ||
1268 | AR_PHY_TIMING_CTRL4(0) + | ||
1269 | regChainOffset) & | ||
1270 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
1271 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
1272 | SM(pModal->iqCalICh[i], | ||
1273 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
1274 | SM(pModal->iqCalQCh[i], | ||
1275 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
1276 | |||
1277 | if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { | ||
1278 | if ((eep->baseEepHeader.version & | ||
1279 | AR5416_EEP_VER_MINOR_MASK) >= | ||
1280 | AR5416_EEP_MINOR_VER_3) { | ||
1281 | txRxAttenLocal = pModal->txRxAttenCh[i]; | ||
1282 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1283 | REG_RMW_FIELD(ah, | ||
1284 | AR_PHY_GAIN_2GHZ + | ||
1285 | regChainOffset, | ||
1286 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
1287 | pModal-> | ||
1288 | bswMargin[i]); | ||
1289 | REG_RMW_FIELD(ah, | ||
1290 | AR_PHY_GAIN_2GHZ + | ||
1291 | regChainOffset, | ||
1292 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, | ||
1293 | pModal-> | ||
1294 | bswAtten[i]); | ||
1295 | REG_RMW_FIELD(ah, | ||
1296 | AR_PHY_GAIN_2GHZ + | ||
1297 | regChainOffset, | ||
1298 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
1299 | pModal-> | ||
1300 | xatten2Margin[i]); | ||
1301 | REG_RMW_FIELD(ah, | ||
1302 | AR_PHY_GAIN_2GHZ + | ||
1303 | regChainOffset, | ||
1304 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, | ||
1305 | pModal-> | ||
1306 | xatten2Db[i]); | ||
1307 | } else { | ||
1308 | REG_WRITE(ah, | ||
1309 | AR_PHY_GAIN_2GHZ + | ||
1310 | regChainOffset, | ||
1311 | (REG_READ(ah, | ||
1312 | AR_PHY_GAIN_2GHZ + | ||
1313 | regChainOffset) & | ||
1314 | ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | ||
1315 | | SM(pModal-> | ||
1316 | bswMargin[i], | ||
1317 | AR_PHY_GAIN_2GHZ_BSW_MARGIN)); | ||
1318 | REG_WRITE(ah, | ||
1319 | AR_PHY_GAIN_2GHZ + | ||
1320 | regChainOffset, | ||
1321 | (REG_READ(ah, | ||
1322 | AR_PHY_GAIN_2GHZ + | ||
1323 | regChainOffset) & | ||
1324 | ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | ||
1325 | | SM(pModal->bswAtten[i], | ||
1326 | AR_PHY_GAIN_2GHZ_BSW_ATTEN)); | ||
1327 | } | ||
1328 | } | ||
1329 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1330 | REG_RMW_FIELD(ah, | ||
1331 | AR_PHY_RXGAIN + | ||
1332 | regChainOffset, | ||
1333 | AR9280_PHY_RXGAIN_TXRX_ATTEN, | ||
1334 | txRxAttenLocal); | ||
1335 | REG_RMW_FIELD(ah, | ||
1336 | AR_PHY_RXGAIN + | ||
1337 | regChainOffset, | ||
1338 | AR9280_PHY_RXGAIN_TXRX_MARGIN, | ||
1339 | pModal->rxTxMarginCh[i]); | ||
1340 | } else { | ||
1341 | REG_WRITE(ah, | ||
1342 | AR_PHY_RXGAIN + regChainOffset, | ||
1343 | (REG_READ(ah, | ||
1344 | AR_PHY_RXGAIN + | ||
1345 | regChainOffset) & | ||
1346 | ~AR_PHY_RXGAIN_TXRX_ATTEN) | | ||
1347 | SM(txRxAttenLocal, | ||
1348 | AR_PHY_RXGAIN_TXRX_ATTEN)); | ||
1349 | REG_WRITE(ah, | ||
1350 | AR_PHY_GAIN_2GHZ + | ||
1351 | regChainOffset, | ||
1352 | (REG_READ(ah, | ||
1353 | AR_PHY_GAIN_2GHZ + | ||
1354 | regChainOffset) & | ||
1355 | ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | | ||
1356 | SM(pModal->rxTxMarginCh[i], | ||
1357 | AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); | ||
1358 | } | ||
1359 | } | ||
1360 | } | ||
1361 | |||
1362 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1363 | if (IS_CHAN_2GHZ(chan)) { | ||
1364 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, | ||
1365 | AR_AN_RF2G1_CH0_OB, | ||
1366 | AR_AN_RF2G1_CH0_OB_S, | ||
1367 | pModal->ob); | ||
1368 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, | ||
1369 | AR_AN_RF2G1_CH0_DB, | ||
1370 | AR_AN_RF2G1_CH0_DB_S, | ||
1371 | pModal->db); | ||
1372 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, | ||
1373 | AR_AN_RF2G1_CH1_OB, | ||
1374 | AR_AN_RF2G1_CH1_OB_S, | ||
1375 | pModal->ob_ch1); | ||
1376 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, | ||
1377 | AR_AN_RF2G1_CH1_DB, | ||
1378 | AR_AN_RF2G1_CH1_DB_S, | ||
1379 | pModal->db_ch1); | ||
1380 | } else { | ||
1381 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, | ||
1382 | AR_AN_RF5G1_CH0_OB5, | ||
1383 | AR_AN_RF5G1_CH0_OB5_S, | ||
1384 | pModal->ob); | ||
1385 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, | ||
1386 | AR_AN_RF5G1_CH0_DB5, | ||
1387 | AR_AN_RF5G1_CH0_DB5_S, | ||
1388 | pModal->db); | ||
1389 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, | ||
1390 | AR_AN_RF5G1_CH1_OB5, | ||
1391 | AR_AN_RF5G1_CH1_OB5_S, | ||
1392 | pModal->ob_ch1); | ||
1393 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, | ||
1394 | AR_AN_RF5G1_CH1_DB5, | ||
1395 | AR_AN_RF5G1_CH1_DB5_S, | ||
1396 | pModal->db_ch1); | ||
1397 | } | ||
1398 | ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, | ||
1399 | AR_AN_TOP2_XPABIAS_LVL, | ||
1400 | AR_AN_TOP2_XPABIAS_LVL_S, | ||
1401 | pModal->xpaBiasLvl); | ||
1402 | ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, | ||
1403 | AR_AN_TOP2_LOCALBIAS, | ||
1404 | AR_AN_TOP2_LOCALBIAS_S, | ||
1405 | pModal->local_bias); | ||
1406 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ForceXPAon: %d\n", | ||
1407 | pModal->force_xpaon); | ||
1408 | REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, | ||
1409 | pModal->force_xpaon); | ||
1410 | } | ||
1411 | |||
1412 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, | ||
1413 | pModal->switchSettling); | ||
1414 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, | ||
1415 | pModal->adcDesiredSize); | ||
1416 | |||
1417 | if (!AR_SREV_9280_10_OR_LATER(ah)) | ||
1418 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, | ||
1419 | AR_PHY_DESIRED_SZ_PGA, | ||
1420 | pModal->pgaDesiredSize); | ||
1421 | |||
1422 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
1423 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | ||
1424 | | SM(pModal->txEndToXpaOff, | ||
1425 | AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | ||
1426 | | SM(pModal->txFrameToXpaOn, | ||
1427 | AR_PHY_RF_CTL4_FRAME_XPAA_ON) | ||
1428 | | SM(pModal->txFrameToXpaOn, | ||
1429 | AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
1430 | |||
1431 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, | ||
1432 | pModal->txEndToRxOn); | ||
1433 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1434 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, | ||
1435 | pModal->thresh62); | ||
1436 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, | ||
1437 | AR_PHY_EXT_CCA0_THRESH62, | ||
1438 | pModal->thresh62); | ||
1439 | } else { | ||
1440 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, | ||
1441 | pModal->thresh62); | ||
1442 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, | ||
1443 | AR_PHY_EXT_CCA_THRESH62, | ||
1444 | pModal->thresh62); | ||
1445 | } | ||
1446 | |||
1447 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1448 | AR5416_EEP_MINOR_VER_2) { | ||
1449 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, | ||
1450 | AR_PHY_TX_END_DATA_START, | ||
1451 | pModal->txFrameToDataStart); | ||
1452 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, | ||
1453 | pModal->txFrameToPaOn); | ||
1454 | } | ||
1455 | |||
1456 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1457 | AR5416_EEP_MINOR_VER_3) { | ||
1458 | if (IS_CHAN_HT40(chan)) | ||
1459 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1460 | AR_PHY_SETTLING_SWITCH, | ||
1461 | pModal->swSettleHt40); | ||
1462 | } | ||
1463 | |||
1464 | return true; | ||
1465 | } | ||
1466 | |||
1467 | int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, | ||
1468 | struct ath9k_channel *chan, | ||
1469 | u8 index, u16 *config) | ||
1470 | { | ||
1471 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
1472 | struct ar5416_eeprom *eep = &ahp->ah_eeprom; | ||
1473 | struct modal_eep_header *pModal = | ||
1474 | &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
1475 | struct base_eep_header *pBase = &eep->baseEepHeader; | ||
1476 | |||
1477 | switch (index) { | ||
1478 | case 0: | ||
1479 | *config = pModal->antCtrlCommon & 0xFFFF; | ||
1480 | return 0; | ||
1481 | case 1: | ||
1482 | if (pBase->version >= 0x0E0D) { | ||
1483 | if (pModal->useAnt1) { | ||
1484 | *config = | ||
1485 | ((pModal->antCtrlCommon & 0xFFFF0000) >> 16); | ||
1486 | return 0; | ||
1487 | } | ||
1488 | } | ||
1489 | break; | ||
1490 | default: | ||
1491 | break; | ||
1492 | } | ||
1493 | |||
1494 | return -EINVAL; | ||
1495 | } | ||
1496 | |||
1497 | u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, | ||
1498 | enum ieee80211_band freq_band) | ||
1499 | { | ||
1500 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
1501 | struct ar5416_eeprom *eep = &ahp->ah_eeprom; | ||
1502 | struct modal_eep_header *pModal = | ||
1503 | &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]); | ||
1504 | struct base_eep_header *pBase = &eep->baseEepHeader; | ||
1505 | u8 num_ant_config; | ||
1506 | |||
1507 | num_ant_config = 1; | ||
1508 | |||
1509 | if (pBase->version >= 0x0E0D) | ||
1510 | if (pModal->useAnt1) | ||
1511 | num_ant_config += 1; | ||
1512 | |||
1513 | return num_ant_config; | ||
1514 | } | ||
1515 | |||
1516 | u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz) | ||
1517 | { | ||
1518 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
1519 | struct ar5416_eeprom *eep = | ||
1520 | (struct ar5416_eeprom *) &ahp->ah_eeprom; | ||
1521 | u16 spur_val = AR_NO_SPUR; | ||
1522 | |||
1523 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1524 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
1525 | i, is2GHz, ah->ah_config.spurchans[i][is2GHz]); | ||
1526 | |||
1527 | switch (ah->ah_config.spurmode) { | ||
1528 | case SPUR_DISABLE: | ||
1529 | break; | ||
1530 | case SPUR_ENABLE_IOCTL: | ||
1531 | spur_val = ah->ah_config.spurchans[i][is2GHz]; | ||
1532 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1533 | "Getting spur val from new loc. %d\n", spur_val); | ||
1534 | break; | ||
1535 | case SPUR_ENABLE_EEPROM: | ||
1536 | spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan; | ||
1537 | break; | ||
1538 | |||
1539 | } | ||
1540 | |||
1541 | return spur_val; | ||
1542 | } | ||
1543 | |||
1544 | u32 ath9k_hw_get_eeprom(struct ath_hal *ah, | ||
1545 | enum eeprom_param param) | ||
1546 | { | ||
1547 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
1548 | struct ar5416_eeprom *eep = &ahp->ah_eeprom; | ||
1549 | struct modal_eep_header *pModal = eep->modalHeader; | ||
1550 | struct base_eep_header *pBase = &eep->baseEepHeader; | ||
1551 | |||
1552 | switch (param) { | ||
1553 | case EEP_NFTHRESH_5: | ||
1554 | return -pModal[0].noiseFloorThreshCh[0]; | ||
1555 | case EEP_NFTHRESH_2: | ||
1556 | return -pModal[1].noiseFloorThreshCh[0]; | ||
1557 | case AR_EEPROM_MAC(0): | ||
1558 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
1559 | case AR_EEPROM_MAC(1): | ||
1560 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
1561 | case AR_EEPROM_MAC(2): | ||
1562 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
1563 | case EEP_REG_0: | ||
1564 | return pBase->regDmn[0]; | ||
1565 | case EEP_REG_1: | ||
1566 | return pBase->regDmn[1]; | ||
1567 | case EEP_OP_CAP: | ||
1568 | return pBase->deviceCap; | ||
1569 | case EEP_OP_MODE: | ||
1570 | return pBase->opCapFlags; | ||
1571 | case EEP_RF_SILENT: | ||
1572 | return pBase->rfSilent; | ||
1573 | case EEP_OB_5: | ||
1574 | return pModal[0].ob; | ||
1575 | case EEP_DB_5: | ||
1576 | return pModal[0].db; | ||
1577 | case EEP_OB_2: | ||
1578 | return pModal[1].ob; | ||
1579 | case EEP_DB_2: | ||
1580 | return pModal[1].db; | ||
1581 | case EEP_MINOR_REV: | ||
1582 | return pBase->version & AR5416_EEP_VER_MINOR_MASK; | ||
1583 | case EEP_TX_MASK: | ||
1584 | return pBase->txMask; | ||
1585 | case EEP_RX_MASK: | ||
1586 | return pBase->rxMask; | ||
1587 | default: | ||
1588 | return 0; | ||
1589 | } | ||
1590 | } | ||
1591 | |||
1592 | int ath9k_hw_eeprom_attach(struct ath_hal *ah) | ||
1593 | { | ||
1594 | int status; | ||
1595 | |||
1596 | if (ath9k_hw_use_flash(ah)) | ||
1597 | ath9k_hw_flash_map(ah); | ||
1598 | |||
1599 | if (!ath9k_hw_fill_eeprom(ah)) | ||
1600 | return -EIO; | ||
1601 | |||
1602 | status = ath9k_hw_check_eeprom(ah); | ||
1603 | |||
1604 | return status; | ||
1605 | } | ||