Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2008-2011 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 "hw.h"
18 : : #include <linux/ath9k_platform.h>
19 : :
20 : 0 : void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
21 : : {
22 : 0 : REG_WRITE(ah, reg, val);
23 : :
24 [ # # ]: 0 : if (ah->config.analog_shiftreg)
25 : 0 : udelay(100);
26 : 0 : }
27 : :
28 : 0 : void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
29 : : u32 shift, u32 val)
30 : : {
31 : 0 : REG_RMW(ah, reg, ((val << shift) & mask), mask);
32 : :
33 [ # # ]: 0 : if (ah->config.analog_shiftreg)
34 : 0 : udelay(100);
35 : 0 : }
36 : :
37 : 0 : int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
38 : : int16_t targetLeft, int16_t targetRight)
39 : : {
40 : 0 : int16_t rv;
41 : :
42 [ # # # # ]: 0 : if (srcRight == srcLeft) {
43 : : rv = targetLeft;
44 : : } else {
45 : 0 : rv = (int16_t) (((target - srcLeft) * targetRight +
46 : 0 : (srcRight - target) * targetLeft) /
47 : 0 : (srcRight - srcLeft));
48 : : }
49 : 0 : return rv;
50 : : }
51 : :
52 : 0 : bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
53 : : u16 *indexL, u16 *indexR)
54 : : {
55 : 0 : u16 i;
56 : :
57 [ # # ]: 0 : if (target <= pList[0]) {
58 : 0 : *indexL = *indexR = 0;
59 : 0 : return true;
60 : : }
61 [ # # ]: 0 : if (target >= pList[listSize - 1]) {
62 : 0 : *indexL = *indexR = (u16) (listSize - 1);
63 : 0 : return true;
64 : : }
65 : :
66 [ # # ]: 0 : for (i = 0; i < listSize - 1; i++) {
67 [ # # ]: 0 : if (pList[i] == target) {
68 : 0 : *indexL = *indexR = i;
69 : 0 : return true;
70 : : }
71 [ # # ]: 0 : if (target < pList[i + 1]) {
72 : 0 : *indexL = i;
73 : 0 : *indexR = (u16) (i + 1);
74 : 0 : return false;
75 : : }
76 : : }
77 : : return false;
78 : : }
79 : :
80 : 0 : void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
81 : : int eep_start_loc, int size)
82 : : {
83 : 0 : int i = 0, j, addr;
84 : 0 : u32 addrdata[8];
85 : 0 : u32 data[8];
86 : :
87 [ # # ]: 0 : for (addr = 0; addr < size; addr++) {
88 : 0 : addrdata[i] = AR5416_EEPROM_OFFSET +
89 : 0 : ((addr + eep_start_loc) << AR5416_EEPROM_S);
90 : 0 : i++;
91 [ # # ]: 0 : if (i == 8) {
92 : 0 : REG_READ_MULTI(ah, addrdata, data, i);
93 : :
94 [ # # ]: 0 : for (j = 0; j < i; j++) {
95 : 0 : *eep_data = data[j];
96 : 0 : eep_data++;
97 : : }
98 : : i = 0;
99 : : }
100 : : }
101 : :
102 [ # # ]: 0 : if (i != 0) {
103 : 0 : REG_READ_MULTI(ah, addrdata, data, i);
104 : :
105 [ # # ]: 0 : for (j = 0; j < i; j++) {
106 : 0 : *eep_data = data[j];
107 : 0 : eep_data++;
108 : : }
109 : : }
110 : 0 : }
111 : :
112 : 0 : static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size,
113 : : off_t offset, u16 *data)
114 : : {
115 : 0 : if (offset >= blob_size)
116 : : return false;
117 : :
118 : 0 : *data = blob[offset];
119 : 0 : return true;
120 : : }
121 : :
122 : 0 : static bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data *pdata,
123 : : off_t offset, u16 *data)
124 : : {
125 : 0 : return ath9k_hw_nvram_read_array(pdata->eeprom_data,
126 : : ARRAY_SIZE(pdata->eeprom_data),
127 : : offset, data);
128 : : }
129 : :
130 : 0 : static bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob,
131 : : off_t offset, u16 *data)
132 : : {
133 : 0 : return ath9k_hw_nvram_read_array((u16 *) eeprom_blob->data,
134 : : eeprom_blob->size / sizeof(u16),
135 : : offset, data);
136 : : }
137 : :
138 : 4909 : bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
139 : : {
140 [ - + ]: 4909 : struct ath_common *common = ath9k_hw_common(ah);
141 : 4909 : struct ath9k_platform_data *pdata = ah->dev->platform_data;
142 : 4909 : bool ret;
143 : :
144 [ - + ]: 4909 : if (ah->eeprom_blob)
145 [ # # ]: 0 : ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data);
146 [ - + - - ]: 4909 : else if (pdata && !pdata->use_eeprom)
147 [ # # ]: 0 : ret = ath9k_hw_nvram_read_pdata(pdata, off, data);
148 : : else
149 : 4909 : ret = common->bus_ops->eeprom_read(common, off, data);
150 : :
151 [ - + ]: 4909 : if (!ret)
152 [ # # ]: 0 : ath_dbg(common, EEPROM,
153 : : "unable to read eeprom region at offset %u\n", off);
154 : :
155 : 4909 : return ret;
156 : : }
157 : :
158 : 3 : int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
159 : : {
160 : 3 : u16 magic;
161 : 3 : u16 *eepdata;
162 : 3 : int i;
163 : 3 : bool needs_byteswap = false;
164 : 3 : struct ath_common *common = ath9k_hw_common(ah);
165 : :
166 [ - + ]: 3 : if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
167 : 0 : ath_err(common, "Reading Magic # failed\n");
168 : 0 : return -EIO;
169 : : }
170 : :
171 [ - + ]: 3 : if (swab16(magic) == AR5416_EEPROM_MAGIC) {
172 : 0 : needs_byteswap = true;
173 [ # # ]: 0 : ath_dbg(common, EEPROM,
174 : : "EEPROM needs byte-swapping to correct endianness.\n");
175 [ + + ]: 3 : } else if (magic != AR5416_EEPROM_MAGIC) {
176 [ - + ]: 1 : if (ath9k_hw_use_flash(ah)) {
177 [ # # ]: 0 : ath_dbg(common, EEPROM,
178 : : "Ignoring invalid EEPROM magic (0x%04x).\n",
179 : : magic);
180 : : } else {
181 : 1 : ath_err(common,
182 : : "Invalid EEPROM magic (0x%04x).\n", magic);
183 : 1 : return -EINVAL;
184 : : }
185 : : }
186 : :
187 : 0 : if (needs_byteswap) {
188 [ # # ]: 0 : if (ah->ah_flags & AH_NO_EEP_SWAP) {
189 : 0 : ath_info(common,
190 : : "Ignoring endianness difference in EEPROM magic bytes.\n");
191 : : } else {
192 : 0 : eepdata = (u16 *)(&ah->eeprom);
193 : :
194 [ # # ]: 0 : for (i = 0; i < size; i++)
195 : 0 : eepdata[i] = swab16(eepdata[i]);
196 : : }
197 : : }
198 : :
199 [ - + ]: 2 : if (ah->eep_ops->get_eepmisc(ah) & AR5416_EEPMISC_BIG_ENDIAN) {
200 : 0 : *swap_needed = true;
201 [ # # ]: 0 : ath_dbg(common, EEPROM,
202 : : "Big Endian EEPROM detected according to EEPMISC register.\n");
203 : : } else {
204 : 2 : *swap_needed = false;
205 : : }
206 : :
207 : : return 0;
208 : : }
209 : :
210 : 2 : bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
211 : : {
212 : 2 : u32 i, sum = 0;
213 : 2 : u16 *eepdata = (u16 *)(&ah->eeprom);
214 : 2 : struct ath_common *common = ath9k_hw_common(ah);
215 : :
216 [ + + ]: 3258 : for (i = 0; i < size; i++)
217 : 3256 : sum ^= eepdata[i];
218 : :
219 [ - + ]: 2 : if (sum != 0xffff) {
220 : 0 : ath_err(common, "Bad EEPROM checksum 0x%x\n", sum);
221 : 0 : return false;
222 : : }
223 : :
224 : : return true;
225 : : }
226 : :
227 : 2 : bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev)
228 : : {
229 : 2 : struct ath_common *common = ath9k_hw_common(ah);
230 : :
231 [ + - - + ]: 4 : if (ah->eep_ops->get_eeprom_ver(ah) != version ||
232 : 2 : ah->eep_ops->get_eeprom_rev(ah) < minrev) {
233 : 0 : ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n",
234 : : ah->eep_ops->get_eeprom_ver(ah),
235 : : ah->eep_ops->get_eeprom_rev(ah));
236 : 0 : return false;
237 : : }
238 : :
239 : : return true;
240 : : }
241 : :
242 : 0 : void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
243 : : u8 *pVpdList, u16 numIntercepts,
244 : : u8 *pRetVpdList)
245 : : {
246 : 0 : u16 i, k;
247 : 0 : u8 currPwr = pwrMin;
248 : 0 : u16 idxL = 0, idxR = 0;
249 : :
250 [ # # ]: 0 : for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
251 : 0 : ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
252 : : numIntercepts, &(idxL),
253 : : &(idxR));
254 [ # # ]: 0 : if (idxR < 1)
255 : 0 : idxR = 1;
256 [ # # ]: 0 : if (idxL == numIntercepts - 1)
257 : 0 : idxL = (u16) (numIntercepts - 2);
258 [ # # ]: 0 : if (pPwrList[idxL] == pPwrList[idxR])
259 : 0 : k = pVpdList[idxL];
260 : : else
261 : 0 : k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
262 : 0 : (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
263 : 0 : (pPwrList[idxR] - pPwrList[idxL]));
264 : 0 : pRetVpdList[i] = (u8) k;
265 : 0 : currPwr += 2;
266 : : }
267 : 0 : }
268 : :
269 : 104 : void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
270 : : struct ath9k_channel *chan,
271 : : struct cal_target_power_leg *powInfo,
272 : : u16 numChannels,
273 : : struct cal_target_power_leg *pNewPower,
274 : : u16 numRates, bool isExtTarget)
275 : : {
276 : 104 : struct chan_centers centers;
277 : 104 : u16 clo, chi;
278 : 104 : int i;
279 : 104 : int matchIndex = -1, lowIndex = -1;
280 : 104 : u16 freq;
281 : :
282 : 104 : ath9k_hw_get_channel_centers(ah, chan, ¢ers);
283 [ - + ]: 104 : freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
284 : :
285 [ + - ]: 104 : if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
286 [ + - ]: 104 : IS_CHAN_2GHZ(chan))) {
287 : : matchIndex = 0;
288 : : } else {
289 [ + + ]: 468 : for (i = 0; (i < numChannels) &&
290 [ + - ]: 728 : (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
291 [ + - + - ]: 728 : if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
292 : : IS_CHAN_2GHZ(chan))) {
293 : : matchIndex = i;
294 : : break;
295 [ + - - + ]: 728 : } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
296 [ # # # # ]: 0 : IS_CHAN_2GHZ(chan)) && i > 0 &&
297 [ # # ]: 0 : freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
298 : : IS_CHAN_2GHZ(chan))) {
299 : : lowIndex = i - 1;
300 : : break;
301 : : }
302 : : }
303 [ + - + - ]: 104 : if ((matchIndex == -1) && (lowIndex == -1))
304 : 104 : matchIndex = i - 1;
305 : : }
306 : :
307 [ + - ]: 104 : if (matchIndex != -1) {
308 : 104 : *pNewPower = powInfo[matchIndex];
309 : : } else {
310 [ # # ]: 0 : clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
311 : : IS_CHAN_2GHZ(chan));
312 [ # # ]: 0 : chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
313 : : IS_CHAN_2GHZ(chan));
314 : :
315 [ # # ]: 0 : for (i = 0; i < numRates; i++) {
316 : 0 : pNewPower->tPow2x[i] =
317 : 0 : (u8)ath9k_hw_interpolate(freq, clo, chi,
318 : 0 : powInfo[lowIndex].tPow2x[i],
319 [ # # ]: 0 : powInfo[lowIndex + 1].tPow2x[i]);
320 : : }
321 : : }
322 : 104 : }
323 : :
324 : 52 : void ath9k_hw_get_target_powers(struct ath_hw *ah,
325 : : struct ath9k_channel *chan,
326 : : struct cal_target_power_ht *powInfo,
327 : : u16 numChannels,
328 : : struct cal_target_power_ht *pNewPower,
329 : : u16 numRates, bool isHt40Target)
330 : : {
331 : 52 : struct chan_centers centers;
332 : 52 : u16 clo, chi;
333 : 52 : int i;
334 : 52 : int matchIndex = -1, lowIndex = -1;
335 : 52 : u16 freq;
336 : :
337 : 52 : ath9k_hw_get_channel_centers(ah, chan, ¢ers);
338 [ - + ]: 52 : freq = isHt40Target ? centers.synth_center : centers.ctl_center;
339 : :
340 [ + - + - ]: 104 : if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
341 : : matchIndex = 0;
342 : : } else {
343 [ + + ]: 260 : for (i = 0; (i < numChannels) &&
344 [ + - ]: 416 : (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
345 [ + - + - ]: 416 : if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
346 : : IS_CHAN_2GHZ(chan))) {
347 : : matchIndex = i;
348 : : break;
349 : : } else
350 [ + - - + ]: 416 : if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
351 [ # # # # ]: 0 : IS_CHAN_2GHZ(chan)) && i > 0 &&
352 [ # # ]: 0 : freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
353 : : IS_CHAN_2GHZ(chan))) {
354 : : lowIndex = i - 1;
355 : : break;
356 : : }
357 : : }
358 [ + - + - ]: 52 : if ((matchIndex == -1) && (lowIndex == -1))
359 : 52 : matchIndex = i - 1;
360 : : }
361 : :
362 [ + - ]: 52 : if (matchIndex != -1) {
363 : 52 : *pNewPower = powInfo[matchIndex];
364 : : } else {
365 [ # # ]: 0 : clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
366 : : IS_CHAN_2GHZ(chan));
367 [ # # ]: 0 : chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
368 : : IS_CHAN_2GHZ(chan));
369 : :
370 [ # # ]: 0 : for (i = 0; i < numRates; i++) {
371 : 0 : pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
372 : : clo, chi,
373 : 0 : powInfo[lowIndex].tPow2x[i],
374 [ # # ]: 0 : powInfo[lowIndex + 1].tPow2x[i]);
375 : : }
376 : : }
377 : 52 : }
378 : :
379 : 0 : u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
380 : : bool is2GHz, int num_band_edges)
381 : : {
382 : 0 : u16 twiceMaxEdgePower = MAX_RATE_POWER;
383 : 0 : int i;
384 : :
385 [ # # ]: 0 : for (i = 0; (i < num_band_edges) &&
386 [ # # ]: 0 : (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
387 [ # # # # ]: 0 : if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
388 : 0 : twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
389 : 0 : break;
390 [ # # # # ]: 0 : } else if ((i > 0) &&
391 : : (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
392 : : is2GHz))) {
393 [ # # # # ]: 0 : if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
394 : 0 : is2GHz) < freq &&
395 [ # # ]: 0 : CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
396 : 0 : twiceMaxEdgePower =
397 : : CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
398 : : }
399 : : break;
400 : : }
401 : : }
402 : :
403 : 0 : return twiceMaxEdgePower;
404 : : }
405 : :
406 : 252 : u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
407 : : u8 antenna_reduction)
408 : : {
409 : 252 : u16 reduction = antenna_reduction;
410 : :
411 : : /*
412 : : * Reduce scaled Power by number of chains active
413 : : * to get the per chain tx power level.
414 : : */
415 [ + + - ]: 252 : switch (ar5416_get_ntxchains(ah->txchainmask)) {
416 : : case 1:
417 : : break;
418 : 102 : case 2:
419 : 102 : reduction += POWER_CORRECTION_FOR_TWO_CHAIN;
420 : 102 : break;
421 : 150 : case 3:
422 : 150 : reduction += POWER_CORRECTION_FOR_THREE_CHAIN;
423 : 150 : break;
424 : : }
425 : :
426 [ + + ]: 252 : if (power_limit > reduction)
427 : 197 : power_limit -= reduction;
428 : : else
429 : : power_limit = 0;
430 : :
431 : 252 : return min_t(u16, power_limit, MAX_RATE_POWER);
432 : : }
433 : :
434 : 252 : void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
435 : : {
436 [ + + - - ]: 252 : struct ath_common *common = ath9k_hw_common(ah);
437 [ + + - - ]: 252 : struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
438 : :
439 [ + + - - ]: 252 : switch (ar5416_get_ntxchains(ah->txchainmask)) {
440 : : case 1:
441 : : break;
442 : 102 : case 2:
443 : 102 : regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN;
444 : 102 : break;
445 : 150 : case 3:
446 : 150 : regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN;
447 : 150 : break;
448 : 0 : default:
449 [ # # ]: 0 : ath_dbg(common, EEPROM, "Invalid chainmask configuration\n");
450 : : break;
451 : : }
452 : 252 : }
453 : :
454 : 0 : void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
455 : : struct ath9k_channel *chan,
456 : : void *pRawDataSet,
457 : : u8 *bChans, u16 availPiers,
458 : : u16 tPdGainOverlap,
459 : : u16 *pPdGainBoundaries, u8 *pPDADCValues,
460 : : u16 numXpdGains)
461 : : {
462 : 0 : int i, j, k;
463 : 0 : int16_t ss;
464 : 0 : u16 idxL = 0, idxR = 0, numPiers;
465 : 0 : static u8 vpdTableL[AR5416_NUM_PD_GAINS]
466 : : [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
467 : 0 : static u8 vpdTableR[AR5416_NUM_PD_GAINS]
468 : : [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
469 : 0 : static u8 vpdTableI[AR5416_NUM_PD_GAINS]
470 : : [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
471 : :
472 : 0 : u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
473 : 0 : u8 minPwrT4[AR5416_NUM_PD_GAINS];
474 : 0 : u8 maxPwrT4[AR5416_NUM_PD_GAINS];
475 : 0 : int16_t vpdStep;
476 : 0 : int16_t tmpVal;
477 : 0 : u16 sizeCurrVpdTable, maxIndex, tgtIndex;
478 : 0 : bool match;
479 : 0 : int16_t minDelta = 0;
480 : 0 : struct chan_centers centers;
481 : 0 : int pdgain_boundary_default;
482 : 0 : struct cal_data_per_freq *data_def = pRawDataSet;
483 : 0 : struct cal_data_per_freq_4k *data_4k = pRawDataSet;
484 : 0 : struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
485 [ # # # # ]: 0 : bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
486 : 0 : int intercepts;
487 : :
488 [ # # ]: 0 : if (AR_SREV_9287(ah))
489 : : intercepts = AR9287_PD_GAIN_ICEPTS;
490 : : else
491 : 0 : intercepts = AR5416_PD_GAIN_ICEPTS;
492 : :
493 : 0 : memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
494 : 0 : ath9k_hw_get_channel_centers(ah, chan, ¢ers);
495 : :
496 [ # # ]: 0 : for (numPiers = 0; numPiers < availPiers; numPiers++) {
497 [ # # ]: 0 : if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
498 : : break;
499 : : }
500 : :
501 [ # # ]: 0 : match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
502 : : IS_CHAN_2GHZ(chan)),
503 : : bChans, numPiers, &idxL, &idxR);
504 : :
505 [ # # ]: 0 : if (match) {
506 [ # # ]: 0 : if (AR_SREV_9287(ah)) {
507 [ # # ]: 0 : for (i = 0; i < numXpdGains; i++) {
508 : 0 : minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
509 : 0 : maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1];
510 : 0 : ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
511 : 0 : data_9287[idxL].pwrPdg[i],
512 : 0 : data_9287[idxL].vpdPdg[i],
513 : : intercepts,
514 : 0 : vpdTableI[i]);
515 : : }
516 [ # # ]: 0 : } else if (eeprom_4k) {
517 [ # # ]: 0 : for (i = 0; i < numXpdGains; i++) {
518 : 0 : minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
519 : 0 : maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1];
520 : 0 : ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
521 : 0 : data_4k[idxL].pwrPdg[i],
522 : 0 : data_4k[idxL].vpdPdg[i],
523 : : intercepts,
524 : 0 : vpdTableI[i]);
525 : : }
526 : : } else {
527 [ # # ]: 0 : for (i = 0; i < numXpdGains; i++) {
528 : 0 : minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
529 : 0 : maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1];
530 : 0 : ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
531 : 0 : data_def[idxL].pwrPdg[i],
532 : 0 : data_def[idxL].vpdPdg[i],
533 : : intercepts,
534 : 0 : vpdTableI[i]);
535 : : }
536 : : }
537 : : } else {
538 [ # # ]: 0 : for (i = 0; i < numXpdGains; i++) {
539 [ # # ]: 0 : if (AR_SREV_9287(ah)) {
540 : 0 : pVpdL = data_9287[idxL].vpdPdg[i];
541 : 0 : pPwrL = data_9287[idxL].pwrPdg[i];
542 : 0 : pVpdR = data_9287[idxR].vpdPdg[i];
543 : 0 : pPwrR = data_9287[idxR].pwrPdg[i];
544 [ # # ]: 0 : } else if (eeprom_4k) {
545 : 0 : pVpdL = data_4k[idxL].vpdPdg[i];
546 : 0 : pPwrL = data_4k[idxL].pwrPdg[i];
547 : 0 : pVpdR = data_4k[idxR].vpdPdg[i];
548 : 0 : pPwrR = data_4k[idxR].pwrPdg[i];
549 : : } else {
550 : 0 : pVpdL = data_def[idxL].vpdPdg[i];
551 : 0 : pPwrL = data_def[idxL].pwrPdg[i];
552 : 0 : pVpdR = data_def[idxR].vpdPdg[i];
553 : 0 : pPwrR = data_def[idxR].pwrPdg[i];
554 : : }
555 : :
556 : 0 : minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
557 : :
558 : 0 : maxPwrT4[i] =
559 : 0 : min(pPwrL[intercepts - 1],
560 : : pPwrR[intercepts - 1]);
561 : :
562 : :
563 : 0 : ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
564 : : pPwrL, pVpdL,
565 : : intercepts,
566 : 0 : vpdTableL[i]);
567 : 0 : ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
568 : : pPwrR, pVpdR,
569 : : intercepts,
570 : 0 : vpdTableR[i]);
571 : :
572 [ # # ]: 0 : for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
573 : 0 : vpdTableI[i][j] =
574 : 0 : (u8)(ath9k_hw_interpolate((u16)
575 : 0 : FREQ2FBIN(centers.
576 : : synth_center,
577 : : IS_CHAN_2GHZ
578 : : (chan)),
579 : 0 : bChans[idxL], bChans[idxR],
580 [ # # ]: 0 : vpdTableL[i][j], vpdTableR[i][j]));
581 : : }
582 : : }
583 : : }
584 : :
585 : : k = 0;
586 : :
587 [ # # ]: 0 : for (i = 0; i < numXpdGains; i++) {
588 [ # # ]: 0 : if (i == (numXpdGains - 1))
589 : 0 : pPdGainBoundaries[i] =
590 : 0 : (u16)(maxPwrT4[i] / 2);
591 : : else
592 : 0 : pPdGainBoundaries[i] =
593 : 0 : (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
594 : :
595 : 0 : pPdGainBoundaries[i] =
596 : 0 : min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
597 : :
598 : 0 : minDelta = 0;
599 : :
600 [ # # ]: 0 : if (i == 0) {
601 [ # # ]: 0 : if (AR_SREV_9280_20_OR_LATER(ah))
602 : 0 : ss = (int16_t)(0 - (minPwrT4[i] / 2));
603 : : else
604 : : ss = 0;
605 : : } else {
606 : 0 : ss = (int16_t)((pPdGainBoundaries[i - 1] -
607 : 0 : (minPwrT4[i] / 2)) -
608 : : tPdGainOverlap + 1 + minDelta);
609 : : }
610 : 0 : vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
611 : 0 : vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
612 : :
613 [ # # # # ]: 0 : while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
614 : 0 : tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
615 : 0 : pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
616 : 0 : ss++;
617 : : }
618 : :
619 : 0 : sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
620 : 0 : tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
621 : : (minPwrT4[i] / 2));
622 : 0 : maxIndex = (tgtIndex < sizeCurrVpdTable) ?
623 : : tgtIndex : sizeCurrVpdTable;
624 : :
625 [ # # # # ]: 0 : while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
626 : 0 : pPDADCValues[k++] = vpdTableI[i][ss++];
627 : : }
628 : :
629 : 0 : vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
630 : 0 : vpdTableI[i][sizeCurrVpdTable - 2]);
631 : 0 : vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
632 : :
633 [ # # ]: 0 : if (tgtIndex >= maxIndex) {
634 [ # # # # ]: 0 : while ((ss <= tgtIndex) &&
635 : : (k < (AR5416_NUM_PDADC_VALUES - 1))) {
636 : 0 : tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
637 : 0 : (ss - maxIndex + 1) * vpdStep));
638 : 0 : pPDADCValues[k++] = (u8)((tmpVal > 255) ?
639 : : 255 : tmpVal);
640 : 0 : ss++;
641 : : }
642 : : }
643 : : }
644 : :
645 [ # # ]: 0 : if (eeprom_4k)
646 : : pdgain_boundary_default = 58;
647 : : else
648 : 0 : pdgain_boundary_default = pPdGainBoundaries[i - 1];
649 : :
650 [ # # ]: 0 : while (i < AR5416_PD_GAINS_IN_MASK) {
651 : 0 : pPdGainBoundaries[i] = pdgain_boundary_default;
652 : 0 : i++;
653 : : }
654 : :
655 [ # # ]: 0 : while (k < AR5416_NUM_PDADC_VALUES) {
656 : 0 : pPDADCValues[k] = pPDADCValues[k - 1];
657 : 0 : k++;
658 : : }
659 : 0 : }
660 : :
661 : 8 : int ath9k_hw_eeprom_init(struct ath_hw *ah)
662 : : {
663 : 8 : int status;
664 : :
665 [ + + ]: 8 : if (AR_SREV_9300_20_OR_LATER(ah))
666 : 5 : ah->eep_ops = &eep_ar9300_ops;
667 [ - + ]: 3 : else if (AR_SREV_9287(ah)) {
668 : 0 : ah->eep_ops = &eep_ar9287_ops;
669 [ + - - + ]: 3 : } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
670 : 0 : ah->eep_ops = &eep_4k_ops;
671 : : } else {
672 : 3 : ah->eep_ops = &eep_def_ops;
673 : : }
674 : :
675 [ + + ]: 8 : if (!ah->eep_ops->fill_eeprom(ah))
676 : : return -EIO;
677 : :
678 : 7 : status = ah->eep_ops->check_eeprom(ah);
679 : :
680 : 7 : return status;
681 : : }
|