176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * PHY functions 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com> 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org> 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Lightly modified for gPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>. 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Permission to use, copy, modify, and distribute this software for any 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * purpose with or without fee is hereby granted, provided that the above 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * copyright notice and this permission notice appear in all copies. 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2576d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( MIT ); 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define _ATH5K_PHY 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <unistd.h> 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h> 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "ath5k.h" 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "reg.h" 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "base.h" 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "rfbuffer.h" 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "rfgain.h" 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline int min(int x, int y) 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return (x < y) ? x : y; 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline int max(int x, int y) 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return (x > y) ? x : y; 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Used to modify RF Banks before writing them to AR5K_RF_BUFFER 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah, 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_rf_reg *rf_regs, 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 val, u8 reg_id, int set) 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_rf_reg *rfreg = NULL; 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 offset, bank, num_bits, col, position; 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 entry; 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 mask, data, last_bit, bits_shifted, first_bit; 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 *rfb; 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s32 bits_left; 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned i; 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = 0; 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfb = ah->ah_rf_banks; 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < ah->ah_rf_regs_count; i++) { 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (rf_regs[i].index == reg_id) { 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfreg = &rf_regs[i]; 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (rfb == NULL || rfreg == NULL) { 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("ath5k: RF register not found!\n"); 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* should not happen */ 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bank = rfreg->bank; 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman num_bits = rfreg->field.len; 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman first_bit = rfreg->field.pos; 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman col = rfreg->field.col; 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* first_bit is an offset from bank's 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * start. Since we have all banks on 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the same array, we use this offset 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to mark each bank's start */ 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman offset = ah->ah_offset[bank]; 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Boundary check */ 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) { 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("ath5k: RF invalid values at offset %d\n", offset); 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman entry = ((first_bit - 1) / 8) + offset; 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman position = (first_bit - 1) % 8; 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (set) 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = ath5k_hw_bitswap(val, num_bits); 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (bits_shifted = 0, bits_left = num_bits; bits_left > 0; 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman position = 0, entry++) { 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman last_bit = (position + bits_left > 8) ? 8 : 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman position + bits_left; 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) << 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (col * 8); 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (set) { 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfb[entry] &= ~mask; 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfb[entry] |= ((data << position) << (col * 8)) & mask; 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data >>= (8 - position); 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data |= (((rfb[entry] & mask) >> (col * 8)) >> position) 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman << bits_shifted; 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits_shifted += last_bit - position; 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits_left -= 8 - position; 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = set ? 1 : ath5k_hw_bitswap(data, num_bits); 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return data; 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**********************\ 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman* RF Gain optimization * 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman\**********************/ 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This code is used to optimize rf gain on different environments 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (temprature mostly) based on feedback from a power detector. 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * It's only used on RF5111 and RF5112, later RF chips seem to have 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * auto adjustment on hw -notice they have a much smaller BANK 7 and 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * no gain optimization ladder-. 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * For more infos check out this patent doc 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * http://www.freepatentsonline.com/7400691.html 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This paper describes power drops as seen on the receiver due to 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * probe packets 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * %20of%20Power%20Control.pdf 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * And this is the MadWiFi bug entry related to the above 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * http://madwifi-project.org/ticket/1659 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * with various measurements and diagrams 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * TODO: Deal with power drops due to probes by setting an apropriate 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * tx power on the probe packets ! Make this part of the calibration process. 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Initialize ah_gain durring attach */ 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize the gain optimization values */ 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (ah->ah_radio) { 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5111: 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default; 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_low = 20; 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_high = 35; 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5112: 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_low = 20; 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_high = 85; 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Schedule a gain probe check on the next transmited packet. 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * That means our next packet is going to be sent with lower 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * tx power and a Peak to Average Power Detector (PAPD) will try 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to measure the gain. 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * TODO: Use propper tx power setting for the probe packet so 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * that we don't observe a serious power drop on the receiver 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XXX: How about forcing a tx packet (bypassing PCU arbitrator etc) 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * just after we enable the probe so that we don't mess with 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * standard traffic ? Maybe it's time to use sw interrupts and 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a probe tasklet !!! 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Skip if gain calibration is inactive or 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * we already handle a probe request */ 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE) 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Send the packet with 2dB below max power as 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * patent doc suggest */ 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4, 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_PAPD_PROBE_TXPOWER) | 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED; 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Calculate gain_F measurement correction 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * based on the current step for RF5112 rev. 2 */ 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 mix, step; 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 *rf; 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_gain_opt *go; 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_gain_opt_step *g_step; 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_rf_reg *rf_regs; 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Only RF5112 Rev. 2 supports it */ 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((ah->ah_radio != AR5K_RF5112) || 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A)) 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman go = &rfgain_opt_5112; 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_5112a; 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a); 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman g_step = &go->go_step[ah->ah_gain.g_step_idx]; 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_rf_banks == NULL) 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf = ah->ah_rf_banks; 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_f_corr = 0; 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* No VGA (Variable Gain Amplifier) override, skip */ 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, 0) != 1) 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Mix gain stepping */ 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXGAIN_STEP, 0); 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Mix gain override */ 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mix = g_step->gos_param[0]; 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (mix) { 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 3: 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_f_corr = step * 2; 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 2: 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_f_corr = (step - 5) * 2; 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 1: 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_f_corr = step; 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_f_corr = 0; 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ah->ah_gain.g_f_corr; 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Check if current gain_F measurement is in the range of our 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * power detector windows. If we get a measurement outside range 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * we know it's not accurate (detectors can't measure anything outside 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * their detection window) so we must ignore it */ 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_rf_reg *rf_regs; 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 step, mix_ovr, level[4]; 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 *rf; 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_rf_banks == NULL) 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf = ah->ah_rf_banks; 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_radio == AR5K_RF5111) { 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_5111; 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111); 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_RFGAIN_STEP, 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0); 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman level[0] = 0; 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman level[1] = (step == 63) ? 50 : step + 4; 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman level[2] = (step != 63) ? 64 : level[0]; 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman level[3] = level[2] + 50 ; 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_high = level[3] - 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_low = level[0] + 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_5112; 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112); 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0); 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman level[0] = level[2] = 0; 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mix_ovr == 1) { 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman level[1] = level[3] = 83; 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman level[1] = level[3] = 107; 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_high = 55; 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return (ah->ah_gain.g_current >= level[0] && 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_current <= level[1]) || 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (ah->ah_gain.g_current >= level[2] && 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_current <= level[3]); 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Perform gain_F adjustment by choosing the right set 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * of parameters from rf gain optimization ladder */ 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_gain_opt *go; 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_gain_opt_step *g_step; 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ret = 0; 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (ah->ah_radio) { 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5111: 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman go = &rfgain_opt_5111; 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5112: 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman go = &rfgain_opt_5112; 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman g_step = &go->go_step[ah->ah_gain.g_step_idx]; 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_gain.g_current >= ah->ah_gain.g_high) { 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Reached maximum */ 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_gain.g_step_idx == 0) 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (ah->ah_gain.g_target = ah->ah_gain.g_current; 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_target >= ah->ah_gain.g_high && 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_step_idx > 0; 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman g_step = &go->go_step[ah->ah_gain.g_step_idx]) 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_target -= 2 * 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain - 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman g_step->gos_gain); 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = 1; 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_gain.g_current <= ah->ah_gain.g_low) { 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Reached minimum */ 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1)) 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -2; 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (ah->ah_gain.g_target = ah->ah_gain.g_current; 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_target <= ah->ah_gain.g_low && 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_step_idx < go->go_steps_count-1; 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman g_step = &go->go_step[ah->ah_gain.g_step_idx]) 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_target -= 2 * 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (go->go_step[++ah->ah_gain.g_step_idx].gos_gain - 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman g_step->gos_gain); 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = 2; 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmandone: 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2("ath5k RF adjust: ret %d, gain step %d, current gain %d, " 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "target gain %d\n", ret, ah->ah_gain.g_step_idx, 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_current, ah->ah_gain.g_target); 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Main callback for thermal rf gain calibration engine 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check for a new gain reading and schedule an adjustment 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * if needed. 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * TODO: Use sw interrupt to schedule reset if gain_F needs 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * adjustment */ 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanenum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 data, type; 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_rf_banks == NULL || 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE) 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return AR5K_RFGAIN_INACTIVE; 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* No check requested, either engine is inactive 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * or an adjustment is already requested */ 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED) 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Read the PAPD (Peak to Average Power Detector) 40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * register */ 41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE); 41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* No probe is scheduled, read gain_F measurement */ 41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) { 41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S; 41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE); 41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If tx packet is CCK correct the gain_F measurement 41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * by cck ofdm gain delta */ 41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) { 42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) 42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_current += 42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ee->ee_cck_ofdm_gain_delta; 42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_current += 42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_GAIN_CCK_PROBE_CORR; 42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Further correct gain_F measurement for 42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * RF5112A radios */ 43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { 43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rf_gainf_corr(ah); 43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_current = 43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ? 43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : 43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 0; 43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check if measurement is ok and if we need 43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to adjust gain, schedule a gain adjustment, 44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * else switch back to the acive state */ 44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ath5k_hw_rf_check_gainf_readback(ah) && 44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) && 44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rf_gainf_adjust(ah)) { 44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE; 44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; 44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmandone: 45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ah->ah_gain.g_state; 45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Write initial rf gain table to set the RF sensitivity 45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * this one works on all RF chips and has nothing to do 45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * with gain_F calibration */ 45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq) 45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_ini_rfgain *ath5k_rfg; 46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i, size; 46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (ah->ah_radio) { 46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5111: 46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_rfg = rfgain_5111; 46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size = ARRAY_SIZE(rfgain_5111); 46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5112: 46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_rfg = rfgain_5112; 46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size = ARRAY_SIZE(rfgain_5112); 47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2413: 47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_rfg = rfgain_2413; 47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size = ARRAY_SIZE(rfgain_2413); 47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2316: 47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_rfg = rfgain_2316; 47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size = ARRAY_SIZE(rfgain_2316); 47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5413: 48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_rfg = rfgain_5413; 48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size = ARRAY_SIZE(rfgain_5413); 48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2317: 48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2425: 48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_rfg = rfgain_2425; 48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size = ARRAY_SIZE(rfgain_2425); 48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (freq) { 49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_INI_RFGAIN_2GHZ: 49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_INI_RFGAIN_5GHZ: 49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < size; i++) { 50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_WAIT(i); 50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq], 50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (u32)ath5k_rfg[i].rfg_register); 50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/********************\ 51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman* RF Registers setup * 51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman\********************/ 51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Setup RF registers by writing rf buffer on hw 51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct net80211_channel *channel, 52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int mode) 52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_rf_reg *rf_regs; 52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_ini_rfbuffer *ini_rfb; 52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_gain_opt *go = NULL; 52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ath5k_gain_opt_step *g_step; 52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; 52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 ee_mode = 0; 52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 *rfb; 52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int obdb = -1, bank = -1; 53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned i; 53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (ah->ah_radio) { 53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5111: 53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_5111; 53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111); 53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ini_rfb = rfb_5111; 53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111); 53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman go = &rfgain_opt_5111; 53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5112: 54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { 54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_5112a; 54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a); 54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ini_rfb = rfb_5112a; 54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a); 54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_5112; 54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112); 54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ini_rfb = rfb_5112; 55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112); 55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman go = &rfgain_opt_5112; 55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2413: 55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_2413; 55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413); 55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ini_rfb = rfb_2413; 55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413); 55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2316: 56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_2316; 56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316); 56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ini_rfb = rfb_2316; 56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316); 56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5413: 56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_5413; 56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413); 56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ini_rfb = rfb_5413; 57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413); 57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2317: 57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_2425; 57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425); 57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ini_rfb = rfb_2317; 57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317); 57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2425: 57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rf_regs = rf_regs_2425; 58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425); 58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_mac_srev < AR5K_SREV_AR2417) { 58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ini_rfb = rfb_2425; 58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425); 58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ini_rfb = rfb_2417; 58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417); 58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If it's the first time we set rf buffer, allocate 59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ah->ah_rf_banks based on ah->ah_rf_banks_size 59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * we set above */ 59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_rf_banks == NULL) { 59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_rf_banks = malloc(sizeof(u32) * ah->ah_rf_banks_size); 59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_rf_banks == NULL) { 59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOMEM; 60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Copy values to modify them */ 60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfb = ah->ah_rf_banks; 60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < ah->ah_rf_banks_size; i++) { 60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) { 60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("ath5k: invalid RF register bank\n"); 60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Bank changed, write down the offset */ 61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (bank != ini_rfb[i].rfb_bank) { 61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bank = ini_rfb[i].rfb_bank; 61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_offset[bank] = i; 61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rfb[i] = ini_rfb[i].rfb_mode_data[mode]; 61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set Output and Driver bias current (OB/DB) */ 62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (channel->hw_value & CHANNEL_2GHZ) { 62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (channel->hw_value & CHANNEL_CCK) 62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ee_mode = AR5K_EEPROM_MODE_11B; 62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ee_mode = AR5K_EEPROM_MODE_11G; 62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* For RF511X/RF211X combination we 63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * use b_OB and b_DB parameters stored 63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * in eeprom on ee->ee_ob[ee_mode][0] 63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * For all other chips we use OB/DB for 2Ghz 63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * stored in the b/g modal section just like 63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 802.11a on ee->ee_ob[ee_mode][1] */ 63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((ah->ah_radio == AR5K_RF5111) || 63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (ah->ah_radio == AR5K_RF5112)) 63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman obdb = 0; 63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman obdb = 1; 64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb], 64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_OB_2GHZ, 1); 64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb], 64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_DB_2GHZ, 1); 64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */ 64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ((channel->hw_value & CHANNEL_5GHZ) || 65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (ah->ah_radio == AR5K_RF5111)) { 65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* For 11a, Turbo and XR we need to choose 65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OB/DB based on frequency range */ 65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ee_mode = AR5K_EEPROM_MODE_11A; 65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman obdb = channel->center_freq >= 5725 ? 3 : 65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (channel->center_freq >= 5500 ? 2 : 65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (channel->center_freq >= 5260 ? 1 : 65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (channel->center_freq > 4000 ? 0 : -1))); 65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (obdb < 0) 66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb], 66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_OB_5GHZ, 1); 66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb], 66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_DB_5GHZ, 1); 66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman g_step = &go->go_step[ah->ah_gain.g_step_idx]; 67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Bank Modifications (chip-specific) */ 67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_radio == AR5K_RF5111) { 67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set gain_F settings according to current step */ 67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (channel->hw_value & CHANNEL_OFDM) { 67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, 67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_FRAME_CTL_TX_CLIP, 68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman g_step->gos_param[0]); 68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1], 68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_90, 1); 68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2], 68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_84, 1); 68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3], 68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_RFGAIN_SEL, 1); 69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We programmed gain_F parameters, switch back 69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to active state */ 69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; 69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Bank 6/7 setup */ 69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, !ee->ee_xpd[ee_mode], 70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_XPD, 1); 70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, ee->ee_x_gain[ee_mode], 70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_XPD_GAIN, 1); 70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode], 70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_GAIN_I, 1); 70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode], 70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PLO_SEL, 1); 71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* TODO: Half/quarter channel support */ 71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_radio == AR5K_RF5112) { 71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set gain_F settings according to current step */ 71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (channel->hw_value & CHANNEL_OFDM) { 71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0], 72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_MIXGAIN_OVR, 1); 72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1], 72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_138, 1); 72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2], 72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_137, 1); 72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3], 72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_136, 1); 73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[4], 73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_132, 1); 73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[5], 73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_131, 1); 73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[6], 73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_130, 1); 73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We programmed gain_F parameters, switch back 74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to active state */ 74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; 74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Bank 6/7 setup */ 74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode], 74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_XPD_SEL, 1); 74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) { 75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Rev. 1 supports only one xpd */ 75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ee->ee_x_gain[ee_mode], 75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_XPD_GAIN, 1); 75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* TODO: Set high and low gain bits */ 75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ee->ee_x_gain[ee_mode], 76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PD_GAIN_LO, 1); 76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ee->ee_x_gain[ee_mode], 76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PD_GAIN_HI, 1); 76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Lower synth voltage on Rev 2 */ 76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 2, 76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_HIGH_VC_CP, 1); 76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 2, 77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_MID_VC_CP, 1); 77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 2, 77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_LOW_VC_CP, 1); 77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 2, 77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PUSH_UP, 1); 77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Decrease power consumption on 5213+ BaseBand */ 77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { 78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 1, 78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PAD2GND, 1); 78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 1, 78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_XB2_LVL, 1); 78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 1, 78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_XB5_LVL, 1); 78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 1, 79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_167, 1); 79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 1, 79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_166, 1); 79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode], 79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_GAIN_I, 1); 79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* TODO: Half/quarter channel support */ 80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_radio == AR5K_RF5413 && 80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman channel->hw_value & CHANNEL_2GHZ) { 80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE, 80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1); 80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set optimum value for early revisions (on pci-e chips) */ 81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_mac_srev >= AR5K_SREV_AR5424 && 81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_mac_srev < AR5K_SREV_AR5413) 81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_rfb_op(ah, rf_regs, ath5k_hw_bitswap(6, 3), 81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_PWD_ICLOBUF_2G, 1); 81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 81876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Write RF banks on hw */ 81976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < ah->ah_rf_banks_size; i++) { 82076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_WAIT(i); 82176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, rfb[i], ini_rfb[i].rfb_ctrl_register); 82276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 82376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 82476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 82576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 82676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 82776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 82876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**************************\ 82976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY/RF channel functions 83076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman\**************************/ 83176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 83276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 83376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check if a channel is supported 83476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 83576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags) 83676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 83776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check if the channel is in our supported range */ 83876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (flags & CHANNEL_2GHZ) { 83976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) && 84076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (freq <= ah->ah_capabilities.cap_range.range_2ghz_max)) 84176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 1; 84276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (flags & CHANNEL_5GHZ) 84376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) && 84476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (freq <= ah->ah_capabilities.cap_range.range_5ghz_max)) 84576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 1; 84676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 84776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 84876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 84976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 85076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 85176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Convertion needed for RF5110 85276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 85376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u32 ath5k_hw_rf5110_chan2athchan(struct net80211_channel *channel) 85476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 85576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 athchan; 85676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 85776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 85876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Convert IEEE channel/MHz to an internal channel value used 85976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * by the AR5210 chipset. This has not been verified with 86076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * newer chipsets like the AR5212A who have a completely 86176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * different RF/PHY part. 86276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 86376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman athchan = (ath5k_hw_bitswap((ath5k_freq_to_channel(channel->center_freq) 86476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman - 24) / 2, 5) << 1) 86576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | (1 << 6) | 0x1; 86676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return athchan; 86776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 86876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 86976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 87076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set channel on RF5110 87176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 87276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ath5k_hw_rf5110_channel(struct ath5k_hw *ah, 87376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel) 87476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 87576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 data; 87676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 87776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 87876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set the channel and wait 87976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 88076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = ath5k_hw_rf5110_chan2athchan(channel); 88176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER); 88276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0); 88376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mdelay(1); 88476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 88576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 88676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 88776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 88876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 88976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Convertion needed for 5111 89076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 89176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ath5k_hw_rf5111_chan2athchan(unsigned int ieee, 89276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_athchan_2ghz *athchan) 89376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 89476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int channel; 89576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 89676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Cast this value to catch negative channel numbers (>= -19) */ 89776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman channel = (int)ieee; 89876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 89976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 90076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Map 2GHz IEEE channel to 5GHz Atheros channel 90176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 90276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (channel <= 13) { 90376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman athchan->a2_athchan = 115 + channel; 90476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman athchan->a2_flags = 0x46; 90576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (channel == 14) { 90676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman athchan->a2_athchan = 124; 90776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman athchan->a2_flags = 0x44; 90876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (channel >= 15 && channel <= 26) { 90976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman athchan->a2_athchan = ((channel - 14) * 4) + 132; 91076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman athchan->a2_flags = 0x46; 91176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else 91276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 91376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 91476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 91576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 91676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 91776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 91876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set channel on 5111 91976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 92076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, 92176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel) 92276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 92376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_athchan_2ghz ath5k_channel_2ghz; 92476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int ath5k_channel = ath5k_freq_to_channel(channel->center_freq); 92576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 data0, data1, clock; 92676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ret; 92776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 92876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 92976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set the channel on the RF5111 radio 93076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 93176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = data1 = 0; 93276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 93376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (channel->hw_value & CHANNEL_2GHZ) { 93476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Map 2GHz channel to 5GHz Atheros channel ID */ 93576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_hw_rf5111_chan2athchan(ath5k_channel, 93676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &ath5k_channel_2ghz); 93776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ret) 93876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 93976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 94076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_channel = ath5k_channel_2ghz.a2_athchan; 94176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff) 94276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman << 5) | (1 << 4); 94376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 94476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 94576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ath5k_channel < 145 || !(ath5k_channel & 1)) { 94676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman clock = 1; 94776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) | 94876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (clock << 1) | (1 << 10) | 1; 94976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 95076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman clock = 0; 95176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff) 95276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman << 2) | (clock << 1) | (1 << 10) | 1; 95376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 95476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 95576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8), 95676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_BUFFER); 95776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00), 95876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_RF_BUFFER_CONTROL_3); 95976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 96076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 96176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 96276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 96376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 96476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set channel on 5112 and newer 96576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 96676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, 96776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel) 96876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 96976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 data, data0, data1, data2; 97076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 c; 97176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 97276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = data0 = data1 = data2 = 0; 97376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman c = channel->center_freq; 97476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 97576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (c < 4800) { 97676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!((c - 2224) % 5)) { 97776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ((2 * (c - 704)) - 3040) / 10; 97876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data1 = 1; 97976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (!((c - 2192) % 5)) { 98076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ((2 * (c - 672)) - 3040) / 10; 98176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data1 = 0; 98276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else 98376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 98476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 98576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); 98676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ((c - (c % 5)) != 2 || c > 5435) { 98776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(c % 20) && c >= 5120) { 98876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); 98976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data2 = ath5k_hw_bitswap(3, 2); 99076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (!(c % 10)) { 99176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8); 99276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data2 = ath5k_hw_bitswap(2, 2); 99376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (!(c % 5)) { 99476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ath5k_hw_bitswap((c - 4800) / 5, 8); 99576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data2 = ath5k_hw_bitswap(1, 2); 99676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else 99776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 99876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 99976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); 100076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data2 = ath5k_hw_bitswap(0, 2); 100176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 100276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 100376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001; 100476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 100576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER); 100676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5); 100776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 100876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 100976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 101076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 101176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 101276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set the channel on the RF2425 101376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 101476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, 101576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel) 101676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 101776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 data, data0, data2; 101876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 c; 101976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 102076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = data0 = data2 = 0; 102176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman c = channel->center_freq; 102276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 102376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (c < 4800) { 102476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ath5k_hw_bitswap((c - 2272), 8); 102576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data2 = 0; 102676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* ? 5GHz ? */ 102776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ((c - (c % 5)) != 2 || c > 5435) { 102876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(c % 20) && c < 5120) 102976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); 103076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else if (!(c % 10)) 103176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8); 103276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else if (!(c % 5)) 103376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ath5k_hw_bitswap((c - 4800) / 5, 8); 103476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 103576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 103676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data2 = ath5k_hw_bitswap(1, 2); 103776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 103876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); 103976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data2 = ath5k_hw_bitswap(0, 2); 104076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 104176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 104276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = (data0 << 4) | data2 << 2 | 0x1001; 104376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 104476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER); 104576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5); 104676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 104776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 104876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 104976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 105076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 105176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set a channel on the radio chip 105276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 105376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_channel(struct ath5k_hw *ah, struct net80211_channel *channel) 105476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 105576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ret; 105676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 105776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check bounds supported by the PHY (we don't care about regultory 105876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * restrictions at this point). Note: hw_value already has the band 105976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok() 106076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * of the band by that */ 106176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) { 106276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("ath5k: channel frequency (%d MHz) out of supported " 106376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "range\n", channel->center_freq); 106476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 106576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 106676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 106776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 106876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set the channel and wait 106976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 107076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (ah->ah_radio) { 107176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5110: 107276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_hw_rf5110_channel(ah, channel); 107376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 107476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5111: 107576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_hw_rf5111_channel(ah, channel); 107676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 107776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2425: 107876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_hw_rf2425_channel(ah, channel); 107976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 108076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 108176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_hw_rf5112_channel(ah, channel); 108276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 108376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 108476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 108576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ret) { 108676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("ath5k: setting channel failed: %s\n", strerror(ret)); 108776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 108876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 108976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 109076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set JAPAN setting for channel 14 */ 109176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (channel->center_freq == 2484) { 109276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL, 109376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_CCKTXCTL_JAPAN); 109476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 109576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL, 109676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_CCKTXCTL_WORLD); 109776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 109876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 109976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_current_channel = channel; 110076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_turbo = (channel->hw_value == CHANNEL_T ? 1 : 0); 110176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 110276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 110376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 110476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 110576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*****************\ 110676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY calibration 110776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman\*****************/ 110876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 110976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 111076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration 111176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 111276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: struct ath5k_hw pointer we are operating on 111376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @freq: the channel frequency, just used for error logging 111476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 111576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This function performs a noise floor calibration of the PHY and waits for 111676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * it to complete. Then the noise floor value is compared to some maximum 111776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * noise floor we consider valid. 111876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 111976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note that this is different from what the madwifi HAL does: it reads the 112076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * noise floor and afterwards initiates the calibration. Since the noise floor 112176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * calibration can take some time to finish, depending on the current channel 112276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * use, that avoids the occasional timeout warnings we are seeing now. 112376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 112476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * See the following link for an Atheros patent on noise floor calibration: 112576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ 112676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7 112776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 112876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XXX: Since during noise floor calibration antennas are detached according to 112976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the patent, we should stop tx queues here. 113076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 113176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint 113276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) 113376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 113476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ret; 113576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i; 113676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s32 noise_floor; 113776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 113876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 113976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Enable noise floor calibration 114076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 114176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, 114276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_AGCCTL_NF); 114376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 114476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, 114576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_AGCCTL_NF, 0, 0); 114676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 114776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ret) { 114876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("ath5k: noise floor calibration timeout (%d MHz)\n", freq); 114976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EAGAIN; 115076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 115176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 115276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Wait until the noise floor is calibrated and read the value */ 115376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 20; i > 0; i--) { 115476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mdelay(1); 115576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF); 115676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman noise_floor = AR5K_PHY_NF_RVAL(noise_floor); 115776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (noise_floor & AR5K_PHY_NF_ACTIVE) { 115876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman noise_floor = AR5K_PHY_NF_AVAL(noise_floor); 115976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 116076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (noise_floor <= AR5K_TUNE_NOISE_FLOOR) 116176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 116276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 116376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 116476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 116576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2("ath5k: noise floor %d\n", noise_floor); 116676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 116776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { 116876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("ath5k: noise floor calibration failed (%d MHz)\n", freq); 116976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EAGAIN; 117076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 117176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 117276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_noise_floor = noise_floor; 117376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 117476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 117576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 117676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 117776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 117876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Perform a PHY calibration on RF5110 117976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * -Fix BPSK/QAM Constellation (I/Q correction) 118076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * -Calculate Noise Floor 118176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 118276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, 118376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel) 118476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 118576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 phy_sig, phy_agc, phy_sat, beacon; 118676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ret; 118776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 118876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 118976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Disable beacons and RX/TX queues, wait 119076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 119176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210, 119276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); 119376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); 119476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); 119576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 119676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mdelay(2); 119776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 119876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 119976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set the channel (with AGC turned off) 120076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 120176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); 120276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(10); 120376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_hw_channel(ah, channel); 120476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 120576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 120676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Activate PHY and wait 120776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 120876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); 120976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mdelay(1); 121076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 121176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); 121276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 121376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ret) 121476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 121576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 121676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 121776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Calibrate the radio chip 121876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 121976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 122076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Remember normal state */ 122176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG); 122276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE); 122376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT); 122476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 122576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Update radio registers */ 122676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) | 122776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG); 122876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 122976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI | 123076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_AGCCOARSE_LO)) | 123176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) | 123276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE); 123376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 123476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT | 123576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_ADCSAT_THR)) | 123676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) | 123776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT); 123876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 123976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(20); 124076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 124176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); 124276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(10); 124376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG); 124476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); 124576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 124676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mdelay(1); 124776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 124876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 124976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Enable calibration and wait until completion 125076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 125176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL); 125276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 125376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, 125476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_AGCCTL_CAL, 0, 0); 125576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 125676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Reset to normal state */ 125776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG); 125876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE); 125976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT); 126076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 126176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ret) { 126276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("ath5k: calibration timeout (%d MHz)\n", 126376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman channel->center_freq); 126476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 126576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 126676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 126776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_noise_floor_calibration(ah, channel->center_freq); 126876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 126976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 127076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Re-enable RX/TX and beacons 127176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 127276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210, 127376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); 127476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210); 127576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 127676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 127776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 127876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 127976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 128076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Perform a PHY calibration on RF5111/5112 and newer chips 128176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 128276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, 128376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel) 128476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 128576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 i_pwr, q_pwr; 128676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; 128776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 128876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 128976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!ah->ah_calibration || 129076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) 129176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 129276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 129376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Calibration has finished, get the results and re-run */ 129476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i <= 10; i++) { 129576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); 129676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); 129776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); 129876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 129976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 130076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; 130176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman q_coffd = q_pwr >> 7; 130276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 130376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* No correction */ 130476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (i_coffd == 0 || q_coffd == 0) 130576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 130676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 130776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i_coff = ((-iq_corr) / i_coffd) & 0x3f; 130876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 130976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Boundary check */ 131076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (i_coff > 31) 131176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i_coff = 31; 131276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (i_coff < -32) 131376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i_coff = -32; 131476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 131576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f; 131676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 131776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Boundary check */ 131876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (q_coff > 15) 131976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman q_coff = 15; 132076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (q_coff < -16) 132176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman q_coff = -16; 132276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 132376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Commit new I/Q value */ 132476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | 132576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); 132676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 132776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Re-enable calibration -if we don't we'll commit 132876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the same values again and again */ 132976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, 133076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); 133176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN); 133276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 133376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmandone: 133476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 133576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* TODO: Separate noise floor calibration from I/Q calibration 133676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * since noise floor calibration interrupts rx path while I/Q 133776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * calibration doesn't. We don't need to run noise floor calibration 133876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * as often as I/Q calibration.*/ 133976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_noise_floor_calibration(ah, channel->center_freq); 134076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 134176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initiate a gain_F calibration */ 134276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_request_rfgain_probe(ah); 134376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 134476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 134576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 134676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 134776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 134876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Perform a PHY calibration 134976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 135076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_phy_calibrate(struct ath5k_hw *ah, 135176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel) 135276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 135376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ret; 135476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 135576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_radio == AR5K_RF5110) 135676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_hw_rf5110_calibrate(ah, channel); 135776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 135876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_hw_rf511x_calibrate(ah, channel); 135976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 136076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 136176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 136276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 136376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_phy_disable(struct ath5k_hw *ah) 136476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 136576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); 136676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 136776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 136876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 136976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 137076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/********************\ 137176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Misc PHY functions 137276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman\********************/ 137376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 137476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 137576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Get the PHY Chip revision 137676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 137776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanu16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) 137876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 137976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i; 138076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 srev; 138176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 ret; 138276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 138376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 138476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set the radio chip access register 138576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 138676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (chan) { 138776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHANNEL_2GHZ: 138876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0)); 138976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 139076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHANNEL_5GHZ: 139176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); 139276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 139376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 139476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 139576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 139676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 139776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mdelay(2); 139876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 139976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* ...wait until PHY is ready and read the selected radio revision */ 140076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34)); 140176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 140276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < 8; i++) 140376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20)); 140476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 140576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version == AR5K_AR5210) { 140676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf; 140776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = (u16)ath5k_hw_bitswap(srev, 4) + 1; 140876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 140976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff; 141076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) | 141176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((srev & 0x0f) << 4), 8); 141276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 141376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 141476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Reset to the 5GHz mode */ 141576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); 141676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 141776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 141876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 141976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 142076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid /*TODO:Boundary check*/ 142176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant) 142276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 142376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version != AR5K_AR5210) 142476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA); 142576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 142676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 142776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanunsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah) 142876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 142976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version != AR5K_AR5210) 143076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); 143176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 143276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; /*XXX: What do we return for 5210 ?*/ 143376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 143476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 143576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 143676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/****************\ 143776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman* TX power setup * 143876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman\****************/ 143976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 144076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 144176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Helper functions 144276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 144376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 144476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 144576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Do linear interpolation between two given (x, y) points 144676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 144776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic s16 144876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right, 144976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 y_left, s16 y_right) 145076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 145176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 ratio, result; 145276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 145376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Avoid divide by zero and skip interpolation 145476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * if we have the same point */ 145576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((x_left == x_right) || (y_left == y_right)) 145676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return y_left; 145776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 145876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 145976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Since we use ints and not fps, we need to scale up in 146076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * order to get a sane ratio value (or else we 'll eg. get 146176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * always 1 instead of 1.25, 1.75 etc). We scale up by 100 146276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to have some accuracy both for 0.5 and 0.25 steps. 146376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 146476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left)); 146576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 146676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Now scale down to be in range */ 146776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman result = y_left + (ratio * (target - x_left) / 100); 146876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 146976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return result; 147076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 147176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 147276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 147376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Find vertical boundary (min pwr) for the linear PCDAC curve. 147476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 147576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Since we have the top of the curve and we draw the line below 147676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * until we reach 1 (1 pcdac step) we need to know which point 147776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (x value) that is so that we don't go below y axis and have negative 147876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pcdac values when creating the curve, or fill the table with zeroes. 147976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 148076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic s16 148176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, 148276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const s16 *pwrL, const s16 *pwrR) 148376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 148476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s8 tmp; 148576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 min_pwrL, min_pwrR; 148676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 pwr_i; 148776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 148876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pwrL[0] == pwrL[1]) 148976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_pwrL = pwrL[0]; 149076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else { 149176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_i = pwrL[0]; 149276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 149376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_i--; 149476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tmp = (s8) ath5k_get_interpolated_value(pwr_i, 149576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwrL[0], pwrL[1], 149676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman stepL[0], stepL[1]); 149776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (tmp > 1); 149876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 149976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_pwrL = pwr_i; 150076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 150176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 150276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pwrR[0] == pwrR[1]) 150376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_pwrR = pwrR[0]; 150476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else { 150576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_i = pwrR[0]; 150676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 150776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_i--; 150876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tmp = (s8) ath5k_get_interpolated_value(pwr_i, 150976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwrR[0], pwrR[1], 151076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman stepR[0], stepR[1]); 151176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (tmp > 1); 151276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 151376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_pwrR = pwr_i; 151476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 151576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 151676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Keep the right boundary so that it works for both curves */ 151776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return max(min_pwrL, min_pwrR); 151876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 151976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 152076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 152176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Interpolate (pwr,vpd) points to create a Power to PDADC or a 152276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Power to PCDAC curve. 152376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 152476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Each curve has power on x axis (in 0.5dB units) and PCDAC/PDADC 152576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * steps (offsets) on y axis. Power can go up to 31.5dB and max 152676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * PCDAC/PDADC step for each curve is 64 but we can write more than 152776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * one curves on hw so we can go up to 128 (which is the max step we 152876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * can write on the final table). 152976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 153076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * We write y values (PCDAC/PDADC steps) on hw. 153176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 153276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 153376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_create_power_curve(s16 pmin, s16 pmax, 153476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const s16 *pwr, const u8 *vpd, 153576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 num_points, 153676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *vpd_table, u8 type) 153776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 153876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 idx[2] = { 0, 1 }; 153976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 pwr_i = 2*pmin; 154076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 154176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 154276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (num_points < 2) 154376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 154476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 154576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We want the whole line, so adjust boundaries 154676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to cover the entire power range. Note that 154776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * power values are already 0.25dB so no need 154876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to multiply pwr_i by 2 */ 154976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (type == AR5K_PWRTABLE_LINEAR_PCDAC) { 155076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_i = pmin; 155176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pmin = 0; 155276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pmax = 63; 155376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 155476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 155576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Find surrounding turning points (TPs) 155676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and interpolate between them */ 155776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; (i <= (u16) (pmax - pmin)) && 155876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) { 155976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 156076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We passed the right TP, move to the next set of TPs 156176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * if we pass the last TP, extrapolate above using the last 156276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * two TPs for ratio */ 156376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((pwr_i > pwr[idx[1]]) && (idx[1] < num_points - 1)) { 156476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx[0]++; 156576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx[1]++; 156676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 156776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 156876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman vpd_table[i] = (u8) ath5k_get_interpolated_value(pwr_i, 156976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr[idx[0]], pwr[idx[1]], 157076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman vpd[idx[0]], vpd[idx[1]]); 157176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 157276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Increase by 0.5dB 157376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (0.25 dB units) */ 157476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_i += 2; 157576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 157676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 157776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 157876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 157976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Get the surrounding per-channel power calibration piers 158076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * for a given frequency so that we can interpolate between 158176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * them and come up with an apropriate dataset for our current 158276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * channel. 158376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 158476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 158576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah, 158676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel, 158776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_chan_pcal_info **pcinfo_l, 158876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_chan_pcal_info **pcinfo_r) 158976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 159076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; 159176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_chan_pcal_info *pcinfo; 159276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 idx_l, idx_r; 159376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 mode, max, i; 159476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 target = channel->center_freq; 159576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 159676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_l = 0; 159776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_r = 0; 159876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 159976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(channel->hw_value & CHANNEL_OFDM)) { 160076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcinfo = ee->ee_pwr_cal_b; 160176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mode = AR5K_EEPROM_MODE_11B; 160276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (channel->hw_value & CHANNEL_2GHZ) { 160376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcinfo = ee->ee_pwr_cal_g; 160476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mode = AR5K_EEPROM_MODE_11G; 160576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 160676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcinfo = ee->ee_pwr_cal_a; 160776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mode = AR5K_EEPROM_MODE_11A; 160876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 160976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max = ee->ee_n_piers[mode] - 1; 161076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 161176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Frequency is below our calibrated 161276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * range. Use the lowest power curve 161376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * we have */ 161476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (target < pcinfo[0].freq) { 161576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_l = idx_r = 0; 161676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 161776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 161876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 161976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Frequency is above our calibrated 162076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * range. Use the highest power curve 162176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * we have */ 162276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (target > pcinfo[max].freq) { 162376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_l = idx_r = max; 162476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 162576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 162676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 162776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Frequency is inside our calibrated 162876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * channel range. Pick the surrounding 162976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * calibration piers so that we can 163076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * interpolate */ 163176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i <= max; i++) { 163276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 163376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Frequency matches one of our calibration 163476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * piers, no need to interpolate, just use 163576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * that calibration pier */ 163676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pcinfo[i].freq == target) { 163776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_l = idx_r = i; 163876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 163976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 164076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 164176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We found a calibration pier that's above 164276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * frequency, use this pier and the previous 164376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * one to interpolate */ 164476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (target < pcinfo[i].freq) { 164576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_r = i; 164676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_l = idx_r - 1; 164776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 164876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 164976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 165076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 165176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmandone: 165276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *pcinfo_l = &pcinfo[idx_l]; 165376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *pcinfo_r = &pcinfo[idx_r]; 165476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 165576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 165676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 165776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 165876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 165976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Get the surrounding per-rate power calibration data 166076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * for a given frequency and interpolate between power 166176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * values to set max target power supported by hw for 166276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * each rate. 166376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 166476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 166576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_get_rate_pcal_data(struct ath5k_hw *ah, 166676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel, 166776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_rate_pcal_info *rates) 166876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 166976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; 167076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_rate_pcal_info *rpinfo; 167176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 idx_l, idx_r; 167276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 mode, max, i; 167376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 target = channel->center_freq; 167476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 167576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_l = 0; 167676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_r = 0; 167776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 167876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(channel->hw_value & CHANNEL_OFDM)) { 167976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo = ee->ee_rate_tpwr_b; 168076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mode = AR5K_EEPROM_MODE_11B; 168176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (channel->hw_value & CHANNEL_2GHZ) { 168276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo = ee->ee_rate_tpwr_g; 168376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mode = AR5K_EEPROM_MODE_11G; 168476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 168576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo = ee->ee_rate_tpwr_a; 168676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mode = AR5K_EEPROM_MODE_11A; 168776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 168876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max = ee->ee_rate_target_pwr_num[mode] - 1; 168976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 169076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Get the surrounding calibration 169176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * piers - same as above */ 169276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (target < rpinfo[0].freq) { 169376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_l = idx_r = 0; 169476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 169576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 169676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 169776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (target > rpinfo[max].freq) { 169876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_l = idx_r = max; 169976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 170076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 170176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 170276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i <= max; i++) { 170376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 170476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (rpinfo[i].freq == target) { 170576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_l = idx_r = i; 170676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 170776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 170876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 170976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (target < rpinfo[i].freq) { 171076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_r = i; 171176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman idx_l = idx_r - 1; 171276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 171376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 171476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 171576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 171676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmandone: 171776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Now interpolate power value, based on the frequency */ 171876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates->freq = target; 171976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 172076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates->target_power_6to24 = 172176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, 172276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_r].freq, 172376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_l].target_power_6to24, 172476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_r].target_power_6to24); 172576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 172676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates->target_power_36 = 172776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, 172876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_r].freq, 172976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_l].target_power_36, 173076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_r].target_power_36); 173176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 173276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates->target_power_48 = 173376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, 173476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_r].freq, 173576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_l].target_power_48, 173676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_r].target_power_48); 173776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 173876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates->target_power_54 = 173976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, 174076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_r].freq, 174176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_l].target_power_54, 174276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rpinfo[idx_r].target_power_54); 174376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 174476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 174576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 174676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Get the max edge power for this channel if 174776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * we have such data from EEPROM's Conformance Test 174876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Limits (CTL), and limit max power if needed. 174976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 175076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * FIXME: Only works for world regulatory domains 175176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 175276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 175376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_get_max_ctl_power(struct ath5k_hw *ah, 175476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel) 175576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 175676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; 175776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_edge_power *rep = ee->ee_ctl_pwr; 175876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *ctl_val = ee->ee_ctl; 175976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 max_chan_pwr = ah->ah_txpower.txp_max_pwr / 4; 176076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 edge_pwr = 0; 176176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 rep_idx; 176276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 i, ctl_mode; 176376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 ctl_idx = 0xFF; 176476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 target = channel->center_freq; 176576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 176676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Find out a CTL for our mode that's not mapped 176776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * on a specific reg domain. 176876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 176976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * TODO: Map our current reg domain to one of the 3 available 177076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * reg domain ids so that we can support more CTLs. */ 177176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (channel->hw_value & CHANNEL_MODES) { 177276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHANNEL_A: 177376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN; 177476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 177576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHANNEL_G: 177676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN; 177776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 177876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHANNEL_B: 177976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN; 178076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 178176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHANNEL_T: 178276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN; 178376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 178476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHANNEL_TG: 178576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN; 178676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 178776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHANNEL_XR: 178876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fall through */ 178976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 179076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 179176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 179276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 179376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < ee->ee_ctls; i++) { 179476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ctl_val[i] == ctl_mode) { 179576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctl_idx = i; 179676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 179776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 179876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 179976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 180076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If we have a CTL dataset available grab it and find the 180176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * edge power for our frequency */ 180276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ctl_idx == 0xFF) 180376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 180476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 180576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Edge powers are sorted by frequency from lower 180676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to higher. Each CTL corresponds to 8 edge power 180776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * measurements. */ 180876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rep_idx = ctl_idx * AR5K_EEPROM_N_EDGES; 180976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 181076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Don't do boundaries check because we 181176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * might have more that one bands defined 181276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * for this mode */ 181376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 181476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Get the edge power that's closer to our 181576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * frequency */ 181676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < AR5K_EEPROM_N_EDGES; i++) { 181776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rep_idx += i; 181876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (target <= rep[rep_idx].freq) 181976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman edge_pwr = (s16) rep[rep_idx].edge; 182076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 182176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 182276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (edge_pwr) { 182376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr); 182476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 182576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 182676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 182776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 182876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 182976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Power to PCDAC table functions 183076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 183176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 183276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 183376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Fill Power to PCDAC table on RF5111 183476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 183576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * No further processing is needed for RF5111, the only thing we have to 183676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * do is fill the values below and above calibration range since eeprom data 183776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * may not cover the entire PCDAC table. 183876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 183976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 184076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min, 184176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 *table_max) 184276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 184376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pcdac_out = ah->ah_txpower.txp_pd_table; 184476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pcdac_tmp = ah->ah_txpower.tmpL[0]; 184576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 pcdac_0, pcdac_n, pcdac_i, pwr_idx, i; 184676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 min_pwr, max_pwr; 184776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 184876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Get table boundaries */ 184976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_pwr = table_min[0]; 185076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_0 = pcdac_tmp[0]; 185176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 185276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_pwr = table_max[0]; 185376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_n = pcdac_tmp[table_max[0] - table_min[0]]; 185476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 185576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Extrapolate below minimum using pcdac_0 */ 185676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_i = 0; 185776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < min_pwr; i++) 185876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_out[pcdac_i++] = pcdac_0; 185976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 186076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Copy values from pcdac_tmp */ 186176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_idx = min_pwr; 186276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0 ; pwr_idx <= max_pwr && 186376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) { 186476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_out[pcdac_i++] = pcdac_tmp[i]; 186576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_idx++; 186676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 186776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 186876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Extrapolate above maximum */ 186976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE) 187076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_out[pcdac_i++] = pcdac_n; 187176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 187276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 187376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 187476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 187576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Combine available XPD Curves and fill Linear Power to PCDAC table 187676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * on RF5112 187776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 187876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * RFX112 can have up to 2 curves (one for low txpower range and one for 187976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * higher txpower range). We need to put them both on pcdac_out and place 188076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * them in the correct location. In case we only have one curve available 188176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * just fit it on pcdac_out (it's supposed to cover the entire range of 188276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * available pwr levels since it's always the higher power curve). Extrapolate 188376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * below and above final table if needed. 188476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 188576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 188676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, 188776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 *table_max, u8 pdcurves) 188876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 188976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pcdac_out = ah->ah_txpower.txp_pd_table; 189076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pcdac_low_pwr; 189176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pcdac_high_pwr; 189276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pcdac_tmp; 189376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 pwr; 189476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 max_pwr_idx; 189576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 min_pwr_idx; 189676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 mid_pwr_idx = 0; 189776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Edge flag turs on the 7nth bit on the PCDAC 189876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to delcare the higher power curve (force values 189976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to be greater than 64). If we only have one curve 190076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * we don't need to set this, if we have 2 curves and 190176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * fill the table backwards this can also be used to 190276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * switch from higher power curve to lower power curve */ 190376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 edge_flag; 190476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 190576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 190676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* When we have only one curve available 190776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * that's the higher power curve. If we have 190876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * two curves the first is the high power curve 190976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and the next is the low power curve. */ 191076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pdcurves > 1) { 191176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_low_pwr = ah->ah_txpower.tmpL[1]; 191276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_high_pwr = ah->ah_txpower.tmpL[0]; 191376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mid_pwr_idx = table_max[1] - table_min[1] - 1; 191476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_pwr_idx = (table_max[0] - table_min[0]) / 2; 191576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 191676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If table size goes beyond 31.5dB, keep the 191776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * upper 31.5dB range when setting tx power. 191876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note: 126 = 31.5 dB in quarter dB steps */ 191976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (table_max[0] - table_min[1] > 126) 192076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_pwr_idx = table_max[0] - 126; 192176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 192276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_pwr_idx = table_min[1]; 192376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 192476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Since we fill table backwards 192576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * start from high power curve */ 192676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_tmp = pcdac_high_pwr; 192776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 192876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman edge_flag = 0x40; 192976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 193076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */ 193176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_high_pwr = ah->ah_txpower.tmpL[0]; 193276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_pwr_idx = table_min[0]; 193376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_pwr_idx = (table_max[0] - table_min[0]) / 2; 193476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_tmp = pcdac_high_pwr; 193576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman edge_flag = 0; 193676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 193776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 193876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* This is used when setting tx power*/ 193976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_min_idx = min_pwr_idx/2; 194076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 194176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fill Power to PCDAC table backwards */ 194276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr = max_pwr_idx; 194376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 63; i >= 0; i--) { 194476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Entering lower power range, reset 194576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * edge flag and set pcdac_tmp to lower 194676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * power curve.*/ 194776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (edge_flag == 0x40 && 194876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) { 194976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman edge_flag = 0x00; 195076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_tmp = pcdac_low_pwr; 195176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr = mid_pwr_idx/2; 195276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 195376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 195476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Don't go below 1, extrapolate below if we have 195576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * already swithced to the lower power curve -or 195676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * we only have one curve and edge_flag is zero 195776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * anyway */ 195876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) { 195976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (i >= 0) { 196076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_out[i] = pcdac_out[i + 1]; 196176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i--; 196276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 196376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 196476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 196576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 196676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_out[i] = pcdac_tmp[pwr] | edge_flag; 196776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 196876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Extrapolate above if pcdac is greater than 196976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 126 -this can happen because we OR pcdac_out 197076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * value with edge_flag on high power curve */ 197176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pcdac_out[i] > 126) 197276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcdac_out[i] = 126; 197376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 197476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Decrease by a 0.5dB step */ 197576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr--; 197676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 197776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 197876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 197976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Write PCDAC values on hw */ 198076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 198176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_setup_pcdac_table(struct ath5k_hw *ah) 198276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 198376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pcdac_out = ah->ah_txpower.txp_pd_table; 198476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 198576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 198676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 198776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write TX power values 198876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 198976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { 199076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 199176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) | 199276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16), 199376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_PCDAC_TXPOWER(i)); 199476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 199576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 199676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 199776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 199876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 199976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Power to PDADC table functions 200076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 200176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 200276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 200376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set the gain boundaries and create final Power to PDADC table 200476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 200576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * We can have up to 4 pd curves, we need to do a simmilar process 200676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * as we do for RF5112. This time we don't have an edge_flag but we 200776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * set the gain boundaries on a separate register. 200876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 200976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 201076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, 201176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 *pwr_min, s16 *pwr_max, u8 pdcurves) 201276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 201376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 gain_boundaries[AR5K_EEPROM_N_PD_GAINS]; 201476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pdadc_out = ah->ah_txpower.txp_pd_table; 201576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pdadc_tmp; 201676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 pdadc_0; 201776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 pdadc_i, pdadc_n, pwr_step, pdg, max_idx, table_size; 201876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 pd_gain_overlap; 201976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 202076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Note: Register value is initialized on initvals 202176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * there is no feedback from hw. 202276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XXX: What about pd_gain_overlap from EEPROM ? */ 202376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pd_gain_overlap = (u8) ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) & 202476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP; 202576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 202676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Create final PDADC table */ 202776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (pdg = 0, pdadc_i = 0; pdg < pdcurves; pdg++) { 202876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_tmp = ah->ah_txpower.tmpL[pdg]; 202976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 203076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pdg == pdcurves - 1) 203176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 2 dB boundary stretch for last 203276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (higher power) curve */ 203376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gain_boundaries[pdg] = pwr_max[pdg] + 4; 203476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 203576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set gain boundary in the middle 203676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * between this curve and the next one */ 203776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gain_boundaries[pdg] = 203876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (pwr_max[pdg] + pwr_min[pdg + 1]) / 2; 203976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 204076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Sanity check in case our 2 db stretch got out of 204176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * range. */ 204276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (gain_boundaries[pdg] > AR5K_TUNE_MAX_TXPOWER) 204376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gain_boundaries[pdg] = AR5K_TUNE_MAX_TXPOWER; 204476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 204576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* For the first curve (lower power) 204676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * start from 0 dB */ 204776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pdg == 0) 204876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_0 = 0; 204976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 205076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* For the other curves use the gain overlap */ 205176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_0 = (gain_boundaries[pdg - 1] - pwr_min[pdg]) - 205276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pd_gain_overlap; 205376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 205476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Force each power step to be at least 0.5 dB */ 205576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1) 205676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_step = pdadc_tmp[1] - pdadc_tmp[0]; 205776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 205876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_step = 1; 205976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 206076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If pdadc_0 is negative, we need to extrapolate 206176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * below this pdgain by a number of pwr_steps */ 206276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while ((pdadc_0 < 0) && (pdadc_i < 128)) { 206376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 tmp = pdadc_tmp[0] + pdadc_0 * pwr_step; 206476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_out[pdadc_i++] = (tmp < 0) ? 0 : (u8) tmp; 206576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_0++; 206676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 206776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 206876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set last pwr level, using gain boundaries */ 206976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_n = gain_boundaries[pdg] + pd_gain_overlap - pwr_min[pdg]; 207076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Limit it to be inside pwr range */ 207176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman table_size = pwr_max[pdg] - pwr_min[pdg]; 207276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_idx = (pdadc_n < table_size) ? pdadc_n : table_size; 207376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 207476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fill pdadc_out table */ 207576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (pdadc_0 < max_idx) 207676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++]; 207776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 207876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Need to extrapolate above this pdgain? */ 207976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pdadc_n <= max_idx) 208076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 208176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 208276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Force each power step to be at least 0.5 dB */ 208376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1) 208476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_step = pdadc_tmp[table_size - 1] - 208576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_tmp[table_size - 2]; 208676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 208776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pwr_step = 1; 208876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 208976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Extrapolate above */ 209076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while ((pdadc_0 < (s16) pdadc_n) && 209176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2)) { 209276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 tmp = pdadc_tmp[table_size - 1] + 209376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (pdadc_0 - max_idx) * pwr_step; 209476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_out[pdadc_i++] = (tmp > 127) ? 127 : (u8) tmp; 209576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_0++; 209676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 209776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 209876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 209976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (pdg < AR5K_EEPROM_N_PD_GAINS) { 210076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gain_boundaries[pdg] = gain_boundaries[pdg - 1]; 210176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg++; 210276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 210376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 210476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2) { 210576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_out[pdadc_i] = pdadc_out[pdadc_i - 1]; 210676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdadc_i++; 210776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 210876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 210976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set gain boundaries */ 211076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 211176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(pd_gain_overlap, 211276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) | 211376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(gain_boundaries[0], 211476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) | 211576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(gain_boundaries[1], 211676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) | 211776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(gain_boundaries[2], 211876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) | 211976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(gain_boundaries[3], 212076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4), 212176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_TPC_RG5); 212276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 212376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Used for setting rate power table */ 212476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_min_idx = pwr_min[0]; 212576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 212676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 212776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 212876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Write PDADC values on hw */ 212976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 213076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_setup_pwr_to_pdadc_table(struct ath5k_hw *ah, 213176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 pdcurves, u8 *pdg_to_idx) 213276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 213376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pdadc_out = ah->ah_txpower.txp_pd_table; 213476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 reg; 213576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 i; 213676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 213776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Select the right pdgain curves */ 213876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 213976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Clear current settings */ 214076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1); 214176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 | 214276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_TPC_RG1_PDGAIN_2 | 214376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_TPC_RG1_PDGAIN_3 | 214476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_TPC_RG1_NUM_PD_GAIN); 214576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 214676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 214776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Use pd_gains curve from eeprom 214876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 214976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This overrides the default setting from initvals 215076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * in case some vendors (e.g. Zcomax) don't use the default 215176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * curves. If we don't honor their settings we 'll get a 215276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 5dB (1 * gain overlap ?) drop. 215376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 215476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= AR5K_REG_SM(pdcurves, AR5K_PHY_TPC_RG1_NUM_PD_GAIN); 215576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 215676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (pdcurves) { 215776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 3: 215876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3); 215976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fall through */ 216076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 2: 216176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2); 216276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fall through */ 216376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 1: 216476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1); 216576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 216676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 216776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1); 216876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 216976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 217076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write TX power values 217176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 217276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { 217376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 217476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((pdadc_out[4*i + 0] & 0xff) << 0) | 217576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((pdadc_out[4*i + 1] & 0xff) << 8) | 217676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((pdadc_out[4*i + 2] & 0xff) << 16) | 217776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((pdadc_out[4*i + 3] & 0xff) << 24), 217876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_PHY_PDADC_TXPOWER(i)); 217976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 218076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 218176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 218276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 218376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 218476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Common code for PCDAC/PDADC tables 218576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 218676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 218776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 218876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is the main function that uses all of the above 218976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to set PCDAC/PDADC table on hw for the current channel. 219076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This table is used for tx power calibration on the basband, 219176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * without it we get weird tx power levels and in some cases 219276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * distorted spectral mask 219376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 219476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int 219576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_setup_channel_powertable(struct ath5k_hw *ah, 219676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel, 219776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 ee_mode, u8 type) 219876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 219976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_pdgain_info *pdg_L, *pdg_R; 220076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_chan_pcal_info *pcinfo_L; 220176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_chan_pcal_info *pcinfo_R; 220276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; 220376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode]; 220476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 table_min[AR5K_EEPROM_N_PD_GAINS]; 220576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman s16 table_max[AR5K_EEPROM_N_PD_GAINS]; 220676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *tmpL; 220776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 *tmpR; 220876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 target = channel->center_freq; 220976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int pdg, i; 221076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 221176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Get surounding freq piers for this channel */ 221276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_get_chan_pcal_surrounding_piers(ah, channel, 221376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &pcinfo_L, 221476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &pcinfo_R); 221576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 221676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Loop over pd gain curves on 221776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * surounding freq piers by index */ 221876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) { 221976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 222076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fill curves in reverse order 222176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * from lower power (max gain) 222276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to higher power. Use curve -> idx 222376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * backmaping we did on eeprom init */ 222476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 idx = pdg_curve_to_idx[pdg]; 222576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 222676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Grab the needed curves by index */ 222776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_L = &pcinfo_L->pd_curves[idx]; 222876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_R = &pcinfo_R->pd_curves[idx]; 222976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 223076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize the temp tables */ 223176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tmpL = ah->ah_txpower.tmpL[pdg]; 223276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tmpR = ah->ah_txpower.tmpR[pdg]; 223376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 223476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set curve's x boundaries and create 223576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * curves so that they cover the same 223676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * range (if we don't do that one table 223776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * will have values on some range and the 223876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * other one won't have any so interpolation 223976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * will fail) */ 224076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman table_min[pdg] = min(pdg_L->pd_pwr[0], 224176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_R->pd_pwr[0]) / 2; 224276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 224376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman table_max[pdg] = max(pdg_L->pd_pwr[pdg_L->pd_points - 1], 224476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_R->pd_pwr[pdg_R->pd_points - 1]) / 2; 224576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 224676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Now create the curves on surrounding channels 224776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and interpolate if needed to get the final 224876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * curve for this gain on this channel */ 224976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (type) { 225076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_PWRTABLE_LINEAR_PCDAC: 225176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Override min/max so that we don't loose 225276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * accuracy (don't divide by 2) */ 225376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman table_min[pdg] = min(pdg_L->pd_pwr[0], 225476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_R->pd_pwr[0]); 225576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 225676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman table_max[pdg] = 225776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max(pdg_L->pd_pwr[pdg_L->pd_points - 1], 225876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_R->pd_pwr[pdg_R->pd_points - 1]); 225976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 226076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Override minimum so that we don't get 226176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * out of bounds while extrapolating 226276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * below. Don't do this when we have 2 226376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * curves and we are on the high power curve 226476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * because table_min is ok in this case */ 226576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(ee->ee_pd_gains[ee_mode] > 1 && pdg == 0)) { 226676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 226776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman table_min[pdg] = 226876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_get_linear_pcdac_min(pdg_L->pd_step, 226976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_R->pd_step, 227076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_L->pd_pwr, 227176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_R->pd_pwr); 227276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 227376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Don't go too low because we will 227476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * miss the upper part of the curve. 227576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note: 126 = 31.5dB (max power supported) 227676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * in 0.25dB units */ 227776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (table_max[pdg] - table_min[pdg] > 126) 227876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman table_min[pdg] = table_max[pdg] - 126; 227976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 228076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 228176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fall through */ 228276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_PWRTABLE_PWR_TO_PCDAC: 228376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_PWRTABLE_PWR_TO_PDADC: 228476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 228576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_create_power_curve(table_min[pdg], 228676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman table_max[pdg], 228776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_L->pd_pwr, 228876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_L->pd_step, 228976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_L->pd_points, tmpL, type); 229076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 229176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We are in a calibration 229276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pier, no need to interpolate 229376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * between freq piers */ 229476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pcinfo_L == pcinfo_R) 229576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 229676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 229776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_create_power_curve(table_min[pdg], 229876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman table_max[pdg], 229976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_R->pd_pwr, 230076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_R->pd_step, 230176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pdg_R->pd_points, tmpR, type); 230276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 230376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 230476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 230576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 230676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 230776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Interpolate between curves 230876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * of surounding freq piers to 230976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * get the final curve for this 231076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pd gain. Re-use tmpL for interpolation 231176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * output */ 231276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; (i < (u16) (table_max[pdg] - table_min[pdg])) && 231376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) { 231476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tmpL[i] = (u8) ath5k_get_interpolated_value(target, 231576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (s16) pcinfo_L->freq, 231676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (s16) pcinfo_R->freq, 231776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (s16) tmpL[i], 231876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (s16) tmpR[i]); 231976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 232076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 232176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 232276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Now we have a set of curves for this 232376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * channel on tmpL (x range is table_max - table_min 232476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and y values are tmpL[pdg][]) sorted in the same 232576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * order as EEPROM (because we've used the backmaping). 232676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * So for RF5112 it's from higher power to lower power 232776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and for RF2413 it's from lower power to higher power. 232876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * For RF5111 we only have one curve. */ 232976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 233076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fill min and max power levels for this 233176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * channel by interpolating the values on 233276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * surounding channels to complete the dataset */ 233376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target, 233476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (s16) pcinfo_L->freq, 233576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (s16) pcinfo_R->freq, 233676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcinfo_L->min_pwr, pcinfo_R->min_pwr); 233776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 233876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_max_pwr = ath5k_get_interpolated_value(target, 233976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (s16) pcinfo_L->freq, 234076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (s16) pcinfo_R->freq, 234176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pcinfo_L->max_pwr, pcinfo_R->max_pwr); 234276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 234376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We are ready to go, fill PCDAC/PDADC 234476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * table and write settings on hardware */ 234576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (type) { 234676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_PWRTABLE_LINEAR_PCDAC: 234776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* For RF5112 we can have one or two curves 234876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and each curve covers a certain power lvl 234976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * range so we need to do some more processing */ 235076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_combine_linear_pcdac_curves(ah, table_min, table_max, 235176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ee->ee_pd_gains[ee_mode]); 235276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 235376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set txp.offset so that we can 235476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * match max power value with max 235576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * table index */ 235676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2); 235776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 235876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Write settings on hw */ 235976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_setup_pcdac_table(ah); 236076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 236176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_PWRTABLE_PWR_TO_PCDAC: 236276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We are done for RF5111 since it has only 236376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * one curve, just fit the curve on the table */ 236476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_fill_pwr_to_pcdac_table(ah, table_min, table_max); 236576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 236676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* No rate powertable adjustment for RF5111 */ 236776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_min_idx = 0; 236876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_offset = 0; 236976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 237076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Write settings on hw */ 237176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_setup_pcdac_table(ah); 237276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 237376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_PWRTABLE_PWR_TO_PDADC: 237476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set PDADC boundaries and fill 237576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * final PDADC table */ 237676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max, 237776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ee->ee_pd_gains[ee_mode]); 237876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 237976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Write settings on hw */ 238076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_setup_pwr_to_pdadc_table(ah, pdg, pdg_curve_to_idx); 238176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 238276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set txp.offset, note that table_min 238376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * can be negative */ 238476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_offset = table_min[0]; 238576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 238676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 238776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 238876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 238976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 239076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 239176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 239276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 239376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 239476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 239576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Per-rate tx power setting 239676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 239776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is the code that sets the desired tx power (below 239876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * maximum) on hw for each rate (we also have TPC that sets 239976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * power per packet). We do that by providing an index on the 240076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * PCDAC/PDADC table we set up. 240176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 240276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 240376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 240476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set rate power table 240576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 240676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * For now we only limit txpower based on maximum tx power 240776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * supported by hw (what's inside rate_info). We need to limit 240876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * this even more, based on regulatory domain etc. 240976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 241076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps) 241176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and is indexed as follows: 241276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * rates[0] - rates[7] -> OFDM rates 241376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * rates[8] - rates[14] -> CCK rates 241476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * rates[15] -> XR rates (they all have the same power) 241576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 241676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 241776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, 241876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_rate_pcal_info *rate_info, 241976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 ee_mode) 242076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 242176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i; 242276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 *rates; 242376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 242476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* max_pwr is power level we got from driver/user in 0.5dB 242576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * units, switch to 0.25dB units so we can compare */ 242676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_pwr *= 2; 242776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max_pwr) / 2; 242876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 242976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* apply rate limits */ 243076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates = ah->ah_txpower.txp_rates_power_table; 243176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 243276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* OFDM rates 6 to 24Mb/s */ 243376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < 5; i++) 243476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[i] = min(max_pwr, rate_info->target_power_6to24); 243576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 243676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Rest OFDM rates */ 243776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[5] = min(rates[0], rate_info->target_power_36); 243876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[6] = min(rates[0], rate_info->target_power_48); 243976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[7] = min(rates[0], rate_info->target_power_54); 244076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 244176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* CCK rates */ 244276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 1L */ 244376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[8] = min(rates[0], rate_info->target_power_6to24); 244476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 2L */ 244576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[9] = min(rates[0], rate_info->target_power_36); 244676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 2S */ 244776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[10] = min(rates[0], rate_info->target_power_36); 244876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 5L */ 244976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[11] = min(rates[0], rate_info->target_power_48); 245076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 5S */ 245176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[12] = min(rates[0], rate_info->target_power_48); 245276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 11L */ 245376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[13] = min(rates[0], rate_info->target_power_54); 245476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 11S */ 245576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[14] = min(rates[0], rate_info->target_power_54); 245676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 245776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* XR rates */ 245876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[15] = min(rates[0], rate_info->target_power_6to24); 245976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 246076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* CCK rates have different peak to average ratio 246176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * so we have to tweak their power so that gainf 246276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * correction works ok. For this we use OFDM to 246376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * CCK delta from eeprom */ 246476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((ee_mode == AR5K_EEPROM_MODE_11G) && 246576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (ah->ah_phy_revision < AR5K_SREV_PHY_5212A)) 246676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 8; i <= 15; i++) 246776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta; 246876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 246976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_min_pwr = rates[7]; 247076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_max_pwr = rates[0]; 247176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_ofdm = rates[7]; 247276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 247376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 247476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 247576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 247676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set transmition power 247776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 247876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint 247976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanath5k_hw_txpower(struct ath5k_hw *ah, struct net80211_channel *channel, 248076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 ee_mode, u8 txpower) 248176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 248276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ath5k_rate_pcal_info rate_info; 248376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 type; 248476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ret; 248576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 248676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (txpower > AR5K_TUNE_MAX_TXPOWER) { 248776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("ath5k: invalid tx power %d\n", txpower); 248876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 248976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 249076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (txpower == 0) 249176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman txpower = AR5K_TUNE_DEFAULT_TXPOWER; 249276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 249376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Reset TX power values */ 249476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); 249576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; 249676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_min_pwr = 0; 249776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER; 249876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 249976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize TX power table */ 250076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (ah->ah_radio) { 250176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5111: 250276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman type = AR5K_PWRTABLE_PWR_TO_PCDAC; 250376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 250476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5112: 250576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman type = AR5K_PWRTABLE_LINEAR_PCDAC; 250676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 250776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2413: 250876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF5413: 250976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2316: 251076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2317: 251176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case AR5K_RF2425: 251276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman type = AR5K_PWRTABLE_PWR_TO_PDADC; 251376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 251476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 251576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EINVAL; 251676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 251776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 251876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* FIXME: Only on channel/mode change */ 251976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type); 252076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ret) 252176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 252276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 252376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Limit max power if we have a CTL available */ 252476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_get_max_ctl_power(ah, channel); 252576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 252676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* FIXME: Tx power limit for this regdomain 252776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XXX: Mac80211/CRDA will do that anyway ? */ 252876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 252976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* FIXME: Antenna reduction stuff */ 253076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 253176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* FIXME: Limit power on turbo modes */ 253276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 253376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* FIXME: TPC scale reduction */ 253476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 253576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Get surounding channels for per-rate power table 253676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * calibration */ 253776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_get_rate_pcal_data(ah, channel, &rate_info); 253876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 253976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Setup rate power table */ 254076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_setup_rate_powertable(ah, txpower, &rate_info, ee_mode); 254176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 254276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Write rate power table on hw */ 254376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) | 254476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) | 254576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1); 254676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 254776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) | 254876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) | 254976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2); 255076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 255176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) | 255276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) | 255376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3); 255476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 255576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) | 255676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | 255776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); 255876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 255976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* FIXME: TPC support */ 256076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_txpower.txp_tpc) { 256176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | 256276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); 256376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 256476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 256576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) | 256676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) | 256776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP), 256876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TPC); 256976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 257076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | 257176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); 257276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 257376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 257476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 257576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 257676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 257776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 mode, u8 txpower) 257876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 257976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net80211_channel *channel = ah->ah_current_channel; 258076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 258176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2("ath5k: changing txpower to %d\n", txpower); 258276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 258376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ath5k_hw_txpower(ah, channel, mode, txpower); 258476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 258576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 258676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#undef _ATH5K_PHY 2587