Commit | Line | Data |
---|---|---|
f1dc5600 | 1 | /* |
5b68138e | 2 | * Copyright (c) 2008-2011 Atheros Communications Inc. |
f1dc5600 S |
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 | ||
5bb12791 | 17 | #include "hw.h" |
f1dc5600 | 18 | |
79d7f4bc S |
19 | void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val) |
20 | { | |
21 | REG_WRITE(ah, reg, val); | |
22 | ||
23 | if (ah->config.analog_shiftreg) | |
24 | udelay(100); | |
25 | } | |
26 | ||
b5aec950 S |
27 | void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, |
28 | u32 shift, u32 val) | |
f1dc5600 S |
29 | { |
30 | u32 regVal; | |
31 | ||
32 | regVal = REG_READ(ah, reg) & ~mask; | |
33 | regVal |= (val << shift) & mask; | |
34 | ||
35 | REG_WRITE(ah, reg, regVal); | |
36 | ||
2660b81a | 37 | if (ah->config.analog_shiftreg) |
f1dc5600 | 38 | udelay(100); |
f1dc5600 S |
39 | } |
40 | ||
b5aec950 S |
41 | int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, |
42 | int16_t targetLeft, int16_t targetRight) | |
f1dc5600 S |
43 | { |
44 | int16_t rv; | |
45 | ||
46 | if (srcRight == srcLeft) { | |
47 | rv = targetLeft; | |
48 | } else { | |
49 | rv = (int16_t) (((target - srcLeft) * targetRight + | |
50 | (srcRight - target) * targetLeft) / | |
51 | (srcRight - srcLeft)); | |
52 | } | |
53 | return rv; | |
54 | } | |
55 | ||
b5aec950 S |
56 | bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, |
57 | u16 *indexL, u16 *indexR) | |
f1dc5600 S |
58 | { |
59 | u16 i; | |
60 | ||
61 | if (target <= pList[0]) { | |
62 | *indexL = *indexR = 0; | |
63 | return true; | |
64 | } | |
65 | if (target >= pList[listSize - 1]) { | |
66 | *indexL = *indexR = (u16) (listSize - 1); | |
67 | return true; | |
68 | } | |
69 | ||
70 | for (i = 0; i < listSize - 1; i++) { | |
71 | if (pList[i] == target) { | |
72 | *indexL = *indexR = i; | |
73 | return true; | |
74 | } | |
75 | if (target < pList[i + 1]) { | |
76 | *indexL = i; | |
77 | *indexR = (u16) (i + 1); | |
78 | return false; | |
79 | } | |
80 | } | |
81 | return false; | |
82 | } | |
83 | ||
04cf53f4 SM |
84 | void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, |
85 | int eep_start_loc, int size) | |
86 | { | |
87 | int i = 0, j, addr; | |
88 | u32 addrdata[8]; | |
89 | u32 data[8]; | |
90 | ||
91 | for (addr = 0; addr < size; addr++) { | |
92 | addrdata[i] = AR5416_EEPROM_OFFSET + | |
93 | ((addr + eep_start_loc) << AR5416_EEPROM_S); | |
94 | i++; | |
95 | if (i == 8) { | |
96 | REG_READ_MULTI(ah, addrdata, data, i); | |
97 | ||
98 | for (j = 0; j < i; j++) { | |
99 | *eep_data = data[j]; | |
100 | eep_data++; | |
101 | } | |
102 | i = 0; | |
103 | } | |
104 | } | |
105 | ||
106 | if (i != 0) { | |
107 | REG_READ_MULTI(ah, addrdata, data, i); | |
108 | ||
109 | for (j = 0; j < i; j++) { | |
110 | *eep_data = data[j]; | |
111 | eep_data++; | |
112 | } | |
113 | } | |
114 | } | |
115 | ||
ab5c4f71 GJ |
116 | static bool ath9k_hw_nvram_read_blob(struct ath_hw *ah, u32 off, |
117 | u16 *data) | |
118 | { | |
119 | u16 *blob_data; | |
120 | ||
121 | if (off * sizeof(u16) > ah->eeprom_blob->size) | |
122 | return false; | |
123 | ||
124 | blob_data = (u16 *)ah->eeprom_blob->data; | |
125 | *data = blob_data[off]; | |
126 | return true; | |
127 | } | |
128 | ||
0e4b9f2f | 129 | bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) |
f1dc5600 | 130 | { |
0e4b9f2f | 131 | struct ath_common *common = ath9k_hw_common(ah); |
2fd2cdfb GJ |
132 | bool ret; |
133 | ||
ab5c4f71 GJ |
134 | if (ah->eeprom_blob) |
135 | ret = ath9k_hw_nvram_read_blob(ah, off, data); | |
136 | else | |
137 | ret = common->bus_ops->eeprom_read(common, off, data); | |
138 | ||
2fd2cdfb | 139 | if (!ret) |
7177d8f9 GJ |
140 | ath_dbg(common, EEPROM, |
141 | "unable to read eeprom region at offset %u\n", off); | |
2fd2cdfb GJ |
142 | |
143 | return ret; | |
f1dc5600 S |
144 | } |
145 | ||
b5aec950 S |
146 | void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, |
147 | u8 *pVpdList, u16 numIntercepts, | |
148 | u8 *pRetVpdList) | |
f74df6fb S |
149 | { |
150 | u16 i, k; | |
151 | u8 currPwr = pwrMin; | |
152 | u16 idxL = 0, idxR = 0; | |
153 | ||
154 | for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { | |
155 | ath9k_hw_get_lower_upper_index(currPwr, pPwrList, | |
156 | numIntercepts, &(idxL), | |
157 | &(idxR)); | |
158 | if (idxR < 1) | |
159 | idxR = 1; | |
160 | if (idxL == numIntercepts - 1) | |
161 | idxL = (u16) (numIntercepts - 2); | |
162 | if (pPwrList[idxL] == pPwrList[idxR]) | |
163 | k = pVpdList[idxL]; | |
164 | else | |
165 | k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + | |
166 | (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / | |
167 | (pPwrList[idxR] - pPwrList[idxL])); | |
168 | pRetVpdList[i] = (u8) k; | |
169 | currPwr += 2; | |
170 | } | |
f74df6fb S |
171 | } |
172 | ||
b5aec950 S |
173 | void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, |
174 | struct ath9k_channel *chan, | |
175 | struct cal_target_power_leg *powInfo, | |
176 | u16 numChannels, | |
177 | struct cal_target_power_leg *pNewPower, | |
178 | u16 numRates, bool isExtTarget) | |
f74df6fb S |
179 | { |
180 | struct chan_centers centers; | |
181 | u16 clo, chi; | |
182 | int i; | |
183 | int matchIndex = -1, lowIndex = -1; | |
184 | u16 freq; | |
185 | ||
186 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | |
187 | freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; | |
188 | ||
189 | if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, | |
190 | IS_CHAN_2GHZ(chan))) { | |
191 | matchIndex = 0; | |
192 | } else { | |
193 | for (i = 0; (i < numChannels) && | |
194 | (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { | |
195 | if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, | |
196 | IS_CHAN_2GHZ(chan))) { | |
197 | matchIndex = i; | |
198 | break; | |
73f57f83 RK |
199 | } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, |
200 | IS_CHAN_2GHZ(chan)) && i > 0 && | |
201 | freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, | |
202 | IS_CHAN_2GHZ(chan))) { | |
f74df6fb S |
203 | lowIndex = i - 1; |
204 | break; | |
205 | } | |
206 | } | |
207 | if ((matchIndex == -1) && (lowIndex == -1)) | |
208 | matchIndex = i - 1; | |
209 | } | |
210 | ||
211 | if (matchIndex != -1) { | |
212 | *pNewPower = powInfo[matchIndex]; | |
213 | } else { | |
214 | clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, | |
215 | IS_CHAN_2GHZ(chan)); | |
216 | chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, | |
217 | IS_CHAN_2GHZ(chan)); | |
218 | ||
219 | for (i = 0; i < numRates; i++) { | |
220 | pNewPower->tPow2x[i] = | |
221 | (u8)ath9k_hw_interpolate(freq, clo, chi, | |
222 | powInfo[lowIndex].tPow2x[i], | |
223 | powInfo[lowIndex + 1].tPow2x[i]); | |
224 | } | |
225 | } | |
226 | } | |
227 | ||
b5aec950 S |
228 | void ath9k_hw_get_target_powers(struct ath_hw *ah, |
229 | struct ath9k_channel *chan, | |
230 | struct cal_target_power_ht *powInfo, | |
231 | u16 numChannels, | |
232 | struct cal_target_power_ht *pNewPower, | |
233 | u16 numRates, bool isHt40Target) | |
f74df6fb S |
234 | { |
235 | struct chan_centers centers; | |
236 | u16 clo, chi; | |
237 | int i; | |
238 | int matchIndex = -1, lowIndex = -1; | |
239 | u16 freq; | |
240 | ||
241 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | |
242 | freq = isHt40Target ? centers.synth_center : centers.ctl_center; | |
243 | ||
244 | if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { | |
245 | matchIndex = 0; | |
246 | } else { | |
247 | for (i = 0; (i < numChannels) && | |
248 | (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { | |
249 | if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, | |
250 | IS_CHAN_2GHZ(chan))) { | |
251 | matchIndex = i; | |
252 | break; | |
253 | } else | |
73f57f83 RK |
254 | if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, |
255 | IS_CHAN_2GHZ(chan)) && i > 0 && | |
256 | freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, | |
257 | IS_CHAN_2GHZ(chan))) { | |
f74df6fb S |
258 | lowIndex = i - 1; |
259 | break; | |
260 | } | |
261 | } | |
262 | if ((matchIndex == -1) && (lowIndex == -1)) | |
263 | matchIndex = i - 1; | |
264 | } | |
265 | ||
266 | if (matchIndex != -1) { | |
267 | *pNewPower = powInfo[matchIndex]; | |
268 | } else { | |
269 | clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, | |
270 | IS_CHAN_2GHZ(chan)); | |
271 | chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, | |
272 | IS_CHAN_2GHZ(chan)); | |
273 | ||
274 | for (i = 0; i < numRates; i++) { | |
275 | pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, | |
276 | clo, chi, | |
277 | powInfo[lowIndex].tPow2x[i], | |
278 | powInfo[lowIndex + 1].tPow2x[i]); | |
279 | } | |
280 | } | |
281 | } | |
282 | ||
b5aec950 S |
283 | u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, |
284 | bool is2GHz, int num_band_edges) | |
f74df6fb | 285 | { |
4ddfcd7d | 286 | u16 twiceMaxEdgePower = MAX_RATE_POWER; |
f74df6fb S |
287 | int i; |
288 | ||
289 | for (i = 0; (i < num_band_edges) && | |
290 | (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { | |
291 | if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { | |
e702ba18 | 292 | twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl); |
f74df6fb S |
293 | break; |
294 | } else if ((i > 0) && | |
295 | (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, | |
296 | is2GHz))) { | |
297 | if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, | |
298 | is2GHz) < freq && | |
e702ba18 | 299 | CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) { |
f74df6fb | 300 | twiceMaxEdgePower = |
e702ba18 | 301 | CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl); |
f74df6fb S |
302 | } |
303 | break; | |
304 | } | |
305 | } | |
306 | ||
307 | return twiceMaxEdgePower; | |
308 | } | |
309 | ||
ea6f792b GJ |
310 | u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit, |
311 | u8 antenna_reduction) | |
312 | { | |
8f942b9b | 313 | u16 reduction = antenna_reduction; |
ea6f792b GJ |
314 | |
315 | /* | |
316 | * Reduce scaled Power by number of chains active | |
317 | * to get the per chain tx power level. | |
318 | */ | |
319 | switch (ar5416_get_ntxchains(ah->txchainmask)) { | |
320 | case 1: | |
321 | break; | |
322 | case 2: | |
6010e72c | 323 | reduction += POWER_CORRECTION_FOR_TWO_CHAIN; |
ea6f792b GJ |
324 | break; |
325 | case 3: | |
6010e72c | 326 | reduction += POWER_CORRECTION_FOR_THREE_CHAIN; |
ea6f792b GJ |
327 | break; |
328 | } | |
329 | ||
8f942b9b GJ |
330 | if (power_limit > reduction) |
331 | power_limit -= reduction; | |
332 | else | |
333 | power_limit = 0; | |
ea6f792b | 334 | |
8f942b9b | 335 | return power_limit; |
ea6f792b GJ |
336 | } |
337 | ||
a55f8588 S |
338 | void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah) |
339 | { | |
340 | struct ath_common *common = ath9k_hw_common(ah); | |
341 | struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); | |
342 | ||
343 | switch (ar5416_get_ntxchains(ah->txchainmask)) { | |
344 | case 1: | |
345 | break; | |
346 | case 2: | |
6010e72c | 347 | regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN; |
a55f8588 S |
348 | break; |
349 | case 3: | |
6010e72c | 350 | regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN; |
a55f8588 S |
351 | break; |
352 | default: | |
d2182b69 | 353 | ath_dbg(common, EEPROM, "Invalid chainmask configuration\n"); |
a55f8588 S |
354 | break; |
355 | } | |
356 | } | |
357 | ||
115277a3 FF |
358 | void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, |
359 | struct ath9k_channel *chan, | |
360 | void *pRawDataSet, | |
361 | u8 *bChans, u16 availPiers, | |
362 | u16 tPdGainOverlap, | |
363 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | |
364 | u16 numXpdGains) | |
365 | { | |
366 | int i, j, k; | |
367 | int16_t ss; | |
368 | u16 idxL = 0, idxR = 0, numPiers; | |
369 | static u8 vpdTableL[AR5416_NUM_PD_GAINS] | |
370 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | |
371 | static u8 vpdTableR[AR5416_NUM_PD_GAINS] | |
372 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | |
373 | static u8 vpdTableI[AR5416_NUM_PD_GAINS] | |
374 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | |
375 | ||
376 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | |
377 | u8 minPwrT4[AR5416_NUM_PD_GAINS]; | |
378 | u8 maxPwrT4[AR5416_NUM_PD_GAINS]; | |
379 | int16_t vpdStep; | |
380 | int16_t tmpVal; | |
381 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | |
382 | bool match; | |
383 | int16_t minDelta = 0; | |
384 | struct chan_centers centers; | |
385 | int pdgain_boundary_default; | |
386 | struct cal_data_per_freq *data_def = pRawDataSet; | |
387 | struct cal_data_per_freq_4k *data_4k = pRawDataSet; | |
940cd2c1 | 388 | struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet; |
115277a3 | 389 | bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah); |
940cd2c1 FF |
390 | int intercepts; |
391 | ||
392 | if (AR_SREV_9287(ah)) | |
393 | intercepts = AR9287_PD_GAIN_ICEPTS; | |
394 | else | |
395 | intercepts = AR5416_PD_GAIN_ICEPTS; | |
115277a3 FF |
396 | |
397 | memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS); | |
398 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | |
399 | ||
400 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | |
401 | if (bChans[numPiers] == AR5416_BCHAN_UNUSED) | |
402 | break; | |
403 | } | |
404 | ||
405 | match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, | |
406 | IS_CHAN_2GHZ(chan)), | |
407 | bChans, numPiers, &idxL, &idxR); | |
408 | ||
409 | if (match) { | |
940cd2c1 FF |
410 | if (AR_SREV_9287(ah)) { |
411 | /* FIXME: array overrun? */ | |
412 | for (i = 0; i < numXpdGains; i++) { | |
413 | minPwrT4[i] = data_9287[idxL].pwrPdg[i][0]; | |
414 | maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4]; | |
415 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | |
416 | data_9287[idxL].pwrPdg[i], | |
417 | data_9287[idxL].vpdPdg[i], | |
418 | intercepts, | |
419 | vpdTableI[i]); | |
420 | } | |
421 | } else if (eeprom_4k) { | |
115277a3 FF |
422 | for (i = 0; i < numXpdGains; i++) { |
423 | minPwrT4[i] = data_4k[idxL].pwrPdg[i][0]; | |
424 | maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4]; | |
425 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | |
426 | data_4k[idxL].pwrPdg[i], | |
427 | data_4k[idxL].vpdPdg[i], | |
940cd2c1 | 428 | intercepts, |
115277a3 FF |
429 | vpdTableI[i]); |
430 | } | |
431 | } else { | |
432 | for (i = 0; i < numXpdGains; i++) { | |
433 | minPwrT4[i] = data_def[idxL].pwrPdg[i][0]; | |
434 | maxPwrT4[i] = data_def[idxL].pwrPdg[i][4]; | |
435 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | |
436 | data_def[idxL].pwrPdg[i], | |
437 | data_def[idxL].vpdPdg[i], | |
940cd2c1 | 438 | intercepts, |
115277a3 FF |
439 | vpdTableI[i]); |
440 | } | |
441 | } | |
442 | } else { | |
443 | for (i = 0; i < numXpdGains; i++) { | |
940cd2c1 FF |
444 | if (AR_SREV_9287(ah)) { |
445 | pVpdL = data_9287[idxL].vpdPdg[i]; | |
446 | pPwrL = data_9287[idxL].pwrPdg[i]; | |
447 | pVpdR = data_9287[idxR].vpdPdg[i]; | |
448 | pPwrR = data_9287[idxR].pwrPdg[i]; | |
449 | } else if (eeprom_4k) { | |
115277a3 FF |
450 | pVpdL = data_4k[idxL].vpdPdg[i]; |
451 | pPwrL = data_4k[idxL].pwrPdg[i]; | |
452 | pVpdR = data_4k[idxR].vpdPdg[i]; | |
453 | pPwrR = data_4k[idxR].pwrPdg[i]; | |
454 | } else { | |
455 | pVpdL = data_def[idxL].vpdPdg[i]; | |
456 | pPwrL = data_def[idxL].pwrPdg[i]; | |
457 | pVpdR = data_def[idxR].vpdPdg[i]; | |
458 | pPwrR = data_def[idxR].pwrPdg[i]; | |
459 | } | |
460 | ||
461 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | |
462 | ||
463 | maxPwrT4[i] = | |
940cd2c1 FF |
464 | min(pPwrL[intercepts - 1], |
465 | pPwrR[intercepts - 1]); | |
115277a3 FF |
466 | |
467 | ||
468 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | |
469 | pPwrL, pVpdL, | |
940cd2c1 | 470 | intercepts, |
115277a3 FF |
471 | vpdTableL[i]); |
472 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | |
473 | pPwrR, pVpdR, | |
940cd2c1 | 474 | intercepts, |
115277a3 FF |
475 | vpdTableR[i]); |
476 | ||
477 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | |
478 | vpdTableI[i][j] = | |
479 | (u8)(ath9k_hw_interpolate((u16) | |
480 | FREQ2FBIN(centers. | |
481 | synth_center, | |
482 | IS_CHAN_2GHZ | |
483 | (chan)), | |
484 | bChans[idxL], bChans[idxR], | |
485 | vpdTableL[i][j], vpdTableR[i][j])); | |
486 | } | |
487 | } | |
488 | } | |
489 | ||
490 | k = 0; | |
491 | ||
492 | for (i = 0; i < numXpdGains; i++) { | |
493 | if (i == (numXpdGains - 1)) | |
494 | pPdGainBoundaries[i] = | |
495 | (u16)(maxPwrT4[i] / 2); | |
496 | else | |
497 | pPdGainBoundaries[i] = | |
498 | (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); | |
499 | ||
500 | pPdGainBoundaries[i] = | |
501 | min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]); | |
502 | ||
1b8714f7 | 503 | minDelta = 0; |
115277a3 FF |
504 | |
505 | if (i == 0) { | |
506 | if (AR_SREV_9280_20_OR_LATER(ah)) | |
507 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | |
508 | else | |
509 | ss = 0; | |
510 | } else { | |
511 | ss = (int16_t)((pPdGainBoundaries[i - 1] - | |
512 | (minPwrT4[i] / 2)) - | |
513 | tPdGainOverlap + 1 + minDelta); | |
514 | } | |
515 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | |
516 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | |
517 | ||
518 | while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | |
519 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | |
520 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | |
521 | ss++; | |
522 | } | |
523 | ||
524 | sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | |
525 | tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - | |
526 | (minPwrT4[i] / 2)); | |
527 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | |
528 | tgtIndex : sizeCurrVpdTable; | |
529 | ||
530 | while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | |
531 | pPDADCValues[k++] = vpdTableI[i][ss++]; | |
532 | } | |
533 | ||
534 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | |
535 | vpdTableI[i][sizeCurrVpdTable - 2]); | |
536 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | |
537 | ||
538 | if (tgtIndex >= maxIndex) { | |
539 | while ((ss <= tgtIndex) && | |
540 | (k < (AR5416_NUM_PDADC_VALUES - 1))) { | |
541 | tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + | |
542 | (ss - maxIndex + 1) * vpdStep)); | |
543 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | |
544 | 255 : tmpVal); | |
545 | ss++; | |
546 | } | |
547 | } | |
548 | } | |
549 | ||
550 | if (eeprom_4k) | |
551 | pdgain_boundary_default = 58; | |
552 | else | |
553 | pdgain_boundary_default = pPdGainBoundaries[i - 1]; | |
554 | ||
555 | while (i < AR5416_PD_GAINS_IN_MASK) { | |
556 | pPdGainBoundaries[i] = pdgain_boundary_default; | |
557 | i++; | |
558 | } | |
559 | ||
560 | while (k < AR5416_NUM_PDADC_VALUES) { | |
561 | pPDADCValues[k] = pPDADCValues[k - 1]; | |
562 | k++; | |
563 | } | |
564 | } | |
565 | ||
f637cfd6 | 566 | int ath9k_hw_eeprom_init(struct ath_hw *ah) |
f1dc5600 S |
567 | { |
568 | int status; | |
c16c9d06 | 569 | |
15c9ee7a SB |
570 | if (AR_SREV_9300_20_OR_LATER(ah)) |
571 | ah->eep_ops = &eep_ar9300_ops; | |
572 | else if (AR_SREV_9287(ah)) { | |
0b8f6f2b | 573 | ah->eep_ops = &eep_ar9287_ops; |
d7e7d229 | 574 | } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { |
f74df6fb S |
575 | ah->eep_ops = &eep_4k_ops; |
576 | } else { | |
f74df6fb S |
577 | ah->eep_ops = &eep_def_ops; |
578 | } | |
e7594072 | 579 | |
f74df6fb | 580 | if (!ah->eep_ops->fill_eeprom(ah)) |
f1dc5600 S |
581 | return -EIO; |
582 | ||
f74df6fb | 583 | status = ah->eep_ops->check_eeprom(ah); |
f1dc5600 S |
584 | |
585 | return status; | |
586 | } |