diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/eeprom_4k.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/eeprom_4k.c | 1186 |
1 files changed, 1186 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c new file mode 100644 index 000000000000..d34dd23e806a --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c | |||
@@ -0,0 +1,1186 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "ath9k.h" | ||
18 | |||
19 | static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) | ||
20 | { | ||
21 | return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); | ||
22 | } | ||
23 | |||
24 | static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) | ||
25 | { | ||
26 | return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); | ||
27 | } | ||
28 | |||
29 | static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) | ||
30 | { | ||
31 | #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) | ||
32 | u16 *eep_data = (u16 *)&ah->eeprom.map4k; | ||
33 | int addr, eep_start_loc = 0; | ||
34 | |||
35 | eep_start_loc = 64; | ||
36 | |||
37 | if (!ath9k_hw_use_flash(ah)) { | ||
38 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
39 | "Reading from EEPROM, not flash\n"); | ||
40 | } | ||
41 | |||
42 | for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { | ||
43 | if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { | ||
44 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
45 | "Unable to read eeprom region \n"); | ||
46 | return false; | ||
47 | } | ||
48 | eep_data++; | ||
49 | } | ||
50 | |||
51 | return true; | ||
52 | #undef SIZE_EEPROM_4K | ||
53 | } | ||
54 | |||
55 | static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) | ||
56 | { | ||
57 | #define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) | ||
58 | struct ar5416_eeprom_4k *eep = | ||
59 | (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; | ||
60 | u16 *eepdata, temp, magic, magic2; | ||
61 | u32 sum = 0, el; | ||
62 | bool need_swap = false; | ||
63 | int i, addr; | ||
64 | |||
65 | |||
66 | if (!ath9k_hw_use_flash(ah)) { | ||
67 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, | ||
68 | &magic)) { | ||
69 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
70 | "Reading Magic # failed\n"); | ||
71 | return false; | ||
72 | } | ||
73 | |||
74 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
75 | "Read Magic = 0x%04X\n", magic); | ||
76 | |||
77 | if (magic != AR5416_EEPROM_MAGIC) { | ||
78 | magic2 = swab16(magic); | ||
79 | |||
80 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
81 | need_swap = true; | ||
82 | eepdata = (u16 *) (&ah->eeprom); | ||
83 | |||
84 | for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { | ||
85 | temp = swab16(*eepdata); | ||
86 | *eepdata = temp; | ||
87 | eepdata++; | ||
88 | } | ||
89 | } else { | ||
90 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
91 | "Invalid EEPROM Magic. " | ||
92 | "endianness mismatch.\n"); | ||
93 | return -EINVAL; | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | |||
98 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", | ||
99 | need_swap ? "True" : "False"); | ||
100 | |||
101 | if (need_swap) | ||
102 | el = swab16(ah->eeprom.map4k.baseEepHeader.length); | ||
103 | else | ||
104 | el = ah->eeprom.map4k.baseEepHeader.length; | ||
105 | |||
106 | if (el > sizeof(struct ar5416_eeprom_4k)) | ||
107 | el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); | ||
108 | else | ||
109 | el = el / sizeof(u16); | ||
110 | |||
111 | eepdata = (u16 *)(&ah->eeprom); | ||
112 | |||
113 | for (i = 0; i < el; i++) | ||
114 | sum ^= *eepdata++; | ||
115 | |||
116 | if (need_swap) { | ||
117 | u32 integer; | ||
118 | u16 word; | ||
119 | |||
120 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
121 | "EEPROM Endianness is not native.. Changing\n"); | ||
122 | |||
123 | word = swab16(eep->baseEepHeader.length); | ||
124 | eep->baseEepHeader.length = word; | ||
125 | |||
126 | word = swab16(eep->baseEepHeader.checksum); | ||
127 | eep->baseEepHeader.checksum = word; | ||
128 | |||
129 | word = swab16(eep->baseEepHeader.version); | ||
130 | eep->baseEepHeader.version = word; | ||
131 | |||
132 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
133 | eep->baseEepHeader.regDmn[0] = word; | ||
134 | |||
135 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
136 | eep->baseEepHeader.regDmn[1] = word; | ||
137 | |||
138 | word = swab16(eep->baseEepHeader.rfSilent); | ||
139 | eep->baseEepHeader.rfSilent = word; | ||
140 | |||
141 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
142 | eep->baseEepHeader.blueToothOptions = word; | ||
143 | |||
144 | word = swab16(eep->baseEepHeader.deviceCap); | ||
145 | eep->baseEepHeader.deviceCap = word; | ||
146 | |||
147 | integer = swab32(eep->modalHeader.antCtrlCommon); | ||
148 | eep->modalHeader.antCtrlCommon = integer; | ||
149 | |||
150 | for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { | ||
151 | integer = swab32(eep->modalHeader.antCtrlChain[i]); | ||
152 | eep->modalHeader.antCtrlChain[i] = integer; | ||
153 | } | ||
154 | |||
155 | for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { | ||
156 | word = swab16(eep->modalHeader.spurChans[i].spurChan); | ||
157 | eep->modalHeader.spurChans[i].spurChan = word; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || | ||
162 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | ||
163 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
164 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
165 | sum, ah->eep_ops->get_eeprom_ver(ah)); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | #undef EEPROM_4K_SIZE | ||
171 | } | ||
172 | |||
173 | static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, | ||
174 | enum eeprom_param param) | ||
175 | { | ||
176 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
177 | struct modal_eep_4k_header *pModal = &eep->modalHeader; | ||
178 | struct base_eep_header_4k *pBase = &eep->baseEepHeader; | ||
179 | |||
180 | switch (param) { | ||
181 | case EEP_NFTHRESH_2: | ||
182 | return pModal->noiseFloorThreshCh[0]; | ||
183 | case AR_EEPROM_MAC(0): | ||
184 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
185 | case AR_EEPROM_MAC(1): | ||
186 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
187 | case AR_EEPROM_MAC(2): | ||
188 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
189 | case EEP_REG_0: | ||
190 | return pBase->regDmn[0]; | ||
191 | case EEP_REG_1: | ||
192 | return pBase->regDmn[1]; | ||
193 | case EEP_OP_CAP: | ||
194 | return pBase->deviceCap; | ||
195 | case EEP_OP_MODE: | ||
196 | return pBase->opCapFlags; | ||
197 | case EEP_RF_SILENT: | ||
198 | return pBase->rfSilent; | ||
199 | case EEP_OB_2: | ||
200 | return pModal->ob_0; | ||
201 | case EEP_DB_2: | ||
202 | return pModal->db1_1; | ||
203 | case EEP_MINOR_REV: | ||
204 | return pBase->version & AR5416_EEP_VER_MINOR_MASK; | ||
205 | case EEP_TX_MASK: | ||
206 | return pBase->txMask; | ||
207 | case EEP_RX_MASK: | ||
208 | return pBase->rxMask; | ||
209 | case EEP_FRAC_N_5G: | ||
210 | return 0; | ||
211 | default: | ||
212 | return 0; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, | ||
217 | struct ath9k_channel *chan, | ||
218 | struct cal_data_per_freq_4k *pRawDataSet, | ||
219 | u8 *bChans, u16 availPiers, | ||
220 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
221 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
222 | u16 numXpdGains) | ||
223 | { | ||
224 | #define TMP_VAL_VPD_TABLE \ | ||
225 | ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); | ||
226 | int i, j, k; | ||
227 | int16_t ss; | ||
228 | u16 idxL = 0, idxR = 0, numPiers; | ||
229 | static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] | ||
230 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
231 | static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] | ||
232 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
233 | static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] | ||
234 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
235 | |||
236 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
237 | u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; | ||
238 | u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; | ||
239 | int16_t vpdStep; | ||
240 | int16_t tmpVal; | ||
241 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
242 | bool match; | ||
243 | int16_t minDelta = 0; | ||
244 | struct chan_centers centers; | ||
245 | #define PD_GAIN_BOUNDARY_DEFAULT 58; | ||
246 | |||
247 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
248 | |||
249 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
250 | if (bChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
251 | break; | ||
252 | } | ||
253 | |||
254 | match = ath9k_hw_get_lower_upper_index( | ||
255 | (u8)FREQ2FBIN(centers.synth_center, | ||
256 | IS_CHAN_2GHZ(chan)), bChans, numPiers, | ||
257 | &idxL, &idxR); | ||
258 | |||
259 | if (match) { | ||
260 | for (i = 0; i < numXpdGains; i++) { | ||
261 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
262 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
263 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
264 | pRawDataSet[idxL].pwrPdg[i], | ||
265 | pRawDataSet[idxL].vpdPdg[i], | ||
266 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
267 | vpdTableI[i]); | ||
268 | } | ||
269 | } else { | ||
270 | for (i = 0; i < numXpdGains; i++) { | ||
271 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
272 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
273 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
274 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
275 | |||
276 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
277 | |||
278 | maxPwrT4[i] = | ||
279 | min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], | ||
280 | pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); | ||
281 | |||
282 | |||
283 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
284 | pPwrL, pVpdL, | ||
285 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
286 | vpdTableL[i]); | ||
287 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
288 | pPwrR, pVpdR, | ||
289 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
290 | vpdTableR[i]); | ||
291 | |||
292 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
293 | vpdTableI[i][j] = | ||
294 | (u8)(ath9k_hw_interpolate((u16) | ||
295 | FREQ2FBIN(centers. | ||
296 | synth_center, | ||
297 | IS_CHAN_2GHZ | ||
298 | (chan)), | ||
299 | bChans[idxL], bChans[idxR], | ||
300 | vpdTableL[i][j], vpdTableR[i][j])); | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | |||
305 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
306 | |||
307 | k = 0; | ||
308 | |||
309 | for (i = 0; i < numXpdGains; i++) { | ||
310 | if (i == (numXpdGains - 1)) | ||
311 | pPdGainBoundaries[i] = | ||
312 | (u16)(maxPwrT4[i] / 2); | ||
313 | else | ||
314 | pPdGainBoundaries[i] = | ||
315 | (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); | ||
316 | |||
317 | pPdGainBoundaries[i] = | ||
318 | min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); | ||
319 | |||
320 | if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { | ||
321 | minDelta = pPdGainBoundaries[0] - 23; | ||
322 | pPdGainBoundaries[0] = 23; | ||
323 | } else { | ||
324 | minDelta = 0; | ||
325 | } | ||
326 | |||
327 | if (i == 0) { | ||
328 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
329 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
330 | else | ||
331 | ss = 0; | ||
332 | } else { | ||
333 | ss = (int16_t)((pPdGainBoundaries[i - 1] - | ||
334 | (minPwrT4[i] / 2)) - | ||
335 | tPdGainOverlap + 1 + minDelta); | ||
336 | } | ||
337 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
338 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
339 | |||
340 | while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
341 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
342 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
343 | ss++; | ||
344 | } | ||
345 | |||
346 | sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
347 | tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - | ||
348 | (minPwrT4[i] / 2)); | ||
349 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
350 | tgtIndex : sizeCurrVpdTable; | ||
351 | |||
352 | while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) | ||
353 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
354 | |||
355 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
356 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
357 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
358 | |||
359 | if (tgtIndex >= maxIndex) { | ||
360 | while ((ss <= tgtIndex) && | ||
361 | (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
362 | tmpVal = (int16_t) TMP_VAL_VPD_TABLE; | ||
363 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
364 | 255 : tmpVal); | ||
365 | ss++; | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | |||
370 | while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { | ||
371 | pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; | ||
372 | i++; | ||
373 | } | ||
374 | |||
375 | while (k < AR5416_NUM_PDADC_VALUES) { | ||
376 | pPDADCValues[k] = pPDADCValues[k - 1]; | ||
377 | k++; | ||
378 | } | ||
379 | |||
380 | return; | ||
381 | #undef TMP_VAL_VPD_TABLE | ||
382 | } | ||
383 | |||
384 | static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, | ||
385 | struct ath9k_channel *chan, | ||
386 | int16_t *pTxPowerIndexOffset) | ||
387 | { | ||
388 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
389 | struct cal_data_per_freq_4k *pRawDataset; | ||
390 | u8 *pCalBChans = NULL; | ||
391 | u16 pdGainOverlap_t2; | ||
392 | static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; | ||
393 | u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; | ||
394 | u16 numPiers, i, j; | ||
395 | int16_t tMinCalPower; | ||
396 | u16 numXpdGain, xpdMask; | ||
397 | u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; | ||
398 | u32 reg32, regOffset, regChainOffset; | ||
399 | |||
400 | xpdMask = pEepData->modalHeader.xpdGain; | ||
401 | |||
402 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
403 | AR5416_EEP_MINOR_VER_2) { | ||
404 | pdGainOverlap_t2 = | ||
405 | pEepData->modalHeader.pdGainOverlap; | ||
406 | } else { | ||
407 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
408 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
409 | } | ||
410 | |||
411 | pCalBChans = pEepData->calFreqPier2G; | ||
412 | numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; | ||
413 | |||
414 | numXpdGain = 0; | ||
415 | |||
416 | for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { | ||
417 | if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { | ||
418 | if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) | ||
419 | break; | ||
420 | xpdGainValues[numXpdGain] = | ||
421 | (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); | ||
422 | numXpdGain++; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
427 | (numXpdGain - 1) & 0x3); | ||
428 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
429 | xpdGainValues[0]); | ||
430 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
431 | xpdGainValues[1]); | ||
432 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); | ||
433 | |||
434 | for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { | ||
435 | if (AR_SREV_5416_20_OR_LATER(ah) && | ||
436 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && | ||
437 | (i != 0)) { | ||
438 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
439 | } else | ||
440 | regChainOffset = i * 0x1000; | ||
441 | |||
442 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
443 | pRawDataset = pEepData->calPierData2G[i]; | ||
444 | |||
445 | ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, | ||
446 | pRawDataset, pCalBChans, | ||
447 | numPiers, pdGainOverlap_t2, | ||
448 | &tMinCalPower, gainBoundaries, | ||
449 | pdadcValues, numXpdGain); | ||
450 | |||
451 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { | ||
452 | REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, | ||
453 | SM(pdGainOverlap_t2, | ||
454 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | ||
455 | | SM(gainBoundaries[0], | ||
456 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | ||
457 | | SM(gainBoundaries[1], | ||
458 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | ||
459 | | SM(gainBoundaries[2], | ||
460 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | ||
461 | | SM(gainBoundaries[3], | ||
462 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); | ||
463 | } | ||
464 | |||
465 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; | ||
466 | for (j = 0; j < 32; j++) { | ||
467 | reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | | ||
468 | ((pdadcValues[4 * j + 1] & 0xFF) << 8) | | ||
469 | ((pdadcValues[4 * j + 2] & 0xFF) << 16)| | ||
470 | ((pdadcValues[4 * j + 3] & 0xFF) << 24); | ||
471 | REG_WRITE(ah, regOffset, reg32); | ||
472 | |||
473 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
474 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
475 | i, regChainOffset, regOffset, | ||
476 | reg32); | ||
477 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
478 | "PDADC: Chain %d | " | ||
479 | "PDADC %3d Value %3d | " | ||
480 | "PDADC %3d Value %3d | " | ||
481 | "PDADC %3d Value %3d | " | ||
482 | "PDADC %3d Value %3d |\n", | ||
483 | i, 4 * j, pdadcValues[4 * j], | ||
484 | 4 * j + 1, pdadcValues[4 * j + 1], | ||
485 | 4 * j + 2, pdadcValues[4 * j + 2], | ||
486 | 4 * j + 3, | ||
487 | pdadcValues[4 * j + 3]); | ||
488 | |||
489 | regOffset += 4; | ||
490 | } | ||
491 | } | ||
492 | } | ||
493 | |||
494 | *pTxPowerIndexOffset = 0; | ||
495 | } | ||
496 | |||
497 | static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, | ||
498 | struct ath9k_channel *chan, | ||
499 | int16_t *ratesArray, | ||
500 | u16 cfgCtl, | ||
501 | u16 AntennaReduction, | ||
502 | u16 twiceMaxRegulatoryPower, | ||
503 | u16 powerLimit) | ||
504 | { | ||
505 | #define CMP_TEST_GRP \ | ||
506 | (((cfgCtl & ~CTL_MODE_M)| (pCtlMode[ctlMode] & CTL_MODE_M)) == \ | ||
507 | pEepData->ctlIndex[i]) \ | ||
508 | || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ | ||
509 | ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) | ||
510 | |||
511 | int i; | ||
512 | int16_t twiceLargestAntenna; | ||
513 | u16 twiceMinEdgePower; | ||
514 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
515 | u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
516 | u16 numCtlModes, *pCtlMode, ctlMode, freq; | ||
517 | struct chan_centers centers; | ||
518 | struct cal_ctl_data_4k *rep; | ||
519 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
520 | static const u16 tpScaleReductionTable[5] = | ||
521 | { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; | ||
522 | struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { | ||
523 | 0, { 0, 0, 0, 0} | ||
524 | }; | ||
525 | struct cal_target_power_leg targetPowerOfdmExt = { | ||
526 | 0, { 0, 0, 0, 0} }, targetPowerCckExt = { | ||
527 | 0, { 0, 0, 0, 0 } | ||
528 | }; | ||
529 | struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { | ||
530 | 0, {0, 0, 0, 0} | ||
531 | }; | ||
532 | u16 ctlModesFor11g[] = | ||
533 | { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, | ||
534 | CTL_2GHT40 | ||
535 | }; | ||
536 | |||
537 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
538 | |||
539 | twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; | ||
540 | twiceLargestAntenna = (int16_t)min(AntennaReduction - | ||
541 | twiceLargestAntenna, 0); | ||
542 | |||
543 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
544 | if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { | ||
545 | maxRegAllowedPower -= | ||
546 | (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); | ||
547 | } | ||
548 | |||
549 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
550 | scaledPower = max((u16)0, scaledPower); | ||
551 | |||
552 | numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; | ||
553 | pCtlMode = ctlModesFor11g; | ||
554 | |||
555 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
556 | pEepData->calTargetPowerCck, | ||
557 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
558 | &targetPowerCck, 4, false); | ||
559 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
560 | pEepData->calTargetPower2G, | ||
561 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
562 | &targetPowerOfdm, 4, false); | ||
563 | ath9k_hw_get_target_powers(ah, chan, | ||
564 | pEepData->calTargetPower2GHT20, | ||
565 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
566 | &targetPowerHt20, 8, false); | ||
567 | |||
568 | if (IS_CHAN_HT40(chan)) { | ||
569 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
570 | ath9k_hw_get_target_powers(ah, chan, | ||
571 | pEepData->calTargetPower2GHT40, | ||
572 | AR5416_NUM_2G_40_TARGET_POWERS, | ||
573 | &targetPowerHt40, 8, true); | ||
574 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
575 | pEepData->calTargetPowerCck, | ||
576 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
577 | &targetPowerCckExt, 4, true); | ||
578 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
579 | pEepData->calTargetPower2G, | ||
580 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
581 | &targetPowerOfdmExt, 4, true); | ||
582 | } | ||
583 | |||
584 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
585 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
586 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
587 | |||
588 | if (isHt40CtlMode) | ||
589 | freq = centers.synth_center; | ||
590 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
591 | freq = centers.ext_center; | ||
592 | else | ||
593 | freq = centers.ctl_center; | ||
594 | |||
595 | if (ah->eep_ops->get_eeprom_ver(ah) == 14 && | ||
596 | ah->eep_ops->get_eeprom_rev(ah) <= 2) | ||
597 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
598 | |||
599 | for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && | ||
600 | pEepData->ctlIndex[i]; i++) { | ||
601 | |||
602 | if (CMP_TEST_GRP) { | ||
603 | rep = &(pEepData->ctlData[i]); | ||
604 | |||
605 | twiceMinEdgePower = ath9k_hw_get_max_edge_power( | ||
606 | freq, | ||
607 | rep->ctlEdges[ | ||
608 | ar5416_get_ntxchains(ah->txchainmask) - 1], | ||
609 | IS_CHAN_2GHZ(chan), | ||
610 | AR5416_EEP4K_NUM_BAND_EDGES); | ||
611 | |||
612 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { | ||
613 | twiceMaxEdgePower = | ||
614 | min(twiceMaxEdgePower, | ||
615 | twiceMinEdgePower); | ||
616 | } else { | ||
617 | twiceMaxEdgePower = twiceMinEdgePower; | ||
618 | break; | ||
619 | } | ||
620 | } | ||
621 | } | ||
622 | |||
623 | minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); | ||
624 | |||
625 | switch (pCtlMode[ctlMode]) { | ||
626 | case CTL_11B: | ||
627 | for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { | ||
628 | targetPowerCck.tPow2x[i] = | ||
629 | min((u16)targetPowerCck.tPow2x[i], | ||
630 | minCtlPower); | ||
631 | } | ||
632 | break; | ||
633 | case CTL_11G: | ||
634 | for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { | ||
635 | targetPowerOfdm.tPow2x[i] = | ||
636 | min((u16)targetPowerOfdm.tPow2x[i], | ||
637 | minCtlPower); | ||
638 | } | ||
639 | break; | ||
640 | case CTL_2GHT20: | ||
641 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { | ||
642 | targetPowerHt20.tPow2x[i] = | ||
643 | min((u16)targetPowerHt20.tPow2x[i], | ||
644 | minCtlPower); | ||
645 | } | ||
646 | break; | ||
647 | case CTL_11B_EXT: | ||
648 | targetPowerCckExt.tPow2x[0] = | ||
649 | min((u16)targetPowerCckExt.tPow2x[0], | ||
650 | minCtlPower); | ||
651 | break; | ||
652 | case CTL_11G_EXT: | ||
653 | targetPowerOfdmExt.tPow2x[0] = | ||
654 | min((u16)targetPowerOfdmExt.tPow2x[0], | ||
655 | minCtlPower); | ||
656 | break; | ||
657 | case CTL_2GHT40: | ||
658 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
659 | targetPowerHt40.tPow2x[i] = | ||
660 | min((u16)targetPowerHt40.tPow2x[i], | ||
661 | minCtlPower); | ||
662 | } | ||
663 | break; | ||
664 | default: | ||
665 | break; | ||
666 | } | ||
667 | } | ||
668 | |||
669 | ratesArray[rate6mb] = | ||
670 | ratesArray[rate9mb] = | ||
671 | ratesArray[rate12mb] = | ||
672 | ratesArray[rate18mb] = | ||
673 | ratesArray[rate24mb] = | ||
674 | targetPowerOfdm.tPow2x[0]; | ||
675 | |||
676 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
677 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
678 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
679 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
680 | |||
681 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
682 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
683 | |||
684 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
685 | ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; | ||
686 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; | ||
687 | ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; | ||
688 | |||
689 | if (IS_CHAN_HT40(chan)) { | ||
690 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
691 | ratesArray[rateHt40_0 + i] = | ||
692 | targetPowerHt40.tPow2x[i]; | ||
693 | } | ||
694 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
695 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
696 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
697 | ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; | ||
698 | } | ||
699 | |||
700 | #undef CMP_TEST_GRP | ||
701 | } | ||
702 | |||
703 | static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ||
704 | struct ath9k_channel *chan, | ||
705 | u16 cfgCtl, | ||
706 | u8 twiceAntennaReduction, | ||
707 | u8 twiceMaxRegulatoryPower, | ||
708 | u8 powerLimit) | ||
709 | { | ||
710 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
711 | struct modal_eep_4k_header *pModal = &pEepData->modalHeader; | ||
712 | int16_t ratesArray[Ar5416RateSize]; | ||
713 | int16_t txPowerIndexOffset = 0; | ||
714 | u8 ht40PowerIncForPdadc = 2; | ||
715 | int i; | ||
716 | |||
717 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
718 | |||
719 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
720 | AR5416_EEP_MINOR_VER_2) { | ||
721 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
722 | } | ||
723 | |||
724 | ath9k_hw_set_4k_power_per_rate_table(ah, chan, | ||
725 | &ratesArray[0], cfgCtl, | ||
726 | twiceAntennaReduction, | ||
727 | twiceMaxRegulatoryPower, | ||
728 | powerLimit); | ||
729 | |||
730 | ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); | ||
731 | |||
732 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
733 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
734 | if (ratesArray[i] > AR5416_MAX_RATE_POWER) | ||
735 | ratesArray[i] = AR5416_MAX_RATE_POWER; | ||
736 | } | ||
737 | |||
738 | |||
739 | /* Update regulatory */ | ||
740 | |||
741 | i = rate6mb; | ||
742 | if (IS_CHAN_HT40(chan)) | ||
743 | i = rateHt40_0; | ||
744 | else if (IS_CHAN_HT20(chan)) | ||
745 | i = rateHt20_0; | ||
746 | |||
747 | ah->regulatory.max_power_level = ratesArray[i]; | ||
748 | |||
749 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
750 | for (i = 0; i < Ar5416RateSize; i++) | ||
751 | ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; | ||
752 | } | ||
753 | |||
754 | /* OFDM power per rate */ | ||
755 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
756 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
757 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
758 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
759 | | ATH9K_POW_SM(ratesArray[rate6mb], 0)); | ||
760 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
761 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
762 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
763 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
764 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | ||
765 | |||
766 | /* CCK power per rate */ | ||
767 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
768 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
769 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
770 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
771 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
772 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
773 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
774 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
775 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
776 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
777 | |||
778 | /* HT20 power per rate */ | ||
779 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
780 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
781 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
782 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
783 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); | ||
784 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
785 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
786 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
787 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
788 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); | ||
789 | |||
790 | /* HT40 power per rate */ | ||
791 | if (IS_CHAN_HT40(chan)) { | ||
792 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
793 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
794 | ht40PowerIncForPdadc, 24) | ||
795 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
796 | ht40PowerIncForPdadc, 16) | ||
797 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
798 | ht40PowerIncForPdadc, 8) | ||
799 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
800 | ht40PowerIncForPdadc, 0)); | ||
801 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
802 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
803 | ht40PowerIncForPdadc, 24) | ||
804 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
805 | ht40PowerIncForPdadc, 16) | ||
806 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
807 | ht40PowerIncForPdadc, 8) | ||
808 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
809 | ht40PowerIncForPdadc, 0)); | ||
810 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
811 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
812 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
813 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
814 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
815 | } | ||
816 | } | ||
817 | |||
818 | static void ath9k_hw_4k_set_addac(struct ath_hw *ah, | ||
819 | struct ath9k_channel *chan) | ||
820 | { | ||
821 | struct modal_eep_4k_header *pModal; | ||
822 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
823 | u8 biaslevel; | ||
824 | |||
825 | if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) | ||
826 | return; | ||
827 | |||
828 | if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) | ||
829 | return; | ||
830 | |||
831 | pModal = &eep->modalHeader; | ||
832 | |||
833 | if (pModal->xpaBiasLvl != 0xff) { | ||
834 | biaslevel = pModal->xpaBiasLvl; | ||
835 | INI_RA(&ah->iniAddac, 7, 1) = | ||
836 | (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; | ||
837 | } | ||
838 | } | ||
839 | |||
840 | static void ath9k_hw_4k_set_gain(struct ath_hw *ah, | ||
841 | struct modal_eep_4k_header *pModal, | ||
842 | struct ar5416_eeprom_4k *eep, | ||
843 | u8 txRxAttenLocal) | ||
844 | { | ||
845 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0, | ||
846 | pModal->antCtrlChain[0]); | ||
847 | |||
848 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), | ||
849 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & | ||
850 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
851 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
852 | SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
853 | SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
854 | |||
855 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
856 | AR5416_EEP_MINOR_VER_3) { | ||
857 | txRxAttenLocal = pModal->txRxAttenCh[0]; | ||
858 | |||
859 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, | ||
860 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); | ||
861 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, | ||
862 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); | ||
863 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, | ||
864 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
865 | pModal->xatten2Margin[0]); | ||
866 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, | ||
867 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); | ||
868 | |||
869 | /* Set the block 1 value to block 0 value */ | ||
870 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
871 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
872 | pModal->bswMargin[0]); | ||
873 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
874 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); | ||
875 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
876 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
877 | pModal->xatten2Margin[0]); | ||
878 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
879 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, | ||
880 | pModal->xatten2Db[0]); | ||
881 | } | ||
882 | |||
883 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN, | ||
884 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
885 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN, | ||
886 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); | ||
887 | |||
888 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, | ||
889 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
890 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, | ||
891 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); | ||
892 | |||
893 | if (AR_SREV_9285_11(ah)) | ||
894 | REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); | ||
895 | } | ||
896 | |||
897 | /* | ||
898 | * Read EEPROM header info and program the device for correct operation | ||
899 | * given the channel value. | ||
900 | */ | ||
901 | static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, | ||
902 | struct ath9k_channel *chan) | ||
903 | { | ||
904 | struct modal_eep_4k_header *pModal; | ||
905 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
906 | u8 txRxAttenLocal; | ||
907 | u8 ob[5], db1[5], db2[5]; | ||
908 | u8 ant_div_control1, ant_div_control2; | ||
909 | u32 regVal; | ||
910 | |||
911 | pModal = &eep->modalHeader; | ||
912 | txRxAttenLocal = 23; | ||
913 | |||
914 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
915 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
916 | |||
917 | /* Single chain for 4K EEPROM*/ | ||
918 | ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal); | ||
919 | |||
920 | /* Initialize Ant Diversity settings from EEPROM */ | ||
921 | if (pModal->version >= 3) { | ||
922 | ant_div_control1 = pModal->antdiv_ctl1; | ||
923 | ant_div_control2 = pModal->antdiv_ctl2; | ||
924 | |||
925 | regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); | ||
926 | regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL)); | ||
927 | |||
928 | regVal |= SM(ant_div_control1, | ||
929 | AR_PHY_9285_ANT_DIV_CTL); | ||
930 | regVal |= SM(ant_div_control2, | ||
931 | AR_PHY_9285_ANT_DIV_ALT_LNACONF); | ||
932 | regVal |= SM((ant_div_control2 >> 2), | ||
933 | AR_PHY_9285_ANT_DIV_MAIN_LNACONF); | ||
934 | regVal |= SM((ant_div_control1 >> 1), | ||
935 | AR_PHY_9285_ANT_DIV_ALT_GAINTB); | ||
936 | regVal |= SM((ant_div_control1 >> 2), | ||
937 | AR_PHY_9285_ANT_DIV_MAIN_GAINTB); | ||
938 | |||
939 | |||
940 | REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); | ||
941 | regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); | ||
942 | regVal = REG_READ(ah, AR_PHY_CCK_DETECT); | ||
943 | regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); | ||
944 | regVal |= SM((ant_div_control1 >> 3), | ||
945 | AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); | ||
946 | |||
947 | REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal); | ||
948 | regVal = REG_READ(ah, AR_PHY_CCK_DETECT); | ||
949 | } | ||
950 | |||
951 | if (pModal->version >= 2) { | ||
952 | ob[0] = pModal->ob_0; | ||
953 | ob[1] = pModal->ob_1; | ||
954 | ob[2] = pModal->ob_2; | ||
955 | ob[3] = pModal->ob_3; | ||
956 | ob[4] = pModal->ob_4; | ||
957 | |||
958 | db1[0] = pModal->db1_0; | ||
959 | db1[1] = pModal->db1_1; | ||
960 | db1[2] = pModal->db1_2; | ||
961 | db1[3] = pModal->db1_3; | ||
962 | db1[4] = pModal->db1_4; | ||
963 | |||
964 | db2[0] = pModal->db2_0; | ||
965 | db2[1] = pModal->db2_1; | ||
966 | db2[2] = pModal->db2_2; | ||
967 | db2[3] = pModal->db2_3; | ||
968 | db2[4] = pModal->db2_4; | ||
969 | } else if (pModal->version == 1) { | ||
970 | ob[0] = pModal->ob_0; | ||
971 | ob[1] = ob[2] = ob[3] = ob[4] = pModal->ob_1; | ||
972 | db1[0] = pModal->db1_0; | ||
973 | db1[1] = db1[2] = db1[3] = db1[4] = pModal->db1_1; | ||
974 | db2[0] = pModal->db2_0; | ||
975 | db2[1] = db2[2] = db2[3] = db2[4] = pModal->db2_1; | ||
976 | } else { | ||
977 | int i; | ||
978 | |||
979 | for (i = 0; i < 5; i++) { | ||
980 | ob[i] = pModal->ob_0; | ||
981 | db1[i] = pModal->db1_0; | ||
982 | db2[i] = pModal->db1_0; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | if (AR_SREV_9271(ah)) { | ||
987 | ath9k_hw_analog_shift_rmw(ah, | ||
988 | AR9285_AN_RF2G3, | ||
989 | AR9271_AN_RF2G3_OB_cck, | ||
990 | AR9271_AN_RF2G3_OB_cck_S, | ||
991 | ob[0]); | ||
992 | ath9k_hw_analog_shift_rmw(ah, | ||
993 | AR9285_AN_RF2G3, | ||
994 | AR9271_AN_RF2G3_OB_psk, | ||
995 | AR9271_AN_RF2G3_OB_psk_S, | ||
996 | ob[1]); | ||
997 | ath9k_hw_analog_shift_rmw(ah, | ||
998 | AR9285_AN_RF2G3, | ||
999 | AR9271_AN_RF2G3_OB_qam, | ||
1000 | AR9271_AN_RF2G3_OB_qam_S, | ||
1001 | ob[2]); | ||
1002 | ath9k_hw_analog_shift_rmw(ah, | ||
1003 | AR9285_AN_RF2G3, | ||
1004 | AR9271_AN_RF2G3_DB_1, | ||
1005 | AR9271_AN_RF2G3_DB_1_S, | ||
1006 | db1[0]); | ||
1007 | ath9k_hw_analog_shift_rmw(ah, | ||
1008 | AR9285_AN_RF2G4, | ||
1009 | AR9271_AN_RF2G4_DB_2, | ||
1010 | AR9271_AN_RF2G4_DB_2_S, | ||
1011 | db2[0]); | ||
1012 | } else { | ||
1013 | ath9k_hw_analog_shift_rmw(ah, | ||
1014 | AR9285_AN_RF2G3, | ||
1015 | AR9285_AN_RF2G3_OB_0, | ||
1016 | AR9285_AN_RF2G3_OB_0_S, | ||
1017 | ob[0]); | ||
1018 | ath9k_hw_analog_shift_rmw(ah, | ||
1019 | AR9285_AN_RF2G3, | ||
1020 | AR9285_AN_RF2G3_OB_1, | ||
1021 | AR9285_AN_RF2G3_OB_1_S, | ||
1022 | ob[1]); | ||
1023 | ath9k_hw_analog_shift_rmw(ah, | ||
1024 | AR9285_AN_RF2G3, | ||
1025 | AR9285_AN_RF2G3_OB_2, | ||
1026 | AR9285_AN_RF2G3_OB_2_S, | ||
1027 | ob[2]); | ||
1028 | ath9k_hw_analog_shift_rmw(ah, | ||
1029 | AR9285_AN_RF2G3, | ||
1030 | AR9285_AN_RF2G3_OB_3, | ||
1031 | AR9285_AN_RF2G3_OB_3_S, | ||
1032 | ob[3]); | ||
1033 | ath9k_hw_analog_shift_rmw(ah, | ||
1034 | AR9285_AN_RF2G3, | ||
1035 | AR9285_AN_RF2G3_OB_4, | ||
1036 | AR9285_AN_RF2G3_OB_4_S, | ||
1037 | ob[4]); | ||
1038 | |||
1039 | ath9k_hw_analog_shift_rmw(ah, | ||
1040 | AR9285_AN_RF2G3, | ||
1041 | AR9285_AN_RF2G3_DB1_0, | ||
1042 | AR9285_AN_RF2G3_DB1_0_S, | ||
1043 | db1[0]); | ||
1044 | ath9k_hw_analog_shift_rmw(ah, | ||
1045 | AR9285_AN_RF2G3, | ||
1046 | AR9285_AN_RF2G3_DB1_1, | ||
1047 | AR9285_AN_RF2G3_DB1_1_S, | ||
1048 | db1[1]); | ||
1049 | ath9k_hw_analog_shift_rmw(ah, | ||
1050 | AR9285_AN_RF2G3, | ||
1051 | AR9285_AN_RF2G3_DB1_2, | ||
1052 | AR9285_AN_RF2G3_DB1_2_S, | ||
1053 | db1[2]); | ||
1054 | ath9k_hw_analog_shift_rmw(ah, | ||
1055 | AR9285_AN_RF2G4, | ||
1056 | AR9285_AN_RF2G4_DB1_3, | ||
1057 | AR9285_AN_RF2G4_DB1_3_S, | ||
1058 | db1[3]); | ||
1059 | ath9k_hw_analog_shift_rmw(ah, | ||
1060 | AR9285_AN_RF2G4, | ||
1061 | AR9285_AN_RF2G4_DB1_4, | ||
1062 | AR9285_AN_RF2G4_DB1_4_S, db1[4]); | ||
1063 | |||
1064 | ath9k_hw_analog_shift_rmw(ah, | ||
1065 | AR9285_AN_RF2G4, | ||
1066 | AR9285_AN_RF2G4_DB2_0, | ||
1067 | AR9285_AN_RF2G4_DB2_0_S, | ||
1068 | db2[0]); | ||
1069 | ath9k_hw_analog_shift_rmw(ah, | ||
1070 | AR9285_AN_RF2G4, | ||
1071 | AR9285_AN_RF2G4_DB2_1, | ||
1072 | AR9285_AN_RF2G4_DB2_1_S, | ||
1073 | db2[1]); | ||
1074 | ath9k_hw_analog_shift_rmw(ah, | ||
1075 | AR9285_AN_RF2G4, | ||
1076 | AR9285_AN_RF2G4_DB2_2, | ||
1077 | AR9285_AN_RF2G4_DB2_2_S, | ||
1078 | db2[2]); | ||
1079 | ath9k_hw_analog_shift_rmw(ah, | ||
1080 | AR9285_AN_RF2G4, | ||
1081 | AR9285_AN_RF2G4_DB2_3, | ||
1082 | AR9285_AN_RF2G4_DB2_3_S, | ||
1083 | db2[3]); | ||
1084 | ath9k_hw_analog_shift_rmw(ah, | ||
1085 | AR9285_AN_RF2G4, | ||
1086 | AR9285_AN_RF2G4_DB2_4, | ||
1087 | AR9285_AN_RF2G4_DB2_4_S, | ||
1088 | db2[4]); | ||
1089 | } | ||
1090 | |||
1091 | |||
1092 | if (AR_SREV_9285_11(ah)) | ||
1093 | REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); | ||
1094 | |||
1095 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, | ||
1096 | pModal->switchSettling); | ||
1097 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, | ||
1098 | pModal->adcDesiredSize); | ||
1099 | |||
1100 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
1101 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | | ||
1102 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | | ||
1103 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | | ||
1104 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
1105 | |||
1106 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, | ||
1107 | pModal->txEndToRxOn); | ||
1108 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, | ||
1109 | pModal->thresh62); | ||
1110 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, | ||
1111 | pModal->thresh62); | ||
1112 | |||
1113 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1114 | AR5416_EEP_MINOR_VER_2) { | ||
1115 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, | ||
1116 | pModal->txFrameToDataStart); | ||
1117 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, | ||
1118 | pModal->txFrameToPaOn); | ||
1119 | } | ||
1120 | |||
1121 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1122 | AR5416_EEP_MINOR_VER_3) { | ||
1123 | if (IS_CHAN_HT40(chan)) | ||
1124 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1125 | AR_PHY_SETTLING_SWITCH, | ||
1126 | pModal->swSettleHt40); | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, | ||
1131 | struct ath9k_channel *chan) | ||
1132 | { | ||
1133 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
1134 | struct modal_eep_4k_header *pModal = &eep->modalHeader; | ||
1135 | |||
1136 | return pModal->antCtrlCommon & 0xFFFF; | ||
1137 | } | ||
1138 | |||
1139 | static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, | ||
1140 | enum ieee80211_band freq_band) | ||
1141 | { | ||
1142 | return 1; | ||
1143 | } | ||
1144 | |||
1145 | static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) | ||
1146 | { | ||
1147 | #define EEP_MAP4K_SPURCHAN \ | ||
1148 | (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) | ||
1149 | |||
1150 | u16 spur_val = AR_NO_SPUR; | ||
1151 | |||
1152 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1153 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
1154 | i, is2GHz, ah->config.spurchans[i][is2GHz]); | ||
1155 | |||
1156 | switch (ah->config.spurmode) { | ||
1157 | case SPUR_DISABLE: | ||
1158 | break; | ||
1159 | case SPUR_ENABLE_IOCTL: | ||
1160 | spur_val = ah->config.spurchans[i][is2GHz]; | ||
1161 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1162 | "Getting spur val from new loc. %d\n", spur_val); | ||
1163 | break; | ||
1164 | case SPUR_ENABLE_EEPROM: | ||
1165 | spur_val = EEP_MAP4K_SPURCHAN; | ||
1166 | break; | ||
1167 | } | ||
1168 | |||
1169 | return spur_val; | ||
1170 | |||
1171 | #undef EEP_MAP4K_SPURCHAN | ||
1172 | } | ||
1173 | |||
1174 | const struct eeprom_ops eep_4k_ops = { | ||
1175 | .check_eeprom = ath9k_hw_4k_check_eeprom, | ||
1176 | .get_eeprom = ath9k_hw_4k_get_eeprom, | ||
1177 | .fill_eeprom = ath9k_hw_4k_fill_eeprom, | ||
1178 | .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, | ||
1179 | .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, | ||
1180 | .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, | ||
1181 | .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, | ||
1182 | .set_board_values = ath9k_hw_4k_set_board_values, | ||
1183 | .set_addac = ath9k_hw_4k_set_addac, | ||
1184 | .set_txpower = ath9k_hw_4k_set_txpower, | ||
1185 | .get_spur_channel = ath9k_hw_4k_get_spur_channel | ||
1186 | }; | ||