1 | /* |
2 | * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> |
3 | * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com> |
4 | * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> |
5 | * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org> |
6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. |
10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | * |
19 | */ |
20 | |
21 | /***********************\ |
22 | * PHY related functions * |
23 | \***********************/ |
24 | |
25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
26 | |
27 | #include <linux/delay.h> |
28 | #include <linux/slab.h> |
29 | #include <linux/sort.h> |
30 | #include <asm/unaligned.h> |
31 | |
32 | #include "ath5k.h" |
33 | #include "reg.h" |
34 | #include "rfbuffer.h" |
35 | #include "rfgain.h" |
36 | #include "../regd.h" |
37 | |
38 | |
39 | /** |
40 | * DOC: PHY related functions |
41 | * |
42 | * Here we handle the low-level functions related to baseband |
43 | * and analog frontend (RF) parts. This is by far the most complex |
44 | * part of the hw code so make sure you know what you are doing. |
45 | * |
46 | * Here is a list of what this is all about: |
47 | * |
48 | * - Channel setting/switching |
49 | * |
50 | * - Automatic Gain Control (AGC) calibration |
51 | * |
52 | * - Noise Floor calibration |
53 | * |
54 | * - I/Q imbalance calibration (QAM correction) |
55 | * |
56 | * - Calibration due to thermal changes (gain_F) |
57 | * |
58 | * - Spur noise mitigation |
59 | * |
60 | * - RF/PHY initialization for the various operating modes and bwmodes |
61 | * |
62 | * - Antenna control |
63 | * |
64 | * - TX power control per channel/rate/packet type |
65 | * |
66 | * Also have in mind we never got documentation for most of these |
67 | * functions, what we have comes mostly from Atheros's code, reverse |
68 | * engineering and patent docs/presentations etc. |
69 | */ |
70 | |
71 | |
72 | /******************\ |
73 | * Helper functions * |
74 | \******************/ |
75 | |
76 | /** |
77 | * ath5k_hw_radio_revision() - Get the PHY Chip revision |
78 | * @ah: The &struct ath5k_hw |
79 | * @band: One of enum nl80211_band |
80 | * |
81 | * Returns the revision number of a 2GHz, 5GHz or single chip |
82 | * radio. |
83 | */ |
84 | u16 |
85 | ath5k_hw_radio_revision(struct ath5k_hw *ah, enum nl80211_band band) |
86 | { |
87 | unsigned int i; |
88 | u32 srev; |
89 | u16 ret; |
90 | |
91 | /* |
92 | * Set the radio chip access register |
93 | */ |
94 | switch (band) { |
95 | case NL80211_BAND_2GHZ: |
96 | ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0)); |
97 | break; |
98 | case NL80211_BAND_5GHZ: |
99 | ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); |
100 | break; |
101 | default: |
102 | return 0; |
103 | } |
104 | |
105 | usleep_range(min: 2000, max: 2500); |
106 | |
107 | /* ...wait until PHY is ready and read the selected radio revision */ |
108 | ath5k_hw_reg_write(ah, val: 0x00001c16, AR5K_PHY(0x34)); |
109 | |
110 | for (i = 0; i < 8; i++) |
111 | ath5k_hw_reg_write(ah, val: 0x00010000, AR5K_PHY(0x20)); |
112 | |
113 | if (ah->ah_version == AR5K_AR5210) { |
114 | srev = (ath5k_hw_reg_read(ah, AR5K_PHY(256)) >> 28) & 0xf; |
115 | ret = (u16)ath5k_hw_bitswap(val: srev, bits: 4) + 1; |
116 | } else { |
117 | srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff; |
118 | ret = (u16)ath5k_hw_bitswap(val: ((srev & 0xf0) >> 4) | |
119 | ((srev & 0x0f) << 4), bits: 8); |
120 | } |
121 | |
122 | /* Reset to the 5GHz mode */ |
123 | ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); |
124 | |
125 | return ret; |
126 | } |
127 | |
128 | /** |
129 | * ath5k_channel_ok() - Check if a channel is supported by the hw |
130 | * @ah: The &struct ath5k_hw |
131 | * @channel: The &struct ieee80211_channel |
132 | * |
133 | * Note: We don't do any regulatory domain checks here, it's just |
134 | * a sanity check. |
135 | */ |
136 | bool |
137 | ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel) |
138 | { |
139 | u16 freq = channel->center_freq; |
140 | |
141 | /* Check if the channel is in our supported range */ |
142 | if (channel->band == NL80211_BAND_2GHZ) { |
143 | if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) && |
144 | (freq <= ah->ah_capabilities.cap_range.range_2ghz_max)) |
145 | return true; |
146 | } else if (channel->band == NL80211_BAND_5GHZ) |
147 | if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) && |
148 | (freq <= ah->ah_capabilities.cap_range.range_5ghz_max)) |
149 | return true; |
150 | |
151 | return false; |
152 | } |
153 | |
154 | /** |
155 | * ath5k_hw_chan_has_spur_noise() - Check if channel is sensitive to spur noise |
156 | * @ah: The &struct ath5k_hw |
157 | * @channel: The &struct ieee80211_channel |
158 | */ |
159 | bool |
160 | ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, |
161 | struct ieee80211_channel *channel) |
162 | { |
163 | u8 refclk_freq; |
164 | |
165 | if ((ah->ah_radio == AR5K_RF5112) || |
166 | (ah->ah_radio == AR5K_RF5413) || |
167 | (ah->ah_radio == AR5K_RF2413) || |
168 | (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) |
169 | refclk_freq = 40; |
170 | else |
171 | refclk_freq = 32; |
172 | |
173 | if ((channel->center_freq % refclk_freq != 0) && |
174 | ((channel->center_freq % refclk_freq < 10) || |
175 | (channel->center_freq % refclk_freq > 22))) |
176 | return true; |
177 | else |
178 | return false; |
179 | } |
180 | |
181 | /** |
182 | * ath5k_hw_rfb_op() - Perform an operation on the given RF Buffer |
183 | * @ah: The &struct ath5k_hw |
184 | * @rf_regs: The struct ath5k_rf_reg |
185 | * @val: New value |
186 | * @reg_id: RF register ID |
187 | * @set: Indicate we need to swap data |
188 | * |
189 | * This is an internal function used to modify RF Banks before |
190 | * writing them to AR5K_RF_BUFFER. Check out rfbuffer.h for more |
191 | * infos. |
192 | */ |
193 | static unsigned int |
194 | ath5k_hw_rfb_op(struct ath5k_hw *ah, const struct ath5k_rf_reg *rf_regs, |
195 | u32 val, u8 reg_id, bool set) |
196 | { |
197 | const struct ath5k_rf_reg *rfreg = NULL; |
198 | u8 offset, bank, num_bits, col, position; |
199 | u16 entry; |
200 | u32 mask, data, last_bit, bits_shifted, first_bit; |
201 | u32 *rfb; |
202 | s32 bits_left; |
203 | int i; |
204 | |
205 | data = 0; |
206 | rfb = ah->ah_rf_banks; |
207 | |
208 | for (i = 0; i < ah->ah_rf_regs_count; i++) { |
209 | if (rf_regs[i].index == reg_id) { |
210 | rfreg = &rf_regs[i]; |
211 | break; |
212 | } |
213 | } |
214 | |
215 | if (rfb == NULL || rfreg == NULL) { |
216 | ATH5K_PRINTF("Rf register not found!\n" ); |
217 | /* should not happen */ |
218 | return 0; |
219 | } |
220 | |
221 | bank = rfreg->bank; |
222 | num_bits = rfreg->field.len; |
223 | first_bit = rfreg->field.pos; |
224 | col = rfreg->field.col; |
225 | |
226 | /* first_bit is an offset from bank's |
227 | * start. Since we have all banks on |
228 | * the same array, we use this offset |
229 | * to mark each bank's start */ |
230 | offset = ah->ah_offset[bank]; |
231 | |
232 | /* Boundary check */ |
233 | if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) { |
234 | ATH5K_PRINTF("invalid values at offset %u\n" , offset); |
235 | return 0; |
236 | } |
237 | |
238 | entry = ((first_bit - 1) / 8) + offset; |
239 | position = (first_bit - 1) % 8; |
240 | |
241 | if (set) |
242 | data = ath5k_hw_bitswap(val, bits: num_bits); |
243 | |
244 | for (bits_shifted = 0, bits_left = num_bits; bits_left > 0; |
245 | position = 0, entry++) { |
246 | |
247 | last_bit = (position + bits_left > 8) ? 8 : |
248 | position + bits_left; |
249 | |
250 | mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) << |
251 | (col * 8); |
252 | |
253 | if (set) { |
254 | rfb[entry] &= ~mask; |
255 | rfb[entry] |= ((data << position) << (col * 8)) & mask; |
256 | data >>= (8 - position); |
257 | } else { |
258 | data |= (((rfb[entry] & mask) >> (col * 8)) >> position) |
259 | << bits_shifted; |
260 | bits_shifted += last_bit - position; |
261 | } |
262 | |
263 | bits_left -= 8 - position; |
264 | } |
265 | |
266 | data = set ? 1 : ath5k_hw_bitswap(val: data, bits: num_bits); |
267 | |
268 | return data; |
269 | } |
270 | |
271 | /** |
272 | * ath5k_hw_write_ofdm_timings() - set OFDM timings on AR5212 |
273 | * @ah: the &struct ath5k_hw |
274 | * @channel: the currently set channel upon reset |
275 | * |
276 | * Write the delta slope coefficient (used on pilot tracking ?) for OFDM |
277 | * operation on the AR5212 upon reset. This is a helper for ath5k_hw_phy_init. |
278 | * |
279 | * Since delta slope is floating point we split it on its exponent and |
280 | * mantissa and provide these values on hw. |
281 | * |
282 | * For more infos i think this patent is related |
283 | * "http://www.freepatentsonline.com/7184495.html" |
284 | */ |
285 | static inline int |
286 | ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, |
287 | struct ieee80211_channel *channel) |
288 | { |
289 | /* Get exponent and mantissa and set it */ |
290 | u32 coef_scaled, coef_exp, coef_man, |
291 | ds_coef_exp, ds_coef_man, clock; |
292 | |
293 | BUG_ON(!(ah->ah_version == AR5K_AR5212) || |
294 | (channel->hw_value == AR5K_MODE_11B)); |
295 | |
296 | /* Get coefficient |
297 | * ALGO: coef = (5 * clock / carrier_freq) / 2 |
298 | * we scale coef by shifting clock value by 24 for |
299 | * better precision since we use integers */ |
300 | switch (ah->ah_bwmode) { |
301 | case AR5K_BWMODE_40MHZ: |
302 | clock = 40 * 2; |
303 | break; |
304 | case AR5K_BWMODE_10MHZ: |
305 | clock = 40 / 2; |
306 | break; |
307 | case AR5K_BWMODE_5MHZ: |
308 | clock = 40 / 4; |
309 | break; |
310 | default: |
311 | clock = 40; |
312 | break; |
313 | } |
314 | coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq; |
315 | |
316 | /* Get exponent |
317 | * ALGO: coef_exp = 14 - highest set bit position */ |
318 | coef_exp = ilog2(coef_scaled); |
319 | |
320 | /* Doesn't make sense if it's zero*/ |
321 | if (!coef_scaled || !coef_exp) |
322 | return -EINVAL; |
323 | |
324 | /* Note: we've shifted coef_scaled by 24 */ |
325 | coef_exp = 14 - (coef_exp - 24); |
326 | |
327 | |
328 | /* Get mantissa (significant digits) |
329 | * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */ |
330 | coef_man = coef_scaled + |
331 | (1 << (24 - coef_exp - 1)); |
332 | |
333 | /* Calculate delta slope coefficient exponent |
334 | * and mantissa (remove scaling) and set them on hw */ |
335 | ds_coef_man = coef_man >> (24 - coef_exp); |
336 | ds_coef_exp = coef_exp - 16; |
337 | |
338 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, |
339 | AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man); |
340 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, |
341 | AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp); |
342 | |
343 | return 0; |
344 | } |
345 | |
346 | /** |
347 | * ath5k_hw_phy_disable() - Disable PHY |
348 | * @ah: The &struct ath5k_hw |
349 | */ |
350 | int ath5k_hw_phy_disable(struct ath5k_hw *ah) |
351 | { |
352 | /*Just a try M.F.*/ |
353 | ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); |
354 | |
355 | return 0; |
356 | } |
357 | |
358 | /** |
359 | * ath5k_hw_wait_for_synth() - Wait for synth to settle |
360 | * @ah: The &struct ath5k_hw |
361 | * @channel: The &struct ieee80211_channel |
362 | */ |
363 | static void |
364 | ath5k_hw_wait_for_synth(struct ath5k_hw *ah, |
365 | struct ieee80211_channel *channel) |
366 | { |
367 | /* |
368 | * On 5211+ read activation -> rx delay |
369 | * and use it (100ns steps). |
370 | */ |
371 | if (ah->ah_version != AR5K_AR5210) { |
372 | u32 delay; |
373 | delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & |
374 | AR5K_PHY_RX_DELAY_M; |
375 | delay = (channel->hw_value == AR5K_MODE_11B) ? |
376 | ((delay << 2) / 22) : (delay / 10); |
377 | if (ah->ah_bwmode == AR5K_BWMODE_10MHZ) |
378 | delay = delay << 1; |
379 | if (ah->ah_bwmode == AR5K_BWMODE_5MHZ) |
380 | delay = delay << 2; |
381 | /* XXX: /2 on turbo ? Let's be safe |
382 | * for now */ |
383 | usleep_range(min: 100 + delay, max: 100 + (2 * delay)); |
384 | } else { |
385 | usleep_range(min: 1000, max: 1500); |
386 | } |
387 | } |
388 | |
389 | |
390 | /**********************\ |
391 | * RF Gain optimization * |
392 | \**********************/ |
393 | |
394 | /** |
395 | * DOC: RF Gain optimization |
396 | * |
397 | * This code is used to optimize RF gain on different environments |
398 | * (temperature mostly) based on feedback from a power detector. |
399 | * |
400 | * It's only used on RF5111 and RF5112, later RF chips seem to have |
401 | * auto adjustment on hw -notice they have a much smaller BANK 7 and |
402 | * no gain optimization ladder-. |
403 | * |
404 | * For more infos check out this patent doc |
405 | * "http://www.freepatentsonline.com/7400691.html" |
406 | * |
407 | * This paper describes power drops as seen on the receiver due to |
408 | * probe packets |
409 | * "http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues |
410 | * %20of%20Power%20Control.pdf" |
411 | * |
412 | * And this is the MadWiFi bug entry related to the above |
413 | * "http://madwifi-project.org/ticket/1659" |
414 | * with various measurements and diagrams |
415 | */ |
416 | |
417 | /** |
418 | * ath5k_hw_rfgain_opt_init() - Initialize ah_gain during attach |
419 | * @ah: The &struct ath5k_hw |
420 | */ |
421 | int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) |
422 | { |
423 | /* Initialize the gain optimization values */ |
424 | switch (ah->ah_radio) { |
425 | case AR5K_RF5111: |
426 | ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default; |
427 | ah->ah_gain.g_low = 20; |
428 | ah->ah_gain.g_high = 35; |
429 | ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; |
430 | break; |
431 | case AR5K_RF5112: |
432 | ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; |
433 | ah->ah_gain.g_low = 20; |
434 | ah->ah_gain.g_high = 85; |
435 | ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; |
436 | break; |
437 | default: |
438 | return -EINVAL; |
439 | } |
440 | |
441 | return 0; |
442 | } |
443 | |
444 | /** |
445 | * ath5k_hw_request_rfgain_probe() - Request a PAPD probe packet |
446 | * @ah: The &struct ath5k_hw |
447 | * |
448 | * Schedules a gain probe check on the next transmitted packet. |
449 | * That means our next packet is going to be sent with lower |
450 | * tx power and a Peak to Average Power Detector (PAPD) will try |
451 | * to measure the gain. |
452 | * |
453 | * TODO: Force a tx packet (bypassing PCU arbitrator etc) |
454 | * just after we enable the probe so that we don't mess with |
455 | * standard traffic. |
456 | */ |
457 | static void |
458 | ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) |
459 | { |
460 | |
461 | /* Skip if gain calibration is inactive or |
462 | * we already handle a probe request */ |
463 | if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE) |
464 | return; |
465 | |
466 | /* Send the packet with 2dB below max power as |
467 | * patent doc suggest */ |
468 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_ofdm - 4, |
469 | AR5K_PHY_PAPD_PROBE_TXPOWER) | |
470 | AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); |
471 | |
472 | ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED; |
473 | |
474 | } |
475 | |
476 | /** |
477 | * ath5k_hw_rf_gainf_corr() - Calculate Gain_F measurement correction |
478 | * @ah: The &struct ath5k_hw |
479 | * |
480 | * Calculate Gain_F measurement correction |
481 | * based on the current step for RF5112 rev. 2 |
482 | */ |
483 | static u32 |
484 | ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) |
485 | { |
486 | u32 mix, step; |
487 | const struct ath5k_gain_opt *go; |
488 | const struct ath5k_gain_opt_step *g_step; |
489 | const struct ath5k_rf_reg *rf_regs; |
490 | |
491 | /* Only RF5112 Rev. 2 supports it */ |
492 | if ((ah->ah_radio != AR5K_RF5112) || |
493 | (ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A)) |
494 | return 0; |
495 | |
496 | go = &rfgain_opt_5112; |
497 | rf_regs = rf_regs_5112a; |
498 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a); |
499 | |
500 | g_step = &go->go_step[ah->ah_gain.g_step_idx]; |
501 | |
502 | if (ah->ah_rf_banks == NULL) |
503 | return 0; |
504 | |
505 | ah->ah_gain.g_f_corr = 0; |
506 | |
507 | /* No VGA (Variable Gain Amplifier) override, skip */ |
508 | if (ath5k_hw_rfb_op(ah, rf_regs, val: 0, reg_id: AR5K_RF_MIXVGA_OVR, set: false) != 1) |
509 | return 0; |
510 | |
511 | /* Mix gain stepping */ |
512 | step = ath5k_hw_rfb_op(ah, rf_regs, val: 0, reg_id: AR5K_RF_MIXGAIN_STEP, set: false); |
513 | |
514 | /* Mix gain override */ |
515 | mix = g_step->gos_param[0]; |
516 | |
517 | switch (mix) { |
518 | case 3: |
519 | ah->ah_gain.g_f_corr = step * 2; |
520 | break; |
521 | case 2: |
522 | ah->ah_gain.g_f_corr = (step - 5) * 2; |
523 | break; |
524 | case 1: |
525 | ah->ah_gain.g_f_corr = step; |
526 | break; |
527 | default: |
528 | ah->ah_gain.g_f_corr = 0; |
529 | break; |
530 | } |
531 | |
532 | return ah->ah_gain.g_f_corr; |
533 | } |
534 | |
535 | /** |
536 | * ath5k_hw_rf_check_gainf_readback() - Validate Gain_F feedback from detector |
537 | * @ah: The &struct ath5k_hw |
538 | * |
539 | * Check if current gain_F measurement is in the range of our |
540 | * power detector windows. If we get a measurement outside range |
541 | * we know it's not accurate (detectors can't measure anything outside |
542 | * their detection window) so we must ignore it. |
543 | * |
544 | * Returns true if readback was O.K. or false on failure |
545 | */ |
546 | static bool |
547 | ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) |
548 | { |
549 | const struct ath5k_rf_reg *rf_regs; |
550 | u32 step, mix_ovr, level[4]; |
551 | |
552 | if (ah->ah_rf_banks == NULL) |
553 | return false; |
554 | |
555 | if (ah->ah_radio == AR5K_RF5111) { |
556 | |
557 | rf_regs = rf_regs_5111; |
558 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111); |
559 | |
560 | step = ath5k_hw_rfb_op(ah, rf_regs, val: 0, reg_id: AR5K_RF_RFGAIN_STEP, |
561 | set: false); |
562 | |
563 | level[0] = 0; |
564 | level[1] = (step == 63) ? 50 : step + 4; |
565 | level[2] = (step != 63) ? 64 : level[0]; |
566 | level[3] = level[2] + 50; |
567 | |
568 | ah->ah_gain.g_high = level[3] - |
569 | (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); |
570 | ah->ah_gain.g_low = level[0] + |
571 | (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); |
572 | } else { |
573 | |
574 | rf_regs = rf_regs_5112; |
575 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112); |
576 | |
577 | mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, val: 0, reg_id: AR5K_RF_MIXVGA_OVR, |
578 | set: false); |
579 | |
580 | level[0] = level[2] = 0; |
581 | |
582 | if (mix_ovr == 1) { |
583 | level[1] = level[3] = 83; |
584 | } else { |
585 | level[1] = level[3] = 107; |
586 | ah->ah_gain.g_high = 55; |
587 | } |
588 | } |
589 | |
590 | return (ah->ah_gain.g_current >= level[0] && |
591 | ah->ah_gain.g_current <= level[1]) || |
592 | (ah->ah_gain.g_current >= level[2] && |
593 | ah->ah_gain.g_current <= level[3]); |
594 | } |
595 | |
596 | /** |
597 | * ath5k_hw_rf_gainf_adjust() - Perform Gain_F adjustment |
598 | * @ah: The &struct ath5k_hw |
599 | * |
600 | * Choose the right target gain based on current gain |
601 | * and RF gain optimization ladder |
602 | */ |
603 | static s8 |
604 | ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) |
605 | { |
606 | const struct ath5k_gain_opt *go; |
607 | const struct ath5k_gain_opt_step *g_step; |
608 | int ret = 0; |
609 | |
610 | switch (ah->ah_radio) { |
611 | case AR5K_RF5111: |
612 | go = &rfgain_opt_5111; |
613 | break; |
614 | case AR5K_RF5112: |
615 | go = &rfgain_opt_5112; |
616 | break; |
617 | default: |
618 | return 0; |
619 | } |
620 | |
621 | g_step = &go->go_step[ah->ah_gain.g_step_idx]; |
622 | |
623 | if (ah->ah_gain.g_current >= ah->ah_gain.g_high) { |
624 | |
625 | /* Reached maximum */ |
626 | if (ah->ah_gain.g_step_idx == 0) |
627 | return -1; |
628 | |
629 | for (ah->ah_gain.g_target = ah->ah_gain.g_current; |
630 | ah->ah_gain.g_target >= ah->ah_gain.g_high && |
631 | ah->ah_gain.g_step_idx > 0; |
632 | g_step = &go->go_step[ah->ah_gain.g_step_idx]) |
633 | ah->ah_gain.g_target -= 2 * |
634 | (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain - |
635 | g_step->gos_gain); |
636 | |
637 | ret = 1; |
638 | goto done; |
639 | } |
640 | |
641 | if (ah->ah_gain.g_current <= ah->ah_gain.g_low) { |
642 | |
643 | /* Reached minimum */ |
644 | if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1)) |
645 | return -2; |
646 | |
647 | for (ah->ah_gain.g_target = ah->ah_gain.g_current; |
648 | ah->ah_gain.g_target <= ah->ah_gain.g_low && |
649 | ah->ah_gain.g_step_idx < go->go_steps_count - 1; |
650 | g_step = &go->go_step[ah->ah_gain.g_step_idx]) |
651 | ah->ah_gain.g_target -= 2 * |
652 | (go->go_step[++ah->ah_gain.g_step_idx].gos_gain - |
653 | g_step->gos_gain); |
654 | |
655 | ret = 2; |
656 | goto done; |
657 | } |
658 | |
659 | done: |
660 | ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, |
661 | "ret %d, gain step %u, current gain %u, target gain %u\n" , |
662 | ret, ah->ah_gain.g_step_idx, ah->ah_gain.g_current, |
663 | ah->ah_gain.g_target); |
664 | |
665 | return ret; |
666 | } |
667 | |
668 | /** |
669 | * ath5k_hw_gainf_calibrate() - Do a gain_F calibration |
670 | * @ah: The &struct ath5k_hw |
671 | * |
672 | * Main callback for thermal RF gain calibration engine |
673 | * Check for a new gain reading and schedule an adjustment |
674 | * if needed. |
675 | * |
676 | * Returns one of enum ath5k_rfgain codes |
677 | */ |
678 | enum ath5k_rfgain |
679 | ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) |
680 | { |
681 | u32 data, type; |
682 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
683 | |
684 | if (ah->ah_rf_banks == NULL || |
685 | ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE) |
686 | return AR5K_RFGAIN_INACTIVE; |
687 | |
688 | /* No check requested, either engine is inactive |
689 | * or an adjustment is already requested */ |
690 | if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED) |
691 | goto done; |
692 | |
693 | /* Read the PAPD (Peak to Average Power Detector) |
694 | * register */ |
695 | data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE); |
696 | |
697 | /* No probe is scheduled, read gain_F measurement */ |
698 | if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) { |
699 | ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S; |
700 | type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE); |
701 | |
702 | /* If tx packet is CCK correct the gain_F measurement |
703 | * by cck ofdm gain delta */ |
704 | if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) { |
705 | if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) |
706 | ah->ah_gain.g_current += |
707 | ee->ee_cck_ofdm_gain_delta; |
708 | else |
709 | ah->ah_gain.g_current += |
710 | AR5K_GAIN_CCK_PROBE_CORR; |
711 | } |
712 | |
713 | /* Further correct gain_F measurement for |
714 | * RF5112A radios */ |
715 | if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { |
716 | ath5k_hw_rf_gainf_corr(ah); |
717 | ah->ah_gain.g_current = |
718 | ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ? |
719 | (ah->ah_gain.g_current - ah->ah_gain.g_f_corr) : |
720 | 0; |
721 | } |
722 | |
723 | /* Check if measurement is ok and if we need |
724 | * to adjust gain, schedule a gain adjustment, |
725 | * else switch back to the active state */ |
726 | if (ath5k_hw_rf_check_gainf_readback(ah) && |
727 | AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) && |
728 | ath5k_hw_rf_gainf_adjust(ah)) { |
729 | ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE; |
730 | } else { |
731 | ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; |
732 | } |
733 | } |
734 | |
735 | done: |
736 | return ah->ah_gain.g_state; |
737 | } |
738 | |
739 | /** |
740 | * ath5k_hw_rfgain_init() - Write initial RF gain settings to hw |
741 | * @ah: The &struct ath5k_hw |
742 | * @band: One of enum nl80211_band |
743 | * |
744 | * Write initial RF gain table to set the RF sensitivity. |
745 | * |
746 | * NOTE: This one works on all RF chips and has nothing to do |
747 | * with Gain_F calibration |
748 | */ |
749 | static int |
750 | ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum nl80211_band band) |
751 | { |
752 | const struct ath5k_ini_rfgain *ath5k_rfg; |
753 | unsigned int i, size, index; |
754 | |
755 | switch (ah->ah_radio) { |
756 | case AR5K_RF5111: |
757 | ath5k_rfg = rfgain_5111; |
758 | size = ARRAY_SIZE(rfgain_5111); |
759 | break; |
760 | case AR5K_RF5112: |
761 | ath5k_rfg = rfgain_5112; |
762 | size = ARRAY_SIZE(rfgain_5112); |
763 | break; |
764 | case AR5K_RF2413: |
765 | ath5k_rfg = rfgain_2413; |
766 | size = ARRAY_SIZE(rfgain_2413); |
767 | break; |
768 | case AR5K_RF2316: |
769 | ath5k_rfg = rfgain_2316; |
770 | size = ARRAY_SIZE(rfgain_2316); |
771 | break; |
772 | case AR5K_RF5413: |
773 | ath5k_rfg = rfgain_5413; |
774 | size = ARRAY_SIZE(rfgain_5413); |
775 | break; |
776 | case AR5K_RF2317: |
777 | case AR5K_RF2425: |
778 | ath5k_rfg = rfgain_2425; |
779 | size = ARRAY_SIZE(rfgain_2425); |
780 | break; |
781 | default: |
782 | return -EINVAL; |
783 | } |
784 | |
785 | index = (band == NL80211_BAND_2GHZ) ? 1 : 0; |
786 | |
787 | for (i = 0; i < size; i++) { |
788 | AR5K_REG_WAIT(i); |
789 | ath5k_hw_reg_write(ah, val: ath5k_rfg[i].rfg_value[index], |
790 | reg: (u32)ath5k_rfg[i].rfg_register); |
791 | } |
792 | |
793 | return 0; |
794 | } |
795 | |
796 | |
797 | /********************\ |
798 | * RF Registers setup * |
799 | \********************/ |
800 | |
801 | /** |
802 | * ath5k_hw_rfregs_init() - Initialize RF register settings |
803 | * @ah: The &struct ath5k_hw |
804 | * @channel: The &struct ieee80211_channel |
805 | * @mode: One of enum ath5k_driver_mode |
806 | * |
807 | * Setup RF registers by writing RF buffer on hw. For |
808 | * more infos on this, check out rfbuffer.h |
809 | */ |
810 | static int |
811 | ath5k_hw_rfregs_init(struct ath5k_hw *ah, |
812 | struct ieee80211_channel *channel, |
813 | unsigned int mode) |
814 | { |
815 | const struct ath5k_rf_reg *rf_regs; |
816 | const struct ath5k_ini_rfbuffer *ini_rfb; |
817 | const struct ath5k_gain_opt *go = NULL; |
818 | const struct ath5k_gain_opt_step *g_step; |
819 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
820 | u8 ee_mode = 0; |
821 | u32 *rfb; |
822 | int i, obdb = -1, bank = -1; |
823 | |
824 | switch (ah->ah_radio) { |
825 | case AR5K_RF5111: |
826 | rf_regs = rf_regs_5111; |
827 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111); |
828 | ini_rfb = rfb_5111; |
829 | ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111); |
830 | go = &rfgain_opt_5111; |
831 | break; |
832 | case AR5K_RF5112: |
833 | if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { |
834 | rf_regs = rf_regs_5112a; |
835 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a); |
836 | ini_rfb = rfb_5112a; |
837 | ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a); |
838 | } else { |
839 | rf_regs = rf_regs_5112; |
840 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112); |
841 | ini_rfb = rfb_5112; |
842 | ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112); |
843 | } |
844 | go = &rfgain_opt_5112; |
845 | break; |
846 | case AR5K_RF2413: |
847 | rf_regs = rf_regs_2413; |
848 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413); |
849 | ini_rfb = rfb_2413; |
850 | ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413); |
851 | break; |
852 | case AR5K_RF2316: |
853 | rf_regs = rf_regs_2316; |
854 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316); |
855 | ini_rfb = rfb_2316; |
856 | ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316); |
857 | break; |
858 | case AR5K_RF5413: |
859 | rf_regs = rf_regs_5413; |
860 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413); |
861 | ini_rfb = rfb_5413; |
862 | ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413); |
863 | break; |
864 | case AR5K_RF2317: |
865 | rf_regs = rf_regs_2425; |
866 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425); |
867 | ini_rfb = rfb_2317; |
868 | ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317); |
869 | break; |
870 | case AR5K_RF2425: |
871 | rf_regs = rf_regs_2425; |
872 | ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425); |
873 | if (ah->ah_mac_srev < AR5K_SREV_AR2417) { |
874 | ini_rfb = rfb_2425; |
875 | ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425); |
876 | } else { |
877 | ini_rfb = rfb_2417; |
878 | ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417); |
879 | } |
880 | break; |
881 | default: |
882 | return -EINVAL; |
883 | } |
884 | |
885 | /* If it's the first time we set RF buffer, allocate |
886 | * ah->ah_rf_banks based on ah->ah_rf_banks_size |
887 | * we set above */ |
888 | if (ah->ah_rf_banks == NULL) { |
889 | ah->ah_rf_banks = kmalloc_array(n: ah->ah_rf_banks_size, |
890 | size: sizeof(u32), |
891 | GFP_KERNEL); |
892 | if (ah->ah_rf_banks == NULL) { |
893 | ATH5K_ERR(ah, "out of memory\n" ); |
894 | return -ENOMEM; |
895 | } |
896 | } |
897 | |
898 | /* Copy values to modify them */ |
899 | rfb = ah->ah_rf_banks; |
900 | |
901 | for (i = 0; i < ah->ah_rf_banks_size; i++) { |
902 | if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) { |
903 | ATH5K_ERR(ah, "invalid bank\n" ); |
904 | return -EINVAL; |
905 | } |
906 | |
907 | /* Bank changed, write down the offset */ |
908 | if (bank != ini_rfb[i].rfb_bank) { |
909 | bank = ini_rfb[i].rfb_bank; |
910 | ah->ah_offset[bank] = i; |
911 | } |
912 | |
913 | rfb[i] = ini_rfb[i].rfb_mode_data[mode]; |
914 | } |
915 | |
916 | /* Set Output and Driver bias current (OB/DB) */ |
917 | if (channel->band == NL80211_BAND_2GHZ) { |
918 | |
919 | if (channel->hw_value == AR5K_MODE_11B) |
920 | ee_mode = AR5K_EEPROM_MODE_11B; |
921 | else |
922 | ee_mode = AR5K_EEPROM_MODE_11G; |
923 | |
924 | /* For RF511X/RF211X combination we |
925 | * use b_OB and b_DB parameters stored |
926 | * in eeprom on ee->ee_ob[ee_mode][0] |
927 | * |
928 | * For all other chips we use OB/DB for 2GHz |
929 | * stored in the b/g modal section just like |
930 | * 802.11a on ee->ee_ob[ee_mode][1] */ |
931 | if ((ah->ah_radio == AR5K_RF5111) || |
932 | (ah->ah_radio == AR5K_RF5112)) |
933 | obdb = 0; |
934 | else |
935 | obdb = 1; |
936 | |
937 | ath5k_hw_rfb_op(ah, rf_regs, val: ee->ee_ob[ee_mode][obdb], |
938 | reg_id: AR5K_RF_OB_2GHZ, set: true); |
939 | |
940 | ath5k_hw_rfb_op(ah, rf_regs, val: ee->ee_db[ee_mode][obdb], |
941 | reg_id: AR5K_RF_DB_2GHZ, set: true); |
942 | |
943 | /* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */ |
944 | } else if ((channel->band == NL80211_BAND_5GHZ) || |
945 | (ah->ah_radio == AR5K_RF5111)) { |
946 | |
947 | /* For 11a, Turbo and XR we need to choose |
948 | * OB/DB based on frequency range */ |
949 | ee_mode = AR5K_EEPROM_MODE_11A; |
950 | obdb = channel->center_freq >= 5725 ? 3 : |
951 | (channel->center_freq >= 5500 ? 2 : |
952 | (channel->center_freq >= 5260 ? 1 : |
953 | (channel->center_freq > 4000 ? 0 : -1))); |
954 | |
955 | if (obdb < 0) |
956 | return -EINVAL; |
957 | |
958 | ath5k_hw_rfb_op(ah, rf_regs, val: ee->ee_ob[ee_mode][obdb], |
959 | reg_id: AR5K_RF_OB_5GHZ, set: true); |
960 | |
961 | ath5k_hw_rfb_op(ah, rf_regs, val: ee->ee_db[ee_mode][obdb], |
962 | reg_id: AR5K_RF_DB_5GHZ, set: true); |
963 | } |
964 | |
965 | g_step = &go->go_step[ah->ah_gain.g_step_idx]; |
966 | |
967 | /* Set turbo mode (N/A on RF5413) */ |
968 | if ((ah->ah_bwmode == AR5K_BWMODE_40MHZ) && |
969 | (ah->ah_radio != AR5K_RF5413)) |
970 | ath5k_hw_rfb_op(ah, rf_regs, val: 1, reg_id: AR5K_RF_TURBO, set: false); |
971 | |
972 | /* Bank Modifications (chip-specific) */ |
973 | if (ah->ah_radio == AR5K_RF5111) { |
974 | |
975 | /* Set gain_F settings according to current step */ |
976 | if (channel->hw_value != AR5K_MODE_11B) { |
977 | |
978 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, |
979 | AR5K_PHY_FRAME_CTL_TX_CLIP, |
980 | g_step->gos_param[0]); |
981 | |
982 | ath5k_hw_rfb_op(ah, rf_regs, val: g_step->gos_param[1], |
983 | reg_id: AR5K_RF_PWD_90, set: true); |
984 | |
985 | ath5k_hw_rfb_op(ah, rf_regs, val: g_step->gos_param[2], |
986 | reg_id: AR5K_RF_PWD_84, set: true); |
987 | |
988 | ath5k_hw_rfb_op(ah, rf_regs, val: g_step->gos_param[3], |
989 | reg_id: AR5K_RF_RFGAIN_SEL, set: true); |
990 | |
991 | /* We programmed gain_F parameters, switch back |
992 | * to active state */ |
993 | ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; |
994 | |
995 | } |
996 | |
997 | /* Bank 6/7 setup */ |
998 | |
999 | ath5k_hw_rfb_op(ah, rf_regs, val: !ee->ee_xpd[ee_mode], |
1000 | reg_id: AR5K_RF_PWD_XPD, set: true); |
1001 | |
1002 | ath5k_hw_rfb_op(ah, rf_regs, val: ee->ee_x_gain[ee_mode], |
1003 | reg_id: AR5K_RF_XPD_GAIN, set: true); |
1004 | |
1005 | ath5k_hw_rfb_op(ah, rf_regs, val: ee->ee_i_gain[ee_mode], |
1006 | reg_id: AR5K_RF_GAIN_I, set: true); |
1007 | |
1008 | ath5k_hw_rfb_op(ah, rf_regs, val: ee->ee_xpd[ee_mode], |
1009 | reg_id: AR5K_RF_PLO_SEL, set: true); |
1010 | |
1011 | /* Tweak power detectors for half/quarter rate support */ |
1012 | if (ah->ah_bwmode == AR5K_BWMODE_5MHZ || |
1013 | ah->ah_bwmode == AR5K_BWMODE_10MHZ) { |
1014 | u8 wait_i; |
1015 | |
1016 | ath5k_hw_rfb_op(ah, rf_regs, val: 0x1f, |
1017 | reg_id: AR5K_RF_WAIT_S, set: true); |
1018 | |
1019 | wait_i = (ah->ah_bwmode == AR5K_BWMODE_5MHZ) ? |
1020 | 0x1f : 0x10; |
1021 | |
1022 | ath5k_hw_rfb_op(ah, rf_regs, val: wait_i, |
1023 | reg_id: AR5K_RF_WAIT_I, set: true); |
1024 | ath5k_hw_rfb_op(ah, rf_regs, val: 3, |
1025 | reg_id: AR5K_RF_MAX_TIME, set: true); |
1026 | |
1027 | } |
1028 | } |
1029 | |
1030 | if (ah->ah_radio == AR5K_RF5112) { |
1031 | |
1032 | /* Set gain_F settings according to current step */ |
1033 | if (channel->hw_value != AR5K_MODE_11B) { |
1034 | |
1035 | ath5k_hw_rfb_op(ah, rf_regs, val: g_step->gos_param[0], |
1036 | reg_id: AR5K_RF_MIXGAIN_OVR, set: true); |
1037 | |
1038 | ath5k_hw_rfb_op(ah, rf_regs, val: g_step->gos_param[1], |
1039 | reg_id: AR5K_RF_PWD_138, set: true); |
1040 | |
1041 | ath5k_hw_rfb_op(ah, rf_regs, val: g_step->gos_param[2], |
1042 | reg_id: AR5K_RF_PWD_137, set: true); |
1043 | |
1044 | ath5k_hw_rfb_op(ah, rf_regs, val: g_step->gos_param[3], |
1045 | reg_id: AR5K_RF_PWD_136, set: true); |
1046 | |
1047 | ath5k_hw_rfb_op(ah, rf_regs, val: g_step->gos_param[4], |
1048 | reg_id: AR5K_RF_PWD_132, set: true); |
1049 | |
1050 | ath5k_hw_rfb_op(ah, rf_regs, val: g_step->gos_param[5], |
1051 | reg_id: AR5K_RF_PWD_131, set: true); |
1052 | |
1053 | ath5k_hw_rfb_op(ah, rf_regs, val: g_step->gos_param[6], |
1054 | reg_id: AR5K_RF_PWD_130, set: true); |
1055 | |
1056 | /* We programmed gain_F parameters, switch back |
1057 | * to active state */ |
1058 | ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; |
1059 | } |
1060 | |
1061 | /* Bank 6/7 setup */ |
1062 | |
1063 | ath5k_hw_rfb_op(ah, rf_regs, val: ee->ee_xpd[ee_mode], |
1064 | reg_id: AR5K_RF_XPD_SEL, set: true); |
1065 | |
1066 | if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) { |
1067 | /* Rev. 1 supports only one xpd */ |
1068 | ath5k_hw_rfb_op(ah, rf_regs, |
1069 | val: ee->ee_x_gain[ee_mode], |
1070 | reg_id: AR5K_RF_XPD_GAIN, set: true); |
1071 | |
1072 | } else { |
1073 | u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode]; |
1074 | if (ee->ee_pd_gains[ee_mode] > 1) { |
1075 | ath5k_hw_rfb_op(ah, rf_regs, |
1076 | val: pdg_curve_to_idx[0], |
1077 | reg_id: AR5K_RF_PD_GAIN_LO, set: true); |
1078 | ath5k_hw_rfb_op(ah, rf_regs, |
1079 | val: pdg_curve_to_idx[1], |
1080 | reg_id: AR5K_RF_PD_GAIN_HI, set: true); |
1081 | } else { |
1082 | ath5k_hw_rfb_op(ah, rf_regs, |
1083 | val: pdg_curve_to_idx[0], |
1084 | reg_id: AR5K_RF_PD_GAIN_LO, set: true); |
1085 | ath5k_hw_rfb_op(ah, rf_regs, |
1086 | val: pdg_curve_to_idx[0], |
1087 | reg_id: AR5K_RF_PD_GAIN_HI, set: true); |
1088 | } |
1089 | |
1090 | /* Lower synth voltage on Rev 2 */ |
1091 | if (ah->ah_radio == AR5K_RF5112 && |
1092 | (ah->ah_radio_5ghz_revision & AR5K_SREV_REV) > 0) { |
1093 | ath5k_hw_rfb_op(ah, rf_regs, val: 2, |
1094 | reg_id: AR5K_RF_HIGH_VC_CP, set: true); |
1095 | |
1096 | ath5k_hw_rfb_op(ah, rf_regs, val: 2, |
1097 | reg_id: AR5K_RF_MID_VC_CP, set: true); |
1098 | |
1099 | ath5k_hw_rfb_op(ah, rf_regs, val: 2, |
1100 | reg_id: AR5K_RF_LOW_VC_CP, set: true); |
1101 | |
1102 | ath5k_hw_rfb_op(ah, rf_regs, val: 2, |
1103 | reg_id: AR5K_RF_PUSH_UP, set: true); |
1104 | } |
1105 | |
1106 | /* Decrease power consumption on 5213+ BaseBand */ |
1107 | if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { |
1108 | ath5k_hw_rfb_op(ah, rf_regs, val: 1, |
1109 | reg_id: AR5K_RF_PAD2GND, set: true); |
1110 | |
1111 | ath5k_hw_rfb_op(ah, rf_regs, val: 1, |
1112 | reg_id: AR5K_RF_XB2_LVL, set: true); |
1113 | |
1114 | ath5k_hw_rfb_op(ah, rf_regs, val: 1, |
1115 | reg_id: AR5K_RF_XB5_LVL, set: true); |
1116 | |
1117 | ath5k_hw_rfb_op(ah, rf_regs, val: 1, |
1118 | reg_id: AR5K_RF_PWD_167, set: true); |
1119 | |
1120 | ath5k_hw_rfb_op(ah, rf_regs, val: 1, |
1121 | reg_id: AR5K_RF_PWD_166, set: true); |
1122 | } |
1123 | } |
1124 | |
1125 | ath5k_hw_rfb_op(ah, rf_regs, val: ee->ee_i_gain[ee_mode], |
1126 | reg_id: AR5K_RF_GAIN_I, set: true); |
1127 | |
1128 | /* Tweak power detector for half/quarter rates */ |
1129 | if (ah->ah_bwmode == AR5K_BWMODE_5MHZ || |
1130 | ah->ah_bwmode == AR5K_BWMODE_10MHZ) { |
1131 | u8 pd_delay; |
1132 | |
1133 | pd_delay = (ah->ah_bwmode == AR5K_BWMODE_5MHZ) ? |
1134 | 0xf : 0x8; |
1135 | |
1136 | ath5k_hw_rfb_op(ah, rf_regs, val: pd_delay, |
1137 | reg_id: AR5K_RF_PD_PERIOD_A, set: true); |
1138 | ath5k_hw_rfb_op(ah, rf_regs, val: 0xf, |
1139 | reg_id: AR5K_RF_PD_DELAY_A, set: true); |
1140 | |
1141 | } |
1142 | } |
1143 | |
1144 | if (ah->ah_radio == AR5K_RF5413 && |
1145 | channel->band == NL80211_BAND_2GHZ) { |
1146 | |
1147 | ath5k_hw_rfb_op(ah, rf_regs, val: 1, reg_id: AR5K_RF_DERBY_CHAN_SEL_MODE, |
1148 | set: true); |
1149 | |
1150 | /* Set optimum value for early revisions (on pci-e chips) */ |
1151 | if (ah->ah_mac_srev >= AR5K_SREV_AR5424 && |
1152 | ah->ah_mac_srev < AR5K_SREV_AR5413) |
1153 | ath5k_hw_rfb_op(ah, rf_regs, val: ath5k_hw_bitswap(val: 6, bits: 3), |
1154 | reg_id: AR5K_RF_PWD_ICLOBUF_2G, set: true); |
1155 | |
1156 | } |
1157 | |
1158 | /* Write RF banks on hw */ |
1159 | for (i = 0; i < ah->ah_rf_banks_size; i++) { |
1160 | AR5K_REG_WAIT(i); |
1161 | ath5k_hw_reg_write(ah, val: rfb[i], reg: ini_rfb[i].rfb_ctrl_register); |
1162 | } |
1163 | |
1164 | return 0; |
1165 | } |
1166 | |
1167 | |
1168 | /**************************\ |
1169 | PHY/RF channel functions |
1170 | \**************************/ |
1171 | |
1172 | /** |
1173 | * ath5k_hw_rf5110_chan2athchan() - Convert channel freq on RF5110 |
1174 | * @channel: The &struct ieee80211_channel |
1175 | * |
1176 | * Map channel frequency to IEEE channel number and convert it |
1177 | * to an internal channel value used by the RF5110 chipset. |
1178 | */ |
1179 | static u32 |
1180 | ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) |
1181 | { |
1182 | u32 athchan; |
1183 | |
1184 | athchan = (ath5k_hw_bitswap( |
1185 | val: (ieee80211_frequency_to_channel( |
1186 | freq: channel->center_freq) - 24) / 2, bits: 5) |
1187 | << 1) | (1 << 6) | 0x1; |
1188 | return athchan; |
1189 | } |
1190 | |
1191 | /** |
1192 | * ath5k_hw_rf5110_channel() - Set channel frequency on RF5110 |
1193 | * @ah: The &struct ath5k_hw |
1194 | * @channel: The &struct ieee80211_channel |
1195 | */ |
1196 | static int |
1197 | ath5k_hw_rf5110_channel(struct ath5k_hw *ah, |
1198 | struct ieee80211_channel *channel) |
1199 | { |
1200 | u32 data; |
1201 | |
1202 | /* |
1203 | * Set the channel and wait |
1204 | */ |
1205 | data = ath5k_hw_rf5110_chan2athchan(channel); |
1206 | ath5k_hw_reg_write(ah, val: data, AR5K_RF_BUFFER); |
1207 | ath5k_hw_reg_write(ah, val: 0, AR5K_RF_BUFFER_CONTROL_0); |
1208 | usleep_range(min: 1000, max: 1500); |
1209 | |
1210 | return 0; |
1211 | } |
1212 | |
1213 | /** |
1214 | * ath5k_hw_rf5111_chan2athchan() - Handle 2GHz channels on RF5111/2111 |
1215 | * @ieee: IEEE channel number |
1216 | * @athchan: The &struct ath5k_athchan_2ghz |
1217 | * |
1218 | * In order to enable the RF2111 frequency converter on RF5111/2111 setups |
1219 | * we need to add some offsets and extra flags to the data values we pass |
1220 | * on to the PHY. So for every 2GHz channel this function gets called |
1221 | * to do the conversion. |
1222 | */ |
1223 | static int |
1224 | ath5k_hw_rf5111_chan2athchan(unsigned int ieee, |
1225 | struct ath5k_athchan_2ghz *athchan) |
1226 | { |
1227 | int channel; |
1228 | |
1229 | /* Cast this value to catch negative channel numbers (>= -19) */ |
1230 | channel = (int)ieee; |
1231 | |
1232 | /* |
1233 | * Map 2GHz IEEE channel to 5GHz Atheros channel |
1234 | */ |
1235 | if (channel <= 13) { |
1236 | athchan->a2_athchan = 115 + channel; |
1237 | athchan->a2_flags = 0x46; |
1238 | } else if (channel == 14) { |
1239 | athchan->a2_athchan = 124; |
1240 | athchan->a2_flags = 0x44; |
1241 | } else if (channel >= 15 && channel <= 26) { |
1242 | athchan->a2_athchan = ((channel - 14) * 4) + 132; |
1243 | athchan->a2_flags = 0x46; |
1244 | } else |
1245 | return -EINVAL; |
1246 | |
1247 | return 0; |
1248 | } |
1249 | |
1250 | /** |
1251 | * ath5k_hw_rf5111_channel() - Set channel frequency on RF5111/2111 |
1252 | * @ah: The &struct ath5k_hw |
1253 | * @channel: The &struct ieee80211_channel |
1254 | */ |
1255 | static int |
1256 | ath5k_hw_rf5111_channel(struct ath5k_hw *ah, |
1257 | struct ieee80211_channel *channel) |
1258 | { |
1259 | struct ath5k_athchan_2ghz ath5k_channel_2ghz; |
1260 | unsigned int ath5k_channel = |
1261 | ieee80211_frequency_to_channel(freq: channel->center_freq); |
1262 | u32 data0, data1, clock; |
1263 | int ret; |
1264 | |
1265 | /* |
1266 | * Set the channel on the RF5111 radio |
1267 | */ |
1268 | data0 = data1 = 0; |
1269 | |
1270 | if (channel->band == NL80211_BAND_2GHZ) { |
1271 | /* Map 2GHz channel to 5GHz Atheros channel ID */ |
1272 | ret = ath5k_hw_rf5111_chan2athchan( |
1273 | ieee: ieee80211_frequency_to_channel(freq: channel->center_freq), |
1274 | athchan: &ath5k_channel_2ghz); |
1275 | if (ret) |
1276 | return ret; |
1277 | |
1278 | ath5k_channel = ath5k_channel_2ghz.a2_athchan; |
1279 | data0 = ((ath5k_hw_bitswap(val: ath5k_channel_2ghz.a2_flags, bits: 8) & 0xff) |
1280 | << 5) | (1 << 4); |
1281 | } |
1282 | |
1283 | if (ath5k_channel < 145 || !(ath5k_channel & 1)) { |
1284 | clock = 1; |
1285 | data1 = ((ath5k_hw_bitswap(val: ath5k_channel - 24, bits: 8) & 0xff) << 2) | |
1286 | (clock << 1) | (1 << 10) | 1; |
1287 | } else { |
1288 | clock = 0; |
1289 | data1 = ((ath5k_hw_bitswap(val: (ath5k_channel - 24) / 2, bits: 8) & 0xff) |
1290 | << 2) | (clock << 1) | (1 << 10) | 1; |
1291 | } |
1292 | |
1293 | ath5k_hw_reg_write(ah, val: (data1 & 0xff) | ((data0 & 0xff) << 8), |
1294 | AR5K_RF_BUFFER); |
1295 | ath5k_hw_reg_write(ah, val: ((data1 >> 8) & 0xff) | (data0 & 0xff00), |
1296 | AR5K_RF_BUFFER_CONTROL_3); |
1297 | |
1298 | return 0; |
1299 | } |
1300 | |
1301 | /** |
1302 | * ath5k_hw_rf5112_channel() - Set channel frequency on 5112 and newer |
1303 | * @ah: The &struct ath5k_hw |
1304 | * @channel: The &struct ieee80211_channel |
1305 | * |
1306 | * On RF5112/2112 and newer we don't need to do any conversion. |
1307 | * We pass the frequency value after a few modifications to the |
1308 | * chip directly. |
1309 | * |
1310 | * NOTE: Make sure channel frequency given is within our range or else |
1311 | * we might damage the chip ! Use ath5k_channel_ok before calling this one. |
1312 | */ |
1313 | static int |
1314 | ath5k_hw_rf5112_channel(struct ath5k_hw *ah, |
1315 | struct ieee80211_channel *channel) |
1316 | { |
1317 | u32 data, data0, data1, data2; |
1318 | u16 c; |
1319 | |
1320 | data = data0 = data1 = data2 = 0; |
1321 | c = channel->center_freq; |
1322 | |
1323 | /* My guess based on code: |
1324 | * 2GHz RF has 2 synth modes, one with a Local Oscillator |
1325 | * at 2224Hz and one with a LO at 2192Hz. IF is 1520Hz |
1326 | * (3040/2). data0 is used to set the PLL divider and data1 |
1327 | * selects synth mode. */ |
1328 | if (c < 4800) { |
1329 | /* Channel 14 and all frequencies with 2Hz spacing |
1330 | * below/above (non-standard channels) */ |
1331 | if (!((c - 2224) % 5)) { |
1332 | /* Same as (c - 2224) / 5 */ |
1333 | data0 = ((2 * (c - 704)) - 3040) / 10; |
1334 | data1 = 1; |
1335 | /* Channel 1 and all frequencies with 5Hz spacing |
1336 | * below/above (standard channels without channel 14) */ |
1337 | } else if (!((c - 2192) % 5)) { |
1338 | /* Same as (c - 2192) / 5 */ |
1339 | data0 = ((2 * (c - 672)) - 3040) / 10; |
1340 | data1 = 0; |
1341 | } else |
1342 | return -EINVAL; |
1343 | |
1344 | data0 = ath5k_hw_bitswap(val: (data0 << 2) & 0xff, bits: 8); |
1345 | /* This is more complex, we have a single synthesizer with |
1346 | * 4 reference clock settings (?) based on frequency spacing |
1347 | * and set using data2. LO is at 4800Hz and data0 is again used |
1348 | * to set some divider. |
1349 | * |
1350 | * NOTE: There is an old atheros presentation at Stanford |
1351 | * that mentions a method called dual direct conversion |
1352 | * with 1GHz sliding IF for RF5110. Maybe that's what we |
1353 | * have here, or an updated version. */ |
1354 | } else if ((c % 5) != 2 || c > 5435) { |
1355 | if (!(c % 20) && c >= 5120) { |
1356 | data0 = ath5k_hw_bitswap(val: ((c - 4800) / 20 << 2), bits: 8); |
1357 | data2 = ath5k_hw_bitswap(val: 3, bits: 2); |
1358 | } else if (!(c % 10)) { |
1359 | data0 = ath5k_hw_bitswap(val: ((c - 4800) / 10 << 1), bits: 8); |
1360 | data2 = ath5k_hw_bitswap(val: 2, bits: 2); |
1361 | } else if (!(c % 5)) { |
1362 | data0 = ath5k_hw_bitswap(val: (c - 4800) / 5, bits: 8); |
1363 | data2 = ath5k_hw_bitswap(val: 1, bits: 2); |
1364 | } else |
1365 | return -EINVAL; |
1366 | } else { |
1367 | data0 = ath5k_hw_bitswap(val: (10 * (c - 2 - 4800)) / 25 + 1, bits: 8); |
1368 | data2 = ath5k_hw_bitswap(val: 0, bits: 2); |
1369 | } |
1370 | |
1371 | data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001; |
1372 | |
1373 | ath5k_hw_reg_write(ah, val: data & 0xff, AR5K_RF_BUFFER); |
1374 | ath5k_hw_reg_write(ah, val: (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5); |
1375 | |
1376 | return 0; |
1377 | } |
1378 | |
1379 | /** |
1380 | * ath5k_hw_rf2425_channel() - Set channel frequency on RF2425 |
1381 | * @ah: The &struct ath5k_hw |
1382 | * @channel: The &struct ieee80211_channel |
1383 | * |
1384 | * AR2425/2417 have a different 2GHz RF so code changes |
1385 | * a little bit from RF5112. |
1386 | */ |
1387 | static int |
1388 | ath5k_hw_rf2425_channel(struct ath5k_hw *ah, |
1389 | struct ieee80211_channel *channel) |
1390 | { |
1391 | u32 data, data0, data2; |
1392 | u16 c; |
1393 | |
1394 | data = data0 = data2 = 0; |
1395 | c = channel->center_freq; |
1396 | |
1397 | if (c < 4800) { |
1398 | data0 = ath5k_hw_bitswap(val: (c - 2272), bits: 8); |
1399 | data2 = 0; |
1400 | /* ? 5GHz ? */ |
1401 | } else if ((c % 5) != 2 || c > 5435) { |
1402 | if (!(c % 20) && c < 5120) |
1403 | data0 = ath5k_hw_bitswap(val: ((c - 4800) / 20 << 2), bits: 8); |
1404 | else if (!(c % 10)) |
1405 | data0 = ath5k_hw_bitswap(val: ((c - 4800) / 10 << 1), bits: 8); |
1406 | else if (!(c % 5)) |
1407 | data0 = ath5k_hw_bitswap(val: (c - 4800) / 5, bits: 8); |
1408 | else |
1409 | return -EINVAL; |
1410 | data2 = ath5k_hw_bitswap(val: 1, bits: 2); |
1411 | } else { |
1412 | data0 = ath5k_hw_bitswap(val: (10 * (c - 2 - 4800)) / 25 + 1, bits: 8); |
1413 | data2 = ath5k_hw_bitswap(val: 0, bits: 2); |
1414 | } |
1415 | |
1416 | data = (data0 << 4) | data2 << 2 | 0x1001; |
1417 | |
1418 | ath5k_hw_reg_write(ah, val: data & 0xff, AR5K_RF_BUFFER); |
1419 | ath5k_hw_reg_write(ah, val: (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5); |
1420 | |
1421 | return 0; |
1422 | } |
1423 | |
1424 | /** |
1425 | * ath5k_hw_channel() - Set a channel on the radio chip |
1426 | * @ah: The &struct ath5k_hw |
1427 | * @channel: The &struct ieee80211_channel |
1428 | * |
1429 | * This is the main function called to set a channel on the |
1430 | * radio chip based on the radio chip version. |
1431 | */ |
1432 | static int |
1433 | ath5k_hw_channel(struct ath5k_hw *ah, |
1434 | struct ieee80211_channel *channel) |
1435 | { |
1436 | int ret; |
1437 | /* |
1438 | * Check bounds supported by the PHY (we don't care about regulatory |
1439 | * restrictions at this point). |
1440 | */ |
1441 | if (!ath5k_channel_ok(ah, channel)) { |
1442 | ATH5K_ERR(ah, |
1443 | "channel frequency (%u MHz) out of supported " |
1444 | "band range\n" , |
1445 | channel->center_freq); |
1446 | return -EINVAL; |
1447 | } |
1448 | |
1449 | /* |
1450 | * Set the channel and wait |
1451 | */ |
1452 | switch (ah->ah_radio) { |
1453 | case AR5K_RF5110: |
1454 | ret = ath5k_hw_rf5110_channel(ah, channel); |
1455 | break; |
1456 | case AR5K_RF5111: |
1457 | ret = ath5k_hw_rf5111_channel(ah, channel); |
1458 | break; |
1459 | case AR5K_RF2317: |
1460 | case AR5K_RF2425: |
1461 | ret = ath5k_hw_rf2425_channel(ah, channel); |
1462 | break; |
1463 | default: |
1464 | ret = ath5k_hw_rf5112_channel(ah, channel); |
1465 | break; |
1466 | } |
1467 | |
1468 | if (ret) |
1469 | return ret; |
1470 | |
1471 | /* Set JAPAN setting for channel 14 */ |
1472 | if (channel->center_freq == 2484) { |
1473 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL, |
1474 | AR5K_PHY_CCKTXCTL_JAPAN); |
1475 | } else { |
1476 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL, |
1477 | AR5K_PHY_CCKTXCTL_WORLD); |
1478 | } |
1479 | |
1480 | ah->ah_current_channel = channel; |
1481 | |
1482 | return 0; |
1483 | } |
1484 | |
1485 | |
1486 | /*****************\ |
1487 | PHY calibration |
1488 | \*****************/ |
1489 | |
1490 | /** |
1491 | * DOC: PHY Calibration routines |
1492 | * |
1493 | * Noise floor calibration: When we tell the hardware to |
1494 | * perform a noise floor calibration by setting the |
1495 | * AR5K_PHY_AGCCTL_NF bit on AR5K_PHY_AGCCTL, it will periodically |
1496 | * sample-and-hold the minimum noise level seen at the antennas. |
1497 | * This value is then stored in a ring buffer of recently measured |
1498 | * noise floor values so we have a moving window of the last few |
1499 | * samples. The median of the values in the history is then loaded |
1500 | * into the hardware for its own use for RSSI and CCA measurements. |
1501 | * This type of calibration doesn't interfere with traffic. |
1502 | * |
1503 | * AGC calibration: When we tell the hardware to perform |
1504 | * an AGC (Automatic Gain Control) calibration by setting the |
1505 | * AR5K_PHY_AGCCTL_CAL, hw disconnects the antennas and does |
1506 | * a calibration on the DC offsets of ADCs. During this period |
1507 | * rx/tx gets disabled so we have to deal with it on the driver |
1508 | * part. |
1509 | * |
1510 | * I/Q calibration: When we tell the hardware to perform |
1511 | * an I/Q calibration, it tries to correct I/Q imbalance and |
1512 | * fix QAM constellation by sampling data from rxed frames. |
1513 | * It doesn't interfere with traffic. |
1514 | * |
1515 | * For more infos on AGC and I/Q calibration check out patent doc |
1516 | * #03/094463. |
1517 | */ |
1518 | |
1519 | /** |
1520 | * ath5k_hw_read_measured_noise_floor() - Read measured NF from hw |
1521 | * @ah: The &struct ath5k_hw |
1522 | */ |
1523 | static s32 |
1524 | ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah) |
1525 | { |
1526 | s32 val; |
1527 | |
1528 | val = ath5k_hw_reg_read(ah, AR5K_PHY_NF); |
1529 | return sign_extend32(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), index: 8); |
1530 | } |
1531 | |
1532 | /** |
1533 | * ath5k_hw_init_nfcal_hist() - Initialize NF calibration history buffer |
1534 | * @ah: The &struct ath5k_hw |
1535 | */ |
1536 | void |
1537 | ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah) |
1538 | { |
1539 | int i; |
1540 | |
1541 | ah->ah_nfcal_hist.index = 0; |
1542 | for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) |
1543 | ah->ah_nfcal_hist.nfval[i] = AR5K_TUNE_CCA_MAX_GOOD_VALUE; |
1544 | } |
1545 | |
1546 | /** |
1547 | * ath5k_hw_update_nfcal_hist() - Update NF calibration history buffer |
1548 | * @ah: The &struct ath5k_hw |
1549 | * @noise_floor: The NF we got from hw |
1550 | */ |
1551 | static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor) |
1552 | { |
1553 | struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist; |
1554 | hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX - 1); |
1555 | hist->nfval[hist->index] = noise_floor; |
1556 | } |
1557 | |
1558 | static int cmps16(const void *a, const void *b) |
1559 | { |
1560 | return *(s16 *)a - *(s16 *)b; |
1561 | } |
1562 | |
1563 | /** |
1564 | * ath5k_hw_get_median_noise_floor() - Get median NF from history buffer |
1565 | * @ah: The &struct ath5k_hw |
1566 | */ |
1567 | static s16 |
1568 | ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) |
1569 | { |
1570 | s16 sorted_nfval[ATH5K_NF_CAL_HIST_MAX]; |
1571 | int i; |
1572 | |
1573 | memcpy(sorted_nfval, ah->ah_nfcal_hist.nfval, sizeof(sorted_nfval)); |
1574 | sort(base: sorted_nfval, ATH5K_NF_CAL_HIST_MAX, size: sizeof(s16), cmp_func: cmps16, NULL); |
1575 | for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) { |
1576 | ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, |
1577 | "cal %d:%d\n" , i, sorted_nfval[i]); |
1578 | } |
1579 | return sorted_nfval[(ATH5K_NF_CAL_HIST_MAX - 1) / 2]; |
1580 | } |
1581 | |
1582 | /** |
1583 | * ath5k_hw_update_noise_floor() - Update NF on hardware |
1584 | * @ah: The &struct ath5k_hw |
1585 | * |
1586 | * This is the main function we call to perform a NF calibration, |
1587 | * it reads NF from hardware, calculates the median and updates |
1588 | * NF on hw. |
1589 | */ |
1590 | void |
1591 | ath5k_hw_update_noise_floor(struct ath5k_hw *ah) |
1592 | { |
1593 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
1594 | u32 val; |
1595 | s16 nf, threshold; |
1596 | u8 ee_mode; |
1597 | |
1598 | /* keep last value if calibration hasn't completed */ |
1599 | if (ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL) & AR5K_PHY_AGCCTL_NF) { |
1600 | ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, |
1601 | "NF did not complete in calibration window\n" ); |
1602 | |
1603 | return; |
1604 | } |
1605 | |
1606 | ah->ah_cal_mask |= AR5K_CALIBRATION_NF; |
1607 | |
1608 | ee_mode = ath5k_eeprom_mode_from_channel(ah, channel: ah->ah_current_channel); |
1609 | |
1610 | /* completed NF calibration, test threshold */ |
1611 | nf = ath5k_hw_read_measured_noise_floor(ah); |
1612 | threshold = ee->ee_noise_floor_thr[ee_mode]; |
1613 | |
1614 | if (nf > threshold) { |
1615 | ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, |
1616 | "noise floor failure detected; " |
1617 | "read %d, threshold %d\n" , |
1618 | nf, threshold); |
1619 | |
1620 | nf = AR5K_TUNE_CCA_MAX_GOOD_VALUE; |
1621 | } |
1622 | |
1623 | ath5k_hw_update_nfcal_hist(ah, noise_floor: nf); |
1624 | nf = ath5k_hw_get_median_noise_floor(ah); |
1625 | |
1626 | /* load noise floor (in .5 dBm) so the hardware will use it */ |
1627 | val = ath5k_hw_reg_read(ah, AR5K_PHY_NF) & ~AR5K_PHY_NF_M; |
1628 | val |= (nf * 2) & AR5K_PHY_NF_M; |
1629 | ath5k_hw_reg_write(ah, val, AR5K_PHY_NF); |
1630 | |
1631 | AR5K_REG_MASKED_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF, |
1632 | ~(AR5K_PHY_AGCCTL_NF_EN | AR5K_PHY_AGCCTL_NF_NOUPDATE)); |
1633 | |
1634 | ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF, |
1635 | val: 0, is_set: false); |
1636 | |
1637 | /* |
1638 | * Load a high max CCA Power value (-50 dBm in .5 dBm units) |
1639 | * so that we're not capped by the median we just loaded. |
1640 | * This will be used as the initial value for the next noise |
1641 | * floor calibration. |
1642 | */ |
1643 | val = (val & ~AR5K_PHY_NF_M) | ((-50 * 2) & AR5K_PHY_NF_M); |
1644 | ath5k_hw_reg_write(ah, val, AR5K_PHY_NF); |
1645 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, |
1646 | AR5K_PHY_AGCCTL_NF_EN | |
1647 | AR5K_PHY_AGCCTL_NF_NOUPDATE | |
1648 | AR5K_PHY_AGCCTL_NF); |
1649 | |
1650 | ah->ah_noise_floor = nf; |
1651 | |
1652 | ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF; |
1653 | |
1654 | ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, |
1655 | "noise floor calibrated: %d\n" , nf); |
1656 | } |
1657 | |
1658 | /** |
1659 | * ath5k_hw_rf5110_calibrate() - Perform a PHY calibration on RF5110 |
1660 | * @ah: The &struct ath5k_hw |
1661 | * @channel: The &struct ieee80211_channel |
1662 | * |
1663 | * Do a complete PHY calibration (AGC + NF + I/Q) on RF5110 |
1664 | */ |
1665 | static int |
1666 | ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, |
1667 | struct ieee80211_channel *channel) |
1668 | { |
1669 | u32 phy_sig, phy_agc, phy_sat, beacon; |
1670 | int ret; |
1671 | |
1672 | if (!(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) |
1673 | return 0; |
1674 | |
1675 | /* |
1676 | * Disable beacons and RX/TX queues, wait |
1677 | */ |
1678 | AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210, |
1679 | AR5K_DIAG_SW_DIS_TX_5210 | AR5K_DIAG_SW_DIS_RX_5210); |
1680 | beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); |
1681 | ath5k_hw_reg_write(ah, val: beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); |
1682 | |
1683 | usleep_range(min: 2000, max: 2500); |
1684 | |
1685 | /* |
1686 | * Set the channel (with AGC turned off) |
1687 | */ |
1688 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); |
1689 | udelay(10); |
1690 | ret = ath5k_hw_channel(ah, channel); |
1691 | |
1692 | /* |
1693 | * Activate PHY and wait |
1694 | */ |
1695 | ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); |
1696 | usleep_range(min: 1000, max: 1500); |
1697 | |
1698 | AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); |
1699 | |
1700 | if (ret) |
1701 | return ret; |
1702 | |
1703 | /* |
1704 | * Calibrate the radio chip |
1705 | */ |
1706 | |
1707 | /* Remember normal state */ |
1708 | phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG); |
1709 | phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE); |
1710 | phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT); |
1711 | |
1712 | /* Update radio registers */ |
1713 | ath5k_hw_reg_write(ah, val: (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) | |
1714 | AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG); |
1715 | |
1716 | ath5k_hw_reg_write(ah, val: (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI | |
1717 | AR5K_PHY_AGCCOARSE_LO)) | |
1718 | AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) | |
1719 | AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE); |
1720 | |
1721 | ath5k_hw_reg_write(ah, val: (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT | |
1722 | AR5K_PHY_ADCSAT_THR)) | |
1723 | AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) | |
1724 | AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT); |
1725 | |
1726 | udelay(20); |
1727 | |
1728 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); |
1729 | udelay(10); |
1730 | ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG); |
1731 | AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); |
1732 | |
1733 | usleep_range(min: 1000, max: 1500); |
1734 | |
1735 | /* |
1736 | * Enable calibration and wait until completion |
1737 | */ |
1738 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL); |
1739 | |
1740 | ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, |
1741 | AR5K_PHY_AGCCTL_CAL, val: 0, is_set: false); |
1742 | |
1743 | /* Reset to normal state */ |
1744 | ath5k_hw_reg_write(ah, val: phy_sig, AR5K_PHY_SIG); |
1745 | ath5k_hw_reg_write(ah, val: phy_agc, AR5K_PHY_AGCCOARSE); |
1746 | ath5k_hw_reg_write(ah, val: phy_sat, AR5K_PHY_ADCSAT); |
1747 | |
1748 | if (ret) { |
1749 | ATH5K_ERR(ah, "calibration timeout (%uMHz)\n" , |
1750 | channel->center_freq); |
1751 | return ret; |
1752 | } |
1753 | |
1754 | /* |
1755 | * Re-enable RX/TX and beacons |
1756 | */ |
1757 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210, |
1758 | AR5K_DIAG_SW_DIS_TX_5210 | AR5K_DIAG_SW_DIS_RX_5210); |
1759 | ath5k_hw_reg_write(ah, val: beacon, AR5K_BEACON_5210); |
1760 | |
1761 | return 0; |
1762 | } |
1763 | |
1764 | /** |
1765 | * ath5k_hw_rf511x_iq_calibrate() - Perform I/Q calibration on RF5111 and newer |
1766 | * @ah: The &struct ath5k_hw |
1767 | */ |
1768 | static int |
1769 | ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah) |
1770 | { |
1771 | u32 i_pwr, q_pwr; |
1772 | s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; |
1773 | int i; |
1774 | |
1775 | /* Skip if I/Q calibration is not needed or if it's still running */ |
1776 | if (!ah->ah_iq_cal_needed) |
1777 | return -EINVAL; |
1778 | else if (ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) { |
1779 | ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_CALIBRATE, |
1780 | "I/Q calibration still running" ); |
1781 | return -EBUSY; |
1782 | } |
1783 | |
1784 | /* Calibration has finished, get the results and re-run */ |
1785 | |
1786 | /* Work around for empty results which can apparently happen on 5212: |
1787 | * Read registers up to 10 times until we get both i_pr and q_pwr */ |
1788 | for (i = 0; i <= 10; i++) { |
1789 | iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); |
1790 | i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); |
1791 | q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); |
1792 | ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_CALIBRATE, |
1793 | "iq_corr:%x i_pwr:%x q_pwr:%x" , iq_corr, i_pwr, q_pwr); |
1794 | if (i_pwr && q_pwr) |
1795 | break; |
1796 | } |
1797 | |
1798 | i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; |
1799 | |
1800 | if (ah->ah_version == AR5K_AR5211) |
1801 | q_coffd = q_pwr >> 6; |
1802 | else |
1803 | q_coffd = q_pwr >> 7; |
1804 | |
1805 | /* In case i_coffd became zero, cancel calibration |
1806 | * not only it's too small, it'll also result a divide |
1807 | * by zero later on. */ |
1808 | if (i_coffd == 0 || q_coffd < 2) |
1809 | return -ECANCELED; |
1810 | |
1811 | /* Protect against loss of sign bits */ |
1812 | |
1813 | i_coff = (-iq_corr) / i_coffd; |
1814 | i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ |
1815 | |
1816 | if (ah->ah_version == AR5K_AR5211) |
1817 | q_coff = (i_pwr / q_coffd) - 64; |
1818 | else |
1819 | q_coff = (i_pwr / q_coffd) - 128; |
1820 | q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */ |
1821 | |
1822 | ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_CALIBRATE, |
1823 | "new I:%d Q:%d (i_coffd:%x q_coffd:%x)" , |
1824 | i_coff, q_coff, i_coffd, q_coffd); |
1825 | |
1826 | /* Commit new I/Q values (set enable bit last to match HAL sources) */ |
1827 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF, i_coff); |
1828 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF, q_coff); |
1829 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE); |
1830 | |
1831 | /* Re-enable calibration -if we don't we'll commit |
1832 | * the same values again and again */ |
1833 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, |
1834 | AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); |
1835 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN); |
1836 | |
1837 | return 0; |
1838 | } |
1839 | |
1840 | /** |
1841 | * ath5k_hw_phy_calibrate() - Perform a PHY calibration |
1842 | * @ah: The &struct ath5k_hw |
1843 | * @channel: The &struct ieee80211_channel |
1844 | * |
1845 | * The main function we call from above to perform |
1846 | * a short or full PHY calibration based on RF chip |
1847 | * and current channel |
1848 | */ |
1849 | int |
1850 | ath5k_hw_phy_calibrate(struct ath5k_hw *ah, |
1851 | struct ieee80211_channel *channel) |
1852 | { |
1853 | int ret; |
1854 | |
1855 | if (ah->ah_radio == AR5K_RF5110) |
1856 | return ath5k_hw_rf5110_calibrate(ah, channel); |
1857 | |
1858 | ret = ath5k_hw_rf511x_iq_calibrate(ah); |
1859 | if (ret) { |
1860 | ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_CALIBRATE, |
1861 | "No I/Q correction performed (%uMHz)\n" , |
1862 | channel->center_freq); |
1863 | |
1864 | /* Happens all the time if there is not much |
1865 | * traffic, consider it normal behaviour. */ |
1866 | ret = 0; |
1867 | } |
1868 | |
1869 | /* On full calibration request a PAPD probe for |
1870 | * gainf calibration if needed */ |
1871 | if ((ah->ah_cal_mask & AR5K_CALIBRATION_FULL) && |
1872 | (ah->ah_radio == AR5K_RF5111 || |
1873 | ah->ah_radio == AR5K_RF5112) && |
1874 | channel->hw_value != AR5K_MODE_11B) |
1875 | ath5k_hw_request_rfgain_probe(ah); |
1876 | |
1877 | /* Update noise floor */ |
1878 | if (!(ah->ah_cal_mask & AR5K_CALIBRATION_NF)) |
1879 | ath5k_hw_update_noise_floor(ah); |
1880 | |
1881 | return ret; |
1882 | } |
1883 | |
1884 | |
1885 | /***************************\ |
1886 | * Spur mitigation functions * |
1887 | \***************************/ |
1888 | |
1889 | /** |
1890 | * ath5k_hw_set_spur_mitigation_filter() - Configure SPUR filter |
1891 | * @ah: The &struct ath5k_hw |
1892 | * @channel: The &struct ieee80211_channel |
1893 | * |
1894 | * This function gets called during PHY initialization to |
1895 | * configure the spur filter for the given channel. Spur is noise |
1896 | * generated due to "reflection" effects, for more information on this |
1897 | * method check out patent US7643810 |
1898 | */ |
1899 | static void |
1900 | ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, |
1901 | struct ieee80211_channel *channel) |
1902 | { |
1903 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
1904 | u32 mag_mask[4] = {0, 0, 0, 0}; |
1905 | u32 pilot_mask[2] = {0, 0}; |
1906 | /* Note: fbin values are scaled up by 2 */ |
1907 | u16 spur_chan_fbin, chan_fbin, symbol_width, spur_detection_window; |
1908 | s32 spur_delta_phase, spur_freq_sigma_delta; |
1909 | s32 spur_offset, num_symbols_x16; |
1910 | u8 num_symbol_offsets, i, freq_band; |
1911 | |
1912 | /* Convert current frequency to fbin value (the same way channels |
1913 | * are stored on EEPROM, check out ath5k_eeprom_bin2freq) and scale |
1914 | * up by 2 so we can compare it later */ |
1915 | if (channel->band == NL80211_BAND_2GHZ) { |
1916 | chan_fbin = (channel->center_freq - 2300) * 10; |
1917 | freq_band = AR5K_EEPROM_BAND_2GHZ; |
1918 | } else { |
1919 | chan_fbin = (channel->center_freq - 4900) * 10; |
1920 | freq_band = AR5K_EEPROM_BAND_5GHZ; |
1921 | } |
1922 | |
1923 | /* Check if any spur_chan_fbin from EEPROM is |
1924 | * within our current channel's spur detection range */ |
1925 | spur_chan_fbin = AR5K_EEPROM_NO_SPUR; |
1926 | spur_detection_window = AR5K_SPUR_CHAN_WIDTH; |
1927 | /* XXX: Half/Quarter channels ?*/ |
1928 | if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) |
1929 | spur_detection_window *= 2; |
1930 | |
1931 | for (i = 0; i < AR5K_EEPROM_N_SPUR_CHANS; i++) { |
1932 | spur_chan_fbin = ee->ee_spur_chans[i][freq_band]; |
1933 | |
1934 | /* Note: mask cleans AR5K_EEPROM_NO_SPUR flag |
1935 | * so it's zero if we got nothing from EEPROM */ |
1936 | if (spur_chan_fbin == AR5K_EEPROM_NO_SPUR) { |
1937 | spur_chan_fbin &= AR5K_EEPROM_SPUR_CHAN_MASK; |
1938 | break; |
1939 | } |
1940 | |
1941 | if ((chan_fbin - spur_detection_window <= |
1942 | (spur_chan_fbin & AR5K_EEPROM_SPUR_CHAN_MASK)) && |
1943 | (chan_fbin + spur_detection_window >= |
1944 | (spur_chan_fbin & AR5K_EEPROM_SPUR_CHAN_MASK))) { |
1945 | spur_chan_fbin &= AR5K_EEPROM_SPUR_CHAN_MASK; |
1946 | break; |
1947 | } |
1948 | } |
1949 | |
1950 | /* We need to enable spur filter for this channel */ |
1951 | if (spur_chan_fbin) { |
1952 | spur_offset = spur_chan_fbin - chan_fbin; |
1953 | /* |
1954 | * Calculate deltas: |
1955 | * spur_freq_sigma_delta -> spur_offset / sample_freq << 21 |
1956 | * spur_delta_phase -> spur_offset / chip_freq << 11 |
1957 | * Note: Both values have 100Hz resolution |
1958 | */ |
1959 | switch (ah->ah_bwmode) { |
1960 | case AR5K_BWMODE_40MHZ: |
1961 | /* Both sample_freq and chip_freq are 80MHz */ |
1962 | spur_delta_phase = (spur_offset << 16) / 25; |
1963 | spur_freq_sigma_delta = (spur_delta_phase >> 10); |
1964 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz * 2; |
1965 | break; |
1966 | case AR5K_BWMODE_10MHZ: |
1967 | /* Both sample_freq and chip_freq are 20MHz (?) */ |
1968 | spur_delta_phase = (spur_offset << 18) / 25; |
1969 | spur_freq_sigma_delta = (spur_delta_phase >> 10); |
1970 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 2; |
1971 | break; |
1972 | case AR5K_BWMODE_5MHZ: |
1973 | /* Both sample_freq and chip_freq are 10MHz (?) */ |
1974 | spur_delta_phase = (spur_offset << 19) / 25; |
1975 | spur_freq_sigma_delta = (spur_delta_phase >> 10); |
1976 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4; |
1977 | break; |
1978 | default: |
1979 | if (channel->band == NL80211_BAND_5GHZ) { |
1980 | /* Both sample_freq and chip_freq are 40MHz */ |
1981 | spur_delta_phase = (spur_offset << 17) / 25; |
1982 | spur_freq_sigma_delta = |
1983 | (spur_delta_phase >> 10); |
1984 | symbol_width = |
1985 | AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz; |
1986 | } else { |
1987 | /* sample_freq -> 40MHz chip_freq -> 44MHz |
1988 | * (for b compatibility) */ |
1989 | spur_delta_phase = (spur_offset << 17) / 25; |
1990 | spur_freq_sigma_delta = |
1991 | (spur_offset << 8) / 55; |
1992 | symbol_width = |
1993 | AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz; |
1994 | } |
1995 | break; |
1996 | } |
1997 | |
1998 | /* Calculate pilot and magnitude masks */ |
1999 | |
2000 | /* Scale up spur_offset by 1000 to switch to 100HZ resolution |
2001 | * and divide by symbol_width to find how many symbols we have |
2002 | * Note: number of symbols is scaled up by 16 */ |
2003 | num_symbols_x16 = ((spur_offset * 1000) << 4) / symbol_width; |
2004 | |
2005 | /* Spur is on a symbol if num_symbols_x16 % 16 is zero */ |
2006 | if (!(num_symbols_x16 & 0xF)) |
2007 | /* _X_ */ |
2008 | num_symbol_offsets = 3; |
2009 | else |
2010 | /* _xx_ */ |
2011 | num_symbol_offsets = 4; |
2012 | |
2013 | for (i = 0; i < num_symbol_offsets; i++) { |
2014 | |
2015 | /* Calculate pilot mask */ |
2016 | s32 curr_sym_off = |
2017 | (num_symbols_x16 / 16) + i + 25; |
2018 | |
2019 | /* Pilot magnitude mask seems to be a way to |
2020 | * declare the boundaries for our detection |
2021 | * window or something, it's 2 for the middle |
2022 | * value(s) where the symbol is expected to be |
2023 | * and 1 on the boundary values */ |
2024 | u8 plt_mag_map = |
2025 | (i == 0 || i == (num_symbol_offsets - 1)) |
2026 | ? 1 : 2; |
2027 | |
2028 | if (curr_sym_off >= 0 && curr_sym_off <= 32) { |
2029 | if (curr_sym_off <= 25) |
2030 | pilot_mask[0] |= 1 << curr_sym_off; |
2031 | else if (curr_sym_off >= 27) |
2032 | pilot_mask[0] |= 1 << (curr_sym_off - 1); |
2033 | } else if (curr_sym_off >= 33 && curr_sym_off <= 52) |
2034 | pilot_mask[1] |= 1 << (curr_sym_off - 33); |
2035 | |
2036 | /* Calculate magnitude mask (for viterbi decoder) */ |
2037 | if (curr_sym_off >= -1 && curr_sym_off <= 14) |
2038 | mag_mask[0] |= |
2039 | plt_mag_map << (curr_sym_off + 1) * 2; |
2040 | else if (curr_sym_off >= 15 && curr_sym_off <= 30) |
2041 | mag_mask[1] |= |
2042 | plt_mag_map << (curr_sym_off - 15) * 2; |
2043 | else if (curr_sym_off >= 31 && curr_sym_off <= 46) |
2044 | mag_mask[2] |= |
2045 | plt_mag_map << (curr_sym_off - 31) * 2; |
2046 | else if (curr_sym_off >= 47 && curr_sym_off <= 53) |
2047 | mag_mask[3] |= |
2048 | plt_mag_map << (curr_sym_off - 47) * 2; |
2049 | |
2050 | } |
2051 | |
2052 | /* Write settings on hw to enable spur filter */ |
2053 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, |
2054 | AR5K_PHY_BIN_MASK_CTL_RATE, 0xff); |
2055 | /* XXX: Self correlator also ? */ |
2056 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, |
2057 | AR5K_PHY_IQ_PILOT_MASK_EN | |
2058 | AR5K_PHY_IQ_CHAN_MASK_EN | |
2059 | AR5K_PHY_IQ_SPUR_FILT_EN); |
2060 | |
2061 | /* Set delta phase and freq sigma delta */ |
2062 | ath5k_hw_reg_write(ah, |
2063 | AR5K_REG_SM(spur_delta_phase, |
2064 | AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE) | |
2065 | AR5K_REG_SM(spur_freq_sigma_delta, |
2066 | AR5K_PHY_TIMING_11_SPUR_FREQ_SD) | |
2067 | AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC, |
2068 | AR5K_PHY_TIMING_11); |
2069 | |
2070 | /* Write pilot masks */ |
2071 | ath5k_hw_reg_write(ah, val: pilot_mask[0], AR5K_PHY_TIMING_7); |
2072 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_8, |
2073 | AR5K_PHY_TIMING_8_PILOT_MASK_2, |
2074 | pilot_mask[1]); |
2075 | |
2076 | ath5k_hw_reg_write(ah, val: pilot_mask[0], AR5K_PHY_TIMING_9); |
2077 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_10, |
2078 | AR5K_PHY_TIMING_10_PILOT_MASK_2, |
2079 | pilot_mask[1]); |
2080 | |
2081 | /* Write magnitude masks */ |
2082 | ath5k_hw_reg_write(ah, val: mag_mask[0], AR5K_PHY_BIN_MASK_1); |
2083 | ath5k_hw_reg_write(ah, val: mag_mask[1], AR5K_PHY_BIN_MASK_2); |
2084 | ath5k_hw_reg_write(ah, val: mag_mask[2], AR5K_PHY_BIN_MASK_3); |
2085 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, |
2086 | AR5K_PHY_BIN_MASK_CTL_MASK_4, |
2087 | mag_mask[3]); |
2088 | |
2089 | ath5k_hw_reg_write(ah, val: mag_mask[0], AR5K_PHY_BIN_MASK2_1); |
2090 | ath5k_hw_reg_write(ah, val: mag_mask[1], AR5K_PHY_BIN_MASK2_2); |
2091 | ath5k_hw_reg_write(ah, val: mag_mask[2], AR5K_PHY_BIN_MASK2_3); |
2092 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK2_4, |
2093 | AR5K_PHY_BIN_MASK2_4_MASK_4, |
2094 | mag_mask[3]); |
2095 | |
2096 | } else if (ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & |
2097 | AR5K_PHY_IQ_SPUR_FILT_EN) { |
2098 | /* Clean up spur mitigation settings and disable filter */ |
2099 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, |
2100 | AR5K_PHY_BIN_MASK_CTL_RATE, 0); |
2101 | AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_IQ, |
2102 | AR5K_PHY_IQ_PILOT_MASK_EN | |
2103 | AR5K_PHY_IQ_CHAN_MASK_EN | |
2104 | AR5K_PHY_IQ_SPUR_FILT_EN); |
2105 | ath5k_hw_reg_write(ah, val: 0, AR5K_PHY_TIMING_11); |
2106 | |
2107 | /* Clear pilot masks */ |
2108 | ath5k_hw_reg_write(ah, val: 0, AR5K_PHY_TIMING_7); |
2109 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_8, |
2110 | AR5K_PHY_TIMING_8_PILOT_MASK_2, |
2111 | 0); |
2112 | |
2113 | ath5k_hw_reg_write(ah, val: 0, AR5K_PHY_TIMING_9); |
2114 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_10, |
2115 | AR5K_PHY_TIMING_10_PILOT_MASK_2, |
2116 | 0); |
2117 | |
2118 | /* Clear magnitude masks */ |
2119 | ath5k_hw_reg_write(ah, val: 0, AR5K_PHY_BIN_MASK_1); |
2120 | ath5k_hw_reg_write(ah, val: 0, AR5K_PHY_BIN_MASK_2); |
2121 | ath5k_hw_reg_write(ah, val: 0, AR5K_PHY_BIN_MASK_3); |
2122 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, |
2123 | AR5K_PHY_BIN_MASK_CTL_MASK_4, |
2124 | 0); |
2125 | |
2126 | ath5k_hw_reg_write(ah, val: 0, AR5K_PHY_BIN_MASK2_1); |
2127 | ath5k_hw_reg_write(ah, val: 0, AR5K_PHY_BIN_MASK2_2); |
2128 | ath5k_hw_reg_write(ah, val: 0, AR5K_PHY_BIN_MASK2_3); |
2129 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK2_4, |
2130 | AR5K_PHY_BIN_MASK2_4_MASK_4, |
2131 | 0); |
2132 | } |
2133 | } |
2134 | |
2135 | |
2136 | /*****************\ |
2137 | * Antenna control * |
2138 | \*****************/ |
2139 | |
2140 | /** |
2141 | * DOC: Antenna control |
2142 | * |
2143 | * Hw supports up to 14 antennas ! I haven't found any card that implements |
2144 | * that. The maximum number of antennas I've seen is up to 4 (2 for 2GHz and 2 |
2145 | * for 5GHz). Antenna 1 (MAIN) should be omnidirectional, 2 (AUX) |
2146 | * omnidirectional or sectorial and antennas 3-14 sectorial (or directional). |
2147 | * |
2148 | * We can have a single antenna for RX and multiple antennas for TX. |
2149 | * RX antenna is our "default" antenna (usually antenna 1) set on |
2150 | * DEFAULT_ANTENNA register and TX antenna is set on each TX control descriptor |
2151 | * (0 for automatic selection, 1 - 14 antenna number). |
2152 | * |
2153 | * We can let hw do all the work doing fast antenna diversity for both |
2154 | * tx and rx or we can do things manually. Here are the options we have |
2155 | * (all are bits of STA_ID1 register): |
2156 | * |
2157 | * AR5K_STA_ID1_DEFAULT_ANTENNA -> When 0 is set as the TX antenna on TX |
2158 | * control descriptor, use the default antenna to transmit or else use the last |
2159 | * antenna on which we received an ACK. |
2160 | * |
2161 | * AR5K_STA_ID1_DESC_ANTENNA -> Update default antenna after each TX frame to |
2162 | * the antenna on which we got the ACK for that frame. |
2163 | * |
2164 | * AR5K_STA_ID1_RTS_DEF_ANTENNA -> Use default antenna for RTS or else use the |
2165 | * one on the TX descriptor. |
2166 | * |
2167 | * AR5K_STA_ID1_SELFGEN_DEF_ANT -> Use default antenna for self generated frames |
2168 | * (ACKs etc), or else use current antenna (the one we just used for TX). |
2169 | * |
2170 | * Using the above we support the following scenarios: |
2171 | * |
2172 | * AR5K_ANTMODE_DEFAULT -> Hw handles antenna diversity etc automatically |
2173 | * |
2174 | * AR5K_ANTMODE_FIXED_A -> Only antenna A (MAIN) is present |
2175 | * |
2176 | * AR5K_ANTMODE_FIXED_B -> Only antenna B (AUX) is present |
2177 | * |
2178 | * AR5K_ANTMODE_SINGLE_AP -> Sta locked on a single ap |
2179 | * |
2180 | * AR5K_ANTMODE_SECTOR_AP -> AP with tx antenna set on tx desc |
2181 | * |
2182 | * AR5K_ANTMODE_SECTOR_STA -> STA with tx antenna set on tx desc |
2183 | * |
2184 | * AR5K_ANTMODE_DEBUG Debug mode -A -> Rx, B-> Tx- |
2185 | * |
2186 | * Also note that when setting antenna to F on tx descriptor card inverts |
2187 | * current tx antenna. |
2188 | */ |
2189 | |
2190 | /** |
2191 | * ath5k_hw_set_def_antenna() - Set default rx antenna on AR5211/5212 and newer |
2192 | * @ah: The &struct ath5k_hw |
2193 | * @ant: Antenna number |
2194 | */ |
2195 | static void |
2196 | ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant) |
2197 | { |
2198 | if (ah->ah_version != AR5K_AR5210) |
2199 | ath5k_hw_reg_write(ah, val: ant & 0x7, AR5K_DEFAULT_ANTENNA); |
2200 | } |
2201 | |
2202 | /** |
2203 | * ath5k_hw_set_fast_div() - Enable/disable fast rx antenna diversity |
2204 | * @ah: The &struct ath5k_hw |
2205 | * @ee_mode: One of enum ath5k_driver_mode |
2206 | * @enable: True to enable, false to disable |
2207 | */ |
2208 | static void |
2209 | ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) |
2210 | { |
2211 | switch (ee_mode) { |
2212 | case AR5K_EEPROM_MODE_11G: |
2213 | /* XXX: This is set to |
2214 | * disabled on initvals !!! */ |
2215 | case AR5K_EEPROM_MODE_11A: |
2216 | if (enable) |
2217 | AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGCCTL, |
2218 | AR5K_PHY_AGCCTL_OFDM_DIV_DIS); |
2219 | else |
2220 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, |
2221 | AR5K_PHY_AGCCTL_OFDM_DIV_DIS); |
2222 | break; |
2223 | case AR5K_EEPROM_MODE_11B: |
2224 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, |
2225 | AR5K_PHY_AGCCTL_OFDM_DIV_DIS); |
2226 | break; |
2227 | default: |
2228 | return; |
2229 | } |
2230 | |
2231 | if (enable) { |
2232 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART, |
2233 | AR5K_PHY_RESTART_DIV_GC, 4); |
2234 | |
2235 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV, |
2236 | AR5K_PHY_FAST_ANT_DIV_EN); |
2237 | } else { |
2238 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART, |
2239 | AR5K_PHY_RESTART_DIV_GC, 0); |
2240 | |
2241 | AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV, |
2242 | AR5K_PHY_FAST_ANT_DIV_EN); |
2243 | } |
2244 | } |
2245 | |
2246 | /** |
2247 | * ath5k_hw_set_antenna_switch() - Set up antenna switch table |
2248 | * @ah: The &struct ath5k_hw |
2249 | * @ee_mode: One of enum ath5k_driver_mode |
2250 | * |
2251 | * Switch table comes from EEPROM and includes information on controlling |
2252 | * the 2 antenna RX attenuators |
2253 | */ |
2254 | void |
2255 | ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode) |
2256 | { |
2257 | u8 ant0, ant1; |
2258 | |
2259 | /* |
2260 | * In case a fixed antenna was set as default |
2261 | * use the same switch table twice. |
2262 | */ |
2263 | if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_A) |
2264 | ant0 = ant1 = AR5K_ANT_SWTABLE_A; |
2265 | else if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_B) |
2266 | ant0 = ant1 = AR5K_ANT_SWTABLE_B; |
2267 | else { |
2268 | ant0 = AR5K_ANT_SWTABLE_A; |
2269 | ant1 = AR5K_ANT_SWTABLE_B; |
2270 | } |
2271 | |
2272 | /* Set antenna idle switch table */ |
2273 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL, |
2274 | AR5K_PHY_ANT_CTL_SWTABLE_IDLE, |
2275 | (ah->ah_ant_ctl[ee_mode][AR5K_ANT_CTL] | |
2276 | AR5K_PHY_ANT_CTL_TXRX_EN)); |
2277 | |
2278 | /* Set antenna switch tables */ |
2279 | ath5k_hw_reg_write(ah, val: ah->ah_ant_ctl[ee_mode][ant0], |
2280 | AR5K_PHY_ANT_SWITCH_TABLE_0); |
2281 | ath5k_hw_reg_write(ah, val: ah->ah_ant_ctl[ee_mode][ant1], |
2282 | AR5K_PHY_ANT_SWITCH_TABLE_1); |
2283 | } |
2284 | |
2285 | /** |
2286 | * ath5k_hw_set_antenna_mode() - Set antenna operating mode |
2287 | * @ah: The &struct ath5k_hw |
2288 | * @ant_mode: One of enum ath5k_ant_mode |
2289 | */ |
2290 | void |
2291 | ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) |
2292 | { |
2293 | struct ieee80211_channel *channel = ah->ah_current_channel; |
2294 | bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div; |
2295 | bool use_def_for_sg; |
2296 | int ee_mode; |
2297 | u8 def_ant, tx_ant; |
2298 | u32 sta_id1 = 0; |
2299 | |
2300 | /* if channel is not initialized yet we can't set the antennas |
2301 | * so just store the mode. it will be set on the next reset */ |
2302 | if (channel == NULL) { |
2303 | ah->ah_ant_mode = ant_mode; |
2304 | return; |
2305 | } |
2306 | |
2307 | def_ant = ah->ah_def_ant; |
2308 | |
2309 | ee_mode = ath5k_eeprom_mode_from_channel(ah, channel); |
2310 | |
2311 | switch (ant_mode) { |
2312 | case AR5K_ANTMODE_DEFAULT: |
2313 | tx_ant = 0; |
2314 | use_def_for_tx = false; |
2315 | update_def_on_tx = false; |
2316 | use_def_for_rts = false; |
2317 | use_def_for_sg = false; |
2318 | fast_div = true; |
2319 | break; |
2320 | case AR5K_ANTMODE_FIXED_A: |
2321 | def_ant = 1; |
2322 | tx_ant = 1; |
2323 | use_def_for_tx = true; |
2324 | update_def_on_tx = false; |
2325 | use_def_for_rts = true; |
2326 | use_def_for_sg = true; |
2327 | fast_div = false; |
2328 | break; |
2329 | case AR5K_ANTMODE_FIXED_B: |
2330 | def_ant = 2; |
2331 | tx_ant = 2; |
2332 | use_def_for_tx = true; |
2333 | update_def_on_tx = false; |
2334 | use_def_for_rts = true; |
2335 | use_def_for_sg = true; |
2336 | fast_div = false; |
2337 | break; |
2338 | case AR5K_ANTMODE_SINGLE_AP: |
2339 | def_ant = 1; /* updated on tx */ |
2340 | tx_ant = 0; |
2341 | use_def_for_tx = true; |
2342 | update_def_on_tx = true; |
2343 | use_def_for_rts = true; |
2344 | use_def_for_sg = true; |
2345 | fast_div = true; |
2346 | break; |
2347 | case AR5K_ANTMODE_SECTOR_AP: |
2348 | tx_ant = 1; /* variable */ |
2349 | use_def_for_tx = false; |
2350 | update_def_on_tx = false; |
2351 | use_def_for_rts = true; |
2352 | use_def_for_sg = false; |
2353 | fast_div = false; |
2354 | break; |
2355 | case AR5K_ANTMODE_SECTOR_STA: |
2356 | tx_ant = 1; /* variable */ |
2357 | use_def_for_tx = true; |
2358 | update_def_on_tx = false; |
2359 | use_def_for_rts = true; |
2360 | use_def_for_sg = false; |
2361 | fast_div = true; |
2362 | break; |
2363 | case AR5K_ANTMODE_DEBUG: |
2364 | def_ant = 1; |
2365 | tx_ant = 2; |
2366 | use_def_for_tx = false; |
2367 | update_def_on_tx = false; |
2368 | use_def_for_rts = false; |
2369 | use_def_for_sg = false; |
2370 | fast_div = false; |
2371 | break; |
2372 | default: |
2373 | return; |
2374 | } |
2375 | |
2376 | ah->ah_tx_ant = tx_ant; |
2377 | ah->ah_ant_mode = ant_mode; |
2378 | ah->ah_def_ant = def_ant; |
2379 | |
2380 | sta_id1 |= use_def_for_tx ? AR5K_STA_ID1_DEFAULT_ANTENNA : 0; |
2381 | sta_id1 |= update_def_on_tx ? AR5K_STA_ID1_DESC_ANTENNA : 0; |
2382 | sta_id1 |= use_def_for_rts ? AR5K_STA_ID1_RTS_DEF_ANTENNA : 0; |
2383 | sta_id1 |= use_def_for_sg ? AR5K_STA_ID1_SELFGEN_DEF_ANT : 0; |
2384 | |
2385 | AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_ANTENNA_SETTINGS); |
2386 | |
2387 | if (sta_id1) |
2388 | AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, sta_id1); |
2389 | |
2390 | ath5k_hw_set_antenna_switch(ah, ee_mode); |
2391 | /* Note: set diversity before default antenna |
2392 | * because it won't work correctly */ |
2393 | ath5k_hw_set_fast_div(ah, ee_mode, enable: fast_div); |
2394 | ath5k_hw_set_def_antenna(ah, ant: def_ant); |
2395 | } |
2396 | |
2397 | |
2398 | /****************\ |
2399 | * TX power setup * |
2400 | \****************/ |
2401 | |
2402 | /* |
2403 | * Helper functions |
2404 | */ |
2405 | |
2406 | /** |
2407 | * ath5k_get_interpolated_value() - Get interpolated Y val between two points |
2408 | * @target: X value of the middle point |
2409 | * @x_left: X value of the left point |
2410 | * @x_right: X value of the right point |
2411 | * @y_left: Y value of the left point |
2412 | * @y_right: Y value of the right point |
2413 | */ |
2414 | static s16 |
2415 | ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right, |
2416 | s16 y_left, s16 y_right) |
2417 | { |
2418 | s16 ratio, result; |
2419 | |
2420 | /* Avoid divide by zero and skip interpolation |
2421 | * if we have the same point */ |
2422 | if ((x_left == x_right) || (y_left == y_right)) |
2423 | return y_left; |
2424 | |
2425 | /* |
2426 | * Since we use ints and not fps, we need to scale up in |
2427 | * order to get a sane ratio value (or else we 'll eg. get |
2428 | * always 1 instead of 1.25, 1.75 etc). We scale up by 100 |
2429 | * to have some accuracy both for 0.5 and 0.25 steps. |
2430 | */ |
2431 | ratio = ((100 * y_right - 100 * y_left) / (x_right - x_left)); |
2432 | |
2433 | /* Now scale down to be in range */ |
2434 | result = y_left + (ratio * (target - x_left) / 100); |
2435 | |
2436 | return result; |
2437 | } |
2438 | |
2439 | /** |
2440 | * ath5k_get_linear_pcdac_min() - Find vertical boundary (min pwr) for the |
2441 | * linear PCDAC curve |
2442 | * @stepL: Left array with y values (pcdac steps) |
2443 | * @stepR: Right array with y values (pcdac steps) |
2444 | * @pwrL: Left array with x values (power steps) |
2445 | * @pwrR: Right array with x values (power steps) |
2446 | * |
2447 | * Since we have the top of the curve and we draw the line below |
2448 | * until we reach 1 (1 pcdac step) we need to know which point |
2449 | * (x value) that is so that we don't go below x axis and have negative |
2450 | * pcdac values when creating the curve, or fill the table with zeros. |
2451 | */ |
2452 | static s16 |
2453 | ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, |
2454 | const s16 *pwrL, const s16 *pwrR) |
2455 | { |
2456 | s8 tmp; |
2457 | s16 min_pwrL, min_pwrR; |
2458 | s16 pwr_i; |
2459 | |
2460 | /* Some vendors write the same pcdac value twice !!! */ |
2461 | if (stepL[0] == stepL[1] || stepR[0] == stepR[1]) |
2462 | return max(pwrL[0], pwrR[0]); |
2463 | |
2464 | if (pwrL[0] == pwrL[1]) |
2465 | min_pwrL = pwrL[0]; |
2466 | else { |
2467 | pwr_i = pwrL[0]; |
2468 | do { |
2469 | pwr_i--; |
2470 | tmp = (s8) ath5k_get_interpolated_value(target: pwr_i, |
2471 | x_left: pwrL[0], x_right: pwrL[1], |
2472 | y_left: stepL[0], y_right: stepL[1]); |
2473 | } while (tmp > 1); |
2474 | |
2475 | min_pwrL = pwr_i; |
2476 | } |
2477 | |
2478 | if (pwrR[0] == pwrR[1]) |
2479 | min_pwrR = pwrR[0]; |
2480 | else { |
2481 | pwr_i = pwrR[0]; |
2482 | do { |
2483 | pwr_i--; |
2484 | tmp = (s8) ath5k_get_interpolated_value(target: pwr_i, |
2485 | x_left: pwrR[0], x_right: pwrR[1], |
2486 | y_left: stepR[0], y_right: stepR[1]); |
2487 | } while (tmp > 1); |
2488 | |
2489 | min_pwrR = pwr_i; |
2490 | } |
2491 | |
2492 | /* Keep the right boundary so that it works for both curves */ |
2493 | return max(min_pwrL, min_pwrR); |
2494 | } |
2495 | |
2496 | /** |
2497 | * ath5k_create_power_curve() - Create a Power to PDADC or PCDAC curve |
2498 | * @pmin: Minimum power value (xmin) |
2499 | * @pmax: Maximum power value (xmax) |
2500 | * @pwr: Array of power steps (x values) |
2501 | * @vpd: Array of matching PCDAC/PDADC steps (y values) |
2502 | * @num_points: Number of provided points |
2503 | * @vpd_table: Array to fill with the full PCDAC/PDADC values (y values) |
2504 | * @type: One of enum ath5k_powertable_type (eeprom.h) |
2505 | * |
2506 | * Interpolate (pwr,vpd) points to create a Power to PDADC or a |
2507 | * Power to PCDAC curve. |
2508 | * |
2509 | * Each curve has power on x axis (in 0.5dB units) and PCDAC/PDADC |
2510 | * steps (offsets) on y axis. Power can go up to 31.5dB and max |
2511 | * PCDAC/PDADC step for each curve is 64 but we can write more than |
2512 | * one curves on hw so we can go up to 128 (which is the max step we |
2513 | * can write on the final table). |
2514 | * |
2515 | * We write y values (PCDAC/PDADC steps) on hw. |
2516 | */ |
2517 | static void |
2518 | ath5k_create_power_curve(s16 pmin, s16 pmax, |
2519 | const s16 *pwr, const u8 *vpd, |
2520 | u8 num_points, |
2521 | u8 *vpd_table, u8 type) |
2522 | { |
2523 | u8 idx[2] = { 0, 1 }; |
2524 | s16 pwr_i = 2 * pmin; |
2525 | int i; |
2526 | |
2527 | if (num_points < 2) |
2528 | return; |
2529 | |
2530 | /* We want the whole line, so adjust boundaries |
2531 | * to cover the entire power range. Note that |
2532 | * power values are already 0.25dB so no need |
2533 | * to multiply pwr_i by 2 */ |
2534 | if (type == AR5K_PWRTABLE_LINEAR_PCDAC) { |
2535 | pwr_i = pmin; |
2536 | pmin = 0; |
2537 | pmax = 63; |
2538 | } |
2539 | |
2540 | /* Find surrounding turning points (TPs) |
2541 | * and interpolate between them */ |
2542 | for (i = 0; (i <= (u16) (pmax - pmin)) && |
2543 | (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) { |
2544 | |
2545 | /* We passed the right TP, move to the next set of TPs |
2546 | * if we pass the last TP, extrapolate above using the last |
2547 | * two TPs for ratio */ |
2548 | if ((pwr_i > pwr[idx[1]]) && (idx[1] < num_points - 1)) { |
2549 | idx[0]++; |
2550 | idx[1]++; |
2551 | } |
2552 | |
2553 | vpd_table[i] = (u8) ath5k_get_interpolated_value(target: pwr_i, |
2554 | x_left: pwr[idx[0]], x_right: pwr[idx[1]], |
2555 | y_left: vpd[idx[0]], y_right: vpd[idx[1]]); |
2556 | |
2557 | /* Increase by 0.5dB |
2558 | * (0.25 dB units) */ |
2559 | pwr_i += 2; |
2560 | } |
2561 | } |
2562 | |
2563 | /** |
2564 | * ath5k_get_chan_pcal_surrounding_piers() - Get surrounding calibration piers |
2565 | * for a given channel. |
2566 | * @ah: The &struct ath5k_hw |
2567 | * @channel: The &struct ieee80211_channel |
2568 | * @pcinfo_l: The &struct ath5k_chan_pcal_info to put the left cal. pier |
2569 | * @pcinfo_r: The &struct ath5k_chan_pcal_info to put the right cal. pier |
2570 | * |
2571 | * Get the surrounding per-channel power calibration piers |
2572 | * for a given frequency so that we can interpolate between |
2573 | * them and come up with an appropriate dataset for our current |
2574 | * channel. |
2575 | */ |
2576 | static void |
2577 | ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah, |
2578 | struct ieee80211_channel *channel, |
2579 | struct ath5k_chan_pcal_info **pcinfo_l, |
2580 | struct ath5k_chan_pcal_info **pcinfo_r) |
2581 | { |
2582 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
2583 | struct ath5k_chan_pcal_info *pcinfo; |
2584 | u8 idx_l, idx_r; |
2585 | u8 mode, max, i; |
2586 | u32 target = channel->center_freq; |
2587 | |
2588 | idx_l = 0; |
2589 | idx_r = 0; |
2590 | |
2591 | switch (channel->hw_value) { |
2592 | case AR5K_EEPROM_MODE_11A: |
2593 | pcinfo = ee->ee_pwr_cal_a; |
2594 | mode = AR5K_EEPROM_MODE_11A; |
2595 | break; |
2596 | case AR5K_EEPROM_MODE_11B: |
2597 | pcinfo = ee->ee_pwr_cal_b; |
2598 | mode = AR5K_EEPROM_MODE_11B; |
2599 | break; |
2600 | case AR5K_EEPROM_MODE_11G: |
2601 | default: |
2602 | pcinfo = ee->ee_pwr_cal_g; |
2603 | mode = AR5K_EEPROM_MODE_11G; |
2604 | break; |
2605 | } |
2606 | max = ee->ee_n_piers[mode] - 1; |
2607 | |
2608 | /* Frequency is below our calibrated |
2609 | * range. Use the lowest power curve |
2610 | * we have */ |
2611 | if (target < pcinfo[0].freq) { |
2612 | idx_l = idx_r = 0; |
2613 | goto done; |
2614 | } |
2615 | |
2616 | /* Frequency is above our calibrated |
2617 | * range. Use the highest power curve |
2618 | * we have */ |
2619 | if (target > pcinfo[max].freq) { |
2620 | idx_l = idx_r = max; |
2621 | goto done; |
2622 | } |
2623 | |
2624 | /* Frequency is inside our calibrated |
2625 | * channel range. Pick the surrounding |
2626 | * calibration piers so that we can |
2627 | * interpolate */ |
2628 | for (i = 0; i <= max; i++) { |
2629 | |
2630 | /* Frequency matches one of our calibration |
2631 | * piers, no need to interpolate, just use |
2632 | * that calibration pier */ |
2633 | if (pcinfo[i].freq == target) { |
2634 | idx_l = idx_r = i; |
2635 | goto done; |
2636 | } |
2637 | |
2638 | /* We found a calibration pier that's above |
2639 | * frequency, use this pier and the previous |
2640 | * one to interpolate */ |
2641 | if (target < pcinfo[i].freq) { |
2642 | idx_r = i; |
2643 | idx_l = idx_r - 1; |
2644 | goto done; |
2645 | } |
2646 | } |
2647 | |
2648 | done: |
2649 | *pcinfo_l = &pcinfo[idx_l]; |
2650 | *pcinfo_r = &pcinfo[idx_r]; |
2651 | } |
2652 | |
2653 | /** |
2654 | * ath5k_get_rate_pcal_data() - Get the interpolated per-rate power |
2655 | * calibration data |
2656 | * @ah: The &struct ath5k_hw *ah, |
2657 | * @channel: The &struct ieee80211_channel |
2658 | * @rates: The &struct ath5k_rate_pcal_info to fill |
2659 | * |
2660 | * Get the surrounding per-rate power calibration data |
2661 | * for a given frequency and interpolate between power |
2662 | * values to set max target power supported by hw for |
2663 | * each rate on this frequency. |
2664 | */ |
2665 | static void |
2666 | ath5k_get_rate_pcal_data(struct ath5k_hw *ah, |
2667 | struct ieee80211_channel *channel, |
2668 | struct ath5k_rate_pcal_info *rates) |
2669 | { |
2670 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
2671 | struct ath5k_rate_pcal_info *rpinfo; |
2672 | u8 idx_l, idx_r; |
2673 | u8 mode, max, i; |
2674 | u32 target = channel->center_freq; |
2675 | |
2676 | idx_l = 0; |
2677 | idx_r = 0; |
2678 | |
2679 | switch (channel->hw_value) { |
2680 | case AR5K_MODE_11A: |
2681 | rpinfo = ee->ee_rate_tpwr_a; |
2682 | mode = AR5K_EEPROM_MODE_11A; |
2683 | break; |
2684 | case AR5K_MODE_11B: |
2685 | rpinfo = ee->ee_rate_tpwr_b; |
2686 | mode = AR5K_EEPROM_MODE_11B; |
2687 | break; |
2688 | case AR5K_MODE_11G: |
2689 | default: |
2690 | rpinfo = ee->ee_rate_tpwr_g; |
2691 | mode = AR5K_EEPROM_MODE_11G; |
2692 | break; |
2693 | } |
2694 | max = ee->ee_rate_target_pwr_num[mode] - 1; |
2695 | |
2696 | /* Get the surrounding calibration |
2697 | * piers - same as above */ |
2698 | if (target < rpinfo[0].freq) { |
2699 | idx_l = idx_r = 0; |
2700 | goto done; |
2701 | } |
2702 | |
2703 | if (target > rpinfo[max].freq) { |
2704 | idx_l = idx_r = max; |
2705 | goto done; |
2706 | } |
2707 | |
2708 | for (i = 0; i <= max; i++) { |
2709 | |
2710 | if (rpinfo[i].freq == target) { |
2711 | idx_l = idx_r = i; |
2712 | goto done; |
2713 | } |
2714 | |
2715 | if (target < rpinfo[i].freq) { |
2716 | idx_r = i; |
2717 | idx_l = idx_r - 1; |
2718 | goto done; |
2719 | } |
2720 | } |
2721 | |
2722 | done: |
2723 | /* Now interpolate power value, based on the frequency */ |
2724 | rates->freq = target; |
2725 | |
2726 | rates->target_power_6to24 = |
2727 | ath5k_get_interpolated_value(target, x_left: rpinfo[idx_l].freq, |
2728 | x_right: rpinfo[idx_r].freq, |
2729 | y_left: rpinfo[idx_l].target_power_6to24, |
2730 | y_right: rpinfo[idx_r].target_power_6to24); |
2731 | |
2732 | rates->target_power_36 = |
2733 | ath5k_get_interpolated_value(target, x_left: rpinfo[idx_l].freq, |
2734 | x_right: rpinfo[idx_r].freq, |
2735 | y_left: rpinfo[idx_l].target_power_36, |
2736 | y_right: rpinfo[idx_r].target_power_36); |
2737 | |
2738 | rates->target_power_48 = |
2739 | ath5k_get_interpolated_value(target, x_left: rpinfo[idx_l].freq, |
2740 | x_right: rpinfo[idx_r].freq, |
2741 | y_left: rpinfo[idx_l].target_power_48, |
2742 | y_right: rpinfo[idx_r].target_power_48); |
2743 | |
2744 | rates->target_power_54 = |
2745 | ath5k_get_interpolated_value(target, x_left: rpinfo[idx_l].freq, |
2746 | x_right: rpinfo[idx_r].freq, |
2747 | y_left: rpinfo[idx_l].target_power_54, |
2748 | y_right: rpinfo[idx_r].target_power_54); |
2749 | } |
2750 | |
2751 | /** |
2752 | * ath5k_get_max_ctl_power() - Get max edge power for a given frequency |
2753 | * @ah: the &struct ath5k_hw |
2754 | * @channel: The &struct ieee80211_channel |
2755 | * |
2756 | * Get the max edge power for this channel if |
2757 | * we have such data from EEPROM's Conformance Test |
2758 | * Limits (CTL), and limit max power if needed. |
2759 | */ |
2760 | static void |
2761 | ath5k_get_max_ctl_power(struct ath5k_hw *ah, |
2762 | struct ieee80211_channel *channel) |
2763 | { |
2764 | struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); |
2765 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
2766 | struct ath5k_edge_power *rep = ee->ee_ctl_pwr; |
2767 | u8 *ctl_val = ee->ee_ctl; |
2768 | s16 max_chan_pwr = ah->ah_txpower.txp_max_pwr / 4; |
2769 | s16 edge_pwr = 0; |
2770 | u8 rep_idx; |
2771 | u8 i, ctl_mode; |
2772 | u8 ctl_idx = 0xFF; |
2773 | u32 target = channel->center_freq; |
2774 | |
2775 | ctl_mode = ath_regd_get_band_ctl(reg: regulatory, band: channel->band); |
2776 | |
2777 | switch (channel->hw_value) { |
2778 | case AR5K_MODE_11A: |
2779 | if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) |
2780 | ctl_mode |= AR5K_CTL_TURBO; |
2781 | else |
2782 | ctl_mode |= AR5K_CTL_11A; |
2783 | break; |
2784 | case AR5K_MODE_11G: |
2785 | if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) |
2786 | ctl_mode |= AR5K_CTL_TURBOG; |
2787 | else |
2788 | ctl_mode |= AR5K_CTL_11G; |
2789 | break; |
2790 | case AR5K_MODE_11B: |
2791 | ctl_mode |= AR5K_CTL_11B; |
2792 | break; |
2793 | default: |
2794 | return; |
2795 | } |
2796 | |
2797 | for (i = 0; i < ee->ee_ctls; i++) { |
2798 | if (ctl_val[i] == ctl_mode) { |
2799 | ctl_idx = i; |
2800 | break; |
2801 | } |
2802 | } |
2803 | |
2804 | /* If we have a CTL dataset available grab it and find the |
2805 | * edge power for our frequency */ |
2806 | if (ctl_idx == 0xFF) |
2807 | return; |
2808 | |
2809 | /* Edge powers are sorted by frequency from lower |
2810 | * to higher. Each CTL corresponds to 8 edge power |
2811 | * measurements. */ |
2812 | rep_idx = ctl_idx * AR5K_EEPROM_N_EDGES; |
2813 | |
2814 | /* Don't do boundaries check because we |
2815 | * might have more that one bands defined |
2816 | * for this mode */ |
2817 | |
2818 | /* Get the edge power that's closer to our |
2819 | * frequency */ |
2820 | for (i = 0; i < AR5K_EEPROM_N_EDGES; i++) { |
2821 | rep_idx += i; |
2822 | if (target <= rep[rep_idx].freq) |
2823 | edge_pwr = (s16) rep[rep_idx].edge; |
2824 | } |
2825 | |
2826 | if (edge_pwr) |
2827 | ah->ah_txpower.txp_max_pwr = 4 * min(edge_pwr, max_chan_pwr); |
2828 | } |
2829 | |
2830 | |
2831 | /* |
2832 | * Power to PCDAC table functions |
2833 | */ |
2834 | |
2835 | /** |
2836 | * DOC: Power to PCDAC table functions |
2837 | * |
2838 | * For RF5111 we have an XPD -eXternal Power Detector- curve |
2839 | * for each calibrated channel. Each curve has 0,5dB Power steps |
2840 | * on x axis and PCDAC steps (offsets) on y axis and looks like an |
2841 | * exponential function. To recreate the curve we read 11 points |
2842 | * from eeprom (eeprom.c) and interpolate here. |
2843 | * |
2844 | * For RF5112 we have 4 XPD -eXternal Power Detector- curves |
2845 | * for each calibrated channel on 0, -6, -12 and -18dBm but we only |
2846 | * use the higher (3) and the lower (0) curves. Each curve again has 0.5dB |
2847 | * power steps on x axis and PCDAC steps on y axis and looks like a |
2848 | * linear function. To recreate the curve and pass the power values |
2849 | * on hw, we get 4 points for xpd 0 (lower gain -> max power) |
2850 | * and 3 points for xpd 3 (higher gain -> lower power) from eeprom (eeprom.c) |
2851 | * and interpolate here. |
2852 | * |
2853 | * For a given channel we get the calibrated points (piers) for it or |
2854 | * -if we don't have calibration data for this specific channel- from the |
2855 | * available surrounding channels we have calibration data for, after we do a |
2856 | * linear interpolation between them. Then since we have our calibrated points |
2857 | * for this channel, we do again a linear interpolation between them to get the |
2858 | * whole curve. |
2859 | * |
2860 | * We finally write the Y values of the curve(s) (the PCDAC values) on hw |
2861 | */ |
2862 | |
2863 | /** |
2864 | * ath5k_fill_pwr_to_pcdac_table() - Fill Power to PCDAC table on RF5111 |
2865 | * @ah: The &struct ath5k_hw |
2866 | * @table_min: Minimum power (x min) |
2867 | * @table_max: Maximum power (x max) |
2868 | * |
2869 | * No further processing is needed for RF5111, the only thing we have to |
2870 | * do is fill the values below and above calibration range since eeprom data |
2871 | * may not cover the entire PCDAC table. |
2872 | */ |
2873 | static void |
2874 | ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min, |
2875 | s16 *table_max) |
2876 | { |
2877 | u8 *pcdac_out = ah->ah_txpower.txp_pd_table; |
2878 | u8 *pcdac_tmp = ah->ah_txpower.tmpL[0]; |
2879 | u8 pcdac_0, pcdac_n, pcdac_i, pwr_idx, i; |
2880 | s16 min_pwr, max_pwr; |
2881 | |
2882 | /* Get table boundaries */ |
2883 | min_pwr = table_min[0]; |
2884 | pcdac_0 = pcdac_tmp[0]; |
2885 | |
2886 | max_pwr = table_max[0]; |
2887 | pcdac_n = pcdac_tmp[table_max[0] - table_min[0]]; |
2888 | |
2889 | /* Extrapolate below minimum using pcdac_0 */ |
2890 | pcdac_i = 0; |
2891 | for (i = 0; i < min_pwr; i++) |
2892 | pcdac_out[pcdac_i++] = pcdac_0; |
2893 | |
2894 | /* Copy values from pcdac_tmp */ |
2895 | pwr_idx = min_pwr; |
2896 | for (i = 0; pwr_idx <= max_pwr && |
2897 | pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) { |
2898 | pcdac_out[pcdac_i++] = pcdac_tmp[i]; |
2899 | pwr_idx++; |
2900 | } |
2901 | |
2902 | /* Extrapolate above maximum */ |
2903 | while (pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE) |
2904 | pcdac_out[pcdac_i++] = pcdac_n; |
2905 | |
2906 | } |
2907 | |
2908 | /** |
2909 | * ath5k_combine_linear_pcdac_curves() - Combine available PCDAC Curves |
2910 | * @ah: The &struct ath5k_hw |
2911 | * @table_min: Minimum power (x min) |
2912 | * @table_max: Maximum power (x max) |
2913 | * @pdcurves: Number of pd curves |
2914 | * |
2915 | * Combine available XPD Curves and fill Linear Power to PCDAC table on RF5112 |
2916 | * RFX112 can have up to 2 curves (one for low txpower range and one for |
2917 | * higher txpower range). We need to put them both on pcdac_out and place |
2918 | * them in the correct location. In case we only have one curve available |
2919 | * just fit it on pcdac_out (it's supposed to cover the entire range of |
2920 | * available pwr levels since it's always the higher power curve). Extrapolate |
2921 | * below and above final table if needed. |
2922 | */ |
2923 | static void |
2924 | ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, |
2925 | s16 *table_max, u8 pdcurves) |
2926 | { |
2927 | u8 *pcdac_out = ah->ah_txpower.txp_pd_table; |
2928 | u8 *pcdac_low_pwr; |
2929 | u8 *pcdac_high_pwr; |
2930 | u8 *pcdac_tmp; |
2931 | u8 pwr; |
2932 | s16 max_pwr_idx; |
2933 | s16 min_pwr_idx; |
2934 | s16 mid_pwr_idx = 0; |
2935 | /* Edge flag turns on the 7nth bit on the PCDAC |
2936 | * to declare the higher power curve (force values |
2937 | * to be greater than 64). If we only have one curve |
2938 | * we don't need to set this, if we have 2 curves and |
2939 | * fill the table backwards this can also be used to |
2940 | * switch from higher power curve to lower power curve */ |
2941 | u8 edge_flag; |
2942 | int i; |
2943 | |
2944 | /* When we have only one curve available |
2945 | * that's the higher power curve. If we have |
2946 | * two curves the first is the high power curve |
2947 | * and the next is the low power curve. */ |
2948 | if (pdcurves > 1) { |
2949 | pcdac_low_pwr = ah->ah_txpower.tmpL[1]; |
2950 | pcdac_high_pwr = ah->ah_txpower.tmpL[0]; |
2951 | mid_pwr_idx = table_max[1] - table_min[1] - 1; |
2952 | max_pwr_idx = (table_max[0] - table_min[0]) / 2; |
2953 | |
2954 | /* If table size goes beyond 31.5dB, keep the |
2955 | * upper 31.5dB range when setting tx power. |
2956 | * Note: 126 = 31.5 dB in quarter dB steps */ |
2957 | if (table_max[0] - table_min[1] > 126) |
2958 | min_pwr_idx = table_max[0] - 126; |
2959 | else |
2960 | min_pwr_idx = table_min[1]; |
2961 | |
2962 | /* Since we fill table backwards |
2963 | * start from high power curve */ |
2964 | pcdac_tmp = pcdac_high_pwr; |
2965 | |
2966 | edge_flag = 0x40; |
2967 | } else { |
2968 | pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */ |
2969 | pcdac_high_pwr = ah->ah_txpower.tmpL[0]; |
2970 | min_pwr_idx = table_min[0]; |
2971 | max_pwr_idx = (table_max[0] - table_min[0]) / 2; |
2972 | pcdac_tmp = pcdac_high_pwr; |
2973 | edge_flag = 0; |
2974 | } |
2975 | |
2976 | /* This is used when setting tx power*/ |
2977 | ah->ah_txpower.txp_min_idx = min_pwr_idx / 2; |
2978 | |
2979 | /* Fill Power to PCDAC table backwards */ |
2980 | pwr = max_pwr_idx; |
2981 | for (i = 63; i >= 0; i--) { |
2982 | /* Entering lower power range, reset |
2983 | * edge flag and set pcdac_tmp to lower |
2984 | * power curve.*/ |
2985 | if (edge_flag == 0x40 && |
2986 | (2 * pwr <= (table_max[1] - table_min[0]) || pwr == 0)) { |
2987 | edge_flag = 0x00; |
2988 | pcdac_tmp = pcdac_low_pwr; |
2989 | pwr = mid_pwr_idx / 2; |
2990 | } |
2991 | |
2992 | /* Don't go below 1, extrapolate below if we have |
2993 | * already switched to the lower power curve -or |
2994 | * we only have one curve and edge_flag is zero |
2995 | * anyway */ |
2996 | if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) { |
2997 | while (i >= 0) { |
2998 | pcdac_out[i] = pcdac_out[i + 1]; |
2999 | i--; |
3000 | } |
3001 | break; |
3002 | } |
3003 | |
3004 | pcdac_out[i] = pcdac_tmp[pwr] | edge_flag; |
3005 | |
3006 | /* Extrapolate above if pcdac is greater than |
3007 | * 126 -this can happen because we OR pcdac_out |
3008 | * value with edge_flag on high power curve */ |
3009 | if (pcdac_out[i] > 126) |
3010 | pcdac_out[i] = 126; |
3011 | |
3012 | /* Decrease by a 0.5dB step */ |
3013 | pwr--; |
3014 | } |
3015 | } |
3016 | |
3017 | /** |
3018 | * ath5k_write_pcdac_table() - Write the PCDAC values on hw |
3019 | * @ah: The &struct ath5k_hw |
3020 | */ |
3021 | static void |
3022 | ath5k_write_pcdac_table(struct ath5k_hw *ah) |
3023 | { |
3024 | u8 *pcdac_out = ah->ah_txpower.txp_pd_table; |
3025 | int i; |
3026 | |
3027 | /* |
3028 | * Write TX power values |
3029 | */ |
3030 | for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { |
3031 | ath5k_hw_reg_write(ah, |
3032 | val: (((pcdac_out[2 * i + 0] << 8 | 0xff) & 0xffff) << 0) | |
3033 | (((pcdac_out[2 * i + 1] << 8 | 0xff) & 0xffff) << 16), |
3034 | AR5K_PHY_PCDAC_TXPOWER(i)); |
3035 | } |
3036 | } |
3037 | |
3038 | |
3039 | /* |
3040 | * Power to PDADC table functions |
3041 | */ |
3042 | |
3043 | /** |
3044 | * DOC: Power to PDADC table functions |
3045 | * |
3046 | * For RF2413 and later we have a Power to PDADC table (Power Detector) |
3047 | * instead of a PCDAC (Power Control) and 4 pd gain curves for each |
3048 | * calibrated channel. Each curve has power on x axis in 0.5 db steps and |
3049 | * PDADC steps on y axis and looks like an exponential function like the |
3050 | * RF5111 curve. |
3051 | * |
3052 | * To recreate the curves we read the points from eeprom (eeprom.c) |
3053 | * and interpolate here. Note that in most cases only 2 (higher and lower) |
3054 | * curves are used (like RF5112) but vendors have the opportunity to include |
3055 | * all 4 curves on eeprom. The final curve (higher power) has an extra |
3056 | * point for better accuracy like RF5112. |
3057 | * |
3058 | * The process is similar to what we do above for RF5111/5112 |
3059 | */ |
3060 | |
3061 | /** |
3062 | * ath5k_combine_pwr_to_pdadc_curves() - Combine the various PDADC curves |
3063 | * @ah: The &struct ath5k_hw |
3064 | * @pwr_min: Minimum power (x min) |
3065 | * @pwr_max: Maximum power (x max) |
3066 | * @pdcurves: Number of available curves |
3067 | * |
3068 | * Combine the various pd curves and create the final Power to PDADC table |
3069 | * We can have up to 4 pd curves, we need to do a similar process |
3070 | * as we do for RF5112. This time we don't have an edge_flag but we |
3071 | * set the gain boundaries on a separate register. |
3072 | */ |
3073 | static void |
3074 | ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, |
3075 | s16 *pwr_min, s16 *pwr_max, u8 pdcurves) |
3076 | { |
3077 | u8 gain_boundaries[AR5K_EEPROM_N_PD_GAINS]; |
3078 | u8 *pdadc_out = ah->ah_txpower.txp_pd_table; |
3079 | u8 *pdadc_tmp; |
3080 | s16 pdadc_0; |
3081 | u8 pdadc_i, pdadc_n, pwr_step, pdg, max_idx, table_size; |
3082 | u8 pd_gain_overlap; |
3083 | |
3084 | /* Note: Register value is initialized on initvals |
3085 | * there is no feedback from hw. |
3086 | * XXX: What about pd_gain_overlap from EEPROM ? */ |
3087 | pd_gain_overlap = (u8) ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) & |
3088 | AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP; |
3089 | |
3090 | /* Create final PDADC table */ |
3091 | for (pdg = 0, pdadc_i = 0; pdg < pdcurves; pdg++) { |
3092 | pdadc_tmp = ah->ah_txpower.tmpL[pdg]; |
3093 | |
3094 | if (pdg == pdcurves - 1) |
3095 | /* 2 dB boundary stretch for last |
3096 | * (higher power) curve */ |
3097 | gain_boundaries[pdg] = pwr_max[pdg] + 4; |
3098 | else |
3099 | /* Set gain boundary in the middle |
3100 | * between this curve and the next one */ |
3101 | gain_boundaries[pdg] = |
3102 | (pwr_max[pdg] + pwr_min[pdg + 1]) / 2; |
3103 | |
3104 | /* Sanity check in case our 2 db stretch got out of |
3105 | * range. */ |
3106 | if (gain_boundaries[pdg] > AR5K_TUNE_MAX_TXPOWER) |
3107 | gain_boundaries[pdg] = AR5K_TUNE_MAX_TXPOWER; |
3108 | |
3109 | /* For the first curve (lower power) |
3110 | * start from 0 dB */ |
3111 | if (pdg == 0) |
3112 | pdadc_0 = 0; |
3113 | else |
3114 | /* For the other curves use the gain overlap */ |
3115 | pdadc_0 = (gain_boundaries[pdg - 1] - pwr_min[pdg]) - |
3116 | pd_gain_overlap; |
3117 | |
3118 | /* Force each power step to be at least 0.5 dB */ |
3119 | if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1) |
3120 | pwr_step = pdadc_tmp[1] - pdadc_tmp[0]; |
3121 | else |
3122 | pwr_step = 1; |
3123 | |
3124 | /* If pdadc_0 is negative, we need to extrapolate |
3125 | * below this pdgain by a number of pwr_steps */ |
3126 | while ((pdadc_0 < 0) && (pdadc_i < 128)) { |
3127 | s16 tmp = pdadc_tmp[0] + pdadc_0 * pwr_step; |
3128 | pdadc_out[pdadc_i++] = (tmp < 0) ? 0 : (u8) tmp; |
3129 | pdadc_0++; |
3130 | } |
3131 | |
3132 | /* Set last pwr level, using gain boundaries */ |
3133 | pdadc_n = gain_boundaries[pdg] + pd_gain_overlap - pwr_min[pdg]; |
3134 | /* Limit it to be inside pwr range */ |
3135 | table_size = pwr_max[pdg] - pwr_min[pdg]; |
3136 | max_idx = min(pdadc_n, table_size); |
3137 | |
3138 | /* Fill pdadc_out table */ |
3139 | while (pdadc_0 < max_idx && pdadc_i < 128) |
3140 | pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++]; |
3141 | |
3142 | /* Need to extrapolate above this pdgain? */ |
3143 | if (pdadc_n <= max_idx) |
3144 | continue; |
3145 | |
3146 | /* Force each power step to be at least 0.5 dB */ |
3147 | if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1) |
3148 | pwr_step = pdadc_tmp[table_size - 1] - |
3149 | pdadc_tmp[table_size - 2]; |
3150 | else |
3151 | pwr_step = 1; |
3152 | |
3153 | /* Extrapolate above */ |
3154 | while ((pdadc_0 < (s16) pdadc_n) && |
3155 | (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2)) { |
3156 | s16 tmp = pdadc_tmp[table_size - 1] + |
3157 | (pdadc_0 - max_idx) * pwr_step; |
3158 | pdadc_out[pdadc_i++] = (tmp > 127) ? 127 : (u8) tmp; |
3159 | pdadc_0++; |
3160 | } |
3161 | } |
3162 | |
3163 | while (pdg < AR5K_EEPROM_N_PD_GAINS) { |
3164 | gain_boundaries[pdg] = gain_boundaries[pdg - 1]; |
3165 | pdg++; |
3166 | } |
3167 | |
3168 | while (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2) { |
3169 | pdadc_out[pdadc_i] = pdadc_out[pdadc_i - 1]; |
3170 | pdadc_i++; |
3171 | } |
3172 | |
3173 | /* Set gain boundaries */ |
3174 | ath5k_hw_reg_write(ah, |
3175 | AR5K_REG_SM(pd_gain_overlap, |
3176 | AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) | |
3177 | AR5K_REG_SM(gain_boundaries[0], |
3178 | AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) | |
3179 | AR5K_REG_SM(gain_boundaries[1], |
3180 | AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) | |
3181 | AR5K_REG_SM(gain_boundaries[2], |
3182 | AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) | |
3183 | AR5K_REG_SM(gain_boundaries[3], |
3184 | AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4), |
3185 | AR5K_PHY_TPC_RG5); |
3186 | |
3187 | /* Used for setting rate power table */ |
3188 | ah->ah_txpower.txp_min_idx = pwr_min[0]; |
3189 | |
3190 | } |
3191 | |
3192 | /** |
3193 | * ath5k_write_pwr_to_pdadc_table() - Write the PDADC values on hw |
3194 | * @ah: The &struct ath5k_hw |
3195 | * @ee_mode: One of enum ath5k_driver_mode |
3196 | */ |
3197 | static void |
3198 | ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode) |
3199 | { |
3200 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
3201 | u8 *pdadc_out = ah->ah_txpower.txp_pd_table; |
3202 | u8 *pdg_to_idx = ee->ee_pdc_to_idx[ee_mode]; |
3203 | u8 pdcurves = ee->ee_pd_gains[ee_mode]; |
3204 | u32 reg; |
3205 | u8 i; |
3206 | |
3207 | /* Select the right pdgain curves */ |
3208 | |
3209 | /* Clear current settings */ |
3210 | reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1); |
3211 | reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 | |
3212 | AR5K_PHY_TPC_RG1_PDGAIN_2 | |
3213 | AR5K_PHY_TPC_RG1_PDGAIN_3 | |
3214 | AR5K_PHY_TPC_RG1_NUM_PD_GAIN); |
3215 | |
3216 | /* |
3217 | * Use pd_gains curve from eeprom |
3218 | * |
3219 | * This overrides the default setting from initvals |
3220 | * in case some vendors (e.g. Zcomax) don't use the default |
3221 | * curves. If we don't honor their settings we 'll get a |
3222 | * 5dB (1 * gain overlap ?) drop. |
3223 | */ |
3224 | reg |= AR5K_REG_SM(pdcurves, AR5K_PHY_TPC_RG1_NUM_PD_GAIN); |
3225 | |
3226 | switch (pdcurves) { |
3227 | case 3: |
3228 | reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3); |
3229 | fallthrough; |
3230 | case 2: |
3231 | reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2); |
3232 | fallthrough; |
3233 | case 1: |
3234 | reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1); |
3235 | break; |
3236 | } |
3237 | ath5k_hw_reg_write(ah, val: reg, AR5K_PHY_TPC_RG1); |
3238 | |
3239 | /* |
3240 | * Write TX power values |
3241 | */ |
3242 | for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { |
3243 | u32 val = get_unaligned_le32(p: &pdadc_out[4 * i]); |
3244 | ath5k_hw_reg_write(ah, val, AR5K_PHY_PDADC_TXPOWER(i)); |
3245 | } |
3246 | } |
3247 | |
3248 | |
3249 | /* |
3250 | * Common code for PCDAC/PDADC tables |
3251 | */ |
3252 | |
3253 | /** |
3254 | * ath5k_setup_channel_powertable() - Set up power table for this channel |
3255 | * @ah: The &struct ath5k_hw |
3256 | * @channel: The &struct ieee80211_channel |
3257 | * @ee_mode: One of enum ath5k_driver_mode |
3258 | * @type: One of enum ath5k_powertable_type (eeprom.h) |
3259 | * |
3260 | * This is the main function that uses all of the above |
3261 | * to set PCDAC/PDADC table on hw for the current channel. |
3262 | * This table is used for tx power calibration on the baseband, |
3263 | * without it we get weird tx power levels and in some cases |
3264 | * distorted spectral mask |
3265 | */ |
3266 | static int |
3267 | ath5k_setup_channel_powertable(struct ath5k_hw *ah, |
3268 | struct ieee80211_channel *channel, |
3269 | u8 ee_mode, u8 type) |
3270 | { |
3271 | struct ath5k_pdgain_info *pdg_L, *pdg_R; |
3272 | struct ath5k_chan_pcal_info *pcinfo_L; |
3273 | struct ath5k_chan_pcal_info *pcinfo_R; |
3274 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
3275 | u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode]; |
3276 | s16 table_min[AR5K_EEPROM_N_PD_GAINS]; |
3277 | s16 table_max[AR5K_EEPROM_N_PD_GAINS]; |
3278 | u8 *tmpL; |
3279 | u8 *tmpR; |
3280 | u32 target = channel->center_freq; |
3281 | int pdg, i; |
3282 | |
3283 | /* Get surrounding freq piers for this channel */ |
3284 | ath5k_get_chan_pcal_surrounding_piers(ah, channel, |
3285 | pcinfo_l: &pcinfo_L, |
3286 | pcinfo_r: &pcinfo_R); |
3287 | |
3288 | /* Loop over pd gain curves on |
3289 | * surrounding freq piers by index */ |
3290 | for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) { |
3291 | |
3292 | /* Fill curves in reverse order |
3293 | * from lower power (max gain) |
3294 | * to higher power. Use curve -> idx |
3295 | * backmapping we did on eeprom init */ |
3296 | u8 idx = pdg_curve_to_idx[pdg]; |
3297 | |
3298 | /* Grab the needed curves by index */ |
3299 | pdg_L = &pcinfo_L->pd_curves[idx]; |
3300 | pdg_R = &pcinfo_R->pd_curves[idx]; |
3301 | |
3302 | /* Initialize the temp tables */ |
3303 | tmpL = ah->ah_txpower.tmpL[pdg]; |
3304 | tmpR = ah->ah_txpower.tmpR[pdg]; |
3305 | |
3306 | /* Set curve's x boundaries and create |
3307 | * curves so that they cover the same |
3308 | * range (if we don't do that one table |
3309 | * will have values on some range and the |
3310 | * other one won't have any so interpolation |
3311 | * will fail) */ |
3312 | table_min[pdg] = min(pdg_L->pd_pwr[0], |
3313 | pdg_R->pd_pwr[0]) / 2; |
3314 | |
3315 | table_max[pdg] = max(pdg_L->pd_pwr[pdg_L->pd_points - 1], |
3316 | pdg_R->pd_pwr[pdg_R->pd_points - 1]) / 2; |
3317 | |
3318 | /* Now create the curves on surrounding channels |
3319 | * and interpolate if needed to get the final |
3320 | * curve for this gain on this channel */ |
3321 | switch (type) { |
3322 | case AR5K_PWRTABLE_LINEAR_PCDAC: |
3323 | /* Override min/max so that we don't loose |
3324 | * accuracy (don't divide by 2) */ |
3325 | table_min[pdg] = min(pdg_L->pd_pwr[0], |
3326 | pdg_R->pd_pwr[0]); |
3327 | |
3328 | table_max[pdg] = |
3329 | max(pdg_L->pd_pwr[pdg_L->pd_points - 1], |
3330 | pdg_R->pd_pwr[pdg_R->pd_points - 1]); |
3331 | |
3332 | /* Override minimum so that we don't get |
3333 | * out of bounds while extrapolating |
3334 | * below. Don't do this when we have 2 |
3335 | * curves and we are on the high power curve |
3336 | * because table_min is ok in this case */ |
3337 | if (!(ee->ee_pd_gains[ee_mode] > 1 && pdg == 0)) { |
3338 | |
3339 | table_min[pdg] = |
3340 | ath5k_get_linear_pcdac_min(stepL: pdg_L->pd_step, |
3341 | stepR: pdg_R->pd_step, |
3342 | pwrL: pdg_L->pd_pwr, |
3343 | pwrR: pdg_R->pd_pwr); |
3344 | |
3345 | /* Don't go too low because we will |
3346 | * miss the upper part of the curve. |
3347 | * Note: 126 = 31.5dB (max power supported) |
3348 | * in 0.25dB units */ |
3349 | if (table_max[pdg] - table_min[pdg] > 126) |
3350 | table_min[pdg] = table_max[pdg] - 126; |
3351 | } |
3352 | |
3353 | fallthrough; |
3354 | case AR5K_PWRTABLE_PWR_TO_PCDAC: |
3355 | case AR5K_PWRTABLE_PWR_TO_PDADC: |
3356 | |
3357 | ath5k_create_power_curve(pmin: table_min[pdg], |
3358 | pmax: table_max[pdg], |
3359 | pwr: pdg_L->pd_pwr, |
3360 | vpd: pdg_L->pd_step, |
3361 | num_points: pdg_L->pd_points, vpd_table: tmpL, type); |
3362 | |
3363 | /* We are in a calibration |
3364 | * pier, no need to interpolate |
3365 | * between freq piers */ |
3366 | if (pcinfo_L == pcinfo_R) |
3367 | continue; |
3368 | |
3369 | ath5k_create_power_curve(pmin: table_min[pdg], |
3370 | pmax: table_max[pdg], |
3371 | pwr: pdg_R->pd_pwr, |
3372 | vpd: pdg_R->pd_step, |
3373 | num_points: pdg_R->pd_points, vpd_table: tmpR, type); |
3374 | break; |
3375 | default: |
3376 | return -EINVAL; |
3377 | } |
3378 | |
3379 | /* Interpolate between curves |
3380 | * of surrounding freq piers to |
3381 | * get the final curve for this |
3382 | * pd gain. Re-use tmpL for interpolation |
3383 | * output */ |
3384 | for (i = 0; (i < (u16) (table_max[pdg] - table_min[pdg])) && |
3385 | (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) { |
3386 | tmpL[i] = (u8) ath5k_get_interpolated_value(target, |
3387 | x_left: (s16) pcinfo_L->freq, |
3388 | x_right: (s16) pcinfo_R->freq, |
3389 | y_left: (s16) tmpL[i], |
3390 | y_right: (s16) tmpR[i]); |
3391 | } |
3392 | } |
3393 | |
3394 | /* Now we have a set of curves for this |
3395 | * channel on tmpL (x range is table_max - table_min |
3396 | * and y values are tmpL[pdg][]) sorted in the same |
3397 | * order as EEPROM (because we've used the backmapping). |
3398 | * So for RF5112 it's from higher power to lower power |
3399 | * and for RF2413 it's from lower power to higher power. |
3400 | * For RF5111 we only have one curve. */ |
3401 | |
3402 | /* Fill min and max power levels for this |
3403 | * channel by interpolating the values on |
3404 | * surrounding channels to complete the dataset */ |
3405 | ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target, |
3406 | x_left: (s16) pcinfo_L->freq, |
3407 | x_right: (s16) pcinfo_R->freq, |
3408 | y_left: pcinfo_L->min_pwr, y_right: pcinfo_R->min_pwr); |
3409 | |
3410 | ah->ah_txpower.txp_max_pwr = ath5k_get_interpolated_value(target, |
3411 | x_left: (s16) pcinfo_L->freq, |
3412 | x_right: (s16) pcinfo_R->freq, |
3413 | y_left: pcinfo_L->max_pwr, y_right: pcinfo_R->max_pwr); |
3414 | |
3415 | /* Fill PCDAC/PDADC table */ |
3416 | switch (type) { |
3417 | case AR5K_PWRTABLE_LINEAR_PCDAC: |
3418 | /* For RF5112 we can have one or two curves |
3419 | * and each curve covers a certain power lvl |
3420 | * range so we need to do some more processing */ |
3421 | ath5k_combine_linear_pcdac_curves(ah, table_min, table_max, |
3422 | pdcurves: ee->ee_pd_gains[ee_mode]); |
3423 | |
3424 | /* Set txp.offset so that we can |
3425 | * match max power value with max |
3426 | * table index */ |
3427 | ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2); |
3428 | break; |
3429 | case AR5K_PWRTABLE_PWR_TO_PCDAC: |
3430 | /* We are done for RF5111 since it has only |
3431 | * one curve, just fit the curve on the table */ |
3432 | ath5k_fill_pwr_to_pcdac_table(ah, table_min, table_max); |
3433 | |
3434 | /* No rate powertable adjustment for RF5111 */ |
3435 | ah->ah_txpower.txp_min_idx = 0; |
3436 | ah->ah_txpower.txp_offset = 0; |
3437 | break; |
3438 | case AR5K_PWRTABLE_PWR_TO_PDADC: |
3439 | /* Set PDADC boundaries and fill |
3440 | * final PDADC table */ |
3441 | ath5k_combine_pwr_to_pdadc_curves(ah, pwr_min: table_min, pwr_max: table_max, |
3442 | pdcurves: ee->ee_pd_gains[ee_mode]); |
3443 | |
3444 | /* Set txp.offset, note that table_min |
3445 | * can be negative */ |
3446 | ah->ah_txpower.txp_offset = table_min[0]; |
3447 | break; |
3448 | default: |
3449 | return -EINVAL; |
3450 | } |
3451 | |
3452 | ah->ah_txpower.txp_setup = true; |
3453 | |
3454 | return 0; |
3455 | } |
3456 | |
3457 | /** |
3458 | * ath5k_write_channel_powertable() - Set power table for current channel on hw |
3459 | * @ah: The &struct ath5k_hw |
3460 | * @ee_mode: One of enum ath5k_driver_mode |
3461 | * @type: One of enum ath5k_powertable_type (eeprom.h) |
3462 | */ |
3463 | static void |
3464 | ath5k_write_channel_powertable(struct ath5k_hw *ah, u8 ee_mode, u8 type) |
3465 | { |
3466 | if (type == AR5K_PWRTABLE_PWR_TO_PDADC) |
3467 | ath5k_write_pwr_to_pdadc_table(ah, ee_mode); |
3468 | else |
3469 | ath5k_write_pcdac_table(ah); |
3470 | } |
3471 | |
3472 | |
3473 | /** |
3474 | * DOC: Per-rate tx power setting |
3475 | * |
3476 | * This is the code that sets the desired tx power limit (below |
3477 | * maximum) on hw for each rate (we also have TPC that sets |
3478 | * power per packet type). We do that by providing an index on the |
3479 | * PCDAC/PDADC table we set up above, for each rate. |
3480 | * |
3481 | * For now we only limit txpower based on maximum tx power |
3482 | * supported by hw (what's inside rate_info) + conformance test |
3483 | * limits. We need to limit this even more, based on regulatory domain |
3484 | * etc to be safe. Normally this is done from above so we don't care |
3485 | * here, all we care is that the tx power we set will be O.K. |
3486 | * for the hw (e.g. won't create noise on PA etc). |
3487 | * |
3488 | * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps - |
3489 | * x values) and is indexed as follows: |
3490 | * rates[0] - rates[7] -> OFDM rates |
3491 | * rates[8] - rates[14] -> CCK rates |
3492 | * rates[15] -> XR rates (they all have the same power) |
3493 | */ |
3494 | |
3495 | /** |
3496 | * ath5k_setup_rate_powertable() - Set up rate power table for a given tx power |
3497 | * @ah: The &struct ath5k_hw |
3498 | * @max_pwr: The maximum tx power requested in 0.5dB steps |
3499 | * @rate_info: The &struct ath5k_rate_pcal_info to fill |
3500 | * @ee_mode: One of enum ath5k_driver_mode |
3501 | */ |
3502 | static void |
3503 | ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, |
3504 | struct ath5k_rate_pcal_info *rate_info, |
3505 | u8 ee_mode) |
3506 | { |
3507 | unsigned int i; |
3508 | u16 *rates; |
3509 | s16 rate_idx_scaled = 0; |
3510 | |
3511 | /* max_pwr is power level we got from driver/user in 0.5dB |
3512 | * units, switch to 0.25dB units so we can compare */ |
3513 | max_pwr *= 2; |
3514 | max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max_pwr) / 2; |
3515 | |
3516 | /* apply rate limits */ |
3517 | rates = ah->ah_txpower.txp_rates_power_table; |
3518 | |
3519 | /* OFDM rates 6 to 24Mb/s */ |
3520 | for (i = 0; i < 5; i++) |
3521 | rates[i] = min(max_pwr, rate_info->target_power_6to24); |
3522 | |
3523 | /* Rest OFDM rates */ |
3524 | rates[5] = min(rates[0], rate_info->target_power_36); |
3525 | rates[6] = min(rates[0], rate_info->target_power_48); |
3526 | rates[7] = min(rates[0], rate_info->target_power_54); |
3527 | |
3528 | /* CCK rates */ |
3529 | /* 1L */ |
3530 | rates[8] = min(rates[0], rate_info->target_power_6to24); |
3531 | /* 2L */ |
3532 | rates[9] = min(rates[0], rate_info->target_power_36); |
3533 | /* 2S */ |
3534 | rates[10] = min(rates[0], rate_info->target_power_36); |
3535 | /* 5L */ |
3536 | rates[11] = min(rates[0], rate_info->target_power_48); |
3537 | /* 5S */ |
3538 | rates[12] = min(rates[0], rate_info->target_power_48); |
3539 | /* 11L */ |
3540 | rates[13] = min(rates[0], rate_info->target_power_54); |
3541 | /* 11S */ |
3542 | rates[14] = min(rates[0], rate_info->target_power_54); |
3543 | |
3544 | /* XR rates */ |
3545 | rates[15] = min(rates[0], rate_info->target_power_6to24); |
3546 | |
3547 | /* CCK rates have different peak to average ratio |
3548 | * so we have to tweak their power so that gainf |
3549 | * correction works ok. For this we use OFDM to |
3550 | * CCK delta from eeprom */ |
3551 | if ((ee_mode == AR5K_EEPROM_MODE_11G) && |
3552 | (ah->ah_phy_revision < AR5K_SREV_PHY_5212A)) |
3553 | for (i = 8; i <= 15; i++) |
3554 | rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta; |
3555 | |
3556 | /* Save min/max and current tx power for this channel |
3557 | * in 0.25dB units. |
3558 | * |
3559 | * Note: We use rates[0] for current tx power because |
3560 | * it covers most of the rates, in most cases. It's our |
3561 | * tx power limit and what the user expects to see. */ |
3562 | ah->ah_txpower.txp_min_pwr = 2 * rates[7]; |
3563 | ah->ah_txpower.txp_cur_pwr = 2 * rates[0]; |
3564 | |
3565 | /* Set max txpower for correct OFDM operation on all rates |
3566 | * -that is the txpower for 54Mbit-, it's used for the PAPD |
3567 | * gain probe and it's in 0.5dB units */ |
3568 | ah->ah_txpower.txp_ofdm = rates[7]; |
3569 | |
3570 | /* Now that we have all rates setup use table offset to |
3571 | * match the power range set by user with the power indices |
3572 | * on PCDAC/PDADC table */ |
3573 | for (i = 0; i < 16; i++) { |
3574 | rate_idx_scaled = rates[i] + ah->ah_txpower.txp_offset; |
3575 | /* Don't get out of bounds */ |
3576 | if (rate_idx_scaled > 63) |
3577 | rate_idx_scaled = 63; |
3578 | if (rate_idx_scaled < 0) |
3579 | rate_idx_scaled = 0; |
3580 | rates[i] = rate_idx_scaled; |
3581 | } |
3582 | } |
3583 | |
3584 | |
3585 | /** |
3586 | * ath5k_hw_txpower() - Set transmission power limit for a given channel |
3587 | * @ah: The &struct ath5k_hw |
3588 | * @channel: The &struct ieee80211_channel |
3589 | * @txpower: Requested tx power in 0.5dB steps |
3590 | * |
3591 | * Combines all of the above to set the requested tx power limit |
3592 | * on hw. |
3593 | */ |
3594 | static int |
3595 | ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, |
3596 | u8 txpower) |
3597 | { |
3598 | struct ath5k_rate_pcal_info rate_info; |
3599 | struct ieee80211_channel *curr_channel = ah->ah_current_channel; |
3600 | int ee_mode; |
3601 | u8 type; |
3602 | int ret; |
3603 | |
3604 | if (txpower > AR5K_TUNE_MAX_TXPOWER) { |
3605 | ATH5K_ERR(ah, "invalid tx power: %u\n" , txpower); |
3606 | return -EINVAL; |
3607 | } |
3608 | |
3609 | ee_mode = ath5k_eeprom_mode_from_channel(ah, channel); |
3610 | |
3611 | /* Initialize TX power table */ |
3612 | switch (ah->ah_radio) { |
3613 | case AR5K_RF5110: |
3614 | /* TODO */ |
3615 | return 0; |
3616 | case AR5K_RF5111: |
3617 | type = AR5K_PWRTABLE_PWR_TO_PCDAC; |
3618 | break; |
3619 | case AR5K_RF5112: |
3620 | type = AR5K_PWRTABLE_LINEAR_PCDAC; |
3621 | break; |
3622 | case AR5K_RF2413: |
3623 | case AR5K_RF5413: |
3624 | case AR5K_RF2316: |
3625 | case AR5K_RF2317: |
3626 | case AR5K_RF2425: |
3627 | type = AR5K_PWRTABLE_PWR_TO_PDADC; |
3628 | break; |
3629 | default: |
3630 | return -EINVAL; |
3631 | } |
3632 | |
3633 | /* |
3634 | * If we don't change channel/mode skip tx powertable calculation |
3635 | * and use the cached one. |
3636 | */ |
3637 | if (!ah->ah_txpower.txp_setup || |
3638 | (channel->hw_value != curr_channel->hw_value) || |
3639 | (channel->center_freq != curr_channel->center_freq)) { |
3640 | /* Reset TX power values but preserve requested |
3641 | * tx power from above */ |
3642 | int requested_txpower = ah->ah_txpower.txp_requested; |
3643 | |
3644 | memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); |
3645 | |
3646 | /* Restore TPC setting and requested tx power */ |
3647 | ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; |
3648 | |
3649 | ah->ah_txpower.txp_requested = requested_txpower; |
3650 | |
3651 | /* Calculate the powertable */ |
3652 | ret = ath5k_setup_channel_powertable(ah, channel, |
3653 | ee_mode, type); |
3654 | if (ret) |
3655 | return ret; |
3656 | } |
3657 | |
3658 | /* Write table on hw */ |
3659 | ath5k_write_channel_powertable(ah, ee_mode, type); |
3660 | |
3661 | /* Limit max power if we have a CTL available */ |
3662 | ath5k_get_max_ctl_power(ah, channel); |
3663 | |
3664 | /* FIXME: Antenna reduction stuff */ |
3665 | |
3666 | /* FIXME: Limit power on turbo modes */ |
3667 | |
3668 | /* FIXME: TPC scale reduction */ |
3669 | |
3670 | /* Get surrounding channels for per-rate power table |
3671 | * calibration */ |
3672 | ath5k_get_rate_pcal_data(ah, channel, rates: &rate_info); |
3673 | |
3674 | /* Setup rate power table */ |
3675 | ath5k_setup_rate_powertable(ah, max_pwr: txpower, rate_info: &rate_info, ee_mode); |
3676 | |
3677 | /* Write rate power table on hw */ |
3678 | ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) | |
3679 | AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) | |
3680 | AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1); |
3681 | |
3682 | ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) | |
3683 | AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) | |
3684 | AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2); |
3685 | |
3686 | ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) | |
3687 | AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) | |
3688 | AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3); |
3689 | |
3690 | ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) | |
3691 | AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | |
3692 | AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); |
3693 | |
3694 | /* FIXME: TPC support */ |
3695 | if (ah->ah_txpower.txp_tpc) { |
3696 | ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | |
3697 | AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); |
3698 | |
3699 | ath5k_hw_reg_write(ah, |
3700 | AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) | |
3701 | AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) | |
3702 | AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP), |
3703 | AR5K_TPC); |
3704 | } else { |
3705 | ath5k_hw_reg_write(ah, AR5K_TUNE_MAX_TXPOWER, |
3706 | AR5K_PHY_TXPOWER_RATE_MAX); |
3707 | } |
3708 | |
3709 | return 0; |
3710 | } |
3711 | |
3712 | /** |
3713 | * ath5k_hw_set_txpower_limit() - Set txpower limit for the current channel |
3714 | * @ah: The &struct ath5k_hw |
3715 | * @txpower: The requested tx power limit in 0.5dB steps |
3716 | * |
3717 | * This function provides access to ath5k_hw_txpower to the driver in |
3718 | * case user or an application changes it while PHY is running. |
3719 | */ |
3720 | int |
3721 | ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) |
3722 | { |
3723 | ATH5K_DBG(ah, ATH5K_DEBUG_TXPOWER, |
3724 | "changing txpower to %d\n" , txpower); |
3725 | |
3726 | return ath5k_hw_txpower(ah, channel: ah->ah_current_channel, txpower); |
3727 | } |
3728 | |
3729 | |
3730 | /*************\ |
3731 | Init function |
3732 | \*************/ |
3733 | |
3734 | /** |
3735 | * ath5k_hw_phy_init() - Initialize PHY |
3736 | * @ah: The &struct ath5k_hw |
3737 | * @channel: The @struct ieee80211_channel |
3738 | * @mode: One of enum ath5k_driver_mode |
3739 | * @fast: Try a fast channel switch instead |
3740 | * |
3741 | * This is the main function used during reset to initialize PHY |
3742 | * or do a fast channel change if possible. |
3743 | * |
3744 | * NOTE: Do not call this one from the driver, it assumes PHY is in a |
3745 | * warm reset state ! |
3746 | */ |
3747 | int |
3748 | ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, |
3749 | u8 mode, bool fast) |
3750 | { |
3751 | struct ieee80211_channel *curr_channel; |
3752 | int ret, i; |
3753 | u32 phy_tst1; |
3754 | ret = 0; |
3755 | |
3756 | /* |
3757 | * Sanity check for fast flag |
3758 | * Don't try fast channel change when changing modulation |
3759 | * mode/band. We check for chip compatibility on |
3760 | * ath5k_hw_reset. |
3761 | */ |
3762 | curr_channel = ah->ah_current_channel; |
3763 | if (fast && (channel->hw_value != curr_channel->hw_value)) |
3764 | return -EINVAL; |
3765 | |
3766 | /* |
3767 | * On fast channel change we only set the synth parameters |
3768 | * while PHY is running, enable calibration and skip the rest. |
3769 | */ |
3770 | if (fast) { |
3771 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_RFBUS_REQ, |
3772 | AR5K_PHY_RFBUS_REQ_REQUEST); |
3773 | for (i = 0; i < 100; i++) { |
3774 | if (ath5k_hw_reg_read(ah, AR5K_PHY_RFBUS_GRANT)) |
3775 | break; |
3776 | udelay(5); |
3777 | } |
3778 | /* Failed */ |
3779 | if (i >= 100) |
3780 | return -EIO; |
3781 | |
3782 | /* Set channel and wait for synth */ |
3783 | ret = ath5k_hw_channel(ah, channel); |
3784 | if (ret) |
3785 | return ret; |
3786 | |
3787 | ath5k_hw_wait_for_synth(ah, channel); |
3788 | } |
3789 | |
3790 | /* |
3791 | * Set TX power |
3792 | * |
3793 | * Note: We need to do that before we set |
3794 | * RF buffer settings on 5211/5212+ so that we |
3795 | * properly set curve indices. |
3796 | */ |
3797 | ret = ath5k_hw_txpower(ah, channel, txpower: ah->ah_txpower.txp_requested ? |
3798 | ah->ah_txpower.txp_requested * 2 : |
3799 | AR5K_TUNE_MAX_TXPOWER); |
3800 | if (ret) |
3801 | return ret; |
3802 | |
3803 | /* Write OFDM timings on 5212*/ |
3804 | if (ah->ah_version == AR5K_AR5212 && |
3805 | channel->hw_value != AR5K_MODE_11B) { |
3806 | |
3807 | ret = ath5k_hw_write_ofdm_timings(ah, channel); |
3808 | if (ret) |
3809 | return ret; |
3810 | |
3811 | /* Spur info is available only from EEPROM versions |
3812 | * greater than 5.3, but the EEPROM routines will use |
3813 | * static values for older versions */ |
3814 | if (ah->ah_mac_srev >= AR5K_SREV_AR5424) |
3815 | ath5k_hw_set_spur_mitigation_filter(ah, |
3816 | channel); |
3817 | } |
3818 | |
3819 | /* If we used fast channel switching |
3820 | * we are done, release RF bus and |
3821 | * fire up NF calibration. |
3822 | * |
3823 | * Note: Only NF calibration due to |
3824 | * channel change, not AGC calibration |
3825 | * since AGC is still running ! |
3826 | */ |
3827 | if (fast) { |
3828 | /* |
3829 | * Release RF Bus grant |
3830 | */ |
3831 | AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ, |
3832 | AR5K_PHY_RFBUS_REQ_REQUEST); |
3833 | |
3834 | /* |
3835 | * Start NF calibration |
3836 | */ |
3837 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, |
3838 | AR5K_PHY_AGCCTL_NF); |
3839 | |
3840 | return ret; |
3841 | } |
3842 | |
3843 | /* |
3844 | * For 5210 we do all initialization using |
3845 | * initvals, so we don't have to modify |
3846 | * any settings (5210 also only supports |
3847 | * a/aturbo modes) |
3848 | */ |
3849 | if (ah->ah_version != AR5K_AR5210) { |
3850 | |
3851 | /* |
3852 | * Write initial RF gain settings |
3853 | * This should work for both 5111/5112 |
3854 | */ |
3855 | ret = ath5k_hw_rfgain_init(ah, band: channel->band); |
3856 | if (ret) |
3857 | return ret; |
3858 | |
3859 | usleep_range(min: 1000, max: 1500); |
3860 | |
3861 | /* |
3862 | * Write RF buffer |
3863 | */ |
3864 | ret = ath5k_hw_rfregs_init(ah, channel, mode); |
3865 | if (ret) |
3866 | return ret; |
3867 | |
3868 | /*Enable/disable 802.11b mode on 5111 |
3869 | (enable 2111 frequency converter + CCK)*/ |
3870 | if (ah->ah_radio == AR5K_RF5111) { |
3871 | if (mode == AR5K_MODE_11B) |
3872 | AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, |
3873 | AR5K_TXCFG_B_MODE); |
3874 | else |
3875 | AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG, |
3876 | AR5K_TXCFG_B_MODE); |
3877 | } |
3878 | |
3879 | } else if (ah->ah_version == AR5K_AR5210) { |
3880 | usleep_range(min: 1000, max: 1500); |
3881 | /* Disable phy and wait */ |
3882 | ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); |
3883 | usleep_range(min: 1000, max: 1500); |
3884 | } |
3885 | |
3886 | /* Set channel on PHY */ |
3887 | ret = ath5k_hw_channel(ah, channel); |
3888 | if (ret) |
3889 | return ret; |
3890 | |
3891 | /* |
3892 | * Enable the PHY and wait until completion |
3893 | * This includes BaseBand and Synthesizer |
3894 | * activation. |
3895 | */ |
3896 | ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); |
3897 | |
3898 | ath5k_hw_wait_for_synth(ah, channel); |
3899 | |
3900 | /* |
3901 | * Perform ADC test to see if baseband is ready |
3902 | * Set tx hold and check adc test register |
3903 | */ |
3904 | phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); |
3905 | ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); |
3906 | for (i = 0; i <= 20; i++) { |
3907 | if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) |
3908 | break; |
3909 | usleep_range(min: 200, max: 250); |
3910 | } |
3911 | ath5k_hw_reg_write(ah, val: phy_tst1, AR5K_PHY_TST1); |
3912 | |
3913 | /* |
3914 | * Start automatic gain control calibration |
3915 | * |
3916 | * During AGC calibration RX path is re-routed to |
3917 | * a power detector so we don't receive anything. |
3918 | * |
3919 | * This method is used to calibrate some static offsets |
3920 | * used together with on-the fly I/Q calibration (the |
3921 | * one performed via ath5k_hw_phy_calibrate), which doesn't |
3922 | * interrupt rx path. |
3923 | * |
3924 | * While rx path is re-routed to the power detector we also |
3925 | * start a noise floor calibration to measure the |
3926 | * card's noise floor (the noise we measure when we are not |
3927 | * transmitting or receiving anything). |
3928 | * |
3929 | * If we are in a noisy environment, AGC calibration may time |
3930 | * out and/or noise floor calibration might timeout. |
3931 | */ |
3932 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, |
3933 | AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF); |
3934 | |
3935 | /* At the same time start I/Q calibration for QAM constellation |
3936 | * -no need for CCK- */ |
3937 | ah->ah_iq_cal_needed = false; |
3938 | if (!(mode == AR5K_MODE_11B)) { |
3939 | ah->ah_iq_cal_needed = true; |
3940 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, |
3941 | AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); |
3942 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, |
3943 | AR5K_PHY_IQ_RUN); |
3944 | } |
3945 | |
3946 | /* Wait for gain calibration to finish (we check for I/Q calibration |
3947 | * during ath5k_phy_calibrate) */ |
3948 | if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, |
3949 | AR5K_PHY_AGCCTL_CAL, val: 0, is_set: false)) { |
3950 | ATH5K_ERR(ah, "gain calibration timeout (%uMHz)\n" , |
3951 | channel->center_freq); |
3952 | } |
3953 | |
3954 | /* Restore antenna mode */ |
3955 | ath5k_hw_set_antenna_mode(ah, ant_mode: ah->ah_ant_mode); |
3956 | |
3957 | return ret; |
3958 | } |
3959 | |