percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
978 lines
28 KiB
C
978 lines
28 KiB
C
/*
|
|
* Copyright (c) 2008-2009 Atheros Communications Inc.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
/**
|
|
* DOC: Programming Atheros 802.11n analog front end radios
|
|
*
|
|
* AR5416 MAC based PCI devices and AR518 MAC based PCI-Express
|
|
* devices have either an external AR2133 analog front end radio for single
|
|
* band 2.4 GHz communication or an AR5133 analog front end radio for dual
|
|
* band 2.4 GHz / 5 GHz communication.
|
|
*
|
|
* All devices after the AR5416 and AR5418 family starting with the AR9280
|
|
* have their analog front radios, MAC/BB and host PCIe/USB interface embedded
|
|
* into a single-chip and require less programming.
|
|
*
|
|
* The following single-chips exist with a respective embedded radio:
|
|
*
|
|
* AR9280 - 11n dual-band 2x2 MIMO for PCIe
|
|
* AR9281 - 11n single-band 1x2 MIMO for PCIe
|
|
* AR9285 - 11n single-band 1x1 for PCIe
|
|
* AR9287 - 11n single-band 2x2 MIMO for PCIe
|
|
*
|
|
* AR9220 - 11n dual-band 2x2 MIMO for PCI
|
|
* AR9223 - 11n single-band 2x2 MIMO for PCI
|
|
*
|
|
* AR9287 - 11n single-band 1x1 MIMO for USB
|
|
*/
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include "hw.h"
|
|
|
|
/**
|
|
* ath9k_hw_write_regs - ??
|
|
*
|
|
* @ah: atheros hardware structure
|
|
* @freqIndex:
|
|
* @regWrites:
|
|
*
|
|
* Used for both the chipsets with an external AR2133/AR5133 radios and
|
|
* single-chip devices.
|
|
*/
|
|
void ath9k_hw_write_regs(struct ath_hw *ah, u32 freqIndex, int regWrites)
|
|
{
|
|
REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites);
|
|
}
|
|
|
|
/**
|
|
* ath9k_hw_ar9280_set_channel - set channel on single-chip device
|
|
* @ah: atheros hardware structure
|
|
* @chan:
|
|
*
|
|
* This is the function to change channel on single-chip devices, that is
|
|
* all devices after ar9280.
|
|
*
|
|
* This function takes the channel value in MHz and sets
|
|
* hardware channel value. Assumes writes have been enabled to analog bus.
|
|
*
|
|
* Actual Expression,
|
|
*
|
|
* For 2GHz channel,
|
|
* Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
|
|
* (freq_ref = 40MHz)
|
|
*
|
|
* For 5GHz channel,
|
|
* Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10)
|
|
* (freq_ref = 40MHz/(24>>amodeRefSel))
|
|
*/
|
|
int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
|
|
{
|
|
u16 bMode, fracMode, aModeRefSel = 0;
|
|
u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0;
|
|
struct chan_centers centers;
|
|
u32 refDivA = 24;
|
|
|
|
ath9k_hw_get_channel_centers(ah, chan, ¢ers);
|
|
freq = centers.synth_center;
|
|
|
|
reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL);
|
|
reg32 &= 0xc0000000;
|
|
|
|
if (freq < 4800) { /* 2 GHz, fractional mode */
|
|
u32 txctl;
|
|
int regWrites = 0;
|
|
|
|
bMode = 1;
|
|
fracMode = 1;
|
|
aModeRefSel = 0;
|
|
channelSel = (freq * 0x10000) / 15;
|
|
|
|
if (AR_SREV_9287_11_OR_LATER(ah)) {
|
|
if (freq == 2484) {
|
|
/* Enable channel spreading for channel 14 */
|
|
REG_WRITE_ARRAY(&ah->iniCckfirJapan2484,
|
|
1, regWrites);
|
|
} else {
|
|
REG_WRITE_ARRAY(&ah->iniCckfirNormal,
|
|
1, regWrites);
|
|
}
|
|
} else {
|
|
txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
|
|
if (freq == 2484) {
|
|
/* Enable channel spreading for channel 14 */
|
|
REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
|
|
txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
|
|
} else {
|
|
REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
|
|
txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
|
|
}
|
|
}
|
|
} else {
|
|
bMode = 0;
|
|
fracMode = 0;
|
|
|
|
switch(ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) {
|
|
case 0:
|
|
if ((freq % 20) == 0) {
|
|
aModeRefSel = 3;
|
|
} else if ((freq % 10) == 0) {
|
|
aModeRefSel = 2;
|
|
}
|
|
if (aModeRefSel)
|
|
break;
|
|
case 1:
|
|
default:
|
|
aModeRefSel = 0;
|
|
/*
|
|
* Enable 2G (fractional) mode for channels
|
|
* which are 5MHz spaced.
|
|
*/
|
|
fracMode = 1;
|
|
refDivA = 1;
|
|
channelSel = (freq * 0x8000) / 15;
|
|
|
|
/* RefDivA setting */
|
|
REG_RMW_FIELD(ah, AR_AN_SYNTH9,
|
|
AR_AN_SYNTH9_REFDIVA, refDivA);
|
|
|
|
}
|
|
|
|
if (!fracMode) {
|
|
ndiv = (freq * (refDivA >> aModeRefSel)) / 60;
|
|
channelSel = ndiv & 0x1ff;
|
|
channelFrac = (ndiv & 0xfffffe00) * 2;
|
|
channelSel = (channelSel << 17) | channelFrac;
|
|
}
|
|
}
|
|
|
|
reg32 = reg32 |
|
|
(bMode << 29) |
|
|
(fracMode << 28) | (aModeRefSel << 26) | (channelSel);
|
|
|
|
REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
|
|
|
|
ah->curchan = chan;
|
|
ah->curchan_rad_index = -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* ath9k_hw_9280_spur_mitigate - convert baseband spur frequency
|
|
* @ah: atheros hardware structure
|
|
* @chan:
|
|
*
|
|
* For single-chip solutions. Converts to baseband spur frequency given the
|
|
* input channel frequency and compute register settings below.
|
|
*/
|
|
void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan)
|
|
{
|
|
int bb_spur = AR_NO_SPUR;
|
|
int freq;
|
|
int bin, cur_bin;
|
|
int bb_spur_off, spur_subchannel_sd;
|
|
int spur_freq_sd;
|
|
int spur_delta_phase;
|
|
int denominator;
|
|
int upper, lower, cur_vit_mask;
|
|
int tmp, newVal;
|
|
int i;
|
|
int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
|
|
AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
|
|
};
|
|
int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
|
|
AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
|
|
};
|
|
int inc[4] = { 0, 100, 0, 0 };
|
|
struct chan_centers centers;
|
|
|
|
int8_t mask_m[123];
|
|
int8_t mask_p[123];
|
|
int8_t mask_amt;
|
|
int tmp_mask;
|
|
int cur_bb_spur;
|
|
bool is2GHz = IS_CHAN_2GHZ(chan);
|
|
|
|
memset(&mask_m, 0, sizeof(int8_t) * 123);
|
|
memset(&mask_p, 0, sizeof(int8_t) * 123);
|
|
|
|
ath9k_hw_get_channel_centers(ah, chan, ¢ers);
|
|
freq = centers.synth_center;
|
|
|
|
ah->config.spurmode = SPUR_ENABLE_EEPROM;
|
|
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
|
|
cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
|
|
|
|
if (is2GHz)
|
|
cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
|
|
else
|
|
cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ;
|
|
|
|
if (AR_NO_SPUR == cur_bb_spur)
|
|
break;
|
|
cur_bb_spur = cur_bb_spur - freq;
|
|
|
|
if (IS_CHAN_HT40(chan)) {
|
|
if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) &&
|
|
(cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) {
|
|
bb_spur = cur_bb_spur;
|
|
break;
|
|
}
|
|
} else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) &&
|
|
(cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) {
|
|
bb_spur = cur_bb_spur;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (AR_NO_SPUR == bb_spur) {
|
|
REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
|
|
AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
|
|
return;
|
|
} else {
|
|
REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
|
|
AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
|
|
}
|
|
|
|
bin = bb_spur * 320;
|
|
|
|
tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
|
|
|
|
newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
|
|
AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
|
|
AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
|
|
AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
|
|
REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal);
|
|
|
|
newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
|
|
AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
|
|
AR_PHY_SPUR_REG_MASK_RATE_SELECT |
|
|
AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
|
|
SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
|
|
REG_WRITE(ah, AR_PHY_SPUR_REG, newVal);
|
|
|
|
if (IS_CHAN_HT40(chan)) {
|
|
if (bb_spur < 0) {
|
|
spur_subchannel_sd = 1;
|
|
bb_spur_off = bb_spur + 10;
|
|
} else {
|
|
spur_subchannel_sd = 0;
|
|
bb_spur_off = bb_spur - 10;
|
|
}
|
|
} else {
|
|
spur_subchannel_sd = 0;
|
|
bb_spur_off = bb_spur;
|
|
}
|
|
|
|
if (IS_CHAN_HT40(chan))
|
|
spur_delta_phase =
|
|
((bb_spur * 262144) /
|
|
10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
|
|
else
|
|
spur_delta_phase =
|
|
((bb_spur * 524288) /
|
|
10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
|
|
|
|
denominator = IS_CHAN_2GHZ(chan) ? 44 : 40;
|
|
spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff;
|
|
|
|
newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
|
|
SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
|
|
SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
|
|
REG_WRITE(ah, AR_PHY_TIMING11, newVal);
|
|
|
|
newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S;
|
|
REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal);
|
|
|
|
cur_bin = -6000;
|
|
upper = bin + 100;
|
|
lower = bin - 100;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
int pilot_mask = 0;
|
|
int chan_mask = 0;
|
|
int bp = 0;
|
|
for (bp = 0; bp < 30; bp++) {
|
|
if ((cur_bin > lower) && (cur_bin < upper)) {
|
|
pilot_mask = pilot_mask | 0x1 << bp;
|
|
chan_mask = chan_mask | 0x1 << bp;
|
|
}
|
|
cur_bin += 100;
|
|
}
|
|
cur_bin += inc[i];
|
|
REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
|
|
REG_WRITE(ah, chan_mask_reg[i], chan_mask);
|
|
}
|
|
|
|
cur_vit_mask = 6100;
|
|
upper = bin + 120;
|
|
lower = bin - 120;
|
|
|
|
for (i = 0; i < 123; i++) {
|
|
if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
|
|
|
|
/* workaround for gcc bug #37014 */
|
|
volatile int tmp_v = abs(cur_vit_mask - bin);
|
|
|
|
if (tmp_v < 75)
|
|
mask_amt = 1;
|
|
else
|
|
mask_amt = 0;
|
|
if (cur_vit_mask < 0)
|
|
mask_m[abs(cur_vit_mask / 100)] = mask_amt;
|
|
else
|
|
mask_p[cur_vit_mask / 100] = mask_amt;
|
|
}
|
|
cur_vit_mask -= 100;
|
|
}
|
|
|
|
tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
|
|
| (mask_m[48] << 26) | (mask_m[49] << 24)
|
|
| (mask_m[50] << 22) | (mask_m[51] << 20)
|
|
| (mask_m[52] << 18) | (mask_m[53] << 16)
|
|
| (mask_m[54] << 14) | (mask_m[55] << 12)
|
|
| (mask_m[56] << 10) | (mask_m[57] << 8)
|
|
| (mask_m[58] << 6) | (mask_m[59] << 4)
|
|
| (mask_m[60] << 2) | (mask_m[61] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
|
|
|
|
tmp_mask = (mask_m[31] << 28)
|
|
| (mask_m[32] << 26) | (mask_m[33] << 24)
|
|
| (mask_m[34] << 22) | (mask_m[35] << 20)
|
|
| (mask_m[36] << 18) | (mask_m[37] << 16)
|
|
| (mask_m[48] << 14) | (mask_m[39] << 12)
|
|
| (mask_m[40] << 10) | (mask_m[41] << 8)
|
|
| (mask_m[42] << 6) | (mask_m[43] << 4)
|
|
| (mask_m[44] << 2) | (mask_m[45] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
|
|
|
|
tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
|
|
| (mask_m[18] << 26) | (mask_m[18] << 24)
|
|
| (mask_m[20] << 22) | (mask_m[20] << 20)
|
|
| (mask_m[22] << 18) | (mask_m[22] << 16)
|
|
| (mask_m[24] << 14) | (mask_m[24] << 12)
|
|
| (mask_m[25] << 10) | (mask_m[26] << 8)
|
|
| (mask_m[27] << 6) | (mask_m[28] << 4)
|
|
| (mask_m[29] << 2) | (mask_m[30] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
|
|
|
|
tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
|
|
| (mask_m[2] << 26) | (mask_m[3] << 24)
|
|
| (mask_m[4] << 22) | (mask_m[5] << 20)
|
|
| (mask_m[6] << 18) | (mask_m[7] << 16)
|
|
| (mask_m[8] << 14) | (mask_m[9] << 12)
|
|
| (mask_m[10] << 10) | (mask_m[11] << 8)
|
|
| (mask_m[12] << 6) | (mask_m[13] << 4)
|
|
| (mask_m[14] << 2) | (mask_m[15] << 0);
|
|
REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
|
|
|
|
tmp_mask = (mask_p[15] << 28)
|
|
| (mask_p[14] << 26) | (mask_p[13] << 24)
|
|
| (mask_p[12] << 22) | (mask_p[11] << 20)
|
|
| (mask_p[10] << 18) | (mask_p[9] << 16)
|
|
| (mask_p[8] << 14) | (mask_p[7] << 12)
|
|
| (mask_p[6] << 10) | (mask_p[5] << 8)
|
|
| (mask_p[4] << 6) | (mask_p[3] << 4)
|
|
| (mask_p[2] << 2) | (mask_p[1] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
|
|
|
|
tmp_mask = (mask_p[30] << 28)
|
|
| (mask_p[29] << 26) | (mask_p[28] << 24)
|
|
| (mask_p[27] << 22) | (mask_p[26] << 20)
|
|
| (mask_p[25] << 18) | (mask_p[24] << 16)
|
|
| (mask_p[23] << 14) | (mask_p[22] << 12)
|
|
| (mask_p[21] << 10) | (mask_p[20] << 8)
|
|
| (mask_p[19] << 6) | (mask_p[18] << 4)
|
|
| (mask_p[17] << 2) | (mask_p[16] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
|
|
|
|
tmp_mask = (mask_p[45] << 28)
|
|
| (mask_p[44] << 26) | (mask_p[43] << 24)
|
|
| (mask_p[42] << 22) | (mask_p[41] << 20)
|
|
| (mask_p[40] << 18) | (mask_p[39] << 16)
|
|
| (mask_p[38] << 14) | (mask_p[37] << 12)
|
|
| (mask_p[36] << 10) | (mask_p[35] << 8)
|
|
| (mask_p[34] << 6) | (mask_p[33] << 4)
|
|
| (mask_p[32] << 2) | (mask_p[31] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
|
|
|
|
tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
|
|
| (mask_p[59] << 26) | (mask_p[58] << 24)
|
|
| (mask_p[57] << 22) | (mask_p[56] << 20)
|
|
| (mask_p[55] << 18) | (mask_p[54] << 16)
|
|
| (mask_p[53] << 14) | (mask_p[52] << 12)
|
|
| (mask_p[51] << 10) | (mask_p[50] << 8)
|
|
| (mask_p[49] << 6) | (mask_p[48] << 4)
|
|
| (mask_p[47] << 2) | (mask_p[46] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
|
|
}
|
|
|
|
/* All code below is for non single-chip solutions */
|
|
|
|
/**
|
|
* ath9k_phy_modify_rx_buffer() - perform analog swizzling of parameters
|
|
* @rfbuf:
|
|
* @reg32:
|
|
* @numBits:
|
|
* @firstBit:
|
|
* @column:
|
|
*
|
|
* Performs analog "swizzling" of parameters into their location.
|
|
* Used on external AR2133/AR5133 radios.
|
|
*/
|
|
static void ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32,
|
|
u32 numBits, u32 firstBit,
|
|
u32 column)
|
|
{
|
|
u32 tmp32, mask, arrayEntry, lastBit;
|
|
int32_t bitPosition, bitsLeft;
|
|
|
|
tmp32 = ath9k_hw_reverse_bits(reg32, numBits);
|
|
arrayEntry = (firstBit - 1) / 8;
|
|
bitPosition = (firstBit - 1) % 8;
|
|
bitsLeft = numBits;
|
|
while (bitsLeft > 0) {
|
|
lastBit = (bitPosition + bitsLeft > 8) ?
|
|
8 : bitPosition + bitsLeft;
|
|
mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
|
|
(column * 8);
|
|
rfBuf[arrayEntry] &= ~mask;
|
|
rfBuf[arrayEntry] |= ((tmp32 << bitPosition) <<
|
|
(column * 8)) & mask;
|
|
bitsLeft -= 8 - bitPosition;
|
|
tmp32 = tmp32 >> (8 - bitPosition);
|
|
bitPosition = 0;
|
|
arrayEntry++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Fix on 2.4 GHz band for orientation sensitivity issue by increasing
|
|
* rf_pwd_icsyndiv.
|
|
*
|
|
* Theoretical Rules:
|
|
* if 2 GHz band
|
|
* if forceBiasAuto
|
|
* if synth_freq < 2412
|
|
* bias = 0
|
|
* else if 2412 <= synth_freq <= 2422
|
|
* bias = 1
|
|
* else // synth_freq > 2422
|
|
* bias = 2
|
|
* else if forceBias > 0
|
|
* bias = forceBias & 7
|
|
* else
|
|
* no change, use value from ini file
|
|
* else
|
|
* no change, invalid band
|
|
*
|
|
* 1st Mod:
|
|
* 2422 also uses value of 2
|
|
* <approved>
|
|
*
|
|
* 2nd Mod:
|
|
* Less than 2412 uses value of 0, 2412 and above uses value of 2
|
|
*/
|
|
static void ath9k_hw_force_bias(struct ath_hw *ah, u16 synth_freq)
|
|
{
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
u32 tmp_reg;
|
|
int reg_writes = 0;
|
|
u32 new_bias = 0;
|
|
|
|
if (!AR_SREV_5416(ah) || synth_freq >= 3000) {
|
|
return;
|
|
}
|
|
|
|
BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
|
|
|
|
if (synth_freq < 2412)
|
|
new_bias = 0;
|
|
else if (synth_freq < 2422)
|
|
new_bias = 1;
|
|
else
|
|
new_bias = 2;
|
|
|
|
/* pre-reverse this field */
|
|
tmp_reg = ath9k_hw_reverse_bits(new_bias, 3);
|
|
|
|
ath_print(common, ATH_DBG_CONFIG,
|
|
"Force rf_pwd_icsyndiv to %1d on %4d\n",
|
|
new_bias, synth_freq);
|
|
|
|
/* swizzle rf_pwd_icsyndiv */
|
|
ath9k_phy_modify_rx_buffer(ah->analogBank6Data, tmp_reg, 3, 181, 3);
|
|
|
|
/* write Bank 6 with new params */
|
|
REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes);
|
|
}
|
|
|
|
/**
|
|
* ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios
|
|
* @ah: atheros hardware stucture
|
|
* @chan:
|
|
*
|
|
* For the external AR2133/AR5133 radios, takes the MHz channel value and set
|
|
* the channel value. Assumes writes enabled to analog bus and bank6 register
|
|
* cache in ah->analogBank6Data.
|
|
*/
|
|
int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
|
|
{
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
u32 channelSel = 0;
|
|
u32 bModeSynth = 0;
|
|
u32 aModeRefSel = 0;
|
|
u32 reg32 = 0;
|
|
u16 freq;
|
|
struct chan_centers centers;
|
|
|
|
ath9k_hw_get_channel_centers(ah, chan, ¢ers);
|
|
freq = centers.synth_center;
|
|
|
|
if (freq < 4800) {
|
|
u32 txctl;
|
|
|
|
if (((freq - 2192) % 5) == 0) {
|
|
channelSel = ((freq - 672) * 2 - 3040) / 10;
|
|
bModeSynth = 0;
|
|
} else if (((freq - 2224) % 5) == 0) {
|
|
channelSel = ((freq - 704) * 2 - 3040) / 10;
|
|
bModeSynth = 1;
|
|
} else {
|
|
ath_print(common, ATH_DBG_FATAL,
|
|
"Invalid channel %u MHz\n", freq);
|
|
return -EINVAL;
|
|
}
|
|
|
|
channelSel = (channelSel << 2) & 0xff;
|
|
channelSel = ath9k_hw_reverse_bits(channelSel, 8);
|
|
|
|
txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
|
|
if (freq == 2484) {
|
|
|
|
REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
|
|
txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
|
|
} else {
|
|
REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
|
|
txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
|
|
}
|
|
|
|
} else if ((freq % 20) == 0 && freq >= 5120) {
|
|
channelSel =
|
|
ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8);
|
|
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
|
|
} else if ((freq % 10) == 0) {
|
|
channelSel =
|
|
ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8);
|
|
if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
|
|
aModeRefSel = ath9k_hw_reverse_bits(2, 2);
|
|
else
|
|
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
|
|
} else if ((freq % 5) == 0) {
|
|
channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
|
|
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
|
|
} else {
|
|
ath_print(common, ATH_DBG_FATAL,
|
|
"Invalid channel %u MHz\n", freq);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ath9k_hw_force_bias(ah, freq);
|
|
|
|
reg32 =
|
|
(channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
|
|
(1 << 5) | 0x1;
|
|
|
|
REG_WRITE(ah, AR_PHY(0x37), reg32);
|
|
|
|
ah->curchan = chan;
|
|
ah->curchan_rad_index = -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* ath9k_hw_spur_mitigate - convert baseband spur frequency for external radios
|
|
* @ah: atheros hardware structure
|
|
* @chan:
|
|
*
|
|
* For non single-chip solutions. Converts to baseband spur frequency given the
|
|
* input channel frequency and compute register settings below.
|
|
*/
|
|
void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan)
|
|
{
|
|
int bb_spur = AR_NO_SPUR;
|
|
int bin, cur_bin;
|
|
int spur_freq_sd;
|
|
int spur_delta_phase;
|
|
int denominator;
|
|
int upper, lower, cur_vit_mask;
|
|
int tmp, new;
|
|
int i;
|
|
int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
|
|
AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
|
|
};
|
|
int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
|
|
AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
|
|
};
|
|
int inc[4] = { 0, 100, 0, 0 };
|
|
|
|
int8_t mask_m[123];
|
|
int8_t mask_p[123];
|
|
int8_t mask_amt;
|
|
int tmp_mask;
|
|
int cur_bb_spur;
|
|
bool is2GHz = IS_CHAN_2GHZ(chan);
|
|
|
|
memset(&mask_m, 0, sizeof(int8_t) * 123);
|
|
memset(&mask_p, 0, sizeof(int8_t) * 123);
|
|
|
|
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
|
|
cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
|
|
if (AR_NO_SPUR == cur_bb_spur)
|
|
break;
|
|
cur_bb_spur = cur_bb_spur - (chan->channel * 10);
|
|
if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
|
|
bb_spur = cur_bb_spur;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (AR_NO_SPUR == bb_spur)
|
|
return;
|
|
|
|
bin = bb_spur * 32;
|
|
|
|
tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
|
|
new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
|
|
AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
|
|
AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
|
|
AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
|
|
|
|
REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
|
|
|
|
new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
|
|
AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
|
|
AR_PHY_SPUR_REG_MASK_RATE_SELECT |
|
|
AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
|
|
SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
|
|
REG_WRITE(ah, AR_PHY_SPUR_REG, new);
|
|
|
|
spur_delta_phase = ((bb_spur * 524288) / 100) &
|
|
AR_PHY_TIMING11_SPUR_DELTA_PHASE;
|
|
|
|
denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
|
|
spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
|
|
|
|
new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
|
|
SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
|
|
SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
|
|
REG_WRITE(ah, AR_PHY_TIMING11, new);
|
|
|
|
cur_bin = -6000;
|
|
upper = bin + 100;
|
|
lower = bin - 100;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
int pilot_mask = 0;
|
|
int chan_mask = 0;
|
|
int bp = 0;
|
|
for (bp = 0; bp < 30; bp++) {
|
|
if ((cur_bin > lower) && (cur_bin < upper)) {
|
|
pilot_mask = pilot_mask | 0x1 << bp;
|
|
chan_mask = chan_mask | 0x1 << bp;
|
|
}
|
|
cur_bin += 100;
|
|
}
|
|
cur_bin += inc[i];
|
|
REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
|
|
REG_WRITE(ah, chan_mask_reg[i], chan_mask);
|
|
}
|
|
|
|
cur_vit_mask = 6100;
|
|
upper = bin + 120;
|
|
lower = bin - 120;
|
|
|
|
for (i = 0; i < 123; i++) {
|
|
if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
|
|
|
|
/* workaround for gcc bug #37014 */
|
|
volatile int tmp_v = abs(cur_vit_mask - bin);
|
|
|
|
if (tmp_v < 75)
|
|
mask_amt = 1;
|
|
else
|
|
mask_amt = 0;
|
|
if (cur_vit_mask < 0)
|
|
mask_m[abs(cur_vit_mask / 100)] = mask_amt;
|
|
else
|
|
mask_p[cur_vit_mask / 100] = mask_amt;
|
|
}
|
|
cur_vit_mask -= 100;
|
|
}
|
|
|
|
tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
|
|
| (mask_m[48] << 26) | (mask_m[49] << 24)
|
|
| (mask_m[50] << 22) | (mask_m[51] << 20)
|
|
| (mask_m[52] << 18) | (mask_m[53] << 16)
|
|
| (mask_m[54] << 14) | (mask_m[55] << 12)
|
|
| (mask_m[56] << 10) | (mask_m[57] << 8)
|
|
| (mask_m[58] << 6) | (mask_m[59] << 4)
|
|
| (mask_m[60] << 2) | (mask_m[61] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
|
|
|
|
tmp_mask = (mask_m[31] << 28)
|
|
| (mask_m[32] << 26) | (mask_m[33] << 24)
|
|
| (mask_m[34] << 22) | (mask_m[35] << 20)
|
|
| (mask_m[36] << 18) | (mask_m[37] << 16)
|
|
| (mask_m[48] << 14) | (mask_m[39] << 12)
|
|
| (mask_m[40] << 10) | (mask_m[41] << 8)
|
|
| (mask_m[42] << 6) | (mask_m[43] << 4)
|
|
| (mask_m[44] << 2) | (mask_m[45] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
|
|
|
|
tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
|
|
| (mask_m[18] << 26) | (mask_m[18] << 24)
|
|
| (mask_m[20] << 22) | (mask_m[20] << 20)
|
|
| (mask_m[22] << 18) | (mask_m[22] << 16)
|
|
| (mask_m[24] << 14) | (mask_m[24] << 12)
|
|
| (mask_m[25] << 10) | (mask_m[26] << 8)
|
|
| (mask_m[27] << 6) | (mask_m[28] << 4)
|
|
| (mask_m[29] << 2) | (mask_m[30] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
|
|
|
|
tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
|
|
| (mask_m[2] << 26) | (mask_m[3] << 24)
|
|
| (mask_m[4] << 22) | (mask_m[5] << 20)
|
|
| (mask_m[6] << 18) | (mask_m[7] << 16)
|
|
| (mask_m[8] << 14) | (mask_m[9] << 12)
|
|
| (mask_m[10] << 10) | (mask_m[11] << 8)
|
|
| (mask_m[12] << 6) | (mask_m[13] << 4)
|
|
| (mask_m[14] << 2) | (mask_m[15] << 0);
|
|
REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
|
|
|
|
tmp_mask = (mask_p[15] << 28)
|
|
| (mask_p[14] << 26) | (mask_p[13] << 24)
|
|
| (mask_p[12] << 22) | (mask_p[11] << 20)
|
|
| (mask_p[10] << 18) | (mask_p[9] << 16)
|
|
| (mask_p[8] << 14) | (mask_p[7] << 12)
|
|
| (mask_p[6] << 10) | (mask_p[5] << 8)
|
|
| (mask_p[4] << 6) | (mask_p[3] << 4)
|
|
| (mask_p[2] << 2) | (mask_p[1] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
|
|
|
|
tmp_mask = (mask_p[30] << 28)
|
|
| (mask_p[29] << 26) | (mask_p[28] << 24)
|
|
| (mask_p[27] << 22) | (mask_p[26] << 20)
|
|
| (mask_p[25] << 18) | (mask_p[24] << 16)
|
|
| (mask_p[23] << 14) | (mask_p[22] << 12)
|
|
| (mask_p[21] << 10) | (mask_p[20] << 8)
|
|
| (mask_p[19] << 6) | (mask_p[18] << 4)
|
|
| (mask_p[17] << 2) | (mask_p[16] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
|
|
|
|
tmp_mask = (mask_p[45] << 28)
|
|
| (mask_p[44] << 26) | (mask_p[43] << 24)
|
|
| (mask_p[42] << 22) | (mask_p[41] << 20)
|
|
| (mask_p[40] << 18) | (mask_p[39] << 16)
|
|
| (mask_p[38] << 14) | (mask_p[37] << 12)
|
|
| (mask_p[36] << 10) | (mask_p[35] << 8)
|
|
| (mask_p[34] << 6) | (mask_p[33] << 4)
|
|
| (mask_p[32] << 2) | (mask_p[31] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
|
|
|
|
tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
|
|
| (mask_p[59] << 26) | (mask_p[58] << 24)
|
|
| (mask_p[57] << 22) | (mask_p[56] << 20)
|
|
| (mask_p[55] << 18) | (mask_p[54] << 16)
|
|
| (mask_p[53] << 14) | (mask_p[52] << 12)
|
|
| (mask_p[51] << 10) | (mask_p[50] << 8)
|
|
| (mask_p[49] << 6) | (mask_p[48] << 4)
|
|
| (mask_p[47] << 2) | (mask_p[46] << 0);
|
|
REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
|
|
REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
|
|
}
|
|
|
|
/**
|
|
* ath9k_hw_rf_alloc_ext_banks - allocates banks for external radio programming
|
|
* @ah: atheros hardware structure
|
|
*
|
|
* Only required for older devices with external AR2133/AR5133 radios.
|
|
*/
|
|
int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah)
|
|
{
|
|
#define ATH_ALLOC_BANK(bank, size) do { \
|
|
bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \
|
|
if (!bank) { \
|
|
ath_print(common, ATH_DBG_FATAL, \
|
|
"Cannot allocate RF banks\n"); \
|
|
return -ENOMEM; \
|
|
} \
|
|
} while (0);
|
|
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
|
|
BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
|
|
|
|
ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
|
|
ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
|
|
ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows);
|
|
ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows);
|
|
ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows);
|
|
ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows);
|
|
ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows);
|
|
ATH_ALLOC_BANK(ah->addac5416_21,
|
|
ah->iniAddac.ia_rows * ah->iniAddac.ia_columns);
|
|
ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows);
|
|
|
|
return 0;
|
|
#undef ATH_ALLOC_BANK
|
|
}
|
|
|
|
|
|
/**
|
|
* ath9k_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers
|
|
* @ah: atheros hardware struture
|
|
* For the external AR2133/AR5133 radios banks.
|
|
*/
|
|
void
|
|
ath9k_hw_rf_free_ext_banks(struct ath_hw *ah)
|
|
{
|
|
#define ATH_FREE_BANK(bank) do { \
|
|
kfree(bank); \
|
|
bank = NULL; \
|
|
} while (0);
|
|
|
|
BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
|
|
|
|
ATH_FREE_BANK(ah->analogBank0Data);
|
|
ATH_FREE_BANK(ah->analogBank1Data);
|
|
ATH_FREE_BANK(ah->analogBank2Data);
|
|
ATH_FREE_BANK(ah->analogBank3Data);
|
|
ATH_FREE_BANK(ah->analogBank6Data);
|
|
ATH_FREE_BANK(ah->analogBank6TPCData);
|
|
ATH_FREE_BANK(ah->analogBank7Data);
|
|
ATH_FREE_BANK(ah->addac5416_21);
|
|
ATH_FREE_BANK(ah->bank6Temp);
|
|
|
|
#undef ATH_FREE_BANK
|
|
}
|
|
|
|
/* *
|
|
* ath9k_hw_set_rf_regs - programs rf registers based on EEPROM
|
|
* @ah: atheros hardware structure
|
|
* @chan:
|
|
* @modesIndex:
|
|
*
|
|
* Used for the external AR2133/AR5133 radios.
|
|
*
|
|
* Reads the EEPROM header info from the device structure and programs
|
|
* all rf registers. This routine requires access to the analog
|
|
* rf device. This is not required for single-chip devices.
|
|
*/
|
|
bool ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan,
|
|
u16 modesIndex)
|
|
{
|
|
u32 eepMinorRev;
|
|
u32 ob5GHz = 0, db5GHz = 0;
|
|
u32 ob2GHz = 0, db2GHz = 0;
|
|
int regWrites = 0;
|
|
|
|
/*
|
|
* Software does not need to program bank data
|
|
* for single chip devices, that is AR9280 or anything
|
|
* after that.
|
|
*/
|
|
if (AR_SREV_9280_10_OR_LATER(ah))
|
|
return true;
|
|
|
|
/* Setup rf parameters */
|
|
eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
|
|
|
|
/* Setup Bank 0 Write */
|
|
RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1);
|
|
|
|
/* Setup Bank 1 Write */
|
|
RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1);
|
|
|
|
/* Setup Bank 2 Write */
|
|
RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1);
|
|
|
|
/* Setup Bank 6 Write */
|
|
RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3,
|
|
modesIndex);
|
|
{
|
|
int i;
|
|
for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) {
|
|
ah->analogBank6Data[i] =
|
|
INI_RA(&ah->iniBank6TPC, i, modesIndex);
|
|
}
|
|
}
|
|
|
|
/* Only the 5 or 2 GHz OB/DB need to be set for a mode */
|
|
if (eepMinorRev >= 2) {
|
|
if (IS_CHAN_2GHZ(chan)) {
|
|
ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2);
|
|
db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2);
|
|
ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
|
|
ob2GHz, 3, 197, 0);
|
|
ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
|
|
db2GHz, 3, 194, 0);
|
|
} else {
|
|
ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5);
|
|
db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5);
|
|
ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
|
|
ob5GHz, 3, 203, 0);
|
|
ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
|
|
db5GHz, 3, 200, 0);
|
|
}
|
|
}
|
|
|
|
/* Setup Bank 7 Setup */
|
|
RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1);
|
|
|
|
/* Write Analog registers */
|
|
REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data,
|
|
regWrites);
|
|
REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data,
|
|
regWrites);
|
|
REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data,
|
|
regWrites);
|
|
REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data,
|
|
regWrites);
|
|
REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data,
|
|
regWrites);
|
|
REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data,
|
|
regWrites);
|
|
|
|
return true;
|
|
}
|