diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/eeprom.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/eeprom.c | 2813 |
1 files changed, 2813 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c new file mode 100644 index 000000000000..44fee5ae8925 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom.c | |||
@@ -0,0 +1,2813 @@ | |||
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 void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, | ||
20 | u32 reg, u32 mask, | ||
21 | u32 shift, u32 val) | ||
22 | { | ||
23 | u32 regVal; | ||
24 | |||
25 | regVal = REG_READ(ah, reg) & ~mask; | ||
26 | regVal |= (val << shift) & mask; | ||
27 | |||
28 | REG_WRITE(ah, reg, regVal); | ||
29 | |||
30 | if (ah->config.analog_shiftreg) | ||
31 | udelay(100); | ||
32 | |||
33 | return; | ||
34 | } | ||
35 | |||
36 | static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) | ||
37 | { | ||
38 | |||
39 | if (fbin == AR5416_BCHAN_UNUSED) | ||
40 | return fbin; | ||
41 | |||
42 | return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); | ||
43 | } | ||
44 | |||
45 | static inline int16_t ath9k_hw_interpolate(u16 target, | ||
46 | u16 srcLeft, u16 srcRight, | ||
47 | int16_t targetLeft, | ||
48 | int16_t targetRight) | ||
49 | { | ||
50 | int16_t rv; | ||
51 | |||
52 | if (srcRight == srcLeft) { | ||
53 | rv = targetLeft; | ||
54 | } else { | ||
55 | rv = (int16_t) (((target - srcLeft) * targetRight + | ||
56 | (srcRight - target) * targetLeft) / | ||
57 | (srcRight - srcLeft)); | ||
58 | } | ||
59 | return rv; | ||
60 | } | ||
61 | |||
62 | static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, | ||
63 | u16 listSize, u16 *indexL, | ||
64 | u16 *indexR) | ||
65 | { | ||
66 | u16 i; | ||
67 | |||
68 | if (target <= pList[0]) { | ||
69 | *indexL = *indexR = 0; | ||
70 | return true; | ||
71 | } | ||
72 | if (target >= pList[listSize - 1]) { | ||
73 | *indexL = *indexR = (u16) (listSize - 1); | ||
74 | return true; | ||
75 | } | ||
76 | |||
77 | for (i = 0; i < listSize - 1; i++) { | ||
78 | if (pList[i] == target) { | ||
79 | *indexL = *indexR = i; | ||
80 | return true; | ||
81 | } | ||
82 | if (target < pList[i + 1]) { | ||
83 | *indexL = i; | ||
84 | *indexR = (u16) (i + 1); | ||
85 | return false; | ||
86 | } | ||
87 | } | ||
88 | return false; | ||
89 | } | ||
90 | |||
91 | static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) | ||
92 | { | ||
93 | struct ath_softc *sc = ah->ah_sc; | ||
94 | |||
95 | return sc->bus_ops->eeprom_read(ah, off, data); | ||
96 | } | ||
97 | |||
98 | static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, | ||
99 | u8 *pVpdList, u16 numIntercepts, | ||
100 | u8 *pRetVpdList) | ||
101 | { | ||
102 | u16 i, k; | ||
103 | u8 currPwr = pwrMin; | ||
104 | u16 idxL = 0, idxR = 0; | ||
105 | |||
106 | for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { | ||
107 | ath9k_hw_get_lower_upper_index(currPwr, pPwrList, | ||
108 | numIntercepts, &(idxL), | ||
109 | &(idxR)); | ||
110 | if (idxR < 1) | ||
111 | idxR = 1; | ||
112 | if (idxL == numIntercepts - 1) | ||
113 | idxL = (u16) (numIntercepts - 2); | ||
114 | if (pPwrList[idxL] == pPwrList[idxR]) | ||
115 | k = pVpdList[idxL]; | ||
116 | else | ||
117 | k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + | ||
118 | (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / | ||
119 | (pPwrList[idxR] - pPwrList[idxL])); | ||
120 | pRetVpdList[i] = (u8) k; | ||
121 | currPwr += 2; | ||
122 | } | ||
123 | |||
124 | return true; | ||
125 | } | ||
126 | |||
127 | static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, | ||
128 | struct ath9k_channel *chan, | ||
129 | struct cal_target_power_leg *powInfo, | ||
130 | u16 numChannels, | ||
131 | struct cal_target_power_leg *pNewPower, | ||
132 | u16 numRates, bool isExtTarget) | ||
133 | { | ||
134 | struct chan_centers centers; | ||
135 | u16 clo, chi; | ||
136 | int i; | ||
137 | int matchIndex = -1, lowIndex = -1; | ||
138 | u16 freq; | ||
139 | |||
140 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
141 | freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; | ||
142 | |||
143 | if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, | ||
144 | IS_CHAN_2GHZ(chan))) { | ||
145 | matchIndex = 0; | ||
146 | } else { | ||
147 | for (i = 0; (i < numChannels) && | ||
148 | (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { | ||
149 | if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, | ||
150 | IS_CHAN_2GHZ(chan))) { | ||
151 | matchIndex = i; | ||
152 | break; | ||
153 | } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, | ||
154 | IS_CHAN_2GHZ(chan))) && | ||
155 | (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, | ||
156 | IS_CHAN_2GHZ(chan)))) { | ||
157 | lowIndex = i - 1; | ||
158 | break; | ||
159 | } | ||
160 | } | ||
161 | if ((matchIndex == -1) && (lowIndex == -1)) | ||
162 | matchIndex = i - 1; | ||
163 | } | ||
164 | |||
165 | if (matchIndex != -1) { | ||
166 | *pNewPower = powInfo[matchIndex]; | ||
167 | } else { | ||
168 | clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, | ||
169 | IS_CHAN_2GHZ(chan)); | ||
170 | chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, | ||
171 | IS_CHAN_2GHZ(chan)); | ||
172 | |||
173 | for (i = 0; i < numRates; i++) { | ||
174 | pNewPower->tPow2x[i] = | ||
175 | (u8)ath9k_hw_interpolate(freq, clo, chi, | ||
176 | powInfo[lowIndex].tPow2x[i], | ||
177 | powInfo[lowIndex + 1].tPow2x[i]); | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | static void ath9k_get_txgain_index(struct ath_hw *ah, | ||
183 | struct ath9k_channel *chan, | ||
184 | struct calDataPerFreqOpLoop *rawDatasetOpLoop, | ||
185 | u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) | ||
186 | { | ||
187 | u8 pcdac, i = 0; | ||
188 | u16 idxL = 0, idxR = 0, numPiers; | ||
189 | bool match; | ||
190 | struct chan_centers centers; | ||
191 | |||
192 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
193 | |||
194 | for (numPiers = 0; numPiers < availPiers; numPiers++) | ||
195 | if (calChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
196 | break; | ||
197 | |||
198 | match = ath9k_hw_get_lower_upper_index( | ||
199 | (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), | ||
200 | calChans, numPiers, &idxL, &idxR); | ||
201 | if (match) { | ||
202 | pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; | ||
203 | *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; | ||
204 | } else { | ||
205 | pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; | ||
206 | *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + | ||
207 | rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; | ||
208 | } | ||
209 | |||
210 | while (pcdac > ah->originalGain[i] && | ||
211 | i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) | ||
212 | i++; | ||
213 | |||
214 | *pcdacIdx = i; | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | static void ath9k_olc_get_pdadcs(struct ath_hw *ah, | ||
219 | u32 initTxGain, | ||
220 | int txPower, | ||
221 | u8 *pPDADCValues) | ||
222 | { | ||
223 | u32 i; | ||
224 | u32 offset; | ||
225 | |||
226 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, | ||
227 | AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); | ||
228 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, | ||
229 | AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); | ||
230 | |||
231 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, | ||
232 | AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); | ||
233 | |||
234 | offset = txPower; | ||
235 | for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) | ||
236 | if (i < offset) | ||
237 | pPDADCValues[i] = 0x0; | ||
238 | else | ||
239 | pPDADCValues[i] = 0xFF; | ||
240 | } | ||
241 | |||
242 | |||
243 | |||
244 | |||
245 | static void ath9k_hw_get_target_powers(struct ath_hw *ah, | ||
246 | struct ath9k_channel *chan, | ||
247 | struct cal_target_power_ht *powInfo, | ||
248 | u16 numChannels, | ||
249 | struct cal_target_power_ht *pNewPower, | ||
250 | u16 numRates, bool isHt40Target) | ||
251 | { | ||
252 | struct chan_centers centers; | ||
253 | u16 clo, chi; | ||
254 | int i; | ||
255 | int matchIndex = -1, lowIndex = -1; | ||
256 | u16 freq; | ||
257 | |||
258 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
259 | freq = isHt40Target ? centers.synth_center : centers.ctl_center; | ||
260 | |||
261 | if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { | ||
262 | matchIndex = 0; | ||
263 | } else { | ||
264 | for (i = 0; (i < numChannels) && | ||
265 | (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { | ||
266 | if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, | ||
267 | IS_CHAN_2GHZ(chan))) { | ||
268 | matchIndex = i; | ||
269 | break; | ||
270 | } else | ||
271 | if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, | ||
272 | IS_CHAN_2GHZ(chan))) && | ||
273 | (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, | ||
274 | IS_CHAN_2GHZ(chan)))) { | ||
275 | lowIndex = i - 1; | ||
276 | break; | ||
277 | } | ||
278 | } | ||
279 | if ((matchIndex == -1) && (lowIndex == -1)) | ||
280 | matchIndex = i - 1; | ||
281 | } | ||
282 | |||
283 | if (matchIndex != -1) { | ||
284 | *pNewPower = powInfo[matchIndex]; | ||
285 | } else { | ||
286 | clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, | ||
287 | IS_CHAN_2GHZ(chan)); | ||
288 | chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, | ||
289 | IS_CHAN_2GHZ(chan)); | ||
290 | |||
291 | for (i = 0; i < numRates; i++) { | ||
292 | pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, | ||
293 | clo, chi, | ||
294 | powInfo[lowIndex].tPow2x[i], | ||
295 | powInfo[lowIndex + 1].tPow2x[i]); | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | |||
300 | static u16 ath9k_hw_get_max_edge_power(u16 freq, | ||
301 | struct cal_ctl_edges *pRdEdgesPower, | ||
302 | bool is2GHz, int num_band_edges) | ||
303 | { | ||
304 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
305 | int i; | ||
306 | |||
307 | for (i = 0; (i < num_band_edges) && | ||
308 | (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { | ||
309 | if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { | ||
310 | twiceMaxEdgePower = pRdEdgesPower[i].tPower; | ||
311 | break; | ||
312 | } else if ((i > 0) && | ||
313 | (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, | ||
314 | is2GHz))) { | ||
315 | if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, | ||
316 | is2GHz) < freq && | ||
317 | pRdEdgesPower[i - 1].flag) { | ||
318 | twiceMaxEdgePower = | ||
319 | pRdEdgesPower[i - 1].tPower; | ||
320 | } | ||
321 | break; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | return twiceMaxEdgePower; | ||
326 | } | ||
327 | |||
328 | /****************************************/ | ||
329 | /* EEPROM Operations for 4K sized cards */ | ||
330 | /****************************************/ | ||
331 | |||
332 | static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) | ||
333 | { | ||
334 | return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); | ||
335 | } | ||
336 | |||
337 | static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) | ||
338 | { | ||
339 | return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); | ||
340 | } | ||
341 | |||
342 | static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) | ||
343 | { | ||
344 | #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) | ||
345 | u16 *eep_data = (u16 *)&ah->eeprom.map4k; | ||
346 | int addr, eep_start_loc = 0; | ||
347 | |||
348 | eep_start_loc = 64; | ||
349 | |||
350 | if (!ath9k_hw_use_flash(ah)) { | ||
351 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
352 | "Reading from EEPROM, not flash\n"); | ||
353 | } | ||
354 | |||
355 | for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { | ||
356 | if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { | ||
357 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
358 | "Unable to read eeprom region \n"); | ||
359 | return false; | ||
360 | } | ||
361 | eep_data++; | ||
362 | } | ||
363 | |||
364 | return true; | ||
365 | #undef SIZE_EEPROM_4K | ||
366 | } | ||
367 | |||
368 | static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) | ||
369 | { | ||
370 | #define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) | ||
371 | struct ar5416_eeprom_4k *eep = | ||
372 | (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; | ||
373 | u16 *eepdata, temp, magic, magic2; | ||
374 | u32 sum = 0, el; | ||
375 | bool need_swap = false; | ||
376 | int i, addr; | ||
377 | |||
378 | |||
379 | if (!ath9k_hw_use_flash(ah)) { | ||
380 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, | ||
381 | &magic)) { | ||
382 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
383 | "Reading Magic # failed\n"); | ||
384 | return false; | ||
385 | } | ||
386 | |||
387 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
388 | "Read Magic = 0x%04X\n", magic); | ||
389 | |||
390 | if (magic != AR5416_EEPROM_MAGIC) { | ||
391 | magic2 = swab16(magic); | ||
392 | |||
393 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
394 | need_swap = true; | ||
395 | eepdata = (u16 *) (&ah->eeprom); | ||
396 | |||
397 | for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { | ||
398 | temp = swab16(*eepdata); | ||
399 | *eepdata = temp; | ||
400 | eepdata++; | ||
401 | } | ||
402 | } else { | ||
403 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
404 | "Invalid EEPROM Magic. " | ||
405 | "endianness mismatch.\n"); | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | } | ||
409 | } | ||
410 | |||
411 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", | ||
412 | need_swap ? "True" : "False"); | ||
413 | |||
414 | if (need_swap) | ||
415 | el = swab16(ah->eeprom.map4k.baseEepHeader.length); | ||
416 | else | ||
417 | el = ah->eeprom.map4k.baseEepHeader.length; | ||
418 | |||
419 | if (el > sizeof(struct ar5416_eeprom_4k)) | ||
420 | el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); | ||
421 | else | ||
422 | el = el / sizeof(u16); | ||
423 | |||
424 | eepdata = (u16 *)(&ah->eeprom); | ||
425 | |||
426 | for (i = 0; i < el; i++) | ||
427 | sum ^= *eepdata++; | ||
428 | |||
429 | if (need_swap) { | ||
430 | u32 integer; | ||
431 | u16 word; | ||
432 | |||
433 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
434 | "EEPROM Endianness is not native.. Changing\n"); | ||
435 | |||
436 | word = swab16(eep->baseEepHeader.length); | ||
437 | eep->baseEepHeader.length = word; | ||
438 | |||
439 | word = swab16(eep->baseEepHeader.checksum); | ||
440 | eep->baseEepHeader.checksum = word; | ||
441 | |||
442 | word = swab16(eep->baseEepHeader.version); | ||
443 | eep->baseEepHeader.version = word; | ||
444 | |||
445 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
446 | eep->baseEepHeader.regDmn[0] = word; | ||
447 | |||
448 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
449 | eep->baseEepHeader.regDmn[1] = word; | ||
450 | |||
451 | word = swab16(eep->baseEepHeader.rfSilent); | ||
452 | eep->baseEepHeader.rfSilent = word; | ||
453 | |||
454 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
455 | eep->baseEepHeader.blueToothOptions = word; | ||
456 | |||
457 | word = swab16(eep->baseEepHeader.deviceCap); | ||
458 | eep->baseEepHeader.deviceCap = word; | ||
459 | |||
460 | integer = swab32(eep->modalHeader.antCtrlCommon); | ||
461 | eep->modalHeader.antCtrlCommon = integer; | ||
462 | |||
463 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
464 | integer = swab32(eep->modalHeader.antCtrlChain[i]); | ||
465 | eep->modalHeader.antCtrlChain[i] = integer; | ||
466 | } | ||
467 | |||
468 | for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { | ||
469 | word = swab16(eep->modalHeader.spurChans[i].spurChan); | ||
470 | eep->modalHeader.spurChans[i].spurChan = word; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || | ||
475 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | ||
476 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
477 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
478 | sum, ah->eep_ops->get_eeprom_ver(ah)); | ||
479 | return -EINVAL; | ||
480 | } | ||
481 | |||
482 | return 0; | ||
483 | #undef EEPROM_4K_SIZE | ||
484 | } | ||
485 | |||
486 | static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, | ||
487 | enum eeprom_param param) | ||
488 | { | ||
489 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
490 | struct modal_eep_4k_header *pModal = &eep->modalHeader; | ||
491 | struct base_eep_header_4k *pBase = &eep->baseEepHeader; | ||
492 | |||
493 | switch (param) { | ||
494 | case EEP_NFTHRESH_2: | ||
495 | return pModal->noiseFloorThreshCh[0]; | ||
496 | case AR_EEPROM_MAC(0): | ||
497 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
498 | case AR_EEPROM_MAC(1): | ||
499 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
500 | case AR_EEPROM_MAC(2): | ||
501 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
502 | case EEP_REG_0: | ||
503 | return pBase->regDmn[0]; | ||
504 | case EEP_REG_1: | ||
505 | return pBase->regDmn[1]; | ||
506 | case EEP_OP_CAP: | ||
507 | return pBase->deviceCap; | ||
508 | case EEP_OP_MODE: | ||
509 | return pBase->opCapFlags; | ||
510 | case EEP_RF_SILENT: | ||
511 | return pBase->rfSilent; | ||
512 | case EEP_OB_2: | ||
513 | return pModal->ob_01; | ||
514 | case EEP_DB_2: | ||
515 | return pModal->db1_01; | ||
516 | case EEP_MINOR_REV: | ||
517 | return pBase->version & AR5416_EEP_VER_MINOR_MASK; | ||
518 | case EEP_TX_MASK: | ||
519 | return pBase->txMask; | ||
520 | case EEP_RX_MASK: | ||
521 | return pBase->rxMask; | ||
522 | case EEP_FRAC_N_5G: | ||
523 | return 0; | ||
524 | default: | ||
525 | return 0; | ||
526 | } | ||
527 | } | ||
528 | |||
529 | static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, | ||
530 | struct ath9k_channel *chan, | ||
531 | struct cal_data_per_freq_4k *pRawDataSet, | ||
532 | u8 *bChans, u16 availPiers, | ||
533 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
534 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
535 | u16 numXpdGains) | ||
536 | { | ||
537 | #define TMP_VAL_VPD_TABLE \ | ||
538 | ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); | ||
539 | int i, j, k; | ||
540 | int16_t ss; | ||
541 | u16 idxL = 0, idxR = 0, numPiers; | ||
542 | static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] | ||
543 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
544 | static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] | ||
545 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
546 | static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] | ||
547 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
548 | |||
549 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
550 | u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; | ||
551 | u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; | ||
552 | int16_t vpdStep; | ||
553 | int16_t tmpVal; | ||
554 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
555 | bool match; | ||
556 | int16_t minDelta = 0; | ||
557 | struct chan_centers centers; | ||
558 | #define PD_GAIN_BOUNDARY_DEFAULT 58; | ||
559 | |||
560 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
561 | |||
562 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
563 | if (bChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
564 | break; | ||
565 | } | ||
566 | |||
567 | match = ath9k_hw_get_lower_upper_index( | ||
568 | (u8)FREQ2FBIN(centers.synth_center, | ||
569 | IS_CHAN_2GHZ(chan)), bChans, numPiers, | ||
570 | &idxL, &idxR); | ||
571 | |||
572 | if (match) { | ||
573 | for (i = 0; i < numXpdGains; i++) { | ||
574 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
575 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
576 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
577 | pRawDataSet[idxL].pwrPdg[i], | ||
578 | pRawDataSet[idxL].vpdPdg[i], | ||
579 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
580 | vpdTableI[i]); | ||
581 | } | ||
582 | } else { | ||
583 | for (i = 0; i < numXpdGains; i++) { | ||
584 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
585 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
586 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
587 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
588 | |||
589 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
590 | |||
591 | maxPwrT4[i] = | ||
592 | min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], | ||
593 | pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); | ||
594 | |||
595 | |||
596 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
597 | pPwrL, pVpdL, | ||
598 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
599 | vpdTableL[i]); | ||
600 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
601 | pPwrR, pVpdR, | ||
602 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
603 | vpdTableR[i]); | ||
604 | |||
605 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
606 | vpdTableI[i][j] = | ||
607 | (u8)(ath9k_hw_interpolate((u16) | ||
608 | FREQ2FBIN(centers. | ||
609 | synth_center, | ||
610 | IS_CHAN_2GHZ | ||
611 | (chan)), | ||
612 | bChans[idxL], bChans[idxR], | ||
613 | vpdTableL[i][j], vpdTableR[i][j])); | ||
614 | } | ||
615 | } | ||
616 | } | ||
617 | |||
618 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
619 | |||
620 | k = 0; | ||
621 | |||
622 | for (i = 0; i < numXpdGains; i++) { | ||
623 | if (i == (numXpdGains - 1)) | ||
624 | pPdGainBoundaries[i] = | ||
625 | (u16)(maxPwrT4[i] / 2); | ||
626 | else | ||
627 | pPdGainBoundaries[i] = | ||
628 | (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); | ||
629 | |||
630 | pPdGainBoundaries[i] = | ||
631 | min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); | ||
632 | |||
633 | if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { | ||
634 | minDelta = pPdGainBoundaries[0] - 23; | ||
635 | pPdGainBoundaries[0] = 23; | ||
636 | } else { | ||
637 | minDelta = 0; | ||
638 | } | ||
639 | |||
640 | if (i == 0) { | ||
641 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
642 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
643 | else | ||
644 | ss = 0; | ||
645 | } else { | ||
646 | ss = (int16_t)((pPdGainBoundaries[i - 1] - | ||
647 | (minPwrT4[i] / 2)) - | ||
648 | tPdGainOverlap + 1 + minDelta); | ||
649 | } | ||
650 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
651 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
652 | |||
653 | while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
654 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
655 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
656 | ss++; | ||
657 | } | ||
658 | |||
659 | sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
660 | tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - | ||
661 | (minPwrT4[i] / 2)); | ||
662 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
663 | tgtIndex : sizeCurrVpdTable; | ||
664 | |||
665 | while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) | ||
666 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
667 | |||
668 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
669 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
670 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
671 | |||
672 | if (tgtIndex >= maxIndex) { | ||
673 | while ((ss <= tgtIndex) && | ||
674 | (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
675 | tmpVal = (int16_t) TMP_VAL_VPD_TABLE; | ||
676 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
677 | 255 : tmpVal); | ||
678 | ss++; | ||
679 | } | ||
680 | } | ||
681 | } | ||
682 | |||
683 | while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { | ||
684 | pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; | ||
685 | i++; | ||
686 | } | ||
687 | |||
688 | while (k < AR5416_NUM_PDADC_VALUES) { | ||
689 | pPDADCValues[k] = pPDADCValues[k - 1]; | ||
690 | k++; | ||
691 | } | ||
692 | |||
693 | return; | ||
694 | #undef TMP_VAL_VPD_TABLE | ||
695 | } | ||
696 | |||
697 | static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, | ||
698 | struct ath9k_channel *chan, | ||
699 | int16_t *pTxPowerIndexOffset) | ||
700 | { | ||
701 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
702 | struct cal_data_per_freq_4k *pRawDataset; | ||
703 | u8 *pCalBChans = NULL; | ||
704 | u16 pdGainOverlap_t2; | ||
705 | static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; | ||
706 | u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; | ||
707 | u16 numPiers, i, j; | ||
708 | int16_t tMinCalPower; | ||
709 | u16 numXpdGain, xpdMask; | ||
710 | u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; | ||
711 | u32 reg32, regOffset, regChainOffset; | ||
712 | |||
713 | xpdMask = pEepData->modalHeader.xpdGain; | ||
714 | |||
715 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
716 | AR5416_EEP_MINOR_VER_2) { | ||
717 | pdGainOverlap_t2 = | ||
718 | pEepData->modalHeader.pdGainOverlap; | ||
719 | } else { | ||
720 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
721 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
722 | } | ||
723 | |||
724 | pCalBChans = pEepData->calFreqPier2G; | ||
725 | numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; | ||
726 | |||
727 | numXpdGain = 0; | ||
728 | |||
729 | for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { | ||
730 | if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { | ||
731 | if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) | ||
732 | break; | ||
733 | xpdGainValues[numXpdGain] = | ||
734 | (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); | ||
735 | numXpdGain++; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
740 | (numXpdGain - 1) & 0x3); | ||
741 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
742 | xpdGainValues[0]); | ||
743 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
744 | xpdGainValues[1]); | ||
745 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); | ||
746 | |||
747 | for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { | ||
748 | if (AR_SREV_5416_20_OR_LATER(ah) && | ||
749 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && | ||
750 | (i != 0)) { | ||
751 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
752 | } else | ||
753 | regChainOffset = i * 0x1000; | ||
754 | |||
755 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
756 | pRawDataset = pEepData->calPierData2G[i]; | ||
757 | |||
758 | ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, | ||
759 | pRawDataset, pCalBChans, | ||
760 | numPiers, pdGainOverlap_t2, | ||
761 | &tMinCalPower, gainBoundaries, | ||
762 | pdadcValues, numXpdGain); | ||
763 | |||
764 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { | ||
765 | REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, | ||
766 | SM(pdGainOverlap_t2, | ||
767 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | ||
768 | | SM(gainBoundaries[0], | ||
769 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | ||
770 | | SM(gainBoundaries[1], | ||
771 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | ||
772 | | SM(gainBoundaries[2], | ||
773 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | ||
774 | | SM(gainBoundaries[3], | ||
775 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); | ||
776 | } | ||
777 | |||
778 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; | ||
779 | for (j = 0; j < 32; j++) { | ||
780 | reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | | ||
781 | ((pdadcValues[4 * j + 1] & 0xFF) << 8) | | ||
782 | ((pdadcValues[4 * j + 2] & 0xFF) << 16)| | ||
783 | ((pdadcValues[4 * j + 3] & 0xFF) << 24); | ||
784 | REG_WRITE(ah, regOffset, reg32); | ||
785 | |||
786 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
787 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
788 | i, regChainOffset, regOffset, | ||
789 | reg32); | ||
790 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
791 | "PDADC: Chain %d | " | ||
792 | "PDADC %3d Value %3d | " | ||
793 | "PDADC %3d Value %3d | " | ||
794 | "PDADC %3d Value %3d | " | ||
795 | "PDADC %3d Value %3d |\n", | ||
796 | i, 4 * j, pdadcValues[4 * j], | ||
797 | 4 * j + 1, pdadcValues[4 * j + 1], | ||
798 | 4 * j + 2, pdadcValues[4 * j + 2], | ||
799 | 4 * j + 3, | ||
800 | pdadcValues[4 * j + 3]); | ||
801 | |||
802 | regOffset += 4; | ||
803 | } | ||
804 | } | ||
805 | } | ||
806 | |||
807 | *pTxPowerIndexOffset = 0; | ||
808 | |||
809 | return true; | ||
810 | } | ||
811 | |||
812 | static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, | ||
813 | struct ath9k_channel *chan, | ||
814 | int16_t *ratesArray, | ||
815 | u16 cfgCtl, | ||
816 | u16 AntennaReduction, | ||
817 | u16 twiceMaxRegulatoryPower, | ||
818 | u16 powerLimit) | ||
819 | { | ||
820 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
821 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
822 | static const u16 tpScaleReductionTable[5] = | ||
823 | { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; | ||
824 | |||
825 | int i; | ||
826 | int16_t twiceLargestAntenna; | ||
827 | struct cal_ctl_data_4k *rep; | ||
828 | struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { | ||
829 | 0, { 0, 0, 0, 0} | ||
830 | }; | ||
831 | struct cal_target_power_leg targetPowerOfdmExt = { | ||
832 | 0, { 0, 0, 0, 0} }, targetPowerCckExt = { | ||
833 | 0, { 0, 0, 0, 0 } | ||
834 | }; | ||
835 | struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { | ||
836 | 0, {0, 0, 0, 0} | ||
837 | }; | ||
838 | u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
839 | u16 ctlModesFor11g[] = | ||
840 | { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, | ||
841 | CTL_2GHT40 | ||
842 | }; | ||
843 | u16 numCtlModes, *pCtlMode, ctlMode, freq; | ||
844 | struct chan_centers centers; | ||
845 | int tx_chainmask; | ||
846 | u16 twiceMinEdgePower; | ||
847 | |||
848 | tx_chainmask = ah->txchainmask; | ||
849 | |||
850 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
851 | |||
852 | twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; | ||
853 | |||
854 | twiceLargestAntenna = (int16_t)min(AntennaReduction - | ||
855 | twiceLargestAntenna, 0); | ||
856 | |||
857 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
858 | |||
859 | if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { | ||
860 | maxRegAllowedPower -= | ||
861 | (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); | ||
862 | } | ||
863 | |||
864 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
865 | scaledPower = max((u16)0, scaledPower); | ||
866 | |||
867 | numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; | ||
868 | pCtlMode = ctlModesFor11g; | ||
869 | |||
870 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
871 | pEepData->calTargetPowerCck, | ||
872 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
873 | &targetPowerCck, 4, false); | ||
874 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
875 | pEepData->calTargetPower2G, | ||
876 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
877 | &targetPowerOfdm, 4, false); | ||
878 | ath9k_hw_get_target_powers(ah, chan, | ||
879 | pEepData->calTargetPower2GHT20, | ||
880 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
881 | &targetPowerHt20, 8, false); | ||
882 | |||
883 | if (IS_CHAN_HT40(chan)) { | ||
884 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
885 | ath9k_hw_get_target_powers(ah, chan, | ||
886 | pEepData->calTargetPower2GHT40, | ||
887 | AR5416_NUM_2G_40_TARGET_POWERS, | ||
888 | &targetPowerHt40, 8, true); | ||
889 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
890 | pEepData->calTargetPowerCck, | ||
891 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
892 | &targetPowerCckExt, 4, true); | ||
893 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
894 | pEepData->calTargetPower2G, | ||
895 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
896 | &targetPowerOfdmExt, 4, true); | ||
897 | } | ||
898 | |||
899 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
900 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
901 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
902 | if (isHt40CtlMode) | ||
903 | freq = centers.synth_center; | ||
904 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
905 | freq = centers.ext_center; | ||
906 | else | ||
907 | freq = centers.ctl_center; | ||
908 | |||
909 | if (ah->eep_ops->get_eeprom_ver(ah) == 14 && | ||
910 | ah->eep_ops->get_eeprom_rev(ah) <= 2) | ||
911 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
912 | |||
913 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
914 | "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " | ||
915 | "EXT_ADDITIVE %d\n", | ||
916 | ctlMode, numCtlModes, isHt40CtlMode, | ||
917 | (pCtlMode[ctlMode] & EXT_ADDITIVE)); | ||
918 | |||
919 | for (i = 0; (i < AR5416_NUM_CTLS) && | ||
920 | pEepData->ctlIndex[i]; i++) { | ||
921 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
922 | " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " | ||
923 | "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " | ||
924 | "chan %d\n", | ||
925 | i, cfgCtl, pCtlMode[ctlMode], | ||
926 | pEepData->ctlIndex[i], chan->channel); | ||
927 | |||
928 | if ((((cfgCtl & ~CTL_MODE_M) | | ||
929 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
930 | pEepData->ctlIndex[i]) || | ||
931 | (((cfgCtl & ~CTL_MODE_M) | | ||
932 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
933 | ((pEepData->ctlIndex[i] & CTL_MODE_M) | | ||
934 | SD_NO_CTL))) { | ||
935 | rep = &(pEepData->ctlData[i]); | ||
936 | |||
937 | twiceMinEdgePower = | ||
938 | ath9k_hw_get_max_edge_power(freq, | ||
939 | rep->ctlEdges[ar5416_get_ntxchains | ||
940 | (tx_chainmask) - 1], | ||
941 | IS_CHAN_2GHZ(chan), | ||
942 | AR5416_EEP4K_NUM_BAND_EDGES); | ||
943 | |||
944 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
945 | " MATCH-EE_IDX %d: ch %d is2 %d " | ||
946 | "2xMinEdge %d chainmask %d chains %d\n", | ||
947 | i, freq, IS_CHAN_2GHZ(chan), | ||
948 | twiceMinEdgePower, tx_chainmask, | ||
949 | ar5416_get_ntxchains | ||
950 | (tx_chainmask)); | ||
951 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { | ||
952 | twiceMaxEdgePower = | ||
953 | min(twiceMaxEdgePower, | ||
954 | twiceMinEdgePower); | ||
955 | } else { | ||
956 | twiceMaxEdgePower = twiceMinEdgePower; | ||
957 | break; | ||
958 | } | ||
959 | } | ||
960 | } | ||
961 | |||
962 | minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); | ||
963 | |||
964 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
965 | " SEL-Min ctlMode %d pCtlMode %d " | ||
966 | "2xMaxEdge %d sP %d minCtlPwr %d\n", | ||
967 | ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, | ||
968 | scaledPower, minCtlPower); | ||
969 | |||
970 | switch (pCtlMode[ctlMode]) { | ||
971 | case CTL_11B: | ||
972 | for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); | ||
973 | i++) { | ||
974 | targetPowerCck.tPow2x[i] = | ||
975 | min((u16)targetPowerCck.tPow2x[i], | ||
976 | minCtlPower); | ||
977 | } | ||
978 | break; | ||
979 | case CTL_11G: | ||
980 | for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); | ||
981 | i++) { | ||
982 | targetPowerOfdm.tPow2x[i] = | ||
983 | min((u16)targetPowerOfdm.tPow2x[i], | ||
984 | minCtlPower); | ||
985 | } | ||
986 | break; | ||
987 | case CTL_2GHT20: | ||
988 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); | ||
989 | i++) { | ||
990 | targetPowerHt20.tPow2x[i] = | ||
991 | min((u16)targetPowerHt20.tPow2x[i], | ||
992 | minCtlPower); | ||
993 | } | ||
994 | break; | ||
995 | case CTL_11B_EXT: | ||
996 | targetPowerCckExt.tPow2x[0] = min((u16) | ||
997 | targetPowerCckExt.tPow2x[0], | ||
998 | minCtlPower); | ||
999 | break; | ||
1000 | case CTL_11G_EXT: | ||
1001 | targetPowerOfdmExt.tPow2x[0] = min((u16) | ||
1002 | targetPowerOfdmExt.tPow2x[0], | ||
1003 | minCtlPower); | ||
1004 | break; | ||
1005 | case CTL_2GHT40: | ||
1006 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); | ||
1007 | i++) { | ||
1008 | targetPowerHt40.tPow2x[i] = | ||
1009 | min((u16)targetPowerHt40.tPow2x[i], | ||
1010 | minCtlPower); | ||
1011 | } | ||
1012 | break; | ||
1013 | default: | ||
1014 | break; | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = | ||
1019 | ratesArray[rate18mb] = ratesArray[rate24mb] = | ||
1020 | targetPowerOfdm.tPow2x[0]; | ||
1021 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
1022 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
1023 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
1024 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
1025 | |||
1026 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
1027 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
1028 | |||
1029 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
1030 | ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; | ||
1031 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; | ||
1032 | ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; | ||
1033 | |||
1034 | if (IS_CHAN_HT40(chan)) { | ||
1035 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
1036 | ratesArray[rateHt40_0 + i] = | ||
1037 | targetPowerHt40.tPow2x[i]; | ||
1038 | } | ||
1039 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
1040 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
1041 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
1042 | ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; | ||
1043 | } | ||
1044 | return true; | ||
1045 | } | ||
1046 | |||
1047 | static int ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ||
1048 | struct ath9k_channel *chan, | ||
1049 | u16 cfgCtl, | ||
1050 | u8 twiceAntennaReduction, | ||
1051 | u8 twiceMaxRegulatoryPower, | ||
1052 | u8 powerLimit) | ||
1053 | { | ||
1054 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
1055 | struct modal_eep_4k_header *pModal = &pEepData->modalHeader; | ||
1056 | int16_t ratesArray[Ar5416RateSize]; | ||
1057 | int16_t txPowerIndexOffset = 0; | ||
1058 | u8 ht40PowerIncForPdadc = 2; | ||
1059 | int i; | ||
1060 | |||
1061 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
1062 | |||
1063 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1064 | AR5416_EEP_MINOR_VER_2) { | ||
1065 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
1066 | } | ||
1067 | |||
1068 | if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan, | ||
1069 | &ratesArray[0], cfgCtl, | ||
1070 | twiceAntennaReduction, | ||
1071 | twiceMaxRegulatoryPower, | ||
1072 | powerLimit)) { | ||
1073 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
1074 | "ath9k_hw_set_txpower: unable to set " | ||
1075 | "tx power per rate table\n"); | ||
1076 | return -EIO; | ||
1077 | } | ||
1078 | |||
1079 | if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) { | ||
1080 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
1081 | "ath9k_hw_set_txpower: unable to set power table\n"); | ||
1082 | return -EIO; | ||
1083 | } | ||
1084 | |||
1085 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
1086 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
1087 | if (ratesArray[i] > AR5416_MAX_RATE_POWER) | ||
1088 | ratesArray[i] = AR5416_MAX_RATE_POWER; | ||
1089 | } | ||
1090 | |||
1091 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1092 | for (i = 0; i < Ar5416RateSize; i++) | ||
1093 | ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; | ||
1094 | } | ||
1095 | |||
1096 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
1097 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
1098 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
1099 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
1100 | | ATH9K_POW_SM(ratesArray[rate6mb], 0)); | ||
1101 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
1102 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
1103 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
1104 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
1105 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | ||
1106 | |||
1107 | if (IS_CHAN_2GHZ(chan)) { | ||
1108 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
1109 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
1110 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
1111 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
1112 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
1113 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
1114 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
1115 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
1116 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
1117 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
1118 | } | ||
1119 | |||
1120 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
1121 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
1122 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
1123 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
1124 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); | ||
1125 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
1126 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
1127 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
1128 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
1129 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); | ||
1130 | |||
1131 | if (IS_CHAN_HT40(chan)) { | ||
1132 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
1133 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
1134 | ht40PowerIncForPdadc, 24) | ||
1135 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
1136 | ht40PowerIncForPdadc, 16) | ||
1137 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
1138 | ht40PowerIncForPdadc, 8) | ||
1139 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
1140 | ht40PowerIncForPdadc, 0)); | ||
1141 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
1142 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
1143 | ht40PowerIncForPdadc, 24) | ||
1144 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
1145 | ht40PowerIncForPdadc, 16) | ||
1146 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
1147 | ht40PowerIncForPdadc, 8) | ||
1148 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
1149 | ht40PowerIncForPdadc, 0)); | ||
1150 | |||
1151 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
1152 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
1153 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
1154 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
1155 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
1156 | } | ||
1157 | |||
1158 | i = rate6mb; | ||
1159 | |||
1160 | if (IS_CHAN_HT40(chan)) | ||
1161 | i = rateHt40_0; | ||
1162 | else if (IS_CHAN_HT20(chan)) | ||
1163 | i = rateHt20_0; | ||
1164 | |||
1165 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
1166 | ah->regulatory.max_power_level = | ||
1167 | ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; | ||
1168 | else | ||
1169 | ah->regulatory.max_power_level = ratesArray[i]; | ||
1170 | |||
1171 | return 0; | ||
1172 | } | ||
1173 | |||
1174 | static void ath9k_hw_4k_set_addac(struct ath_hw *ah, | ||
1175 | struct ath9k_channel *chan) | ||
1176 | { | ||
1177 | struct modal_eep_4k_header *pModal; | ||
1178 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
1179 | u8 biaslevel; | ||
1180 | |||
1181 | if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) | ||
1182 | return; | ||
1183 | |||
1184 | if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) | ||
1185 | return; | ||
1186 | |||
1187 | pModal = &eep->modalHeader; | ||
1188 | |||
1189 | if (pModal->xpaBiasLvl != 0xff) { | ||
1190 | biaslevel = pModal->xpaBiasLvl; | ||
1191 | INI_RA(&ah->iniAddac, 7, 1) = | ||
1192 | (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; | ||
1193 | } | ||
1194 | } | ||
1195 | |||
1196 | static void ath9k_hw_4k_set_gain(struct ath_hw *ah, | ||
1197 | struct modal_eep_4k_header *pModal, | ||
1198 | struct ar5416_eeprom_4k *eep, | ||
1199 | u8 txRxAttenLocal, int regChainOffset) | ||
1200 | { | ||
1201 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, | ||
1202 | pModal->antCtrlChain[0]); | ||
1203 | |||
1204 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | ||
1205 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & | ||
1206 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
1207 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
1208 | SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
1209 | SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
1210 | |||
1211 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1212 | AR5416_EEP_MINOR_VER_3) { | ||
1213 | txRxAttenLocal = pModal->txRxAttenCh[0]; | ||
1214 | |||
1215 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1216 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); | ||
1217 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1218 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); | ||
1219 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1220 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
1221 | pModal->xatten2Margin[0]); | ||
1222 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1223 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); | ||
1224 | } | ||
1225 | |||
1226 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | ||
1227 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
1228 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | ||
1229 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); | ||
1230 | |||
1231 | if (AR_SREV_9285_11(ah)) | ||
1232 | REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); | ||
1233 | } | ||
1234 | |||
1235 | static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, | ||
1236 | struct ath9k_channel *chan) | ||
1237 | { | ||
1238 | struct modal_eep_4k_header *pModal; | ||
1239 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
1240 | u8 txRxAttenLocal; | ||
1241 | u8 ob[5], db1[5], db2[5]; | ||
1242 | u8 ant_div_control1, ant_div_control2; | ||
1243 | u32 regVal; | ||
1244 | |||
1245 | pModal = &eep->modalHeader; | ||
1246 | txRxAttenLocal = 23; | ||
1247 | |||
1248 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
1249 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
1250 | |||
1251 | /* Single chain for 4K EEPROM*/ | ||
1252 | ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); | ||
1253 | |||
1254 | /* Initialize Ant Diversity settings from EEPROM */ | ||
1255 | if (pModal->version == 3) { | ||
1256 | ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); | ||
1257 | ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); | ||
1258 | regVal = REG_READ(ah, 0x99ac); | ||
1259 | regVal &= (~(0x7f000000)); | ||
1260 | regVal |= ((ant_div_control1 & 0x1) << 24); | ||
1261 | regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); | ||
1262 | regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); | ||
1263 | regVal |= ((ant_div_control2 & 0x3) << 25); | ||
1264 | regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); | ||
1265 | REG_WRITE(ah, 0x99ac, regVal); | ||
1266 | regVal = REG_READ(ah, 0x99ac); | ||
1267 | regVal = REG_READ(ah, 0xa208); | ||
1268 | regVal &= (~(0x1 << 13)); | ||
1269 | regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); | ||
1270 | REG_WRITE(ah, 0xa208, regVal); | ||
1271 | regVal = REG_READ(ah, 0xa208); | ||
1272 | } | ||
1273 | |||
1274 | if (pModal->version >= 2) { | ||
1275 | ob[0] = (pModal->ob_01 & 0xf); | ||
1276 | ob[1] = (pModal->ob_01 >> 4) & 0xf; | ||
1277 | ob[2] = (pModal->ob_234 & 0xf); | ||
1278 | ob[3] = ((pModal->ob_234 >> 4) & 0xf); | ||
1279 | ob[4] = ((pModal->ob_234 >> 8) & 0xf); | ||
1280 | |||
1281 | db1[0] = (pModal->db1_01 & 0xf); | ||
1282 | db1[1] = ((pModal->db1_01 >> 4) & 0xf); | ||
1283 | db1[2] = (pModal->db1_234 & 0xf); | ||
1284 | db1[3] = ((pModal->db1_234 >> 4) & 0xf); | ||
1285 | db1[4] = ((pModal->db1_234 >> 8) & 0xf); | ||
1286 | |||
1287 | db2[0] = (pModal->db2_01 & 0xf); | ||
1288 | db2[1] = ((pModal->db2_01 >> 4) & 0xf); | ||
1289 | db2[2] = (pModal->db2_234 & 0xf); | ||
1290 | db2[3] = ((pModal->db2_234 >> 4) & 0xf); | ||
1291 | db2[4] = ((pModal->db2_234 >> 8) & 0xf); | ||
1292 | |||
1293 | } else if (pModal->version == 1) { | ||
1294 | ob[0] = (pModal->ob_01 & 0xf); | ||
1295 | ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; | ||
1296 | db1[0] = (pModal->db1_01 & 0xf); | ||
1297 | db1[1] = db1[2] = db1[3] = | ||
1298 | db1[4] = ((pModal->db1_01 >> 4) & 0xf); | ||
1299 | db2[0] = (pModal->db2_01 & 0xf); | ||
1300 | db2[1] = db2[2] = db2[3] = | ||
1301 | db2[4] = ((pModal->db2_01 >> 4) & 0xf); | ||
1302 | } else { | ||
1303 | int i; | ||
1304 | for (i = 0; i < 5; i++) { | ||
1305 | ob[i] = pModal->ob_01; | ||
1306 | db1[i] = pModal->db1_01; | ||
1307 | db2[i] = pModal->db1_01; | ||
1308 | } | ||
1309 | } | ||
1310 | |||
1311 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, | ||
1312 | AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]); | ||
1313 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, | ||
1314 | AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]); | ||
1315 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, | ||
1316 | AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]); | ||
1317 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, | ||
1318 | AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]); | ||
1319 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, | ||
1320 | AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]); | ||
1321 | |||
1322 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, | ||
1323 | AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]); | ||
1324 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, | ||
1325 | AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]); | ||
1326 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, | ||
1327 | AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]); | ||
1328 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, | ||
1329 | AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]); | ||
1330 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, | ||
1331 | AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]); | ||
1332 | |||
1333 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, | ||
1334 | AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]); | ||
1335 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, | ||
1336 | AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]); | ||
1337 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, | ||
1338 | AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]); | ||
1339 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, | ||
1340 | AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]); | ||
1341 | ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, | ||
1342 | AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]); | ||
1343 | |||
1344 | |||
1345 | if (AR_SREV_9285_11(ah)) | ||
1346 | REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); | ||
1347 | |||
1348 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, | ||
1349 | pModal->switchSettling); | ||
1350 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, | ||
1351 | pModal->adcDesiredSize); | ||
1352 | |||
1353 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
1354 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | | ||
1355 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | | ||
1356 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | | ||
1357 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
1358 | |||
1359 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, | ||
1360 | pModal->txEndToRxOn); | ||
1361 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, | ||
1362 | pModal->thresh62); | ||
1363 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, | ||
1364 | pModal->thresh62); | ||
1365 | |||
1366 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1367 | AR5416_EEP_MINOR_VER_2) { | ||
1368 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, | ||
1369 | pModal->txFrameToDataStart); | ||
1370 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, | ||
1371 | pModal->txFrameToPaOn); | ||
1372 | } | ||
1373 | |||
1374 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1375 | AR5416_EEP_MINOR_VER_3) { | ||
1376 | if (IS_CHAN_HT40(chan)) | ||
1377 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1378 | AR_PHY_SETTLING_SWITCH, | ||
1379 | pModal->swSettleHt40); | ||
1380 | } | ||
1381 | } | ||
1382 | |||
1383 | static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, | ||
1384 | struct ath9k_channel *chan) | ||
1385 | { | ||
1386 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
1387 | struct modal_eep_4k_header *pModal = &eep->modalHeader; | ||
1388 | |||
1389 | return pModal->antCtrlCommon & 0xFFFF; | ||
1390 | } | ||
1391 | |||
1392 | static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, | ||
1393 | enum ieee80211_band freq_band) | ||
1394 | { | ||
1395 | return 1; | ||
1396 | } | ||
1397 | |||
1398 | static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) | ||
1399 | { | ||
1400 | #define EEP_MAP4K_SPURCHAN \ | ||
1401 | (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) | ||
1402 | |||
1403 | u16 spur_val = AR_NO_SPUR; | ||
1404 | |||
1405 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1406 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
1407 | i, is2GHz, ah->config.spurchans[i][is2GHz]); | ||
1408 | |||
1409 | switch (ah->config.spurmode) { | ||
1410 | case SPUR_DISABLE: | ||
1411 | break; | ||
1412 | case SPUR_ENABLE_IOCTL: | ||
1413 | spur_val = ah->config.spurchans[i][is2GHz]; | ||
1414 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1415 | "Getting spur val from new loc. %d\n", spur_val); | ||
1416 | break; | ||
1417 | case SPUR_ENABLE_EEPROM: | ||
1418 | spur_val = EEP_MAP4K_SPURCHAN; | ||
1419 | break; | ||
1420 | } | ||
1421 | |||
1422 | return spur_val; | ||
1423 | |||
1424 | #undef EEP_MAP4K_SPURCHAN | ||
1425 | } | ||
1426 | |||
1427 | static struct eeprom_ops eep_4k_ops = { | ||
1428 | .check_eeprom = ath9k_hw_4k_check_eeprom, | ||
1429 | .get_eeprom = ath9k_hw_4k_get_eeprom, | ||
1430 | .fill_eeprom = ath9k_hw_4k_fill_eeprom, | ||
1431 | .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, | ||
1432 | .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, | ||
1433 | .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, | ||
1434 | .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, | ||
1435 | .set_board_values = ath9k_hw_4k_set_board_values, | ||
1436 | .set_addac = ath9k_hw_4k_set_addac, | ||
1437 | .set_txpower = ath9k_hw_4k_set_txpower, | ||
1438 | .get_spur_channel = ath9k_hw_4k_get_spur_channel | ||
1439 | }; | ||
1440 | |||
1441 | /************************************************/ | ||
1442 | /* EEPROM Operations for non-4K (Default) cards */ | ||
1443 | /************************************************/ | ||
1444 | |||
1445 | static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) | ||
1446 | { | ||
1447 | return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); | ||
1448 | } | ||
1449 | |||
1450 | static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) | ||
1451 | { | ||
1452 | return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); | ||
1453 | } | ||
1454 | |||
1455 | static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) | ||
1456 | { | ||
1457 | #define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) | ||
1458 | u16 *eep_data = (u16 *)&ah->eeprom.def; | ||
1459 | int addr, ar5416_eep_start_loc = 0x100; | ||
1460 | |||
1461 | for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { | ||
1462 | if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, | ||
1463 | eep_data)) { | ||
1464 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
1465 | "Unable to read eeprom region\n"); | ||
1466 | return false; | ||
1467 | } | ||
1468 | eep_data++; | ||
1469 | } | ||
1470 | return true; | ||
1471 | #undef SIZE_EEPROM_DEF | ||
1472 | } | ||
1473 | |||
1474 | static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) | ||
1475 | { | ||
1476 | struct ar5416_eeprom_def *eep = | ||
1477 | (struct ar5416_eeprom_def *) &ah->eeprom.def; | ||
1478 | u16 *eepdata, temp, magic, magic2; | ||
1479 | u32 sum = 0, el; | ||
1480 | bool need_swap = false; | ||
1481 | int i, addr, size; | ||
1482 | |||
1483 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { | ||
1484 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); | ||
1485 | return false; | ||
1486 | } | ||
1487 | |||
1488 | if (!ath9k_hw_use_flash(ah)) { | ||
1489 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
1490 | "Read Magic = 0x%04X\n", magic); | ||
1491 | |||
1492 | if (magic != AR5416_EEPROM_MAGIC) { | ||
1493 | magic2 = swab16(magic); | ||
1494 | |||
1495 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
1496 | size = sizeof(struct ar5416_eeprom_def); | ||
1497 | need_swap = true; | ||
1498 | eepdata = (u16 *) (&ah->eeprom); | ||
1499 | |||
1500 | for (addr = 0; addr < size / sizeof(u16); addr++) { | ||
1501 | temp = swab16(*eepdata); | ||
1502 | *eepdata = temp; | ||
1503 | eepdata++; | ||
1504 | } | ||
1505 | } else { | ||
1506 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
1507 | "Invalid EEPROM Magic. " | ||
1508 | "Endianness mismatch.\n"); | ||
1509 | return -EINVAL; | ||
1510 | } | ||
1511 | } | ||
1512 | } | ||
1513 | |||
1514 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", | ||
1515 | need_swap ? "True" : "False"); | ||
1516 | |||
1517 | if (need_swap) | ||
1518 | el = swab16(ah->eeprom.def.baseEepHeader.length); | ||
1519 | else | ||
1520 | el = ah->eeprom.def.baseEepHeader.length; | ||
1521 | |||
1522 | if (el > sizeof(struct ar5416_eeprom_def)) | ||
1523 | el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); | ||
1524 | else | ||
1525 | el = el / sizeof(u16); | ||
1526 | |||
1527 | eepdata = (u16 *)(&ah->eeprom); | ||
1528 | |||
1529 | for (i = 0; i < el; i++) | ||
1530 | sum ^= *eepdata++; | ||
1531 | |||
1532 | if (need_swap) { | ||
1533 | u32 integer, j; | ||
1534 | u16 word; | ||
1535 | |||
1536 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
1537 | "EEPROM Endianness is not native.. Changing.\n"); | ||
1538 | |||
1539 | word = swab16(eep->baseEepHeader.length); | ||
1540 | eep->baseEepHeader.length = word; | ||
1541 | |||
1542 | word = swab16(eep->baseEepHeader.checksum); | ||
1543 | eep->baseEepHeader.checksum = word; | ||
1544 | |||
1545 | word = swab16(eep->baseEepHeader.version); | ||
1546 | eep->baseEepHeader.version = word; | ||
1547 | |||
1548 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
1549 | eep->baseEepHeader.regDmn[0] = word; | ||
1550 | |||
1551 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
1552 | eep->baseEepHeader.regDmn[1] = word; | ||
1553 | |||
1554 | word = swab16(eep->baseEepHeader.rfSilent); | ||
1555 | eep->baseEepHeader.rfSilent = word; | ||
1556 | |||
1557 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
1558 | eep->baseEepHeader.blueToothOptions = word; | ||
1559 | |||
1560 | word = swab16(eep->baseEepHeader.deviceCap); | ||
1561 | eep->baseEepHeader.deviceCap = word; | ||
1562 | |||
1563 | for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { | ||
1564 | struct modal_eep_header *pModal = | ||
1565 | &eep->modalHeader[j]; | ||
1566 | integer = swab32(pModal->antCtrlCommon); | ||
1567 | pModal->antCtrlCommon = integer; | ||
1568 | |||
1569 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
1570 | integer = swab32(pModal->antCtrlChain[i]); | ||
1571 | pModal->antCtrlChain[i] = integer; | ||
1572 | } | ||
1573 | |||
1574 | for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { | ||
1575 | word = swab16(pModal->spurChans[i].spurChan); | ||
1576 | pModal->spurChans[i].spurChan = word; | ||
1577 | } | ||
1578 | } | ||
1579 | } | ||
1580 | |||
1581 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || | ||
1582 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | ||
1583 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
1584 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
1585 | sum, ah->eep_ops->get_eeprom_ver(ah)); | ||
1586 | return -EINVAL; | ||
1587 | } | ||
1588 | |||
1589 | return 0; | ||
1590 | } | ||
1591 | |||
1592 | static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, | ||
1593 | enum eeprom_param param) | ||
1594 | { | ||
1595 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
1596 | struct modal_eep_header *pModal = eep->modalHeader; | ||
1597 | struct base_eep_header *pBase = &eep->baseEepHeader; | ||
1598 | |||
1599 | switch (param) { | ||
1600 | case EEP_NFTHRESH_5: | ||
1601 | return pModal[0].noiseFloorThreshCh[0]; | ||
1602 | case EEP_NFTHRESH_2: | ||
1603 | return pModal[1].noiseFloorThreshCh[0]; | ||
1604 | case AR_EEPROM_MAC(0): | ||
1605 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
1606 | case AR_EEPROM_MAC(1): | ||
1607 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
1608 | case AR_EEPROM_MAC(2): | ||
1609 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
1610 | case EEP_REG_0: | ||
1611 | return pBase->regDmn[0]; | ||
1612 | case EEP_REG_1: | ||
1613 | return pBase->regDmn[1]; | ||
1614 | case EEP_OP_CAP: | ||
1615 | return pBase->deviceCap; | ||
1616 | case EEP_OP_MODE: | ||
1617 | return pBase->opCapFlags; | ||
1618 | case EEP_RF_SILENT: | ||
1619 | return pBase->rfSilent; | ||
1620 | case EEP_OB_5: | ||
1621 | return pModal[0].ob; | ||
1622 | case EEP_DB_5: | ||
1623 | return pModal[0].db; | ||
1624 | case EEP_OB_2: | ||
1625 | return pModal[1].ob; | ||
1626 | case EEP_DB_2: | ||
1627 | return pModal[1].db; | ||
1628 | case EEP_MINOR_REV: | ||
1629 | return AR5416_VER_MASK; | ||
1630 | case EEP_TX_MASK: | ||
1631 | return pBase->txMask; | ||
1632 | case EEP_RX_MASK: | ||
1633 | return pBase->rxMask; | ||
1634 | case EEP_RXGAIN_TYPE: | ||
1635 | return pBase->rxGainType; | ||
1636 | case EEP_TXGAIN_TYPE: | ||
1637 | return pBase->txGainType; | ||
1638 | case EEP_OL_PWRCTRL: | ||
1639 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1640 | return pBase->openLoopPwrCntl ? true : false; | ||
1641 | else | ||
1642 | return false; | ||
1643 | case EEP_RC_CHAIN_MASK: | ||
1644 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1645 | return pBase->rcChainMask; | ||
1646 | else | ||
1647 | return 0; | ||
1648 | case EEP_DAC_HPWR_5G: | ||
1649 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) | ||
1650 | return pBase->dacHiPwrMode_5G; | ||
1651 | else | ||
1652 | return 0; | ||
1653 | case EEP_FRAC_N_5G: | ||
1654 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) | ||
1655 | return pBase->frac_n_5g; | ||
1656 | else | ||
1657 | return 0; | ||
1658 | default: | ||
1659 | return 0; | ||
1660 | } | ||
1661 | } | ||
1662 | |||
1663 | static void ath9k_hw_def_set_gain(struct ath_hw *ah, | ||
1664 | struct modal_eep_header *pModal, | ||
1665 | struct ar5416_eeprom_def *eep, | ||
1666 | u8 txRxAttenLocal, int regChainOffset, int i) | ||
1667 | { | ||
1668 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { | ||
1669 | txRxAttenLocal = pModal->txRxAttenCh[i]; | ||
1670 | |||
1671 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1672 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1673 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
1674 | pModal->bswMargin[i]); | ||
1675 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1676 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, | ||
1677 | pModal->bswAtten[i]); | ||
1678 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1679 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
1680 | pModal->xatten2Margin[i]); | ||
1681 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1682 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, | ||
1683 | pModal->xatten2Db[i]); | ||
1684 | } else { | ||
1685 | REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1686 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
1687 | ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | ||
1688 | | SM(pModal-> bswMargin[i], | ||
1689 | AR_PHY_GAIN_2GHZ_BSW_MARGIN)); | ||
1690 | REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1691 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
1692 | ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | ||
1693 | | SM(pModal->bswAtten[i], | ||
1694 | AR_PHY_GAIN_2GHZ_BSW_ATTEN)); | ||
1695 | } | ||
1696 | } | ||
1697 | |||
1698 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1699 | REG_RMW_FIELD(ah, | ||
1700 | AR_PHY_RXGAIN + regChainOffset, | ||
1701 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
1702 | REG_RMW_FIELD(ah, | ||
1703 | AR_PHY_RXGAIN + regChainOffset, | ||
1704 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); | ||
1705 | } else { | ||
1706 | REG_WRITE(ah, | ||
1707 | AR_PHY_RXGAIN + regChainOffset, | ||
1708 | (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & | ||
1709 | ~AR_PHY_RXGAIN_TXRX_ATTEN) | ||
1710 | | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); | ||
1711 | REG_WRITE(ah, | ||
1712 | AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1713 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
1714 | ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | | ||
1715 | SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); | ||
1716 | } | ||
1717 | } | ||
1718 | |||
1719 | static void ath9k_hw_def_set_board_values(struct ath_hw *ah, | ||
1720 | struct ath9k_channel *chan) | ||
1721 | { | ||
1722 | struct modal_eep_header *pModal; | ||
1723 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
1724 | int i, regChainOffset; | ||
1725 | u8 txRxAttenLocal; | ||
1726 | |||
1727 | pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
1728 | txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; | ||
1729 | |||
1730 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
1731 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
1732 | |||
1733 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
1734 | if (AR_SREV_9280(ah)) { | ||
1735 | if (i >= 2) | ||
1736 | break; | ||
1737 | } | ||
1738 | |||
1739 | if (AR_SREV_5416_20_OR_LATER(ah) && | ||
1740 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) | ||
1741 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
1742 | else | ||
1743 | regChainOffset = i * 0x1000; | ||
1744 | |||
1745 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, | ||
1746 | pModal->antCtrlChain[i]); | ||
1747 | |||
1748 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | ||
1749 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & | ||
1750 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
1751 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
1752 | SM(pModal->iqCalICh[i], | ||
1753 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
1754 | SM(pModal->iqCalQCh[i], | ||
1755 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
1756 | |||
1757 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) | ||
1758 | ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, | ||
1759 | regChainOffset, i); | ||
1760 | } | ||
1761 | |||
1762 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1763 | if (IS_CHAN_2GHZ(chan)) { | ||
1764 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, | ||
1765 | AR_AN_RF2G1_CH0_OB, | ||
1766 | AR_AN_RF2G1_CH0_OB_S, | ||
1767 | pModal->ob); | ||
1768 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, | ||
1769 | AR_AN_RF2G1_CH0_DB, | ||
1770 | AR_AN_RF2G1_CH0_DB_S, | ||
1771 | pModal->db); | ||
1772 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, | ||
1773 | AR_AN_RF2G1_CH1_OB, | ||
1774 | AR_AN_RF2G1_CH1_OB_S, | ||
1775 | pModal->ob_ch1); | ||
1776 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, | ||
1777 | AR_AN_RF2G1_CH1_DB, | ||
1778 | AR_AN_RF2G1_CH1_DB_S, | ||
1779 | pModal->db_ch1); | ||
1780 | } else { | ||
1781 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, | ||
1782 | AR_AN_RF5G1_CH0_OB5, | ||
1783 | AR_AN_RF5G1_CH0_OB5_S, | ||
1784 | pModal->ob); | ||
1785 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, | ||
1786 | AR_AN_RF5G1_CH0_DB5, | ||
1787 | AR_AN_RF5G1_CH0_DB5_S, | ||
1788 | pModal->db); | ||
1789 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, | ||
1790 | AR_AN_RF5G1_CH1_OB5, | ||
1791 | AR_AN_RF5G1_CH1_OB5_S, | ||
1792 | pModal->ob_ch1); | ||
1793 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, | ||
1794 | AR_AN_RF5G1_CH1_DB5, | ||
1795 | AR_AN_RF5G1_CH1_DB5_S, | ||
1796 | pModal->db_ch1); | ||
1797 | } | ||
1798 | ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, | ||
1799 | AR_AN_TOP2_XPABIAS_LVL, | ||
1800 | AR_AN_TOP2_XPABIAS_LVL_S, | ||
1801 | pModal->xpaBiasLvl); | ||
1802 | ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, | ||
1803 | AR_AN_TOP2_LOCALBIAS, | ||
1804 | AR_AN_TOP2_LOCALBIAS_S, | ||
1805 | pModal->local_bias); | ||
1806 | REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, | ||
1807 | pModal->force_xpaon); | ||
1808 | } | ||
1809 | |||
1810 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, | ||
1811 | pModal->switchSettling); | ||
1812 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, | ||
1813 | pModal->adcDesiredSize); | ||
1814 | |||
1815 | if (!AR_SREV_9280_10_OR_LATER(ah)) | ||
1816 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, | ||
1817 | AR_PHY_DESIRED_SZ_PGA, | ||
1818 | pModal->pgaDesiredSize); | ||
1819 | |||
1820 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
1821 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | ||
1822 | | SM(pModal->txEndToXpaOff, | ||
1823 | AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | ||
1824 | | SM(pModal->txFrameToXpaOn, | ||
1825 | AR_PHY_RF_CTL4_FRAME_XPAA_ON) | ||
1826 | | SM(pModal->txFrameToXpaOn, | ||
1827 | AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
1828 | |||
1829 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, | ||
1830 | pModal->txEndToRxOn); | ||
1831 | |||
1832 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1833 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, | ||
1834 | pModal->thresh62); | ||
1835 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, | ||
1836 | AR_PHY_EXT_CCA0_THRESH62, | ||
1837 | pModal->thresh62); | ||
1838 | } else { | ||
1839 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, | ||
1840 | pModal->thresh62); | ||
1841 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, | ||
1842 | AR_PHY_EXT_CCA_THRESH62, | ||
1843 | pModal->thresh62); | ||
1844 | } | ||
1845 | |||
1846 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { | ||
1847 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, | ||
1848 | AR_PHY_TX_END_DATA_START, | ||
1849 | pModal->txFrameToDataStart); | ||
1850 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, | ||
1851 | pModal->txFrameToPaOn); | ||
1852 | } | ||
1853 | |||
1854 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { | ||
1855 | if (IS_CHAN_HT40(chan)) | ||
1856 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1857 | AR_PHY_SETTLING_SWITCH, | ||
1858 | pModal->swSettleHt40); | ||
1859 | } | ||
1860 | |||
1861 | if (AR_SREV_9280_20_OR_LATER(ah) && | ||
1862 | AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1863 | REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, | ||
1864 | AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, | ||
1865 | pModal->miscBits); | ||
1866 | |||
1867 | |||
1868 | if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { | ||
1869 | if (IS_CHAN_2GHZ(chan)) | ||
1870 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, | ||
1871 | eep->baseEepHeader.dacLpMode); | ||
1872 | else if (eep->baseEepHeader.dacHiPwrMode_5G) | ||
1873 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); | ||
1874 | else | ||
1875 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, | ||
1876 | eep->baseEepHeader.dacLpMode); | ||
1877 | |||
1878 | REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, | ||
1879 | pModal->miscBits >> 2); | ||
1880 | |||
1881 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, | ||
1882 | AR_PHY_TX_DESIRED_SCALE_CCK, | ||
1883 | eep->baseEepHeader.desiredScaleCCK); | ||
1884 | } | ||
1885 | } | ||
1886 | |||
1887 | static void ath9k_hw_def_set_addac(struct ath_hw *ah, | ||
1888 | struct ath9k_channel *chan) | ||
1889 | { | ||
1890 | #define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) | ||
1891 | struct modal_eep_header *pModal; | ||
1892 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
1893 | u8 biaslevel; | ||
1894 | |||
1895 | if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) | ||
1896 | return; | ||
1897 | |||
1898 | if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) | ||
1899 | return; | ||
1900 | |||
1901 | pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
1902 | |||
1903 | if (pModal->xpaBiasLvl != 0xff) { | ||
1904 | biaslevel = pModal->xpaBiasLvl; | ||
1905 | } else { | ||
1906 | u16 resetFreqBin, freqBin, freqCount = 0; | ||
1907 | struct chan_centers centers; | ||
1908 | |||
1909 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
1910 | |||
1911 | resetFreqBin = FREQ2FBIN(centers.synth_center, | ||
1912 | IS_CHAN_2GHZ(chan)); | ||
1913 | freqBin = XPA_LVL_FREQ(0) & 0xff; | ||
1914 | biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); | ||
1915 | |||
1916 | freqCount++; | ||
1917 | |||
1918 | while (freqCount < 3) { | ||
1919 | if (XPA_LVL_FREQ(freqCount) == 0x0) | ||
1920 | break; | ||
1921 | |||
1922 | freqBin = XPA_LVL_FREQ(freqCount) & 0xff; | ||
1923 | if (resetFreqBin >= freqBin) | ||
1924 | biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); | ||
1925 | else | ||
1926 | break; | ||
1927 | freqCount++; | ||
1928 | } | ||
1929 | } | ||
1930 | |||
1931 | if (IS_CHAN_2GHZ(chan)) { | ||
1932 | INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac, | ||
1933 | 7, 1) & (~0x18)) | biaslevel << 3; | ||
1934 | } else { | ||
1935 | INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac, | ||
1936 | 6, 1) & (~0xc0)) | biaslevel << 6; | ||
1937 | } | ||
1938 | #undef XPA_LVL_FREQ | ||
1939 | } | ||
1940 | |||
1941 | static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, | ||
1942 | struct ath9k_channel *chan, | ||
1943 | struct cal_data_per_freq *pRawDataSet, | ||
1944 | u8 *bChans, u16 availPiers, | ||
1945 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
1946 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
1947 | u16 numXpdGains) | ||
1948 | { | ||
1949 | int i, j, k; | ||
1950 | int16_t ss; | ||
1951 | u16 idxL = 0, idxR = 0, numPiers; | ||
1952 | static u8 vpdTableL[AR5416_NUM_PD_GAINS] | ||
1953 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
1954 | static u8 vpdTableR[AR5416_NUM_PD_GAINS] | ||
1955 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
1956 | static u8 vpdTableI[AR5416_NUM_PD_GAINS] | ||
1957 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
1958 | |||
1959 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
1960 | u8 minPwrT4[AR5416_NUM_PD_GAINS]; | ||
1961 | u8 maxPwrT4[AR5416_NUM_PD_GAINS]; | ||
1962 | int16_t vpdStep; | ||
1963 | int16_t tmpVal; | ||
1964 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
1965 | bool match; | ||
1966 | int16_t minDelta = 0; | ||
1967 | struct chan_centers centers; | ||
1968 | |||
1969 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
1970 | |||
1971 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
1972 | if (bChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
1973 | break; | ||
1974 | } | ||
1975 | |||
1976 | match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, | ||
1977 | IS_CHAN_2GHZ(chan)), | ||
1978 | bChans, numPiers, &idxL, &idxR); | ||
1979 | |||
1980 | if (match) { | ||
1981 | for (i = 0; i < numXpdGains; i++) { | ||
1982 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
1983 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
1984 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
1985 | pRawDataSet[idxL].pwrPdg[i], | ||
1986 | pRawDataSet[idxL].vpdPdg[i], | ||
1987 | AR5416_PD_GAIN_ICEPTS, | ||
1988 | vpdTableI[i]); | ||
1989 | } | ||
1990 | } else { | ||
1991 | for (i = 0; i < numXpdGains; i++) { | ||
1992 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
1993 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
1994 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
1995 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
1996 | |||
1997 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
1998 | |||
1999 | maxPwrT4[i] = | ||
2000 | min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], | ||
2001 | pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); | ||
2002 | |||
2003 | |||
2004 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
2005 | pPwrL, pVpdL, | ||
2006 | AR5416_PD_GAIN_ICEPTS, | ||
2007 | vpdTableL[i]); | ||
2008 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
2009 | pPwrR, pVpdR, | ||
2010 | AR5416_PD_GAIN_ICEPTS, | ||
2011 | vpdTableR[i]); | ||
2012 | |||
2013 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
2014 | vpdTableI[i][j] = | ||
2015 | (u8)(ath9k_hw_interpolate((u16) | ||
2016 | FREQ2FBIN(centers. | ||
2017 | synth_center, | ||
2018 | IS_CHAN_2GHZ | ||
2019 | (chan)), | ||
2020 | bChans[idxL], bChans[idxR], | ||
2021 | vpdTableL[i][j], vpdTableR[i][j])); | ||
2022 | } | ||
2023 | } | ||
2024 | } | ||
2025 | |||
2026 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
2027 | |||
2028 | k = 0; | ||
2029 | |||
2030 | for (i = 0; i < numXpdGains; i++) { | ||
2031 | if (i == (numXpdGains - 1)) | ||
2032 | pPdGainBoundaries[i] = | ||
2033 | (u16)(maxPwrT4[i] / 2); | ||
2034 | else | ||
2035 | pPdGainBoundaries[i] = | ||
2036 | (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); | ||
2037 | |||
2038 | pPdGainBoundaries[i] = | ||
2039 | min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); | ||
2040 | |||
2041 | if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { | ||
2042 | minDelta = pPdGainBoundaries[0] - 23; | ||
2043 | pPdGainBoundaries[0] = 23; | ||
2044 | } else { | ||
2045 | minDelta = 0; | ||
2046 | } | ||
2047 | |||
2048 | if (i == 0) { | ||
2049 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
2050 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
2051 | else | ||
2052 | ss = 0; | ||
2053 | } else { | ||
2054 | ss = (int16_t)((pPdGainBoundaries[i - 1] - | ||
2055 | (minPwrT4[i] / 2)) - | ||
2056 | tPdGainOverlap + 1 + minDelta); | ||
2057 | } | ||
2058 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
2059 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
2060 | |||
2061 | while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
2062 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
2063 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
2064 | ss++; | ||
2065 | } | ||
2066 | |||
2067 | sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
2068 | tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - | ||
2069 | (minPwrT4[i] / 2)); | ||
2070 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
2071 | tgtIndex : sizeCurrVpdTable; | ||
2072 | |||
2073 | while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
2074 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
2075 | } | ||
2076 | |||
2077 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
2078 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
2079 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
2080 | |||
2081 | if (tgtIndex > maxIndex) { | ||
2082 | while ((ss <= tgtIndex) && | ||
2083 | (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
2084 | tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + | ||
2085 | (ss - maxIndex + 1) * vpdStep)); | ||
2086 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
2087 | 255 : tmpVal); | ||
2088 | ss++; | ||
2089 | } | ||
2090 | } | ||
2091 | } | ||
2092 | |||
2093 | while (i < AR5416_PD_GAINS_IN_MASK) { | ||
2094 | pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; | ||
2095 | i++; | ||
2096 | } | ||
2097 | |||
2098 | while (k < AR5416_NUM_PDADC_VALUES) { | ||
2099 | pPDADCValues[k] = pPDADCValues[k - 1]; | ||
2100 | k++; | ||
2101 | } | ||
2102 | |||
2103 | return; | ||
2104 | } | ||
2105 | |||
2106 | static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | ||
2107 | struct ath9k_channel *chan, | ||
2108 | int16_t *pTxPowerIndexOffset) | ||
2109 | { | ||
2110 | #define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) | ||
2111 | #define SM_PDGAIN_B(x, y) \ | ||
2112 | SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) | ||
2113 | |||
2114 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | ||
2115 | struct cal_data_per_freq *pRawDataset; | ||
2116 | u8 *pCalBChans = NULL; | ||
2117 | u16 pdGainOverlap_t2; | ||
2118 | static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; | ||
2119 | u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; | ||
2120 | u16 numPiers, i, j; | ||
2121 | int16_t tMinCalPower; | ||
2122 | u16 numXpdGain, xpdMask; | ||
2123 | u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; | ||
2124 | u32 reg32, regOffset, regChainOffset; | ||
2125 | int16_t modalIdx; | ||
2126 | |||
2127 | modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; | ||
2128 | xpdMask = pEepData->modalHeader[modalIdx].xpdGain; | ||
2129 | |||
2130 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
2131 | AR5416_EEP_MINOR_VER_2) { | ||
2132 | pdGainOverlap_t2 = | ||
2133 | pEepData->modalHeader[modalIdx].pdGainOverlap; | ||
2134 | } else { | ||
2135 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
2136 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
2137 | } | ||
2138 | |||
2139 | if (IS_CHAN_2GHZ(chan)) { | ||
2140 | pCalBChans = pEepData->calFreqPier2G; | ||
2141 | numPiers = AR5416_NUM_2G_CAL_PIERS; | ||
2142 | } else { | ||
2143 | pCalBChans = pEepData->calFreqPier5G; | ||
2144 | numPiers = AR5416_NUM_5G_CAL_PIERS; | ||
2145 | } | ||
2146 | |||
2147 | if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { | ||
2148 | pRawDataset = pEepData->calPierData2G[0]; | ||
2149 | ah->initPDADC = ((struct calDataPerFreqOpLoop *) | ||
2150 | pRawDataset)->vpdPdg[0][0]; | ||
2151 | } | ||
2152 | |||
2153 | numXpdGain = 0; | ||
2154 | |||
2155 | for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { | ||
2156 | if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { | ||
2157 | if (numXpdGain >= AR5416_NUM_PD_GAINS) | ||
2158 | break; | ||
2159 | xpdGainValues[numXpdGain] = | ||
2160 | (u16)(AR5416_PD_GAINS_IN_MASK - i); | ||
2161 | numXpdGain++; | ||
2162 | } | ||
2163 | } | ||
2164 | |||
2165 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
2166 | (numXpdGain - 1) & 0x3); | ||
2167 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
2168 | xpdGainValues[0]); | ||
2169 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
2170 | xpdGainValues[1]); | ||
2171 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, | ||
2172 | xpdGainValues[2]); | ||
2173 | |||
2174 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
2175 | if (AR_SREV_5416_20_OR_LATER(ah) && | ||
2176 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && | ||
2177 | (i != 0)) { | ||
2178 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
2179 | } else | ||
2180 | regChainOffset = i * 0x1000; | ||
2181 | |||
2182 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
2183 | if (IS_CHAN_2GHZ(chan)) | ||
2184 | pRawDataset = pEepData->calPierData2G[i]; | ||
2185 | else | ||
2186 | pRawDataset = pEepData->calPierData5G[i]; | ||
2187 | |||
2188 | |||
2189 | if (OLC_FOR_AR9280_20_LATER) { | ||
2190 | u8 pcdacIdx; | ||
2191 | u8 txPower; | ||
2192 | |||
2193 | ath9k_get_txgain_index(ah, chan, | ||
2194 | (struct calDataPerFreqOpLoop *)pRawDataset, | ||
2195 | pCalBChans, numPiers, &txPower, &pcdacIdx); | ||
2196 | ath9k_olc_get_pdadcs(ah, pcdacIdx, | ||
2197 | txPower/2, pdadcValues); | ||
2198 | } else { | ||
2199 | ath9k_hw_get_def_gain_boundaries_pdadcs(ah, | ||
2200 | chan, pRawDataset, | ||
2201 | pCalBChans, numPiers, | ||
2202 | pdGainOverlap_t2, | ||
2203 | &tMinCalPower, | ||
2204 | gainBoundaries, | ||
2205 | pdadcValues, | ||
2206 | numXpdGain); | ||
2207 | } | ||
2208 | |||
2209 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { | ||
2210 | if (OLC_FOR_AR9280_20_LATER) { | ||
2211 | REG_WRITE(ah, | ||
2212 | AR_PHY_TPCRG5 + regChainOffset, | ||
2213 | SM(0x6, | ||
2214 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | | ||
2215 | SM_PD_GAIN(1) | SM_PD_GAIN(2) | | ||
2216 | SM_PD_GAIN(3) | SM_PD_GAIN(4)); | ||
2217 | } else { | ||
2218 | REG_WRITE(ah, | ||
2219 | AR_PHY_TPCRG5 + regChainOffset, | ||
2220 | SM(pdGainOverlap_t2, | ||
2221 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| | ||
2222 | SM_PDGAIN_B(0, 1) | | ||
2223 | SM_PDGAIN_B(1, 2) | | ||
2224 | SM_PDGAIN_B(2, 3) | | ||
2225 | SM_PDGAIN_B(3, 4)); | ||
2226 | } | ||
2227 | } | ||
2228 | |||
2229 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; | ||
2230 | for (j = 0; j < 32; j++) { | ||
2231 | reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | | ||
2232 | ((pdadcValues[4 * j + 1] & 0xFF) << 8) | | ||
2233 | ((pdadcValues[4 * j + 2] & 0xFF) << 16)| | ||
2234 | ((pdadcValues[4 * j + 3] & 0xFF) << 24); | ||
2235 | REG_WRITE(ah, regOffset, reg32); | ||
2236 | |||
2237 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2238 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
2239 | i, regChainOffset, regOffset, | ||
2240 | reg32); | ||
2241 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2242 | "PDADC: Chain %d | PDADC %3d " | ||
2243 | "Value %3d | PDADC %3d Value %3d | " | ||
2244 | "PDADC %3d Value %3d | PDADC %3d " | ||
2245 | "Value %3d |\n", | ||
2246 | i, 4 * j, pdadcValues[4 * j], | ||
2247 | 4 * j + 1, pdadcValues[4 * j + 1], | ||
2248 | 4 * j + 2, pdadcValues[4 * j + 2], | ||
2249 | 4 * j + 3, | ||
2250 | pdadcValues[4 * j + 3]); | ||
2251 | |||
2252 | regOffset += 4; | ||
2253 | } | ||
2254 | } | ||
2255 | } | ||
2256 | |||
2257 | *pTxPowerIndexOffset = 0; | ||
2258 | |||
2259 | return true; | ||
2260 | #undef SM_PD_GAIN | ||
2261 | #undef SM_PDGAIN_B | ||
2262 | } | ||
2263 | |||
2264 | static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, | ||
2265 | struct ath9k_channel *chan, | ||
2266 | int16_t *ratesArray, | ||
2267 | u16 cfgCtl, | ||
2268 | u16 AntennaReduction, | ||
2269 | u16 twiceMaxRegulatoryPower, | ||
2270 | u16 powerLimit) | ||
2271 | { | ||
2272 | #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ | ||
2273 | #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ | ||
2274 | |||
2275 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | ||
2276 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
2277 | static const u16 tpScaleReductionTable[5] = | ||
2278 | { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; | ||
2279 | |||
2280 | int i; | ||
2281 | int16_t twiceLargestAntenna; | ||
2282 | struct cal_ctl_data *rep; | ||
2283 | struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { | ||
2284 | 0, { 0, 0, 0, 0} | ||
2285 | }; | ||
2286 | struct cal_target_power_leg targetPowerOfdmExt = { | ||
2287 | 0, { 0, 0, 0, 0} }, targetPowerCckExt = { | ||
2288 | 0, { 0, 0, 0, 0 } | ||
2289 | }; | ||
2290 | struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { | ||
2291 | 0, {0, 0, 0, 0} | ||
2292 | }; | ||
2293 | u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
2294 | u16 ctlModesFor11a[] = | ||
2295 | { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; | ||
2296 | u16 ctlModesFor11g[] = | ||
2297 | { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, | ||
2298 | CTL_2GHT40 | ||
2299 | }; | ||
2300 | u16 numCtlModes, *pCtlMode, ctlMode, freq; | ||
2301 | struct chan_centers centers; | ||
2302 | int tx_chainmask; | ||
2303 | u16 twiceMinEdgePower; | ||
2304 | |||
2305 | tx_chainmask = ah->txchainmask; | ||
2306 | |||
2307 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
2308 | |||
2309 | twiceLargestAntenna = max( | ||
2310 | pEepData->modalHeader | ||
2311 | [IS_CHAN_2GHZ(chan)].antennaGainCh[0], | ||
2312 | pEepData->modalHeader | ||
2313 | [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); | ||
2314 | |||
2315 | twiceLargestAntenna = max((u8)twiceLargestAntenna, | ||
2316 | pEepData->modalHeader | ||
2317 | [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); | ||
2318 | |||
2319 | twiceLargestAntenna = (int16_t)min(AntennaReduction - | ||
2320 | twiceLargestAntenna, 0); | ||
2321 | |||
2322 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
2323 | |||
2324 | if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { | ||
2325 | maxRegAllowedPower -= | ||
2326 | (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); | ||
2327 | } | ||
2328 | |||
2329 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
2330 | |||
2331 | switch (ar5416_get_ntxchains(tx_chainmask)) { | ||
2332 | case 1: | ||
2333 | break; | ||
2334 | case 2: | ||
2335 | scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; | ||
2336 | break; | ||
2337 | case 3: | ||
2338 | scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; | ||
2339 | break; | ||
2340 | } | ||
2341 | |||
2342 | scaledPower = max((u16)0, scaledPower); | ||
2343 | |||
2344 | if (IS_CHAN_2GHZ(chan)) { | ||
2345 | numCtlModes = ARRAY_SIZE(ctlModesFor11g) - | ||
2346 | SUB_NUM_CTL_MODES_AT_2G_40; | ||
2347 | pCtlMode = ctlModesFor11g; | ||
2348 | |||
2349 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2350 | pEepData->calTargetPowerCck, | ||
2351 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
2352 | &targetPowerCck, 4, false); | ||
2353 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2354 | pEepData->calTargetPower2G, | ||
2355 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
2356 | &targetPowerOfdm, 4, false); | ||
2357 | ath9k_hw_get_target_powers(ah, chan, | ||
2358 | pEepData->calTargetPower2GHT20, | ||
2359 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
2360 | &targetPowerHt20, 8, false); | ||
2361 | |||
2362 | if (IS_CHAN_HT40(chan)) { | ||
2363 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
2364 | ath9k_hw_get_target_powers(ah, chan, | ||
2365 | pEepData->calTargetPower2GHT40, | ||
2366 | AR5416_NUM_2G_40_TARGET_POWERS, | ||
2367 | &targetPowerHt40, 8, true); | ||
2368 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2369 | pEepData->calTargetPowerCck, | ||
2370 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
2371 | &targetPowerCckExt, 4, true); | ||
2372 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2373 | pEepData->calTargetPower2G, | ||
2374 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
2375 | &targetPowerOfdmExt, 4, true); | ||
2376 | } | ||
2377 | } else { | ||
2378 | numCtlModes = ARRAY_SIZE(ctlModesFor11a) - | ||
2379 | SUB_NUM_CTL_MODES_AT_5G_40; | ||
2380 | pCtlMode = ctlModesFor11a; | ||
2381 | |||
2382 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2383 | pEepData->calTargetPower5G, | ||
2384 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
2385 | &targetPowerOfdm, 4, false); | ||
2386 | ath9k_hw_get_target_powers(ah, chan, | ||
2387 | pEepData->calTargetPower5GHT20, | ||
2388 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
2389 | &targetPowerHt20, 8, false); | ||
2390 | |||
2391 | if (IS_CHAN_HT40(chan)) { | ||
2392 | numCtlModes = ARRAY_SIZE(ctlModesFor11a); | ||
2393 | ath9k_hw_get_target_powers(ah, chan, | ||
2394 | pEepData->calTargetPower5GHT40, | ||
2395 | AR5416_NUM_5G_40_TARGET_POWERS, | ||
2396 | &targetPowerHt40, 8, true); | ||
2397 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2398 | pEepData->calTargetPower5G, | ||
2399 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
2400 | &targetPowerOfdmExt, 4, true); | ||
2401 | } | ||
2402 | } | ||
2403 | |||
2404 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
2405 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
2406 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
2407 | if (isHt40CtlMode) | ||
2408 | freq = centers.synth_center; | ||
2409 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
2410 | freq = centers.ext_center; | ||
2411 | else | ||
2412 | freq = centers.ctl_center; | ||
2413 | |||
2414 | if (ah->eep_ops->get_eeprom_ver(ah) == 14 && | ||
2415 | ah->eep_ops->get_eeprom_rev(ah) <= 2) | ||
2416 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
2417 | |||
2418 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2419 | "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " | ||
2420 | "EXT_ADDITIVE %d\n", | ||
2421 | ctlMode, numCtlModes, isHt40CtlMode, | ||
2422 | (pCtlMode[ctlMode] & EXT_ADDITIVE)); | ||
2423 | |||
2424 | for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { | ||
2425 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2426 | " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " | ||
2427 | "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " | ||
2428 | "chan %d\n", | ||
2429 | i, cfgCtl, pCtlMode[ctlMode], | ||
2430 | pEepData->ctlIndex[i], chan->channel); | ||
2431 | |||
2432 | if ((((cfgCtl & ~CTL_MODE_M) | | ||
2433 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
2434 | pEepData->ctlIndex[i]) || | ||
2435 | (((cfgCtl & ~CTL_MODE_M) | | ||
2436 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
2437 | ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { | ||
2438 | rep = &(pEepData->ctlData[i]); | ||
2439 | |||
2440 | twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, | ||
2441 | rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], | ||
2442 | IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); | ||
2443 | |||
2444 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2445 | " MATCH-EE_IDX %d: ch %d is2 %d " | ||
2446 | "2xMinEdge %d chainmask %d chains %d\n", | ||
2447 | i, freq, IS_CHAN_2GHZ(chan), | ||
2448 | twiceMinEdgePower, tx_chainmask, | ||
2449 | ar5416_get_ntxchains | ||
2450 | (tx_chainmask)); | ||
2451 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { | ||
2452 | twiceMaxEdgePower = min(twiceMaxEdgePower, | ||
2453 | twiceMinEdgePower); | ||
2454 | } else { | ||
2455 | twiceMaxEdgePower = twiceMinEdgePower; | ||
2456 | break; | ||
2457 | } | ||
2458 | } | ||
2459 | } | ||
2460 | |||
2461 | minCtlPower = min(twiceMaxEdgePower, scaledPower); | ||
2462 | |||
2463 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2464 | " SEL-Min ctlMode %d pCtlMode %d " | ||
2465 | "2xMaxEdge %d sP %d minCtlPwr %d\n", | ||
2466 | ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, | ||
2467 | scaledPower, minCtlPower); | ||
2468 | |||
2469 | switch (pCtlMode[ctlMode]) { | ||
2470 | case CTL_11B: | ||
2471 | for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { | ||
2472 | targetPowerCck.tPow2x[i] = | ||
2473 | min((u16)targetPowerCck.tPow2x[i], | ||
2474 | minCtlPower); | ||
2475 | } | ||
2476 | break; | ||
2477 | case CTL_11A: | ||
2478 | case CTL_11G: | ||
2479 | for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { | ||
2480 | targetPowerOfdm.tPow2x[i] = | ||
2481 | min((u16)targetPowerOfdm.tPow2x[i], | ||
2482 | minCtlPower); | ||
2483 | } | ||
2484 | break; | ||
2485 | case CTL_5GHT20: | ||
2486 | case CTL_2GHT20: | ||
2487 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { | ||
2488 | targetPowerHt20.tPow2x[i] = | ||
2489 | min((u16)targetPowerHt20.tPow2x[i], | ||
2490 | minCtlPower); | ||
2491 | } | ||
2492 | break; | ||
2493 | case CTL_11B_EXT: | ||
2494 | targetPowerCckExt.tPow2x[0] = min((u16) | ||
2495 | targetPowerCckExt.tPow2x[0], | ||
2496 | minCtlPower); | ||
2497 | break; | ||
2498 | case CTL_11A_EXT: | ||
2499 | case CTL_11G_EXT: | ||
2500 | targetPowerOfdmExt.tPow2x[0] = min((u16) | ||
2501 | targetPowerOfdmExt.tPow2x[0], | ||
2502 | minCtlPower); | ||
2503 | break; | ||
2504 | case CTL_5GHT40: | ||
2505 | case CTL_2GHT40: | ||
2506 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
2507 | targetPowerHt40.tPow2x[i] = | ||
2508 | min((u16)targetPowerHt40.tPow2x[i], | ||
2509 | minCtlPower); | ||
2510 | } | ||
2511 | break; | ||
2512 | default: | ||
2513 | break; | ||
2514 | } | ||
2515 | } | ||
2516 | |||
2517 | ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = | ||
2518 | ratesArray[rate18mb] = ratesArray[rate24mb] = | ||
2519 | targetPowerOfdm.tPow2x[0]; | ||
2520 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
2521 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
2522 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
2523 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
2524 | |||
2525 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
2526 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
2527 | |||
2528 | if (IS_CHAN_2GHZ(chan)) { | ||
2529 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
2530 | ratesArray[rate2s] = ratesArray[rate2l] = | ||
2531 | targetPowerCck.tPow2x[1]; | ||
2532 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = | ||
2533 | targetPowerCck.tPow2x[2]; | ||
2534 | ; | ||
2535 | ratesArray[rate11s] = ratesArray[rate11l] = | ||
2536 | targetPowerCck.tPow2x[3]; | ||
2537 | ; | ||
2538 | } | ||
2539 | if (IS_CHAN_HT40(chan)) { | ||
2540 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
2541 | ratesArray[rateHt40_0 + i] = | ||
2542 | targetPowerHt40.tPow2x[i]; | ||
2543 | } | ||
2544 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
2545 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
2546 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
2547 | if (IS_CHAN_2GHZ(chan)) { | ||
2548 | ratesArray[rateExtCck] = | ||
2549 | targetPowerCckExt.tPow2x[0]; | ||
2550 | } | ||
2551 | } | ||
2552 | return true; | ||
2553 | } | ||
2554 | |||
2555 | static int ath9k_hw_def_set_txpower(struct ath_hw *ah, | ||
2556 | struct ath9k_channel *chan, | ||
2557 | u16 cfgCtl, | ||
2558 | u8 twiceAntennaReduction, | ||
2559 | u8 twiceMaxRegulatoryPower, | ||
2560 | u8 powerLimit) | ||
2561 | { | ||
2562 | #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) | ||
2563 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | ||
2564 | struct modal_eep_header *pModal = | ||
2565 | &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
2566 | int16_t ratesArray[Ar5416RateSize]; | ||
2567 | int16_t txPowerIndexOffset = 0; | ||
2568 | u8 ht40PowerIncForPdadc = 2; | ||
2569 | int i, cck_ofdm_delta = 0; | ||
2570 | |||
2571 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
2572 | |||
2573 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
2574 | AR5416_EEP_MINOR_VER_2) { | ||
2575 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
2576 | } | ||
2577 | |||
2578 | if (!ath9k_hw_set_def_power_per_rate_table(ah, chan, | ||
2579 | &ratesArray[0], cfgCtl, | ||
2580 | twiceAntennaReduction, | ||
2581 | twiceMaxRegulatoryPower, | ||
2582 | powerLimit)) { | ||
2583 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2584 | "ath9k_hw_set_txpower: unable to set " | ||
2585 | "tx power per rate table\n"); | ||
2586 | return -EIO; | ||
2587 | } | ||
2588 | |||
2589 | if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) { | ||
2590 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2591 | "ath9k_hw_set_txpower: unable to set power table\n"); | ||
2592 | return -EIO; | ||
2593 | } | ||
2594 | |||
2595 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
2596 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
2597 | if (ratesArray[i] > AR5416_MAX_RATE_POWER) | ||
2598 | ratesArray[i] = AR5416_MAX_RATE_POWER; | ||
2599 | } | ||
2600 | |||
2601 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
2602 | for (i = 0; i < Ar5416RateSize; i++) | ||
2603 | ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; | ||
2604 | } | ||
2605 | |||
2606 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
2607 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
2608 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
2609 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
2610 | | ATH9K_POW_SM(ratesArray[rate6mb], 0)); | ||
2611 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
2612 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
2613 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
2614 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
2615 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | ||
2616 | |||
2617 | if (IS_CHAN_2GHZ(chan)) { | ||
2618 | if (OLC_FOR_AR9280_20_LATER) { | ||
2619 | cck_ofdm_delta = 2; | ||
2620 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
2621 | ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) | ||
2622 | | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) | ||
2623 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
2624 | | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); | ||
2625 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
2626 | ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) | ||
2627 | | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) | ||
2628 | | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) | ||
2629 | | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); | ||
2630 | } else { | ||
2631 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
2632 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
2633 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
2634 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
2635 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
2636 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
2637 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
2638 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
2639 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
2640 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
2641 | } | ||
2642 | } | ||
2643 | |||
2644 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
2645 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
2646 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
2647 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
2648 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); | ||
2649 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
2650 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
2651 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
2652 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
2653 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); | ||
2654 | |||
2655 | if (IS_CHAN_HT40(chan)) { | ||
2656 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
2657 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
2658 | ht40PowerIncForPdadc, 24) | ||
2659 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
2660 | ht40PowerIncForPdadc, 16) | ||
2661 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
2662 | ht40PowerIncForPdadc, 8) | ||
2663 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
2664 | ht40PowerIncForPdadc, 0)); | ||
2665 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
2666 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
2667 | ht40PowerIncForPdadc, 24) | ||
2668 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
2669 | ht40PowerIncForPdadc, 16) | ||
2670 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
2671 | ht40PowerIncForPdadc, 8) | ||
2672 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
2673 | ht40PowerIncForPdadc, 0)); | ||
2674 | if (OLC_FOR_AR9280_20_LATER) { | ||
2675 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
2676 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
2677 | | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) | ||
2678 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
2679 | | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); | ||
2680 | } else { | ||
2681 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
2682 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
2683 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
2684 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
2685 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
2686 | } | ||
2687 | } | ||
2688 | |||
2689 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, | ||
2690 | ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ||
2691 | | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); | ||
2692 | |||
2693 | i = rate6mb; | ||
2694 | |||
2695 | if (IS_CHAN_HT40(chan)) | ||
2696 | i = rateHt40_0; | ||
2697 | else if (IS_CHAN_HT20(chan)) | ||
2698 | i = rateHt20_0; | ||
2699 | |||
2700 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
2701 | ah->regulatory.max_power_level = | ||
2702 | ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; | ||
2703 | else | ||
2704 | ah->regulatory.max_power_level = ratesArray[i]; | ||
2705 | |||
2706 | switch(ar5416_get_ntxchains(ah->txchainmask)) { | ||
2707 | case 1: | ||
2708 | break; | ||
2709 | case 2: | ||
2710 | ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; | ||
2711 | break; | ||
2712 | case 3: | ||
2713 | ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; | ||
2714 | break; | ||
2715 | default: | ||
2716 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2717 | "Invalid chainmask configuration\n"); | ||
2718 | break; | ||
2719 | } | ||
2720 | |||
2721 | return 0; | ||
2722 | } | ||
2723 | |||
2724 | static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, | ||
2725 | enum ieee80211_band freq_band) | ||
2726 | { | ||
2727 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
2728 | struct modal_eep_header *pModal = | ||
2729 | &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); | ||
2730 | struct base_eep_header *pBase = &eep->baseEepHeader; | ||
2731 | u8 num_ant_config; | ||
2732 | |||
2733 | num_ant_config = 1; | ||
2734 | |||
2735 | if (pBase->version >= 0x0E0D) | ||
2736 | if (pModal->useAnt1) | ||
2737 | num_ant_config += 1; | ||
2738 | |||
2739 | return num_ant_config; | ||
2740 | } | ||
2741 | |||
2742 | static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah, | ||
2743 | struct ath9k_channel *chan) | ||
2744 | { | ||
2745 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
2746 | struct modal_eep_header *pModal = | ||
2747 | &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
2748 | |||
2749 | return pModal->antCtrlCommon & 0xFFFF; | ||
2750 | } | ||
2751 | |||
2752 | static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) | ||
2753 | { | ||
2754 | #define EEP_DEF_SPURCHAN \ | ||
2755 | (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) | ||
2756 | |||
2757 | u16 spur_val = AR_NO_SPUR; | ||
2758 | |||
2759 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
2760 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
2761 | i, is2GHz, ah->config.spurchans[i][is2GHz]); | ||
2762 | |||
2763 | switch (ah->config.spurmode) { | ||
2764 | case SPUR_DISABLE: | ||
2765 | break; | ||
2766 | case SPUR_ENABLE_IOCTL: | ||
2767 | spur_val = ah->config.spurchans[i][is2GHz]; | ||
2768 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
2769 | "Getting spur val from new loc. %d\n", spur_val); | ||
2770 | break; | ||
2771 | case SPUR_ENABLE_EEPROM: | ||
2772 | spur_val = EEP_DEF_SPURCHAN; | ||
2773 | break; | ||
2774 | } | ||
2775 | |||
2776 | return spur_val; | ||
2777 | |||
2778 | #undef EEP_DEF_SPURCHAN | ||
2779 | } | ||
2780 | |||
2781 | static struct eeprom_ops eep_def_ops = { | ||
2782 | .check_eeprom = ath9k_hw_def_check_eeprom, | ||
2783 | .get_eeprom = ath9k_hw_def_get_eeprom, | ||
2784 | .fill_eeprom = ath9k_hw_def_fill_eeprom, | ||
2785 | .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, | ||
2786 | .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, | ||
2787 | .get_num_ant_config = ath9k_hw_def_get_num_ant_config, | ||
2788 | .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg, | ||
2789 | .set_board_values = ath9k_hw_def_set_board_values, | ||
2790 | .set_addac = ath9k_hw_def_set_addac, | ||
2791 | .set_txpower = ath9k_hw_def_set_txpower, | ||
2792 | .get_spur_channel = ath9k_hw_def_get_spur_channel | ||
2793 | }; | ||
2794 | |||
2795 | int ath9k_hw_eeprom_attach(struct ath_hw *ah) | ||
2796 | { | ||
2797 | int status; | ||
2798 | |||
2799 | if (AR_SREV_9285(ah)) { | ||
2800 | ah->eep_map = EEP_MAP_4KBITS; | ||
2801 | ah->eep_ops = &eep_4k_ops; | ||
2802 | } else { | ||
2803 | ah->eep_map = EEP_MAP_DEFAULT; | ||
2804 | ah->eep_ops = &eep_def_ops; | ||
2805 | } | ||
2806 | |||
2807 | if (!ah->eep_ops->fill_eeprom(ah)) | ||
2808 | return -EIO; | ||
2809 | |||
2810 | status = ah->eep_ops->check_eeprom(ah); | ||
2811 | |||
2812 | return status; | ||
2813 | } | ||