ath5k_phy.c

Go to the documentation of this file.
00001 /*
00002  * PHY functions
00003  *
00004  * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
00005  * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
00006  * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
00007  * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org>
00008  *
00009  * Lightly modified for gPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
00010  *
00011  * Permission to use, copy, modify, and distribute this software for any
00012  * purpose with or without fee is hereby granted, provided that the above
00013  * copyright notice and this permission notice appear in all copies.
00014  *
00015  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00016  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00017  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00018  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00019  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00020  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00021  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00022  *
00023  */
00024 
00025 FILE_LICENCE ( MIT );
00026 
00027 #define _ATH5K_PHY
00028 
00029 #include <unistd.h>
00030 #include <stdlib.h>
00031 
00032 #include "ath5k.h"
00033 #include "reg.h"
00034 #include "base.h"
00035 #include "rfbuffer.h"
00036 #include "rfgain.h"
00037 
00038 static inline int min(int x, int y)
00039 {
00040         return (x < y) ? x : y;
00041 }
00042 
00043 static inline int max(int x, int y)
00044 {
00045         return (x > y) ? x : y;
00046 }
00047 
00048 /*
00049  * Used to modify RF Banks before writing them to AR5K_RF_BUFFER
00050  */
00051 static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
00052                                         const struct ath5k_rf_reg *rf_regs,
00053                                         u32 val, u8 reg_id, int set)
00054 {
00055         const struct ath5k_rf_reg *rfreg = NULL;
00056         u8 offset, bank, num_bits, col, position;
00057         u16 entry;
00058         u32 mask, data, last_bit, bits_shifted, first_bit;
00059         u32 *rfb;
00060         s32 bits_left;
00061         unsigned i;
00062 
00063         data = 0;
00064         rfb = ah->ah_rf_banks;
00065 
00066         for (i = 0; i < ah->ah_rf_regs_count; i++) {
00067                 if (rf_regs[i].index == reg_id) {
00068                         rfreg = &rf_regs[i];
00069                         break;
00070                 }
00071         }
00072 
00073         if (rfb == NULL || rfreg == NULL) {
00074                 DBG("ath5k: RF register not found!\n");
00075                 /* should not happen */
00076                 return 0;
00077         }
00078 
00079         bank = rfreg->bank;
00080         num_bits = rfreg->field.len;
00081         first_bit = rfreg->field.pos;
00082         col = rfreg->field.col;
00083 
00084         /* first_bit is an offset from bank's
00085          * start. Since we have all banks on
00086          * the same array, we use this offset
00087          * to mark each bank's start */
00088         offset = ah->ah_offset[bank];
00089 
00090         /* Boundary check */
00091         if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) {
00092                 DBG("ath5k: RF invalid values at offset %d\n", offset);
00093                 return 0;
00094         }
00095 
00096         entry = ((first_bit - 1) / 8) + offset;
00097         position = (first_bit - 1) % 8;
00098 
00099         if (set)
00100                 data = ath5k_hw_bitswap(val, num_bits);
00101 
00102         for (bits_shifted = 0, bits_left = num_bits; bits_left > 0;
00103         position = 0, entry++) {
00104 
00105                 last_bit = (position + bits_left > 8) ? 8 :
00106                                         position + bits_left;
00107 
00108                 mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) <<
00109                                                                 (col * 8);
00110 
00111                 if (set) {
00112                         rfb[entry] &= ~mask;
00113                         rfb[entry] |= ((data << position) << (col * 8)) & mask;
00114                         data >>= (8 - position);
00115                 } else {
00116                         data |= (((rfb[entry] & mask) >> (col * 8)) >> position)
00117                                 << bits_shifted;
00118                         bits_shifted += last_bit - position;
00119                 }
00120 
00121                 bits_left -= 8 - position;
00122         }
00123 
00124         data = set ? 1 : ath5k_hw_bitswap(data, num_bits);
00125 
00126         return data;
00127 }
00128 
00129 /**********************\
00130 * RF Gain optimization *
00131 \**********************/
00132 
00133 /*
00134  * This code is used to optimize rf gain on different environments
00135  * (temprature mostly) based on feedback from a power detector.
00136  *
00137  * It's only used on RF5111 and RF5112, later RF chips seem to have
00138  * auto adjustment on hw -notice they have a much smaller BANK 7 and
00139  * no gain optimization ladder-.
00140  *
00141  * For more infos check out this patent doc
00142  * http://www.freepatentsonline.com/7400691.html
00143  *
00144  * This paper describes power drops as seen on the receiver due to
00145  * probe packets
00146  * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues
00147  * %20of%20Power%20Control.pdf
00148  *
00149  * And this is the MadWiFi bug entry related to the above
00150  * http://madwifi-project.org/ticket/1659
00151  * with various measurements and diagrams
00152  *
00153  * TODO: Deal with power drops due to probes by setting an apropriate
00154  * tx power on the probe packets ! Make this part of the calibration process.
00155  */
00156 
00157 /* Initialize ah_gain durring attach */
00158 int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
00159 {
00160         /* Initialize the gain optimization values */
00161         switch (ah->ah_radio) {
00162         case AR5K_RF5111:
00163                 ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
00164                 ah->ah_gain.g_low = 20;
00165                 ah->ah_gain.g_high = 35;
00166                 ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
00167                 break;
00168         case AR5K_RF5112:
00169                 ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
00170                 ah->ah_gain.g_low = 20;
00171                 ah->ah_gain.g_high = 85;
00172                 ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
00173                 break;
00174         default:
00175                 return -EINVAL;
00176         }
00177 
00178         return 0;
00179 }
00180 
00181 /* Schedule a gain probe check on the next transmited packet.
00182  * That means our next packet is going to be sent with lower
00183  * tx power and a Peak to Average Power Detector (PAPD) will try
00184  * to measure the gain.
00185  *
00186  * TODO: Use propper tx power setting for the probe packet so
00187  * that we don't observe a serious power drop on the receiver
00188  *
00189  * XXX:  How about forcing a tx packet (bypassing PCU arbitrator etc)
00190  * just after we enable the probe so that we don't mess with
00191  * standard traffic ? Maybe it's time to use sw interrupts and
00192  * a probe tasklet !!!
00193  */
00194 static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
00195 {
00196 
00197         /* Skip if gain calibration is inactive or
00198          * we already handle a probe request */
00199         if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE)
00200                 return;
00201 
00202         /* Send the packet with 2dB below max power as
00203          * patent doc suggest */
00204         ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4,
00205                         AR5K_PHY_PAPD_PROBE_TXPOWER) |
00206                         AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
00207 
00208         ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED;
00209 
00210 }
00211 
00212 /* Calculate gain_F measurement correction
00213  * based on the current step for RF5112 rev. 2 */
00214 static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
00215 {
00216         u32 mix, step;
00217         u32 *rf;
00218         const struct ath5k_gain_opt *go;
00219         const struct ath5k_gain_opt_step *g_step;
00220         const struct ath5k_rf_reg *rf_regs;
00221 
00222         /* Only RF5112 Rev. 2 supports it */
00223         if ((ah->ah_radio != AR5K_RF5112) ||
00224         (ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A))
00225                 return 0;
00226 
00227         go = &rfgain_opt_5112;
00228         rf_regs = rf_regs_5112a;
00229         ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
00230 
00231         g_step = &go->go_step[ah->ah_gain.g_step_idx];
00232 
00233         if (ah->ah_rf_banks == NULL)
00234                 return 0;
00235 
00236         rf = ah->ah_rf_banks;
00237         ah->ah_gain.g_f_corr = 0;
00238 
00239         /* No VGA (Variable Gain Amplifier) override, skip */
00240         if (ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, 0) != 1)
00241                 return 0;
00242 
00243         /* Mix gain stepping */
00244         step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXGAIN_STEP, 0);
00245 
00246         /* Mix gain override */
00247         mix = g_step->gos_param[0];
00248 
00249         switch (mix) {
00250         case 3:
00251                 ah->ah_gain.g_f_corr = step * 2;
00252                 break;
00253         case 2:
00254                 ah->ah_gain.g_f_corr = (step - 5) * 2;
00255                 break;
00256         case 1:
00257                 ah->ah_gain.g_f_corr = step;
00258                 break;
00259         default:
00260                 ah->ah_gain.g_f_corr = 0;
00261                 break;
00262         }
00263 
00264         return ah->ah_gain.g_f_corr;
00265 }
00266 
00267 /* Check if current gain_F measurement is in the range of our
00268  * power detector windows. If we get a measurement outside range
00269  * we know it's not accurate (detectors can't measure anything outside
00270  * their detection window) so we must ignore it */
00271 static int ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
00272 {
00273         const struct ath5k_rf_reg *rf_regs;
00274         u32 step, mix_ovr, level[4];
00275         u32 *rf;
00276 
00277         if (ah->ah_rf_banks == NULL)
00278                 return 0;
00279 
00280         rf = ah->ah_rf_banks;
00281 
00282         if (ah->ah_radio == AR5K_RF5111) {
00283 
00284                 rf_regs = rf_regs_5111;
00285                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
00286 
00287                 step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_RFGAIN_STEP,
00288                         0);
00289 
00290                 level[0] = 0;
00291                 level[1] = (step == 63) ? 50 : step + 4;
00292                 level[2] = (step != 63) ? 64 : level[0];
00293                 level[3] = level[2] + 50 ;
00294 
00295                 ah->ah_gain.g_high = level[3] -
00296                         (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
00297                 ah->ah_gain.g_low = level[0] +
00298                         (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
00299         } else {
00300 
00301                 rf_regs = rf_regs_5112;
00302                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
00303 
00304                 mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR,
00305                         0);
00306 
00307                 level[0] = level[2] = 0;
00308 
00309                 if (mix_ovr == 1) {
00310                         level[1] = level[3] = 83;
00311                 } else {
00312                         level[1] = level[3] = 107;
00313                         ah->ah_gain.g_high = 55;
00314                 }
00315         }
00316 
00317         return (ah->ah_gain.g_current >= level[0] &&
00318                         ah->ah_gain.g_current <= level[1]) ||
00319                 (ah->ah_gain.g_current >= level[2] &&
00320                         ah->ah_gain.g_current <= level[3]);
00321 }
00322 
00323 /* Perform gain_F adjustment by choosing the right set
00324  * of parameters from rf gain optimization ladder */
00325 static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
00326 {
00327         const struct ath5k_gain_opt *go;
00328         const struct ath5k_gain_opt_step *g_step;
00329         int ret = 0;
00330 
00331         switch (ah->ah_radio) {
00332         case AR5K_RF5111:
00333                 go = &rfgain_opt_5111;
00334                 break;
00335         case AR5K_RF5112:
00336                 go = &rfgain_opt_5112;
00337                 break;
00338         default:
00339                 return 0;
00340         }
00341 
00342         g_step = &go->go_step[ah->ah_gain.g_step_idx];
00343 
00344         if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
00345 
00346                 /* Reached maximum */
00347                 if (ah->ah_gain.g_step_idx == 0)
00348                         return -1;
00349 
00350                 for (ah->ah_gain.g_target = ah->ah_gain.g_current;
00351                                 ah->ah_gain.g_target >=  ah->ah_gain.g_high &&
00352                                 ah->ah_gain.g_step_idx > 0;
00353                                 g_step = &go->go_step[ah->ah_gain.g_step_idx])
00354                         ah->ah_gain.g_target -= 2 *
00355                             (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
00356                             g_step->gos_gain);
00357 
00358                 ret = 1;
00359                 goto done;
00360         }
00361 
00362         if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
00363 
00364                 /* Reached minimum */
00365                 if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
00366                         return -2;
00367 
00368                 for (ah->ah_gain.g_target = ah->ah_gain.g_current;
00369                                 ah->ah_gain.g_target <= ah->ah_gain.g_low &&
00370                                 ah->ah_gain.g_step_idx < go->go_steps_count-1;
00371                                 g_step = &go->go_step[ah->ah_gain.g_step_idx])
00372                         ah->ah_gain.g_target -= 2 *
00373                             (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
00374                             g_step->gos_gain);
00375 
00376                 ret = 2;
00377                 goto done;
00378         }
00379 
00380 done:
00381         DBG2("ath5k RF adjust: ret %d, gain step %d, current gain %d, "
00382              "target gain %d\n", ret, ah->ah_gain.g_step_idx,
00383              ah->ah_gain.g_current, ah->ah_gain.g_target);
00384 
00385         return ret;
00386 }
00387 
00388 /* Main callback for thermal rf gain calibration engine
00389  * Check for a new gain reading and schedule an adjustment
00390  * if needed.
00391  *
00392  * TODO: Use sw interrupt to schedule reset if gain_F needs
00393  * adjustment */
00394 enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
00395 {
00396         u32 data, type;
00397         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00398 
00399         if (ah->ah_rf_banks == NULL ||
00400         ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
00401                 return AR5K_RFGAIN_INACTIVE;
00402 
00403         /* No check requested, either engine is inactive
00404          * or an adjustment is already requested */
00405         if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED)
00406                 goto done;
00407 
00408         /* Read the PAPD (Peak to Average Power Detector)
00409          * register */
00410         data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
00411 
00412         /* No probe is scheduled, read gain_F measurement */
00413         if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
00414                 ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
00415                 type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
00416 
00417                 /* If tx packet is CCK correct the gain_F measurement
00418                  * by cck ofdm gain delta */
00419                 if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) {
00420                         if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
00421                                 ah->ah_gain.g_current +=
00422                                         ee->ee_cck_ofdm_gain_delta;
00423                         else
00424                                 ah->ah_gain.g_current +=
00425                                         AR5K_GAIN_CCK_PROBE_CORR;
00426                 }
00427 
00428                 /* Further correct gain_F measurement for
00429                  * RF5112A radios */
00430                 if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
00431                         ath5k_hw_rf_gainf_corr(ah);
00432                         ah->ah_gain.g_current =
00433                                 ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
00434                                 (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
00435                                 0;
00436                 }
00437 
00438                 /* Check if measurement is ok and if we need
00439                  * to adjust gain, schedule a gain adjustment,
00440                  * else switch back to the acive state */
00441                 if (ath5k_hw_rf_check_gainf_readback(ah) &&
00442                 AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
00443                 ath5k_hw_rf_gainf_adjust(ah)) {
00444                         ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE;
00445                 } else {
00446                         ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
00447                 }
00448         }
00449 
00450 done:
00451         return ah->ah_gain.g_state;
00452 }
00453 
00454 /* Write initial rf gain table to set the RF sensitivity
00455  * this one works on all RF chips and has nothing to do
00456  * with gain_F calibration */
00457 int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
00458 {
00459         const struct ath5k_ini_rfgain *ath5k_rfg;
00460         unsigned int i, size;
00461 
00462         switch (ah->ah_radio) {
00463         case AR5K_RF5111:
00464                 ath5k_rfg = rfgain_5111;
00465                 size = ARRAY_SIZE(rfgain_5111);
00466                 break;
00467         case AR5K_RF5112:
00468                 ath5k_rfg = rfgain_5112;
00469                 size = ARRAY_SIZE(rfgain_5112);
00470                 break;
00471         case AR5K_RF2413:
00472                 ath5k_rfg = rfgain_2413;
00473                 size = ARRAY_SIZE(rfgain_2413);
00474                 break;
00475         case AR5K_RF2316:
00476                 ath5k_rfg = rfgain_2316;
00477                 size = ARRAY_SIZE(rfgain_2316);
00478                 break;
00479         case AR5K_RF5413:
00480                 ath5k_rfg = rfgain_5413;
00481                 size = ARRAY_SIZE(rfgain_5413);
00482                 break;
00483         case AR5K_RF2317:
00484         case AR5K_RF2425:
00485                 ath5k_rfg = rfgain_2425;
00486                 size = ARRAY_SIZE(rfgain_2425);
00487                 break;
00488         default:
00489                 return -EINVAL;
00490         }
00491 
00492         switch (freq) {
00493         case AR5K_INI_RFGAIN_2GHZ:
00494         case AR5K_INI_RFGAIN_5GHZ:
00495                 break;
00496         default:
00497                 return -EINVAL;
00498         }
00499 
00500         for (i = 0; i < size; i++) {
00501                 AR5K_REG_WAIT(i);
00502                 ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
00503                         (u32)ath5k_rfg[i].rfg_register);
00504         }
00505 
00506         return 0;
00507 }
00508 
00509 
00510 
00511 /********************\
00512 * RF Registers setup *
00513 \********************/
00514 
00515 
00516 /*
00517  * Setup RF registers by writing rf buffer on hw
00518  */
00519 int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct net80211_channel *channel,
00520                 unsigned int mode)
00521 {
00522         const struct ath5k_rf_reg *rf_regs;
00523         const struct ath5k_ini_rfbuffer *ini_rfb;
00524         const struct ath5k_gain_opt *go = NULL;
00525         const struct ath5k_gain_opt_step *g_step;
00526         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00527         u8 ee_mode = 0;
00528         u32 *rfb;
00529         int obdb = -1, bank = -1;
00530         unsigned i;
00531 
00532         switch (ah->ah_radio) {
00533         case AR5K_RF5111:
00534                 rf_regs = rf_regs_5111;
00535                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
00536                 ini_rfb = rfb_5111;
00537                 ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111);
00538                 go = &rfgain_opt_5111;
00539                 break;
00540         case AR5K_RF5112:
00541                 if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
00542                         rf_regs = rf_regs_5112a;
00543                         ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
00544                         ini_rfb = rfb_5112a;
00545                         ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a);
00546                 } else {
00547                         rf_regs = rf_regs_5112;
00548                         ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
00549                         ini_rfb = rfb_5112;
00550                         ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112);
00551                 }
00552                 go = &rfgain_opt_5112;
00553                 break;
00554         case AR5K_RF2413:
00555                 rf_regs = rf_regs_2413;
00556                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413);
00557                 ini_rfb = rfb_2413;
00558                 ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413);
00559                 break;
00560         case AR5K_RF2316:
00561                 rf_regs = rf_regs_2316;
00562                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316);
00563                 ini_rfb = rfb_2316;
00564                 ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316);
00565                 break;
00566         case AR5K_RF5413:
00567                 rf_regs = rf_regs_5413;
00568                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413);
00569                 ini_rfb = rfb_5413;
00570                 ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413);
00571                 break;
00572         case AR5K_RF2317:
00573                 rf_regs = rf_regs_2425;
00574                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
00575                 ini_rfb = rfb_2317;
00576                 ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317);
00577                 break;
00578         case AR5K_RF2425:
00579                 rf_regs = rf_regs_2425;
00580                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
00581                 if (ah->ah_mac_srev < AR5K_SREV_AR2417) {
00582                         ini_rfb = rfb_2425;
00583                         ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425);
00584                 } else {
00585                         ini_rfb = rfb_2417;
00586                         ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417);
00587                 }
00588                 break;
00589         default:
00590                 return -EINVAL;
00591         }
00592 
00593         /* If it's the first time we set rf buffer, allocate
00594          * ah->ah_rf_banks based on ah->ah_rf_banks_size
00595          * we set above */
00596         if (ah->ah_rf_banks == NULL) {
00597                 ah->ah_rf_banks = malloc(sizeof(u32) * ah->ah_rf_banks_size);
00598                 if (ah->ah_rf_banks == NULL) {
00599                         return -ENOMEM;
00600                 }
00601         }
00602 
00603         /* Copy values to modify them */
00604         rfb = ah->ah_rf_banks;
00605 
00606         for (i = 0; i < ah->ah_rf_banks_size; i++) {
00607                 if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) {
00608                         DBG("ath5k: invalid RF register bank\n");
00609                         return -EINVAL;
00610                 }
00611 
00612                 /* Bank changed, write down the offset */
00613                 if (bank != ini_rfb[i].rfb_bank) {
00614                         bank = ini_rfb[i].rfb_bank;
00615                         ah->ah_offset[bank] = i;
00616                 }
00617 
00618                 rfb[i] = ini_rfb[i].rfb_mode_data[mode];
00619         }
00620 
00621         /* Set Output and Driver bias current (OB/DB) */
00622         if (channel->hw_value & CHANNEL_2GHZ) {
00623 
00624                 if (channel->hw_value & CHANNEL_CCK)
00625                         ee_mode = AR5K_EEPROM_MODE_11B;
00626                 else
00627                         ee_mode = AR5K_EEPROM_MODE_11G;
00628 
00629                 /* For RF511X/RF211X combination we
00630                  * use b_OB and b_DB parameters stored
00631                  * in eeprom on ee->ee_ob[ee_mode][0]
00632                  *
00633                  * For all other chips we use OB/DB for 2Ghz
00634                  * stored in the b/g modal section just like
00635                  * 802.11a on ee->ee_ob[ee_mode][1] */
00636                 if ((ah->ah_radio == AR5K_RF5111) ||
00637                 (ah->ah_radio == AR5K_RF5112))
00638                         obdb = 0;
00639                 else
00640                         obdb = 1;
00641 
00642                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
00643                                                 AR5K_RF_OB_2GHZ, 1);
00644 
00645                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
00646                                                 AR5K_RF_DB_2GHZ, 1);
00647 
00648         /* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */
00649         } else if ((channel->hw_value & CHANNEL_5GHZ) ||
00650                         (ah->ah_radio == AR5K_RF5111)) {
00651 
00652                 /* For 11a, Turbo and XR we need to choose
00653                  * OB/DB based on frequency range */
00654                 ee_mode = AR5K_EEPROM_MODE_11A;
00655                 obdb =   channel->center_freq >= 5725 ? 3 :
00656                         (channel->center_freq >= 5500 ? 2 :
00657                         (channel->center_freq >= 5260 ? 1 :
00658                          (channel->center_freq > 4000 ? 0 : -1)));
00659 
00660                 if (obdb < 0)
00661                         return -EINVAL;
00662 
00663                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
00664                                                 AR5K_RF_OB_5GHZ, 1);
00665 
00666                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
00667                                                 AR5K_RF_DB_5GHZ, 1);
00668         }
00669 
00670         g_step = &go->go_step[ah->ah_gain.g_step_idx];
00671 
00672         /* Bank Modifications (chip-specific) */
00673         if (ah->ah_radio == AR5K_RF5111) {
00674 
00675                 /* Set gain_F settings according to current step */
00676                 if (channel->hw_value & CHANNEL_OFDM) {
00677 
00678                         AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
00679                                         AR5K_PHY_FRAME_CTL_TX_CLIP,
00680                                         g_step->gos_param[0]);
00681 
00682                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
00683                                                         AR5K_RF_PWD_90, 1);
00684 
00685                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
00686                                                         AR5K_RF_PWD_84, 1);
00687 
00688                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
00689                                                 AR5K_RF_RFGAIN_SEL, 1);
00690 
00691                         /* We programmed gain_F parameters, switch back
00692                          * to active state */
00693                         ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
00694 
00695                 }
00696 
00697                 /* Bank 6/7 setup */
00698 
00699                 ath5k_hw_rfb_op(ah, rf_regs, !ee->ee_xpd[ee_mode],
00700                                                 AR5K_RF_PWD_XPD, 1);
00701 
00702                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_x_gain[ee_mode],
00703                                                 AR5K_RF_XPD_GAIN, 1);
00704 
00705                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
00706                                                 AR5K_RF_GAIN_I, 1);
00707 
00708                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
00709                                                 AR5K_RF_PLO_SEL, 1);
00710 
00711                 /* TODO: Half/quarter channel support */
00712         }
00713 
00714         if (ah->ah_radio == AR5K_RF5112) {
00715 
00716                 /* Set gain_F settings according to current step */
00717                 if (channel->hw_value & CHANNEL_OFDM) {
00718 
00719                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0],
00720                                                 AR5K_RF_MIXGAIN_OVR, 1);
00721 
00722                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
00723                                                 AR5K_RF_PWD_138, 1);
00724 
00725                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
00726                                                 AR5K_RF_PWD_137, 1);
00727 
00728                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
00729                                                 AR5K_RF_PWD_136, 1);
00730 
00731                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[4],
00732                                                 AR5K_RF_PWD_132, 1);
00733 
00734                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[5],
00735                                                 AR5K_RF_PWD_131, 1);
00736 
00737                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[6],
00738                                                 AR5K_RF_PWD_130, 1);
00739 
00740                         /* We programmed gain_F parameters, switch back
00741                          * to active state */
00742                         ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
00743                 }
00744 
00745                 /* Bank 6/7 setup */
00746 
00747                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
00748                                                 AR5K_RF_XPD_SEL, 1);
00749 
00750                 if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
00751                         /* Rev. 1 supports only one xpd */
00752                         ath5k_hw_rfb_op(ah, rf_regs,
00753                                                 ee->ee_x_gain[ee_mode],
00754                                                 AR5K_RF_XPD_GAIN, 1);
00755 
00756                 } else {
00757                         /* TODO: Set high and low gain bits */
00758                         ath5k_hw_rfb_op(ah, rf_regs,
00759                                                 ee->ee_x_gain[ee_mode],
00760                                                 AR5K_RF_PD_GAIN_LO, 1);
00761                         ath5k_hw_rfb_op(ah, rf_regs,
00762                                                 ee->ee_x_gain[ee_mode],
00763                                                 AR5K_RF_PD_GAIN_HI, 1);
00764 
00765                         /* Lower synth voltage on Rev 2 */
00766                         ath5k_hw_rfb_op(ah, rf_regs, 2,
00767                                         AR5K_RF_HIGH_VC_CP, 1);
00768 
00769                         ath5k_hw_rfb_op(ah, rf_regs, 2,
00770                                         AR5K_RF_MID_VC_CP, 1);
00771 
00772                         ath5k_hw_rfb_op(ah, rf_regs, 2,
00773                                         AR5K_RF_LOW_VC_CP, 1);
00774 
00775                         ath5k_hw_rfb_op(ah, rf_regs, 2,
00776                                         AR5K_RF_PUSH_UP, 1);
00777 
00778                         /* Decrease power consumption on 5213+ BaseBand */
00779                         if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
00780                                 ath5k_hw_rfb_op(ah, rf_regs, 1,
00781                                                 AR5K_RF_PAD2GND, 1);
00782 
00783                                 ath5k_hw_rfb_op(ah, rf_regs, 1,
00784                                                 AR5K_RF_XB2_LVL, 1);
00785 
00786                                 ath5k_hw_rfb_op(ah, rf_regs, 1,
00787                                                 AR5K_RF_XB5_LVL, 1);
00788 
00789                                 ath5k_hw_rfb_op(ah, rf_regs, 1,
00790                                                 AR5K_RF_PWD_167, 1);
00791 
00792                                 ath5k_hw_rfb_op(ah, rf_regs, 1,
00793                                                 AR5K_RF_PWD_166, 1);
00794                         }
00795                 }
00796 
00797                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
00798                                                 AR5K_RF_GAIN_I, 1);
00799 
00800                 /* TODO: Half/quarter channel support */
00801 
00802         }
00803 
00804         if (ah->ah_radio == AR5K_RF5413 &&
00805         channel->hw_value & CHANNEL_2GHZ) {
00806 
00807                 ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE,
00808                                                                         1);
00809 
00810                 /* Set optimum value for early revisions (on pci-e chips) */
00811                 if (ah->ah_mac_srev >= AR5K_SREV_AR5424 &&
00812                 ah->ah_mac_srev < AR5K_SREV_AR5413)
00813                         ath5k_hw_rfb_op(ah, rf_regs, ath5k_hw_bitswap(6, 3),
00814                                                 AR5K_RF_PWD_ICLOBUF_2G, 1);
00815 
00816         }
00817 
00818         /* Write RF banks on hw */
00819         for (i = 0; i < ah->ah_rf_banks_size; i++) {
00820                 AR5K_REG_WAIT(i);
00821                 ath5k_hw_reg_write(ah, rfb[i], ini_rfb[i].rfb_ctrl_register);
00822         }
00823 
00824         return 0;
00825 }
00826 
00827 
00828 /**************************\
00829   PHY/RF channel functions
00830 \**************************/
00831 
00832 /*
00833  * Check if a channel is supported
00834  */
00835 int ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
00836 {
00837         /* Check if the channel is in our supported range */
00838         if (flags & CHANNEL_2GHZ) {
00839                 if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
00840                     (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
00841                         return 1;
00842         } else if (flags & CHANNEL_5GHZ)
00843                 if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
00844                     (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
00845                         return 1;
00846 
00847         return 0;
00848 }
00849 
00850 /*
00851  * Convertion needed for RF5110
00852  */
00853 static u32 ath5k_hw_rf5110_chan2athchan(struct net80211_channel *channel)
00854 {
00855         u32 athchan;
00856 
00857         /*
00858          * Convert IEEE channel/MHz to an internal channel value used
00859          * by the AR5210 chipset. This has not been verified with
00860          * newer chipsets like the AR5212A who have a completely
00861          * different RF/PHY part.
00862          */
00863         athchan = (ath5k_hw_bitswap((ath5k_freq_to_channel(channel->center_freq)
00864                                      - 24) / 2, 5) << 1)
00865                 | (1 << 6) | 0x1;
00866         return athchan;
00867 }
00868 
00869 /*
00870  * Set channel on RF5110
00871  */
00872 static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah,
00873                 struct net80211_channel *channel)
00874 {
00875         u32 data;
00876 
00877         /*
00878          * Set the channel and wait
00879          */
00880         data = ath5k_hw_rf5110_chan2athchan(channel);
00881         ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER);
00882         ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0);
00883         mdelay(1);
00884 
00885         return 0;
00886 }
00887 
00888 /*
00889  * Convertion needed for 5111
00890  */
00891 static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee,
00892                 struct ath5k_athchan_2ghz *athchan)
00893 {
00894         int channel;
00895 
00896         /* Cast this value to catch negative channel numbers (>= -19) */
00897         channel = (int)ieee;
00898 
00899         /*
00900          * Map 2GHz IEEE channel to 5GHz Atheros channel
00901          */
00902         if (channel <= 13) {
00903                 athchan->a2_athchan = 115 + channel;
00904                 athchan->a2_flags = 0x46;
00905         } else if (channel == 14) {
00906                 athchan->a2_athchan = 124;
00907                 athchan->a2_flags = 0x44;
00908         } else if (channel >= 15 && channel <= 26) {
00909                 athchan->a2_athchan = ((channel - 14) * 4) + 132;
00910                 athchan->a2_flags = 0x46;
00911         } else
00912                 return -EINVAL;
00913 
00914         return 0;
00915 }
00916 
00917 /*
00918  * Set channel on 5111
00919  */
00920 static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
00921                 struct net80211_channel *channel)
00922 {
00923         struct ath5k_athchan_2ghz ath5k_channel_2ghz;
00924         unsigned int ath5k_channel = ath5k_freq_to_channel(channel->center_freq);
00925         u32 data0, data1, clock;
00926         int ret;
00927 
00928         /*
00929          * Set the channel on the RF5111 radio
00930          */
00931         data0 = data1 = 0;
00932 
00933         if (channel->hw_value & CHANNEL_2GHZ) {
00934                 /* Map 2GHz channel to 5GHz Atheros channel ID */
00935                 ret = ath5k_hw_rf5111_chan2athchan(ath5k_channel,
00936                                                    &ath5k_channel_2ghz);
00937                 if (ret)
00938                         return ret;
00939 
00940                 ath5k_channel = ath5k_channel_2ghz.a2_athchan;
00941                 data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff)
00942                     << 5) | (1 << 4);
00943         }
00944 
00945         if (ath5k_channel < 145 || !(ath5k_channel & 1)) {
00946                 clock = 1;
00947                 data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) |
00948                         (clock << 1) | (1 << 10) | 1;
00949         } else {
00950                 clock = 0;
00951                 data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff)
00952                         << 2) | (clock << 1) | (1 << 10) | 1;
00953         }
00954 
00955         ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8),
00956                         AR5K_RF_BUFFER);
00957         ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00),
00958                         AR5K_RF_BUFFER_CONTROL_3);
00959 
00960         return 0;
00961 }
00962 
00963 /*
00964  * Set channel on 5112 and newer
00965  */
00966 static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
00967                 struct net80211_channel *channel)
00968 {
00969         u32 data, data0, data1, data2;
00970         u16 c;
00971 
00972         data = data0 = data1 = data2 = 0;
00973         c = channel->center_freq;
00974 
00975         if (c < 4800) {
00976                 if (!((c - 2224) % 5)) {
00977                         data0 = ((2 * (c - 704)) - 3040) / 10;
00978                         data1 = 1;
00979                 } else if (!((c - 2192) % 5)) {
00980                         data0 = ((2 * (c - 672)) - 3040) / 10;
00981                         data1 = 0;
00982                 } else
00983                         return -EINVAL;
00984 
00985                 data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
00986         } else if ((c - (c % 5)) != 2 || c > 5435) {
00987                 if (!(c % 20) && c >= 5120) {
00988                         data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
00989                         data2 = ath5k_hw_bitswap(3, 2);
00990                 } else if (!(c % 10)) {
00991                         data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
00992                         data2 = ath5k_hw_bitswap(2, 2);
00993                 } else if (!(c % 5)) {
00994                         data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
00995                         data2 = ath5k_hw_bitswap(1, 2);
00996                 } else
00997                         return -EINVAL;
00998         } else {
00999                 data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
01000                 data2 = ath5k_hw_bitswap(0, 2);
01001         }
01002 
01003         data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
01004 
01005         ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
01006         ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
01007 
01008         return 0;
01009 }
01010 
01011 /*
01012  * Set the channel on the RF2425
01013  */
01014 static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
01015                 struct net80211_channel *channel)
01016 {
01017         u32 data, data0, data2;
01018         u16 c;
01019 
01020         data = data0 = data2 = 0;
01021         c = channel->center_freq;
01022 
01023         if (c < 4800) {
01024                 data0 = ath5k_hw_bitswap((c - 2272), 8);
01025                 data2 = 0;
01026         /* ? 5GHz ? */
01027         } else if ((c - (c % 5)) != 2 || c > 5435) {
01028                 if (!(c % 20) && c < 5120)
01029                         data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
01030                 else if (!(c % 10))
01031                         data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
01032                 else if (!(c % 5))
01033                         data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
01034                 else
01035                         return -EINVAL;
01036                 data2 = ath5k_hw_bitswap(1, 2);
01037         } else {
01038                 data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
01039                 data2 = ath5k_hw_bitswap(0, 2);
01040         }
01041 
01042         data = (data0 << 4) | data2 << 2 | 0x1001;
01043 
01044         ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
01045         ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
01046 
01047         return 0;
01048 }
01049 
01050 /*
01051  * Set a channel on the radio chip
01052  */
01053 int ath5k_hw_channel(struct ath5k_hw *ah, struct net80211_channel *channel)
01054 {
01055         int ret;
01056         /*
01057          * Check bounds supported by the PHY (we don't care about regultory
01058          * restrictions at this point). Note: hw_value already has the band
01059          * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
01060          * of the band by that */
01061         if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) {
01062                 DBG("ath5k: channel frequency (%d MHz) out of supported "
01063                     "range\n", channel->center_freq);
01064                 return -EINVAL;
01065         }
01066 
01067         /*
01068          * Set the channel and wait
01069          */
01070         switch (ah->ah_radio) {
01071         case AR5K_RF5110:
01072                 ret = ath5k_hw_rf5110_channel(ah, channel);
01073                 break;
01074         case AR5K_RF5111:
01075                 ret = ath5k_hw_rf5111_channel(ah, channel);
01076                 break;
01077         case AR5K_RF2425:
01078                 ret = ath5k_hw_rf2425_channel(ah, channel);
01079                 break;
01080         default:
01081                 ret = ath5k_hw_rf5112_channel(ah, channel);
01082                 break;
01083         }
01084 
01085         if (ret) {
01086                 DBG("ath5k: setting channel failed: %s\n", strerror(ret));
01087                 return ret;
01088         }
01089 
01090         /* Set JAPAN setting for channel 14 */
01091         if (channel->center_freq == 2484) {
01092                 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
01093                                 AR5K_PHY_CCKTXCTL_JAPAN);
01094         } else {
01095                 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
01096                                 AR5K_PHY_CCKTXCTL_WORLD);
01097         }
01098 
01099         ah->ah_current_channel = channel;
01100         ah->ah_turbo = (channel->hw_value == CHANNEL_T ? 1 : 0);
01101 
01102         return 0;
01103 }
01104 
01105 /*****************\
01106   PHY calibration
01107 \*****************/
01108 
01109 /**
01110  * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
01111  *
01112  * @ah: struct ath5k_hw pointer we are operating on
01113  * @freq: the channel frequency, just used for error logging
01114  *
01115  * This function performs a noise floor calibration of the PHY and waits for
01116  * it to complete. Then the noise floor value is compared to some maximum
01117  * noise floor we consider valid.
01118  *
01119  * Note that this is different from what the madwifi HAL does: it reads the
01120  * noise floor and afterwards initiates the calibration. Since the noise floor
01121  * calibration can take some time to finish, depending on the current channel
01122  * use, that avoids the occasional timeout warnings we are seeing now.
01123  *
01124  * See the following link for an Atheros patent on noise floor calibration:
01125  * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
01126  * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
01127  *
01128  * XXX: Since during noise floor calibration antennas are detached according to
01129  * the patent, we should stop tx queues here.
01130  */
01131 int
01132 ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
01133 {
01134         int ret;
01135         unsigned int i;
01136         s32 noise_floor;
01137 
01138         /*
01139          * Enable noise floor calibration
01140          */
01141         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
01142                                 AR5K_PHY_AGCCTL_NF);
01143 
01144         ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
01145                         AR5K_PHY_AGCCTL_NF, 0, 0);
01146 
01147         if (ret) {
01148                 DBG("ath5k: noise floor calibration timeout (%d MHz)\n", freq);
01149                 return -EAGAIN;
01150         }
01151 
01152         /* Wait until the noise floor is calibrated and read the value */
01153         for (i = 20; i > 0; i--) {
01154                 mdelay(1);
01155                 noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
01156                 noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
01157                 if (noise_floor & AR5K_PHY_NF_ACTIVE) {
01158                         noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
01159 
01160                         if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
01161                                 break;
01162                 }
01163         }
01164 
01165         DBG2("ath5k: noise floor %d\n", noise_floor);
01166 
01167         if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
01168                 DBG("ath5k: noise floor calibration failed (%d MHz)\n", freq);
01169                 return -EAGAIN;
01170         }
01171 
01172         ah->ah_noise_floor = noise_floor;
01173 
01174         return 0;
01175 }
01176 
01177 /*
01178  * Perform a PHY calibration on RF5110
01179  * -Fix BPSK/QAM Constellation (I/Q correction)
01180  * -Calculate Noise Floor
01181  */
01182 static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
01183                 struct net80211_channel *channel)
01184 {
01185         u32 phy_sig, phy_agc, phy_sat, beacon;
01186         int ret;
01187 
01188         /*
01189          * Disable beacons and RX/TX queues, wait
01190          */
01191         AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210,
01192                 AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
01193         beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
01194         ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
01195 
01196         mdelay(2);
01197 
01198         /*
01199          * Set the channel (with AGC turned off)
01200          */
01201         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
01202         udelay(10);
01203         ret = ath5k_hw_channel(ah, channel);
01204 
01205         /*
01206          * Activate PHY and wait
01207          */
01208         ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
01209         mdelay(1);
01210 
01211         AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
01212 
01213         if (ret)
01214                 return ret;
01215 
01216         /*
01217          * Calibrate the radio chip
01218          */
01219 
01220         /* Remember normal state */
01221         phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG);
01222         phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE);
01223         phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT);
01224 
01225         /* Update radio registers */
01226         ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) |
01227                 AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG);
01228 
01229         ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI |
01230                         AR5K_PHY_AGCCOARSE_LO)) |
01231                 AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) |
01232                 AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE);
01233 
01234         ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT |
01235                         AR5K_PHY_ADCSAT_THR)) |
01236                 AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) |
01237                 AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT);
01238 
01239         udelay(20);
01240 
01241         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
01242         udelay(10);
01243         ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG);
01244         AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
01245 
01246         mdelay(1);
01247 
01248         /*
01249          * Enable calibration and wait until completion
01250          */
01251         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL);
01252 
01253         ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
01254                         AR5K_PHY_AGCCTL_CAL, 0, 0);
01255 
01256         /* Reset to normal state */
01257         ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG);
01258         ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE);
01259         ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT);
01260 
01261         if (ret) {
01262                 DBG("ath5k: calibration timeout (%d MHz)\n",
01263                     channel->center_freq);
01264                 return ret;
01265         }
01266 
01267         ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
01268 
01269         /*
01270          * Re-enable RX/TX and beacons
01271          */
01272         AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210,
01273                 AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
01274         ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210);
01275 
01276         return 0;
01277 }
01278 
01279 /*
01280  * Perform a PHY calibration on RF5111/5112 and newer chips
01281  */
01282 static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
01283                 struct net80211_channel *channel)
01284 {
01285         u32 i_pwr, q_pwr;
01286         s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
01287         int i;
01288 
01289         if (!ah->ah_calibration ||
01290                 ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
01291                 goto done;
01292 
01293         /* Calibration has finished, get the results and re-run */
01294         for (i = 0; i <= 10; i++) {
01295                 iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
01296                 i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
01297                 q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
01298         }
01299 
01300         i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
01301         q_coffd = q_pwr >> 7;
01302 
01303         /* No correction */
01304         if (i_coffd == 0 || q_coffd == 0)
01305                 goto done;
01306 
01307         i_coff = ((-iq_corr) / i_coffd) & 0x3f;
01308 
01309         /* Boundary check */
01310         if (i_coff > 31)
01311                 i_coff = 31;
01312         if (i_coff < -32)
01313                 i_coff = -32;
01314 
01315         q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f;
01316 
01317         /* Boundary check */
01318         if (q_coff > 15)
01319                 q_coff = 15;
01320         if (q_coff < -16)
01321                 q_coff = -16;
01322 
01323         /* Commit new I/Q value */
01324         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
01325                 ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
01326 
01327         /* Re-enable calibration -if we don't we'll commit
01328          * the same values again and again */
01329         AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
01330                         AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
01331         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN);
01332 
01333 done:
01334 
01335         /* TODO: Separate noise floor calibration from I/Q calibration
01336          * since noise floor calibration interrupts rx path while I/Q
01337          * calibration doesn't. We don't need to run noise floor calibration
01338          * as often as I/Q calibration.*/
01339         ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
01340 
01341         /* Initiate a gain_F calibration */
01342         ath5k_hw_request_rfgain_probe(ah);
01343 
01344         return 0;
01345 }
01346 
01347 /*
01348  * Perform a PHY calibration
01349  */
01350 int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
01351                 struct net80211_channel *channel)
01352 {
01353         int ret;
01354 
01355         if (ah->ah_radio == AR5K_RF5110)
01356                 ret = ath5k_hw_rf5110_calibrate(ah, channel);
01357         else
01358                 ret = ath5k_hw_rf511x_calibrate(ah, channel);
01359 
01360         return ret;
01361 }
01362 
01363 int ath5k_hw_phy_disable(struct ath5k_hw *ah)
01364 {
01365         ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
01366 
01367         return 0;
01368 }
01369 
01370 /********************\
01371   Misc PHY functions
01372 \********************/
01373 
01374 /*
01375  * Get the PHY Chip revision
01376  */
01377 u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
01378 {
01379         unsigned int i;
01380         u32 srev;
01381         u16 ret;
01382 
01383         /*
01384          * Set the radio chip access register
01385          */
01386         switch (chan) {
01387         case CHANNEL_2GHZ:
01388                 ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
01389                 break;
01390         case CHANNEL_5GHZ:
01391                 ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
01392                 break;
01393         default:
01394                 return 0;
01395         }
01396 
01397         mdelay(2);
01398 
01399         /* ...wait until PHY is ready and read the selected radio revision */
01400         ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
01401 
01402         for (i = 0; i < 8; i++)
01403                 ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
01404 
01405         if (ah->ah_version == AR5K_AR5210) {
01406                 srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
01407                 ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
01408         } else {
01409                 srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
01410                 ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
01411                                 ((srev & 0x0f) << 4), 8);
01412         }
01413 
01414         /* Reset to the 5GHz mode */
01415         ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
01416 
01417         return ret;
01418 }
01419 
01420 void /*TODO:Boundary check*/
01421 ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant)
01422 {
01423         if (ah->ah_version != AR5K_AR5210)
01424                 ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA);
01425 }
01426 
01427 unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah)
01428 {
01429         if (ah->ah_version != AR5K_AR5210)
01430                 return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
01431 
01432         return 0; /*XXX: What do we return for 5210 ?*/
01433 }
01434 
01435 
01436 /****************\
01437 * TX power setup *
01438 \****************/
01439 
01440 /*
01441  * Helper functions
01442  */
01443 
01444 /*
01445  * Do linear interpolation between two given (x, y) points
01446  */
01447 static s16
01448 ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right,
01449                                         s16 y_left, s16 y_right)
01450 {
01451         s16 ratio, result;
01452 
01453         /* Avoid divide by zero and skip interpolation
01454          * if we have the same point */
01455         if ((x_left == x_right) || (y_left == y_right))
01456                 return y_left;
01457 
01458         /*
01459          * Since we use ints and not fps, we need to scale up in
01460          * order to get a sane ratio value (or else we 'll eg. get
01461          * always 1 instead of 1.25, 1.75 etc). We scale up by 100
01462          * to have some accuracy both for 0.5 and 0.25 steps.
01463          */
01464         ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left));
01465 
01466         /* Now scale down to be in range */
01467         result = y_left + (ratio * (target - x_left) / 100);
01468 
01469         return result;
01470 }
01471 
01472 /*
01473  * Find vertical boundary (min pwr) for the linear PCDAC curve.
01474  *
01475  * Since we have the top of the curve and we draw the line below
01476  * until we reach 1 (1 pcdac step) we need to know which point
01477  * (x value) that is so that we don't go below y axis and have negative
01478  * pcdac values when creating the curve, or fill the table with zeroes.
01479  */
01480 static s16
01481 ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
01482                                 const s16 *pwrL, const s16 *pwrR)
01483 {
01484         s8 tmp;
01485         s16 min_pwrL, min_pwrR;
01486         s16 pwr_i;
01487 
01488         if (pwrL[0] == pwrL[1])
01489                 min_pwrL = pwrL[0];
01490         else {
01491                 pwr_i = pwrL[0];
01492                 do {
01493                         pwr_i--;
01494                         tmp = (s8) ath5k_get_interpolated_value(pwr_i,
01495                                                         pwrL[0], pwrL[1],
01496                                                         stepL[0], stepL[1]);
01497                 } while (tmp > 1);
01498 
01499                 min_pwrL = pwr_i;
01500         }
01501 
01502         if (pwrR[0] == pwrR[1])
01503                 min_pwrR = pwrR[0];
01504         else {
01505                 pwr_i = pwrR[0];
01506                 do {
01507                         pwr_i--;
01508                         tmp = (s8) ath5k_get_interpolated_value(pwr_i,
01509                                                         pwrR[0], pwrR[1],
01510                                                         stepR[0], stepR[1]);
01511                 } while (tmp > 1);
01512 
01513                 min_pwrR = pwr_i;
01514         }
01515 
01516         /* Keep the right boundary so that it works for both curves */
01517         return max(min_pwrL, min_pwrR);
01518 }
01519 
01520 /*
01521  * Interpolate (pwr,vpd) points to create a Power to PDADC or a
01522  * Power to PCDAC curve.
01523  *
01524  * Each curve has power on x axis (in 0.5dB units) and PCDAC/PDADC
01525  * steps (offsets) on y axis. Power can go up to 31.5dB and max
01526  * PCDAC/PDADC step for each curve is 64 but we can write more than
01527  * one curves on hw so we can go up to 128 (which is the max step we
01528  * can write on the final table).
01529  *
01530  * We write y values (PCDAC/PDADC steps) on hw.
01531  */
01532 static void
01533 ath5k_create_power_curve(s16 pmin, s16 pmax,
01534                         const s16 *pwr, const u8 *vpd,
01535                         u8 num_points,
01536                         u8 *vpd_table, u8 type)
01537 {
01538         u8 idx[2] = { 0, 1 };
01539         s16 pwr_i = 2*pmin;
01540         int i;
01541 
01542         if (num_points < 2)
01543                 return;
01544 
01545         /* We want the whole line, so adjust boundaries
01546          * to cover the entire power range. Note that
01547          * power values are already 0.25dB so no need
01548          * to multiply pwr_i by 2 */
01549         if (type == AR5K_PWRTABLE_LINEAR_PCDAC) {
01550                 pwr_i = pmin;
01551                 pmin = 0;
01552                 pmax = 63;
01553         }
01554 
01555         /* Find surrounding turning points (TPs)
01556          * and interpolate between them */
01557         for (i = 0; (i <= (u16) (pmax - pmin)) &&
01558         (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) {
01559 
01560                 /* We passed the right TP, move to the next set of TPs
01561                  * if we pass the last TP, extrapolate above using the last
01562                  * two TPs for ratio */
01563                 if ((pwr_i > pwr[idx[1]]) && (idx[1] < num_points - 1)) {
01564                         idx[0]++;
01565                         idx[1]++;
01566                 }
01567 
01568                 vpd_table[i] = (u8) ath5k_get_interpolated_value(pwr_i,
01569                                                 pwr[idx[0]], pwr[idx[1]],
01570                                                 vpd[idx[0]], vpd[idx[1]]);
01571 
01572                 /* Increase by 0.5dB
01573                  * (0.25 dB units) */
01574                 pwr_i += 2;
01575         }
01576 }
01577 
01578 /*
01579  * Get the surrounding per-channel power calibration piers
01580  * for a given frequency so that we can interpolate between
01581  * them and come up with an apropriate dataset for our current
01582  * channel.
01583  */
01584 static void
01585 ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah,
01586                         struct net80211_channel *channel,
01587                         struct ath5k_chan_pcal_info **pcinfo_l,
01588                         struct ath5k_chan_pcal_info **pcinfo_r)
01589 {
01590         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01591         struct ath5k_chan_pcal_info *pcinfo;
01592         u8 idx_l, idx_r;
01593         u8 mode, max, i;
01594         u32 target = channel->center_freq;
01595 
01596         idx_l = 0;
01597         idx_r = 0;
01598 
01599         if (!(channel->hw_value & CHANNEL_OFDM)) {
01600                 pcinfo = ee->ee_pwr_cal_b;
01601                 mode = AR5K_EEPROM_MODE_11B;
01602         } else if (channel->hw_value & CHANNEL_2GHZ) {
01603                 pcinfo = ee->ee_pwr_cal_g;
01604                 mode = AR5K_EEPROM_MODE_11G;
01605         } else {
01606                 pcinfo = ee->ee_pwr_cal_a;
01607                 mode = AR5K_EEPROM_MODE_11A;
01608         }
01609         max = ee->ee_n_piers[mode] - 1;
01610 
01611         /* Frequency is below our calibrated
01612          * range. Use the lowest power curve
01613          * we have */
01614         if (target < pcinfo[0].freq) {
01615                 idx_l = idx_r = 0;
01616                 goto done;
01617         }
01618 
01619         /* Frequency is above our calibrated
01620          * range. Use the highest power curve
01621          * we have */
01622         if (target > pcinfo[max].freq) {
01623                 idx_l = idx_r = max;
01624                 goto done;
01625         }
01626 
01627         /* Frequency is inside our calibrated
01628          * channel range. Pick the surrounding
01629          * calibration piers so that we can
01630          * interpolate */
01631         for (i = 0; i <= max; i++) {
01632 
01633                 /* Frequency matches one of our calibration
01634                  * piers, no need to interpolate, just use
01635                  * that calibration pier */
01636                 if (pcinfo[i].freq == target) {
01637                         idx_l = idx_r = i;
01638                         goto done;
01639                 }
01640 
01641                 /* We found a calibration pier that's above
01642                  * frequency, use this pier and the previous
01643                  * one to interpolate */
01644                 if (target < pcinfo[i].freq) {
01645                         idx_r = i;
01646                         idx_l = idx_r - 1;
01647                         goto done;
01648                 }
01649         }
01650 
01651 done:
01652         *pcinfo_l = &pcinfo[idx_l];
01653         *pcinfo_r = &pcinfo[idx_r];
01654 
01655         return;
01656 }
01657 
01658 /*
01659  * Get the surrounding per-rate power calibration data
01660  * for a given frequency and interpolate between power
01661  * values to set max target power supported by hw for
01662  * each rate.
01663  */
01664 static void
01665 ath5k_get_rate_pcal_data(struct ath5k_hw *ah,
01666                         struct net80211_channel *channel,
01667                         struct ath5k_rate_pcal_info *rates)
01668 {
01669         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01670         struct ath5k_rate_pcal_info *rpinfo;
01671         u8 idx_l, idx_r;
01672         u8 mode, max, i;
01673         u32 target = channel->center_freq;
01674 
01675         idx_l = 0;
01676         idx_r = 0;
01677 
01678         if (!(channel->hw_value & CHANNEL_OFDM)) {
01679                 rpinfo = ee->ee_rate_tpwr_b;
01680                 mode = AR5K_EEPROM_MODE_11B;
01681         } else if (channel->hw_value & CHANNEL_2GHZ) {
01682                 rpinfo = ee->ee_rate_tpwr_g;
01683                 mode = AR5K_EEPROM_MODE_11G;
01684         } else {
01685                 rpinfo = ee->ee_rate_tpwr_a;
01686                 mode = AR5K_EEPROM_MODE_11A;
01687         }
01688         max = ee->ee_rate_target_pwr_num[mode] - 1;
01689 
01690         /* Get the surrounding calibration
01691          * piers - same as above */
01692         if (target < rpinfo[0].freq) {
01693                 idx_l = idx_r = 0;
01694                 goto done;
01695         }
01696 
01697         if (target > rpinfo[max].freq) {
01698                 idx_l = idx_r = max;
01699                 goto done;
01700         }
01701 
01702         for (i = 0; i <= max; i++) {
01703 
01704                 if (rpinfo[i].freq == target) {
01705                         idx_l = idx_r = i;
01706                         goto done;
01707                 }
01708 
01709                 if (target < rpinfo[i].freq) {
01710                         idx_r = i;
01711                         idx_l = idx_r - 1;
01712                         goto done;
01713                 }
01714         }
01715 
01716 done:
01717         /* Now interpolate power value, based on the frequency */
01718         rates->freq = target;
01719 
01720         rates->target_power_6to24 =
01721                 ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
01722                                         rpinfo[idx_r].freq,
01723                                         rpinfo[idx_l].target_power_6to24,
01724                                         rpinfo[idx_r].target_power_6to24);
01725 
01726         rates->target_power_36 =
01727                 ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
01728                                         rpinfo[idx_r].freq,
01729                                         rpinfo[idx_l].target_power_36,
01730                                         rpinfo[idx_r].target_power_36);
01731 
01732         rates->target_power_48 =
01733                 ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
01734                                         rpinfo[idx_r].freq,
01735                                         rpinfo[idx_l].target_power_48,
01736                                         rpinfo[idx_r].target_power_48);
01737 
01738         rates->target_power_54 =
01739                 ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
01740                                         rpinfo[idx_r].freq,
01741                                         rpinfo[idx_l].target_power_54,
01742                                         rpinfo[idx_r].target_power_54);
01743 }
01744 
01745 /*
01746  * Get the max edge power for this channel if
01747  * we have such data from EEPROM's Conformance Test
01748  * Limits (CTL), and limit max power if needed.
01749  *
01750  * FIXME: Only works for world regulatory domains
01751  */
01752 static void
01753 ath5k_get_max_ctl_power(struct ath5k_hw *ah,
01754                         struct net80211_channel *channel)
01755 {
01756         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01757         struct ath5k_edge_power *rep = ee->ee_ctl_pwr;
01758         u8 *ctl_val = ee->ee_ctl;
01759         s16 max_chan_pwr = ah->ah_txpower.txp_max_pwr / 4;
01760         s16 edge_pwr = 0;
01761         u8 rep_idx;
01762         u8 i, ctl_mode;
01763         u8 ctl_idx = 0xFF;
01764         u32 target = channel->center_freq;
01765 
01766         /* Find out a CTL for our mode that's not mapped
01767          * on a specific reg domain.
01768          *
01769          * TODO: Map our current reg domain to one of the 3 available
01770          * reg domain ids so that we can support more CTLs. */
01771         switch (channel->hw_value & CHANNEL_MODES) {
01772         case CHANNEL_A:
01773                 ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN;
01774                 break;
01775         case CHANNEL_G:
01776                 ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN;
01777                 break;
01778         case CHANNEL_B:
01779                 ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN;
01780                 break;
01781         case CHANNEL_T:
01782                 ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN;
01783                 break;
01784         case CHANNEL_TG:
01785                 ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN;
01786                 break;
01787         case CHANNEL_XR:
01788                 /* Fall through */
01789         default:
01790                 return;
01791         }
01792 
01793         for (i = 0; i < ee->ee_ctls; i++) {
01794                 if (ctl_val[i] == ctl_mode) {
01795                         ctl_idx = i;
01796                         break;
01797                 }
01798         }
01799 
01800         /* If we have a CTL dataset available grab it and find the
01801          * edge power for our frequency */
01802         if (ctl_idx == 0xFF)
01803                 return;
01804 
01805         /* Edge powers are sorted by frequency from lower
01806          * to higher. Each CTL corresponds to 8 edge power
01807          * measurements. */
01808         rep_idx = ctl_idx * AR5K_EEPROM_N_EDGES;
01809 
01810         /* Don't do boundaries check because we
01811          * might have more that one bands defined
01812          * for this mode */
01813 
01814         /* Get the edge power that's closer to our
01815          * frequency */
01816         for (i = 0; i < AR5K_EEPROM_N_EDGES; i++) {
01817                 rep_idx += i;
01818                 if (target <= rep[rep_idx].freq)
01819                         edge_pwr = (s16) rep[rep_idx].edge;
01820         }
01821 
01822         if (edge_pwr) {
01823                 ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr);
01824         }
01825 }
01826 
01827 
01828 /*
01829  * Power to PCDAC table functions
01830  */
01831 
01832 /*
01833  * Fill Power to PCDAC table on RF5111
01834  *
01835  * No further processing is needed for RF5111, the only thing we have to
01836  * do is fill the values below and above calibration range since eeprom data
01837  * may not cover the entire PCDAC table.
01838  */
01839 static void
01840 ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min,
01841                                                         s16 *table_max)
01842 {
01843         u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
01844         u8      *pcdac_tmp = ah->ah_txpower.tmpL[0];
01845         u8      pcdac_0, pcdac_n, pcdac_i, pwr_idx, i;
01846         s16     min_pwr, max_pwr;
01847 
01848         /* Get table boundaries */
01849         min_pwr = table_min[0];
01850         pcdac_0 = pcdac_tmp[0];
01851 
01852         max_pwr = table_max[0];
01853         pcdac_n = pcdac_tmp[table_max[0] - table_min[0]];
01854 
01855         /* Extrapolate below minimum using pcdac_0 */
01856         pcdac_i = 0;
01857         for (i = 0; i < min_pwr; i++)
01858                 pcdac_out[pcdac_i++] = pcdac_0;
01859 
01860         /* Copy values from pcdac_tmp */
01861         pwr_idx = min_pwr;
01862         for (i = 0 ; pwr_idx <= max_pwr &&
01863         pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) {
01864                 pcdac_out[pcdac_i++] = pcdac_tmp[i];
01865                 pwr_idx++;
01866         }
01867 
01868         /* Extrapolate above maximum */
01869         while (pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE)
01870                 pcdac_out[pcdac_i++] = pcdac_n;
01871 
01872 }
01873 
01874 /*
01875  * Combine available XPD Curves and fill Linear Power to PCDAC table
01876  * on RF5112
01877  *
01878  * RFX112 can have up to 2 curves (one for low txpower range and one for
01879  * higher txpower range). We need to put them both on pcdac_out and place
01880  * them in the correct location. In case we only have one curve available
01881  * just fit it on pcdac_out (it's supposed to cover the entire range of
01882  * available pwr levels since it's always the higher power curve). Extrapolate
01883  * below and above final table if needed.
01884  */
01885 static void
01886 ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
01887                                                 s16 *table_max, u8 pdcurves)
01888 {
01889         u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
01890         u8      *pcdac_low_pwr;
01891         u8      *pcdac_high_pwr;
01892         u8      *pcdac_tmp;
01893         u8      pwr;
01894         s16     max_pwr_idx;
01895         s16     min_pwr_idx;
01896         s16     mid_pwr_idx = 0;
01897         /* Edge flag turs on the 7nth bit on the PCDAC
01898          * to delcare the higher power curve (force values
01899          * to be greater than 64). If we only have one curve
01900          * we don't need to set this, if we have 2 curves and
01901          * fill the table backwards this can also be used to
01902          * switch from higher power curve to lower power curve */
01903         u8      edge_flag;
01904         int     i;
01905 
01906         /* When we have only one curve available
01907          * that's the higher power curve. If we have
01908          * two curves the first is the high power curve
01909          * and the next is the low power curve. */
01910         if (pdcurves > 1) {
01911                 pcdac_low_pwr = ah->ah_txpower.tmpL[1];
01912                 pcdac_high_pwr = ah->ah_txpower.tmpL[0];
01913                 mid_pwr_idx = table_max[1] - table_min[1] - 1;
01914                 max_pwr_idx = (table_max[0] - table_min[0]) / 2;
01915 
01916                 /* If table size goes beyond 31.5dB, keep the
01917                  * upper 31.5dB range when setting tx power.
01918                  * Note: 126 = 31.5 dB in quarter dB steps */
01919                 if (table_max[0] - table_min[1] > 126)
01920                         min_pwr_idx = table_max[0] - 126;
01921                 else
01922                         min_pwr_idx = table_min[1];
01923 
01924                 /* Since we fill table backwards
01925                  * start from high power curve */
01926                 pcdac_tmp = pcdac_high_pwr;
01927 
01928                 edge_flag = 0x40;
01929         } else {
01930                 pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */
01931                 pcdac_high_pwr = ah->ah_txpower.tmpL[0];
01932                 min_pwr_idx = table_min[0];
01933                 max_pwr_idx = (table_max[0] - table_min[0]) / 2;
01934                 pcdac_tmp = pcdac_high_pwr;
01935                 edge_flag = 0;
01936         }
01937 
01938         /* This is used when setting tx power*/
01939         ah->ah_txpower.txp_min_idx = min_pwr_idx/2;
01940 
01941         /* Fill Power to PCDAC table backwards */
01942         pwr = max_pwr_idx;
01943         for (i = 63; i >= 0; i--) {
01944                 /* Entering lower power range, reset
01945                  * edge flag and set pcdac_tmp to lower
01946                  * power curve.*/
01947                 if (edge_flag == 0x40 &&
01948                 (2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) {
01949                         edge_flag = 0x00;
01950                         pcdac_tmp = pcdac_low_pwr;
01951                         pwr = mid_pwr_idx/2;
01952                 }
01953 
01954                 /* Don't go below 1, extrapolate below if we have
01955                  * already swithced to the lower power curve -or
01956                  * we only have one curve and edge_flag is zero
01957                  * anyway */
01958                 if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) {
01959                         while (i >= 0) {
01960                                 pcdac_out[i] = pcdac_out[i + 1];
01961                                 i--;
01962                         }
01963                         break;
01964                 }
01965 
01966                 pcdac_out[i] = pcdac_tmp[pwr] | edge_flag;
01967 
01968                 /* Extrapolate above if pcdac is greater than
01969                  * 126 -this can happen because we OR pcdac_out
01970                  * value with edge_flag on high power curve */
01971                 if (pcdac_out[i] > 126)
01972                         pcdac_out[i] = 126;
01973 
01974                 /* Decrease by a 0.5dB step */
01975                 pwr--;
01976         }
01977 }
01978 
01979 /* Write PCDAC values on hw */
01980 static void
01981 ath5k_setup_pcdac_table(struct ath5k_hw *ah)
01982 {
01983         u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
01984         int     i;
01985 
01986         /*
01987          * Write TX power values
01988          */
01989         for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
01990                 ath5k_hw_reg_write(ah,
01991                         (((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) |
01992                         (((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16),
01993                         AR5K_PHY_PCDAC_TXPOWER(i));
01994         }
01995 }
01996 
01997 
01998 /*
01999  * Power to PDADC table functions
02000  */
02001 
02002 /*
02003  * Set the gain boundaries and create final Power to PDADC table
02004  *
02005  * We can have up to 4 pd curves, we need to do a simmilar process
02006  * as we do for RF5112. This time we don't have an edge_flag but we
02007  * set the gain boundaries on a separate register.
02008  */
02009 static void
02010 ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah,
02011                         s16 *pwr_min, s16 *pwr_max, u8 pdcurves)
02012 {
02013         u8 gain_boundaries[AR5K_EEPROM_N_PD_GAINS];
02014         u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
02015         u8 *pdadc_tmp;
02016         s16 pdadc_0;
02017         u8 pdadc_i, pdadc_n, pwr_step, pdg, max_idx, table_size;
02018         u8 pd_gain_overlap;
02019 
02020         /* Note: Register value is initialized on initvals
02021          * there is no feedback from hw.
02022          * XXX: What about pd_gain_overlap from EEPROM ? */
02023         pd_gain_overlap = (u8) ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) &
02024                 AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP;
02025 
02026         /* Create final PDADC table */
02027         for (pdg = 0, pdadc_i = 0; pdg < pdcurves; pdg++) {
02028                 pdadc_tmp = ah->ah_txpower.tmpL[pdg];
02029 
02030                 if (pdg == pdcurves - 1)
02031                         /* 2 dB boundary stretch for last
02032                          * (higher power) curve */
02033                         gain_boundaries[pdg] = pwr_max[pdg] + 4;
02034                 else
02035                         /* Set gain boundary in the middle
02036                          * between this curve and the next one */
02037                         gain_boundaries[pdg] =
02038                                 (pwr_max[pdg] + pwr_min[pdg + 1]) / 2;
02039 
02040                 /* Sanity check in case our 2 db stretch got out of
02041                  * range. */
02042                 if (gain_boundaries[pdg] > AR5K_TUNE_MAX_TXPOWER)
02043                         gain_boundaries[pdg] = AR5K_TUNE_MAX_TXPOWER;
02044 
02045                 /* For the first curve (lower power)
02046                  * start from 0 dB */
02047                 if (pdg == 0)
02048                         pdadc_0 = 0;
02049                 else
02050                         /* For the other curves use the gain overlap */
02051                         pdadc_0 = (gain_boundaries[pdg - 1] - pwr_min[pdg]) -
02052                                                         pd_gain_overlap;
02053 
02054                 /* Force each power step to be at least 0.5 dB */
02055                 if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1)
02056                         pwr_step = pdadc_tmp[1] - pdadc_tmp[0];
02057                 else
02058                         pwr_step = 1;
02059 
02060                 /* If pdadc_0 is negative, we need to extrapolate
02061                  * below this pdgain by a number of pwr_steps */
02062                 while ((pdadc_0 < 0) && (pdadc_i < 128)) {
02063                         s16 tmp = pdadc_tmp[0] + pdadc_0 * pwr_step;
02064                         pdadc_out[pdadc_i++] = (tmp < 0) ? 0 : (u8) tmp;
02065                         pdadc_0++;
02066                 }
02067 
02068                 /* Set last pwr level, using gain boundaries */
02069                 pdadc_n = gain_boundaries[pdg] + pd_gain_overlap - pwr_min[pdg];
02070                 /* Limit it to be inside pwr range */
02071                 table_size = pwr_max[pdg] - pwr_min[pdg];
02072                 max_idx = (pdadc_n < table_size) ? pdadc_n : table_size;
02073 
02074                 /* Fill pdadc_out table */
02075                 while (pdadc_0 < max_idx)
02076                         pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++];
02077 
02078                 /* Need to extrapolate above this pdgain? */
02079                 if (pdadc_n <= max_idx)
02080                         continue;
02081 
02082                 /* Force each power step to be at least 0.5 dB */
02083                 if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1)
02084                         pwr_step = pdadc_tmp[table_size - 1] -
02085                                                 pdadc_tmp[table_size - 2];
02086                 else
02087                         pwr_step = 1;
02088 
02089                 /* Extrapolate above */
02090                 while ((pdadc_0 < (s16) pdadc_n) &&
02091                 (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2)) {
02092                         s16 tmp = pdadc_tmp[table_size - 1] +
02093                                         (pdadc_0 - max_idx) * pwr_step;
02094                         pdadc_out[pdadc_i++] = (tmp > 127) ? 127 : (u8) tmp;
02095                         pdadc_0++;
02096                 }
02097         }
02098 
02099         while (pdg < AR5K_EEPROM_N_PD_GAINS) {
02100                 gain_boundaries[pdg] = gain_boundaries[pdg - 1];
02101                 pdg++;
02102         }
02103 
02104         while (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2) {
02105                 pdadc_out[pdadc_i] = pdadc_out[pdadc_i - 1];
02106                 pdadc_i++;
02107         }
02108 
02109         /* Set gain boundaries */
02110         ath5k_hw_reg_write(ah,
02111                 AR5K_REG_SM(pd_gain_overlap,
02112                         AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) |
02113                 AR5K_REG_SM(gain_boundaries[0],
02114                         AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) |
02115                 AR5K_REG_SM(gain_boundaries[1],
02116                         AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) |
02117                 AR5K_REG_SM(gain_boundaries[2],
02118                         AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) |
02119                 AR5K_REG_SM(gain_boundaries[3],
02120                         AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4),
02121                 AR5K_PHY_TPC_RG5);
02122 
02123         /* Used for setting rate power table */
02124         ah->ah_txpower.txp_min_idx = pwr_min[0];
02125 
02126 }
02127 
02128 /* Write PDADC values on hw */
02129 static void
02130 ath5k_setup_pwr_to_pdadc_table(struct ath5k_hw *ah,
02131                         u8 pdcurves, u8 *pdg_to_idx)
02132 {
02133         u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
02134         u32 reg;
02135         u8 i;
02136 
02137         /* Select the right pdgain curves */
02138 
02139         /* Clear current settings */
02140         reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1);
02141         reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 |
02142                 AR5K_PHY_TPC_RG1_PDGAIN_2 |
02143                 AR5K_PHY_TPC_RG1_PDGAIN_3 |
02144                 AR5K_PHY_TPC_RG1_NUM_PD_GAIN);
02145 
02146         /*
02147          * Use pd_gains curve from eeprom
02148          *
02149          * This overrides the default setting from initvals
02150          * in case some vendors (e.g. Zcomax) don't use the default
02151          * curves. If we don't honor their settings we 'll get a
02152          * 5dB (1 * gain overlap ?) drop.
02153          */
02154         reg |= AR5K_REG_SM(pdcurves, AR5K_PHY_TPC_RG1_NUM_PD_GAIN);
02155 
02156         switch (pdcurves) {
02157         case 3:
02158                 reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3);
02159                 /* Fall through */
02160         case 2:
02161                 reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2);
02162                 /* Fall through */
02163         case 1:
02164                 reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1);
02165                 break;
02166         }
02167         ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1);
02168 
02169         /*
02170          * Write TX power values
02171          */
02172         for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
02173                 ath5k_hw_reg_write(ah,
02174                         ((pdadc_out[4*i + 0] & 0xff) << 0) |
02175                         ((pdadc_out[4*i + 1] & 0xff) << 8) |
02176                         ((pdadc_out[4*i + 2] & 0xff) << 16) |
02177                         ((pdadc_out[4*i + 3] & 0xff) << 24),
02178                         AR5K_PHY_PDADC_TXPOWER(i));
02179         }
02180 }
02181 
02182 
02183 /*
02184  * Common code for PCDAC/PDADC tables
02185  */
02186 
02187 /*
02188  * This is the main function that uses all of the above
02189  * to set PCDAC/PDADC table on hw for the current channel.
02190  * This table is used for tx power calibration on the basband,
02191  * without it we get weird tx power levels and in some cases
02192  * distorted spectral mask
02193  */
02194 static int
02195 ath5k_setup_channel_powertable(struct ath5k_hw *ah,
02196                         struct net80211_channel *channel,
02197                         u8 ee_mode, u8 type)
02198 {
02199         struct ath5k_pdgain_info *pdg_L, *pdg_R;
02200         struct ath5k_chan_pcal_info *pcinfo_L;
02201         struct ath5k_chan_pcal_info *pcinfo_R;
02202         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
02203         u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode];
02204         s16 table_min[AR5K_EEPROM_N_PD_GAINS];
02205         s16 table_max[AR5K_EEPROM_N_PD_GAINS];
02206         u8 *tmpL;
02207         u8 *tmpR;
02208         u32 target = channel->center_freq;
02209         int pdg, i;
02210 
02211         /* Get surounding freq piers for this channel */
02212         ath5k_get_chan_pcal_surrounding_piers(ah, channel,
02213                                                 &pcinfo_L,
02214                                                 &pcinfo_R);
02215 
02216         /* Loop over pd gain curves on
02217          * surounding freq piers by index */
02218         for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) {
02219 
02220                 /* Fill curves in reverse order
02221                  * from lower power (max gain)
02222                  * to higher power. Use curve -> idx
02223                  * backmaping we did on eeprom init */
02224                 u8 idx = pdg_curve_to_idx[pdg];
02225 
02226                 /* Grab the needed curves by index */
02227                 pdg_L = &pcinfo_L->pd_curves[idx];
02228                 pdg_R = &pcinfo_R->pd_curves[idx];
02229 
02230                 /* Initialize the temp tables */
02231                 tmpL = ah->ah_txpower.tmpL[pdg];
02232                 tmpR = ah->ah_txpower.tmpR[pdg];
02233 
02234                 /* Set curve's x boundaries and create
02235                  * curves so that they cover the same
02236                  * range (if we don't do that one table
02237                  * will have values on some range and the
02238                  * other one won't have any so interpolation
02239                  * will fail) */
02240                 table_min[pdg] = min(pdg_L->pd_pwr[0],
02241                                         pdg_R->pd_pwr[0]) / 2;
02242 
02243                 table_max[pdg] = max(pdg_L->pd_pwr[pdg_L->pd_points - 1],
02244                                 pdg_R->pd_pwr[pdg_R->pd_points - 1]) / 2;
02245 
02246                 /* Now create the curves on surrounding channels
02247                  * and interpolate if needed to get the final
02248                  * curve for this gain on this channel */
02249                 switch (type) {
02250                 case AR5K_PWRTABLE_LINEAR_PCDAC:
02251                         /* Override min/max so that we don't loose
02252                          * accuracy (don't divide by 2) */
02253                         table_min[pdg] = min(pdg_L->pd_pwr[0],
02254                                                 pdg_R->pd_pwr[0]);
02255 
02256                         table_max[pdg] =
02257                                 max(pdg_L->pd_pwr[pdg_L->pd_points - 1],
02258                                         pdg_R->pd_pwr[pdg_R->pd_points - 1]);
02259 
02260                         /* Override minimum so that we don't get
02261                          * out of bounds while extrapolating
02262                          * below. Don't do this when we have 2
02263                          * curves and we are on the high power curve
02264                          * because table_min is ok in this case */
02265                         if (!(ee->ee_pd_gains[ee_mode] > 1 && pdg == 0)) {
02266 
02267                                 table_min[pdg] =
02268                                         ath5k_get_linear_pcdac_min(pdg_L->pd_step,
02269                                                                 pdg_R->pd_step,
02270                                                                 pdg_L->pd_pwr,
02271                                                                 pdg_R->pd_pwr);
02272 
02273                                 /* Don't go too low because we will
02274                                  * miss the upper part of the curve.
02275                                  * Note: 126 = 31.5dB (max power supported)
02276                                  * in 0.25dB units */
02277                                 if (table_max[pdg] - table_min[pdg] > 126)
02278                                         table_min[pdg] = table_max[pdg] - 126;
02279                         }
02280 
02281                         /* Fall through */
02282                 case AR5K_PWRTABLE_PWR_TO_PCDAC:
02283                 case AR5K_PWRTABLE_PWR_TO_PDADC:
02284 
02285                         ath5k_create_power_curve(table_min[pdg],
02286                                                 table_max[pdg],
02287                                                 pdg_L->pd_pwr,
02288                                                 pdg_L->pd_step,
02289                                                 pdg_L->pd_points, tmpL, type);
02290 
02291                         /* We are in a calibration
02292                          * pier, no need to interpolate
02293                          * between freq piers */
02294                         if (pcinfo_L == pcinfo_R)
02295                                 continue;
02296 
02297                         ath5k_create_power_curve(table_min[pdg],
02298                                                 table_max[pdg],
02299                                                 pdg_R->pd_pwr,
02300                                                 pdg_R->pd_step,
02301                                                 pdg_R->pd_points, tmpR, type);
02302                         break;
02303                 default:
02304                         return -EINVAL;
02305                 }
02306 
02307                 /* Interpolate between curves
02308                  * of surounding freq piers to
02309                  * get the final curve for this
02310                  * pd gain. Re-use tmpL for interpolation
02311                  * output */
02312                 for (i = 0; (i < (u16) (table_max[pdg] - table_min[pdg])) &&
02313                 (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) {
02314                         tmpL[i] = (u8) ath5k_get_interpolated_value(target,
02315                                                         (s16) pcinfo_L->freq,
02316                                                         (s16) pcinfo_R->freq,
02317                                                         (s16) tmpL[i],
02318                                                         (s16) tmpR[i]);
02319                 }
02320         }
02321 
02322         /* Now we have a set of curves for this
02323          * channel on tmpL (x range is table_max - table_min
02324          * and y values are tmpL[pdg][]) sorted in the same
02325          * order as EEPROM (because we've used the backmaping).
02326          * So for RF5112 it's from higher power to lower power
02327          * and for RF2413 it's from lower power to higher power.
02328          * For RF5111 we only have one curve. */
02329 
02330         /* Fill min and max power levels for this
02331          * channel by interpolating the values on
02332          * surounding channels to complete the dataset */
02333         ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target,
02334                                         (s16) pcinfo_L->freq,
02335                                         (s16) pcinfo_R->freq,
02336                                         pcinfo_L->min_pwr, pcinfo_R->min_pwr);
02337 
02338         ah->ah_txpower.txp_max_pwr = ath5k_get_interpolated_value(target,
02339                                         (s16) pcinfo_L->freq,
02340                                         (s16) pcinfo_R->freq,
02341                                         pcinfo_L->max_pwr, pcinfo_R->max_pwr);
02342 
02343         /* We are ready to go, fill PCDAC/PDADC
02344          * table and write settings on hardware */
02345         switch (type) {
02346         case AR5K_PWRTABLE_LINEAR_PCDAC:
02347                 /* For RF5112 we can have one or two curves
02348                  * and each curve covers a certain power lvl
02349                  * range so we need to do some more processing */
02350                 ath5k_combine_linear_pcdac_curves(ah, table_min, table_max,
02351                                                 ee->ee_pd_gains[ee_mode]);
02352 
02353                 /* Set txp.offset so that we can
02354                  * match max power value with max
02355                  * table index */
02356                 ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2);
02357 
02358                 /* Write settings on hw */
02359                 ath5k_setup_pcdac_table(ah);
02360                 break;
02361         case AR5K_PWRTABLE_PWR_TO_PCDAC:
02362                 /* We are done for RF5111 since it has only
02363                  * one curve, just fit the curve on the table */
02364                 ath5k_fill_pwr_to_pcdac_table(ah, table_min, table_max);
02365 
02366                 /* No rate powertable adjustment for RF5111 */
02367                 ah->ah_txpower.txp_min_idx = 0;
02368                 ah->ah_txpower.txp_offset = 0;
02369 
02370                 /* Write settings on hw */
02371                 ath5k_setup_pcdac_table(ah);
02372                 break;
02373         case AR5K_PWRTABLE_PWR_TO_PDADC:
02374                 /* Set PDADC boundaries and fill
02375                  * final PDADC table */
02376                 ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max,
02377                                                 ee->ee_pd_gains[ee_mode]);
02378 
02379                 /* Write settings on hw */
02380                 ath5k_setup_pwr_to_pdadc_table(ah, pdg, pdg_curve_to_idx);
02381 
02382                 /* Set txp.offset, note that table_min
02383                  * can be negative */
02384                 ah->ah_txpower.txp_offset = table_min[0];
02385                 break;
02386         default:
02387                 return -EINVAL;
02388         }
02389 
02390         return 0;
02391 }
02392 
02393 
02394 /*
02395  * Per-rate tx power setting
02396  *
02397  * This is the code that sets the desired tx power (below
02398  * maximum) on hw for each rate (we also have TPC that sets
02399  * power per packet). We do that by providing an index on the
02400  * PCDAC/PDADC table we set up.
02401  */
02402 
02403 /*
02404  * Set rate power table
02405  *
02406  * For now we only limit txpower based on maximum tx power
02407  * supported by hw (what's inside rate_info). We need to limit
02408  * this even more, based on regulatory domain etc.
02409  *
02410  * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps)
02411  * and is indexed as follows:
02412  * rates[0] - rates[7] -> OFDM rates
02413  * rates[8] - rates[14] -> CCK rates
02414  * rates[15] -> XR rates (they all have the same power)
02415  */
02416 static void
02417 ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
02418                         struct ath5k_rate_pcal_info *rate_info,
02419                         u8 ee_mode)
02420 {
02421         unsigned int i;
02422         u16 *rates;
02423 
02424         /* max_pwr is power level we got from driver/user in 0.5dB
02425          * units, switch to 0.25dB units so we can compare */
02426         max_pwr *= 2;
02427         max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max_pwr) / 2;
02428 
02429         /* apply rate limits */
02430         rates = ah->ah_txpower.txp_rates_power_table;
02431 
02432         /* OFDM rates 6 to 24Mb/s */
02433         for (i = 0; i < 5; i++)
02434                 rates[i] = min(max_pwr, rate_info->target_power_6to24);
02435 
02436         /* Rest OFDM rates */
02437         rates[5] = min(rates[0], rate_info->target_power_36);
02438         rates[6] = min(rates[0], rate_info->target_power_48);
02439         rates[7] = min(rates[0], rate_info->target_power_54);
02440 
02441         /* CCK rates */
02442         /* 1L */
02443         rates[8] = min(rates[0], rate_info->target_power_6to24);
02444         /* 2L */
02445         rates[9] = min(rates[0], rate_info->target_power_36);
02446         /* 2S */
02447         rates[10] = min(rates[0], rate_info->target_power_36);
02448         /* 5L */
02449         rates[11] = min(rates[0], rate_info->target_power_48);
02450         /* 5S */
02451         rates[12] = min(rates[0], rate_info->target_power_48);
02452         /* 11L */
02453         rates[13] = min(rates[0], rate_info->target_power_54);
02454         /* 11S */
02455         rates[14] = min(rates[0], rate_info->target_power_54);
02456 
02457         /* XR rates */
02458         rates[15] = min(rates[0], rate_info->target_power_6to24);
02459 
02460         /* CCK rates have different peak to average ratio
02461          * so we have to tweak their power so that gainf
02462          * correction works ok. For this we use OFDM to
02463          * CCK delta from eeprom */
02464         if ((ee_mode == AR5K_EEPROM_MODE_11G) &&
02465         (ah->ah_phy_revision < AR5K_SREV_PHY_5212A))
02466                 for (i = 8; i <= 15; i++)
02467                         rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta;
02468 
02469         ah->ah_txpower.txp_min_pwr = rates[7];
02470         ah->ah_txpower.txp_max_pwr = rates[0];
02471         ah->ah_txpower.txp_ofdm = rates[7];
02472 }
02473 
02474 
02475 /*
02476  * Set transmition power
02477  */
02478 int
02479 ath5k_hw_txpower(struct ath5k_hw *ah, struct net80211_channel *channel,
02480                 u8 ee_mode, u8 txpower)
02481 {
02482         struct ath5k_rate_pcal_info rate_info;
02483         u8 type;
02484         int ret;
02485 
02486         if (txpower > AR5K_TUNE_MAX_TXPOWER) {
02487                 DBG("ath5k: invalid tx power %d\n", txpower);
02488                 return -EINVAL;
02489         }
02490         if (txpower == 0)
02491                 txpower = AR5K_TUNE_DEFAULT_TXPOWER;
02492 
02493         /* Reset TX power values */
02494         memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
02495         ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
02496         ah->ah_txpower.txp_min_pwr = 0;
02497         ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER;
02498 
02499         /* Initialize TX power table */
02500         switch (ah->ah_radio) {
02501         case AR5K_RF5111:
02502                 type = AR5K_PWRTABLE_PWR_TO_PCDAC;
02503                 break;
02504         case AR5K_RF5112:
02505                 type = AR5K_PWRTABLE_LINEAR_PCDAC;
02506                 break;
02507         case AR5K_RF2413:
02508         case AR5K_RF5413:
02509         case AR5K_RF2316:
02510         case AR5K_RF2317:
02511         case AR5K_RF2425:
02512                 type = AR5K_PWRTABLE_PWR_TO_PDADC;
02513                 break;
02514         default:
02515                 return -EINVAL;
02516         }
02517 
02518         /* FIXME: Only on channel/mode change */
02519         ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type);
02520         if (ret)
02521                 return ret;
02522 
02523         /* Limit max power if we have a CTL available */
02524         ath5k_get_max_ctl_power(ah, channel);
02525 
02526         /* FIXME: Tx power limit for this regdomain
02527          * XXX: Mac80211/CRDA will do that anyway ? */
02528 
02529         /* FIXME: Antenna reduction stuff */
02530 
02531         /* FIXME: Limit power on turbo modes */
02532 
02533         /* FIXME: TPC scale reduction */
02534 
02535         /* Get surounding channels for per-rate power table
02536          * calibration */
02537         ath5k_get_rate_pcal_data(ah, channel, &rate_info);
02538 
02539         /* Setup rate power table */
02540         ath5k_setup_rate_powertable(ah, txpower, &rate_info, ee_mode);
02541 
02542         /* Write rate power table on hw */
02543         ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) |
02544                 AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) |
02545                 AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1);
02546 
02547         ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) |
02548                 AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) |
02549                 AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2);
02550 
02551         ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) |
02552                 AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) |
02553                 AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3);
02554 
02555         ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) |
02556                 AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) |
02557                 AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4);
02558 
02559         /* FIXME: TPC support */
02560         if (ah->ah_txpower.txp_tpc) {
02561                 ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE |
02562                         AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
02563 
02564                 ath5k_hw_reg_write(ah,
02565                         AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) |
02566                         AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) |
02567                         AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP),
02568                         AR5K_TPC);
02569         } else {
02570                 ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX |
02571                         AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
02572         }
02573 
02574         return 0;
02575 }
02576 
02577 int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 mode, u8 txpower)
02578 {
02579         struct net80211_channel *channel = ah->ah_current_channel;
02580 
02581         DBG2("ath5k: changing txpower to %d\n", txpower);
02582 
02583         return ath5k_hw_txpower(ah, channel, mode, txpower);
02584 }
02585 
02586 #undef _ATH5K_PHY

Generated on Tue Apr 6 20:00:55 2010 for gPXE by  doxygen 1.5.7.1