mirror of
https://github.com/adulau/aha.git
synced 2025-01-03 22:53:18 +00:00
ath5k: Convert chip specific calibration data to a generic format
* Convert chip specific calibration data to a generic format common for all chips Note: We scale up power to be in 0.25dB units for all chips for compatibility with RF5112 v2: Address Bob's and Jiri's comments Signed-off-by: Nick Kossifidis <mickflemm@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
504f365554
commit
8e218fb24f
2 changed files with 628 additions and 272 deletions
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
|
||||
* Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -98,11 +98,6 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah)
|
|||
int ret;
|
||||
u16 val;
|
||||
|
||||
/* Initial TX thermal adjustment values */
|
||||
ee->ee_tx_clip = 4;
|
||||
ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
|
||||
ee->ee_gain_select = 1;
|
||||
|
||||
/*
|
||||
* Read values from EEPROM and store them in the capability structure
|
||||
*/
|
||||
|
@ -504,35 +499,6 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Used to match PCDAC steps with power values on RF5111 chips
|
||||
* (eeprom versions < 4). For RF5111 we have 10 pre-defined PCDAC
|
||||
* steps that match with the power values we read from eeprom. On
|
||||
* older eeprom versions (< 3.2) these steps are equaly spaced at
|
||||
* 10% of the pcdac curve -until the curve reaches it's maximum-
|
||||
* (10 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
|
||||
* these 10 steps are spaced in a different way. This function returns
|
||||
* the pcdac steps based on eeprom version and curve min/max so that we
|
||||
* can have pcdac/pwr points.
|
||||
*/
|
||||
static inline void
|
||||
ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
|
||||
{
|
||||
static const u16 intercepts3[] =
|
||||
{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
|
||||
static const u16 intercepts3_2[] =
|
||||
{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
|
||||
const u16 *ip;
|
||||
int i;
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)
|
||||
ip = intercepts3_2;
|
||||
else
|
||||
ip = intercepts3;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(intercepts3); i++)
|
||||
*vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100;
|
||||
}
|
||||
|
||||
/* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff
|
||||
* frequency mask) */
|
||||
static inline int
|
||||
|
@ -546,28 +512,27 @@ ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
|
|||
int ret;
|
||||
u16 val;
|
||||
|
||||
ee->ee_n_piers[mode] = 0;
|
||||
while(i < max) {
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
|
||||
freq1 = (val >> 8) & 0xff;
|
||||
freq2 = val & 0xff;
|
||||
freq1 = val & 0xff;
|
||||
if (!freq1)
|
||||
break;
|
||||
|
||||
if (freq1) {
|
||||
pc[i++].freq = ath5k_eeprom_bin2freq(ee,
|
||||
freq1, mode);
|
||||
ee->ee_n_piers[mode]++;
|
||||
}
|
||||
|
||||
if (freq2) {
|
||||
freq2 = (val >> 8) & 0xff;
|
||||
if (!freq2)
|
||||
break;
|
||||
|
||||
pc[i++].freq = ath5k_eeprom_bin2freq(ee,
|
||||
freq2, mode);
|
||||
ee->ee_n_piers[mode]++;
|
||||
}
|
||||
|
||||
if (!freq1 || !freq2)
|
||||
break;
|
||||
}
|
||||
|
||||
/* return new offset */
|
||||
*offset = o;
|
||||
|
||||
|
@ -652,13 +617,122 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Read power calibration for RF5111 chips
|
||||
/*
|
||||
* Read power calibration for RF5111 chips
|
||||
*
|
||||
* For RF5111 we have an XPD -eXternal Power Detector- curve
|
||||
* for each calibrated channel. Each curve has PCDAC steps on
|
||||
* x axis and power on y axis and looks like a logarithmic
|
||||
* function. To recreate the curve and pass the power values
|
||||
* on the pcdac table, we read 10 points here and interpolate later.
|
||||
* for each calibrated channel. Each curve has 0,5dB Power steps
|
||||
* on x axis and PCDAC steps (offsets) on y axis and looks like an
|
||||
* exponential function. To recreate the curve we read 11 points
|
||||
* here and interpolate later.
|
||||
*/
|
||||
|
||||
/* Used to match PCDAC steps with power values on RF5111 chips
|
||||
* (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC
|
||||
* steps that match with the power values we read from eeprom. On
|
||||
* older eeprom versions (< 3.2) these steps are equaly spaced at
|
||||
* 10% of the pcdac curve -until the curve reaches it's maximum-
|
||||
* (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
|
||||
* these 11 steps are spaced in a different way. This function returns
|
||||
* the pcdac steps based on eeprom version and curve min/max so that we
|
||||
* can have pcdac/pwr points.
|
||||
*/
|
||||
static inline void
|
||||
ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
|
||||
{
|
||||
const static u16 intercepts3[] =
|
||||
{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
|
||||
const static u16 intercepts3_2[] =
|
||||
{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
|
||||
const u16 *ip;
|
||||
int i;
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)
|
||||
ip = intercepts3_2;
|
||||
else
|
||||
ip = intercepts3;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(intercepts3); i++)
|
||||
vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;
|
||||
}
|
||||
|
||||
/* Convert RF5111 specific data to generic raw data
|
||||
* used by interpolation code */
|
||||
static int
|
||||
ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
|
||||
struct ath5k_chan_pcal_info *chinfo)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct ath5k_chan_pcal_info_rf5111 *pcinfo;
|
||||
struct ath5k_pdgain_info *pd;
|
||||
u8 pier, point, idx;
|
||||
u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
|
||||
|
||||
/* Fill raw data for each calibration pier */
|
||||
for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
|
||||
|
||||
pcinfo = &chinfo[pier].rf5111_info;
|
||||
|
||||
/* Allocate pd_curves for this cal pier */
|
||||
chinfo[pier].pd_curves =
|
||||
kcalloc(AR5K_EEPROM_N_PD_CURVES,
|
||||
sizeof(struct ath5k_pdgain_info),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!chinfo[pier].pd_curves)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Only one curve for RF5111
|
||||
* find out which one and place
|
||||
* in in pd_curves.
|
||||
* Note: ee_x_gain is reversed here */
|
||||
for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) {
|
||||
|
||||
if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) {
|
||||
pdgain_idx[0] = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ee->ee_pd_gains[mode] = 1;
|
||||
|
||||
pd = &chinfo[pier].pd_curves[idx];
|
||||
|
||||
pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111;
|
||||
|
||||
/* Allocate pd points for this curve */
|
||||
pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
|
||||
sizeof(u8), GFP_KERNEL);
|
||||
if (!pd->pd_step)
|
||||
return -ENOMEM;
|
||||
|
||||
pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
|
||||
sizeof(s16), GFP_KERNEL);
|
||||
if (!pd->pd_pwr)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Fill raw dataset
|
||||
* (convert power to 0.25dB units
|
||||
* for RF5112 combatibility) */
|
||||
for (point = 0; point < pd->pd_points; point++) {
|
||||
|
||||
/* Absolute values */
|
||||
pd->pd_pwr[point] = 2 * pcinfo->pwr[point];
|
||||
|
||||
/* Already sorted */
|
||||
pd->pd_step[point] = pcinfo->pcdac[point];
|
||||
}
|
||||
|
||||
/* Set min/max pwr */
|
||||
chinfo[pier].min_pwr = pd->pd_pwr[0];
|
||||
chinfo[pier].max_pwr = pd->pd_pwr[10];
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse EEPROM data */
|
||||
static int
|
||||
ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
|
||||
{
|
||||
|
@ -747,30 +821,165 @@ ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
|
|||
cdata->pcdac_max, cdata->pcdac);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal);
|
||||
}
|
||||
|
||||
/* Read power calibration for RF5112 chips
|
||||
|
||||
/*
|
||||
* Read power calibration for RF5112 chips
|
||||
*
|
||||
* For RF5112 we have 4 XPD -eXternal Power Detector- curves
|
||||
* for each calibrated channel on 0, -6, -12 and -18dbm but we only
|
||||
* use the higher (3) and the lower (0) curves. Each curve has PCDAC
|
||||
* steps on x axis and power on y axis and looks like a linear
|
||||
* function. To recreate the curve and pass the power values
|
||||
* on the pcdac table, we read 4 points for xpd 0 and 3 points
|
||||
* for xpd 3 here and interpolate later.
|
||||
* use the higher (3) and the lower (0) curves. Each curve has 0.5dB
|
||||
* power steps on x axis and PCDAC steps on y axis and looks like a
|
||||
* linear function. To recreate the curve and pass the power values
|
||||
* on hw, we read 4 points for xpd 0 (lower gain -> max power)
|
||||
* and 3 points for xpd 3 (higher gain -> lower power) here and
|
||||
* interpolate later.
|
||||
*
|
||||
* Note: Many vendors just use xpd 0 so xpd 3 is zeroed.
|
||||
*/
|
||||
|
||||
/* Convert RF5112 specific data to generic raw data
|
||||
* used by interpolation code */
|
||||
static int
|
||||
ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
|
||||
struct ath5k_chan_pcal_info *chinfo)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct ath5k_chan_pcal_info_rf5112 *pcinfo;
|
||||
u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
|
||||
unsigned int pier, pdg, point;
|
||||
|
||||
/* Fill raw data for each calibration pier */
|
||||
for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
|
||||
|
||||
pcinfo = &chinfo[pier].rf5112_info;
|
||||
|
||||
/* Allocate pd_curves for this cal pier */
|
||||
chinfo[pier].pd_curves =
|
||||
kcalloc(AR5K_EEPROM_N_PD_CURVES,
|
||||
sizeof(struct ath5k_pdgain_info),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!chinfo[pier].pd_curves)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Fill pd_curves */
|
||||
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
|
||||
|
||||
u8 idx = pdgain_idx[pdg];
|
||||
struct ath5k_pdgain_info *pd =
|
||||
&chinfo[pier].pd_curves[idx];
|
||||
|
||||
/* Lowest gain curve (max power) */
|
||||
if (pdg == 0) {
|
||||
/* One more point for better accuracy */
|
||||
pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS;
|
||||
|
||||
/* Allocate pd points for this curve */
|
||||
pd->pd_step = kcalloc(pd->pd_points,
|
||||
sizeof(u8), GFP_KERNEL);
|
||||
|
||||
if (!pd->pd_step)
|
||||
return -ENOMEM;
|
||||
|
||||
pd->pd_pwr = kcalloc(pd->pd_points,
|
||||
sizeof(s16), GFP_KERNEL);
|
||||
|
||||
if (!pd->pd_pwr)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
/* Fill raw dataset
|
||||
* (all power levels are in 0.25dB units) */
|
||||
pd->pd_step[0] = pcinfo->pcdac_x0[0];
|
||||
pd->pd_pwr[0] = pcinfo->pwr_x0[0];
|
||||
|
||||
for (point = 1; point < pd->pd_points;
|
||||
point++) {
|
||||
/* Absolute values */
|
||||
pd->pd_pwr[point] =
|
||||
pcinfo->pwr_x0[point];
|
||||
|
||||
/* Deltas */
|
||||
pd->pd_step[point] =
|
||||
pd->pd_step[point - 1] +
|
||||
pcinfo->pcdac_x0[point];
|
||||
}
|
||||
|
||||
/* Set min power for this frequency */
|
||||
chinfo[pier].min_pwr = pd->pd_pwr[0];
|
||||
|
||||
/* Highest gain curve (min power) */
|
||||
} else if (pdg == 1) {
|
||||
|
||||
pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS;
|
||||
|
||||
/* Allocate pd points for this curve */
|
||||
pd->pd_step = kcalloc(pd->pd_points,
|
||||
sizeof(u8), GFP_KERNEL);
|
||||
|
||||
if (!pd->pd_step)
|
||||
return -ENOMEM;
|
||||
|
||||
pd->pd_pwr = kcalloc(pd->pd_points,
|
||||
sizeof(s16), GFP_KERNEL);
|
||||
|
||||
if (!pd->pd_pwr)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Fill raw dataset
|
||||
* (all power levels are in 0.25dB units) */
|
||||
for (point = 0; point < pd->pd_points;
|
||||
point++) {
|
||||
/* Absolute values */
|
||||
pd->pd_pwr[point] =
|
||||
pcinfo->pwr_x3[point];
|
||||
|
||||
/* Fixed points */
|
||||
pd->pd_step[point] =
|
||||
pcinfo->pcdac_x3[point];
|
||||
}
|
||||
|
||||
/* Since we have a higher gain curve
|
||||
* override min power */
|
||||
chinfo[pier].min_pwr = pd->pd_pwr[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse EEPROM data */
|
||||
static int
|
||||
ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info;
|
||||
struct ath5k_chan_pcal_info *gen_chan_info;
|
||||
u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
|
||||
u32 offset;
|
||||
unsigned int i, c;
|
||||
u8 i, c;
|
||||
u16 val;
|
||||
int ret;
|
||||
u8 pd_gains = 0;
|
||||
|
||||
/* Count how many curves we have and
|
||||
* identify them (which one of the 4
|
||||
* available curves we have on each count).
|
||||
* Curves are stored from lower (x0) to
|
||||
* higher (x3) gain */
|
||||
for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) {
|
||||
/* ee_x_gain[mode] is x gain mask */
|
||||
if ((ee->ee_x_gain[mode] >> i) & 0x1)
|
||||
pdgain_idx[pd_gains++] = i;
|
||||
}
|
||||
ee->ee_pd_gains[mode] = pd_gains;
|
||||
|
||||
if (pd_gains == 0 || pd_gains > 2)
|
||||
return -EINVAL;
|
||||
|
||||
switch (mode) {
|
||||
case AR5K_EEPROM_MODE_11A:
|
||||
|
@ -808,13 +1017,13 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
|
|||
for (i = 0; i < ee->ee_n_piers[mode]; i++) {
|
||||
chan_pcal_info = &gen_chan_info[i].rf5112_info;
|
||||
|
||||
/* Power values in dBm * 4
|
||||
/* Power values in quarter dB
|
||||
* for the lower xpd gain curve
|
||||
* (0 dBm -> higher output power) */
|
||||
for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pwr_x0[c] = (val & 0xff);
|
||||
chan_pcal_info->pwr_x0[++c] = ((val >> 8) & 0xff);
|
||||
chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff);
|
||||
chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff);
|
||||
}
|
||||
|
||||
/* PCDAC steps
|
||||
|
@ -825,12 +1034,12 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
|
|||
chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f);
|
||||
chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f);
|
||||
|
||||
/* Power values in dBm * 4
|
||||
/* Power values in quarter dB
|
||||
* for the higher xpd gain curve
|
||||
* (18 dBm -> lower output power) */
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pwr_x3[0] = (val & 0xff);
|
||||
chan_pcal_info->pwr_x3[1] = ((val >> 8) & 0xff);
|
||||
chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff);
|
||||
chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff);
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pwr_x3[2] = (val & 0xff);
|
||||
|
@ -843,24 +1052,36 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
|
|||
chan_pcal_info->pcdac_x3[2] = 63;
|
||||
|
||||
if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) {
|
||||
chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0xff);
|
||||
chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f);
|
||||
|
||||
/* Last xpd0 power level is also channel maximum */
|
||||
gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3];
|
||||
} else {
|
||||
chan_pcal_info->pcdac_x0[0] = 1;
|
||||
gen_chan_info[i].max_pwr = ((val >> 8) & 0xff);
|
||||
gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff);
|
||||
}
|
||||
|
||||
/* Recreate pcdac_x0 table for this channel using pcdac steps */
|
||||
chan_pcal_info->pcdac_x0[1] += chan_pcal_info->pcdac_x0[0];
|
||||
chan_pcal_info->pcdac_x0[2] += chan_pcal_info->pcdac_x0[1];
|
||||
chan_pcal_info->pcdac_x0[3] += chan_pcal_info->pcdac_x0[2];
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read power calibration for RF2413 chips
|
||||
*
|
||||
* For RF2413 we have a Power to PDDAC table (Power Detector)
|
||||
* instead of a PCDAC and 4 pd gain curves for each calibrated channel.
|
||||
* Each curve has power on x axis in 0.5 db steps and PDDADC steps on y
|
||||
* axis and looks like an exponential function like the RF5111 curve.
|
||||
*
|
||||
* To recreate the curves we read here the points and interpolate
|
||||
* later. Note that in most cases only 2 (higher and lower) curves are
|
||||
* used (like RF5112) but vendors have the oportunity to include all
|
||||
* 4 curves on eeprom. The final curve (higher power) has an extra
|
||||
* point for better accuracy like RF5112.
|
||||
*/
|
||||
|
||||
/* For RF2413 power calibration data doesn't start on a fixed location and
|
||||
* if a mode is not supported, it's section is missing -not zeroed-.
|
||||
* So we need to calculate the starting offset for each section by using
|
||||
|
@ -890,12 +1111,14 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
|
|||
switch(mode) {
|
||||
case AR5K_EEPROM_MODE_11G:
|
||||
if (AR5K_EEPROM_HDR_11B(ee->ee_header))
|
||||
offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) +
|
||||
offset += ath5k_pdgains_size_2413(ee,
|
||||
AR5K_EEPROM_MODE_11B) +
|
||||
AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
|
||||
/* fall through */
|
||||
case AR5K_EEPROM_MODE_11B:
|
||||
if (AR5K_EEPROM_HDR_11A(ee->ee_header))
|
||||
offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) +
|
||||
offset += ath5k_pdgains_size_2413(ee,
|
||||
AR5K_EEPROM_MODE_11A) +
|
||||
AR5K_EEPROM_N_5GHZ_CHAN / 2;
|
||||
/* fall through */
|
||||
case AR5K_EEPROM_MODE_11A:
|
||||
|
@ -907,37 +1130,118 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
|
|||
return offset;
|
||||
}
|
||||
|
||||
/* Read power calibration for RF2413 chips
|
||||
* For RF2413 we have a PDDAC table (Power Detector) instead
|
||||
* of a PCDAC and 4 pd gain curves for each calibrated channel.
|
||||
* Each curve has PDDAC steps on x axis and power on y axis and
|
||||
* looks like an exponential function. To recreate the curves
|
||||
* we read here the points and interpolate later. Note that
|
||||
* in most cases only higher and lower curves are used (like
|
||||
* RF5112) but vendors have the oportunity to include all 4
|
||||
* curves on eeprom. The final curve (higher power) has an extra
|
||||
* point for better accuracy like RF5112.
|
||||
*/
|
||||
/* Convert RF2413 specific data to generic raw data
|
||||
* used by interpolation code */
|
||||
static int
|
||||
ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
|
||||
struct ath5k_chan_pcal_info *chinfo)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct ath5k_chan_pcal_info_rf2413 *pcinfo;
|
||||
u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
|
||||
unsigned int pier, pdg, point;
|
||||
|
||||
/* Fill raw data for each calibration pier */
|
||||
for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
|
||||
|
||||
pcinfo = &chinfo[pier].rf2413_info;
|
||||
|
||||
/* Allocate pd_curves for this cal pier */
|
||||
chinfo[pier].pd_curves =
|
||||
kcalloc(AR5K_EEPROM_N_PD_CURVES,
|
||||
sizeof(struct ath5k_pdgain_info),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!chinfo[pier].pd_curves)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Fill pd_curves */
|
||||
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
|
||||
|
||||
u8 idx = pdgain_idx[pdg];
|
||||
struct ath5k_pdgain_info *pd =
|
||||
&chinfo[pier].pd_curves[idx];
|
||||
|
||||
/* One more point for the highest power
|
||||
* curve (lowest gain) */
|
||||
if (pdg == ee->ee_pd_gains[mode] - 1)
|
||||
pd->pd_points = AR5K_EEPROM_N_PD_POINTS;
|
||||
else
|
||||
pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1;
|
||||
|
||||
/* Allocate pd points for this curve */
|
||||
pd->pd_step = kcalloc(pd->pd_points,
|
||||
sizeof(u8), GFP_KERNEL);
|
||||
|
||||
if (!pd->pd_step)
|
||||
return -ENOMEM;
|
||||
|
||||
pd->pd_pwr = kcalloc(pd->pd_points,
|
||||
sizeof(s16), GFP_KERNEL);
|
||||
|
||||
if (!pd->pd_pwr)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Fill raw dataset
|
||||
* convert all pwr levels to
|
||||
* quarter dB for RF5112 combatibility */
|
||||
pd->pd_step[0] = pcinfo->pddac_i[pdg];
|
||||
pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg];
|
||||
|
||||
for (point = 1; point < pd->pd_points; point++) {
|
||||
|
||||
pd->pd_pwr[point] = pd->pd_pwr[point - 1] +
|
||||
2 * pcinfo->pwr[pdg][point - 1];
|
||||
|
||||
pd->pd_step[point] = pd->pd_step[point - 1] +
|
||||
pcinfo->pddac[pdg][point - 1];
|
||||
|
||||
}
|
||||
|
||||
/* Highest gain curve -> min power */
|
||||
if (pdg == 0)
|
||||
chinfo[pier].min_pwr = pd->pd_pwr[0];
|
||||
|
||||
/* Lowest gain curve -> max power */
|
||||
if (pdg == ee->ee_pd_gains[mode] - 1)
|
||||
chinfo[pier].max_pwr =
|
||||
pd->pd_pwr[pd->pd_points - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse EEPROM data */
|
||||
static int
|
||||
ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info;
|
||||
struct ath5k_chan_pcal_info *gen_chan_info;
|
||||
unsigned int i, c;
|
||||
struct ath5k_chan_pcal_info_rf2413 *pcinfo;
|
||||
struct ath5k_chan_pcal_info *chinfo;
|
||||
u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
|
||||
u32 offset;
|
||||
int ret;
|
||||
int idx, i, ret;
|
||||
u16 val;
|
||||
u8 pd_gains = 0;
|
||||
|
||||
if (ee->ee_x_gain[mode] & 0x1) pd_gains++;
|
||||
if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++;
|
||||
if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++;
|
||||
if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++;
|
||||
/* Count how many curves we have and
|
||||
* identify them (which one of the 4
|
||||
* available curves we have on each count).
|
||||
* Curves are stored from higher to
|
||||
* lower gain so we go backwards */
|
||||
for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) {
|
||||
/* ee_x_gain[mode] is x gain mask */
|
||||
if ((ee->ee_x_gain[mode] >> idx) & 0x1)
|
||||
pdgain_idx[pd_gains++] = idx;
|
||||
|
||||
}
|
||||
ee->ee_pd_gains[mode] = pd_gains;
|
||||
|
||||
if (pd_gains == 0)
|
||||
return -EINVAL;
|
||||
|
||||
offset = ath5k_cal_data_offset_2413(ee, mode);
|
||||
ee->ee_n_piers[mode] = 0;
|
||||
switch (mode) {
|
||||
case AR5K_EEPROM_MODE_11A:
|
||||
if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
|
||||
|
@ -945,7 +1249,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
|
|||
|
||||
ath5k_eeprom_init_11a_pcal_freq(ah, offset);
|
||||
offset += AR5K_EEPROM_N_5GHZ_CHAN / 2;
|
||||
gen_chan_info = ee->ee_pwr_cal_a;
|
||||
chinfo = ee->ee_pwr_cal_a;
|
||||
break;
|
||||
case AR5K_EEPROM_MODE_11B:
|
||||
if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
|
||||
|
@ -953,7 +1257,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
|
|||
|
||||
ath5k_eeprom_init_11bg_2413(ah, mode, offset);
|
||||
offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
|
||||
gen_chan_info = ee->ee_pwr_cal_b;
|
||||
chinfo = ee->ee_pwr_cal_b;
|
||||
break;
|
||||
case AR5K_EEPROM_MODE_11G:
|
||||
if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
|
||||
|
@ -961,41 +1265,35 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
|
|||
|
||||
ath5k_eeprom_init_11bg_2413(ah, mode, offset);
|
||||
offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
|
||||
gen_chan_info = ee->ee_pwr_cal_g;
|
||||
chinfo = ee->ee_pwr_cal_g;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pd_gains == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ee->ee_n_piers[mode]; i++) {
|
||||
chan_pcal_info = &gen_chan_info[i].rf2413_info;
|
||||
pcinfo = &chinfo[i].rf2413_info;
|
||||
|
||||
/*
|
||||
* Read pwr_i, pddac_i and the first
|
||||
* 2 pd points (pwr, pddac)
|
||||
*/
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pwr_i[0] = val & 0x1f;
|
||||
chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f;
|
||||
chan_pcal_info->pwr[0][0] =
|
||||
(val >> 12) & 0xf;
|
||||
pcinfo->pwr_i[0] = val & 0x1f;
|
||||
pcinfo->pddac_i[0] = (val >> 5) & 0x7f;
|
||||
pcinfo->pwr[0][0] = (val >> 12) & 0xf;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pddac[0][0] = val & 0x3f;
|
||||
chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf;
|
||||
chan_pcal_info->pddac[0][1] =
|
||||
(val >> 10) & 0x3f;
|
||||
pcinfo->pddac[0][0] = val & 0x3f;
|
||||
pcinfo->pwr[0][1] = (val >> 6) & 0xf;
|
||||
pcinfo->pddac[0][1] = (val >> 10) & 0x3f;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pwr[0][2] = val & 0xf;
|
||||
chan_pcal_info->pddac[0][2] =
|
||||
(val >> 4) & 0x3f;
|
||||
pcinfo->pwr[0][2] = val & 0xf;
|
||||
pcinfo->pddac[0][2] = (val >> 4) & 0x3f;
|
||||
|
||||
chan_pcal_info->pwr[0][3] = 0;
|
||||
chan_pcal_info->pddac[0][3] = 0;
|
||||
pcinfo->pwr[0][3] = 0;
|
||||
pcinfo->pddac[0][3] = 0;
|
||||
|
||||
if (pd_gains > 1) {
|
||||
/*
|
||||
|
@ -1003,44 +1301,36 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
|
|||
* so it only has 2 pd points.
|
||||
* Continue wih pd gain 1.
|
||||
*/
|
||||
chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f;
|
||||
pcinfo->pwr_i[1] = (val >> 10) & 0x1f;
|
||||
|
||||
chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1;
|
||||
pcinfo->pddac_i[1] = (val >> 15) & 0x1;
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1;
|
||||
pcinfo->pddac_i[1] |= (val & 0x3F) << 1;
|
||||
|
||||
chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf;
|
||||
chan_pcal_info->pddac[1][0] =
|
||||
(val >> 10) & 0x3f;
|
||||
pcinfo->pwr[1][0] = (val >> 6) & 0xf;
|
||||
pcinfo->pddac[1][0] = (val >> 10) & 0x3f;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pwr[1][1] = val & 0xf;
|
||||
chan_pcal_info->pddac[1][1] =
|
||||
(val >> 4) & 0x3f;
|
||||
chan_pcal_info->pwr[1][2] =
|
||||
(val >> 10) & 0xf;
|
||||
pcinfo->pwr[1][1] = val & 0xf;
|
||||
pcinfo->pddac[1][1] = (val >> 4) & 0x3f;
|
||||
pcinfo->pwr[1][2] = (val >> 10) & 0xf;
|
||||
|
||||
chan_pcal_info->pddac[1][2] =
|
||||
(val >> 14) & 0x3;
|
||||
pcinfo->pddac[1][2] = (val >> 14) & 0x3;
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pddac[1][2] |=
|
||||
(val & 0xF) << 2;
|
||||
pcinfo->pddac[1][2] |= (val & 0xF) << 2;
|
||||
|
||||
chan_pcal_info->pwr[1][3] = 0;
|
||||
chan_pcal_info->pddac[1][3] = 0;
|
||||
pcinfo->pwr[1][3] = 0;
|
||||
pcinfo->pddac[1][3] = 0;
|
||||
} else if (pd_gains == 1) {
|
||||
/*
|
||||
* Pd gain 0 is the last one so
|
||||
* read the extra point.
|
||||
*/
|
||||
chan_pcal_info->pwr[0][3] =
|
||||
(val >> 10) & 0xf;
|
||||
pcinfo->pwr[0][3] = (val >> 10) & 0xf;
|
||||
|
||||
chan_pcal_info->pddac[0][3] =
|
||||
(val >> 14) & 0x3;
|
||||
pcinfo->pddac[0][3] = (val >> 14) & 0x3;
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pddac[0][3] |=
|
||||
(val & 0xF) << 2;
|
||||
pcinfo->pddac[0][3] |= (val & 0xF) << 2;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1048,105 +1338,65 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
|
|||
* as above.
|
||||
*/
|
||||
if (pd_gains > 2) {
|
||||
chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f;
|
||||
chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f;
|
||||
pcinfo->pwr_i[2] = (val >> 4) & 0x1f;
|
||||
pcinfo->pddac_i[2] = (val >> 9) & 0x7f;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pwr[2][0] =
|
||||
(val >> 0) & 0xf;
|
||||
chan_pcal_info->pddac[2][0] =
|
||||
(val >> 4) & 0x3f;
|
||||
chan_pcal_info->pwr[2][1] =
|
||||
(val >> 10) & 0xf;
|
||||
pcinfo->pwr[2][0] = (val >> 0) & 0xf;
|
||||
pcinfo->pddac[2][0] = (val >> 4) & 0x3f;
|
||||
pcinfo->pwr[2][1] = (val >> 10) & 0xf;
|
||||
|
||||
chan_pcal_info->pddac[2][1] =
|
||||
(val >> 14) & 0x3;
|
||||
pcinfo->pddac[2][1] = (val >> 14) & 0x3;
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pddac[2][1] |=
|
||||
(val & 0xF) << 2;
|
||||
pcinfo->pddac[2][1] |= (val & 0xF) << 2;
|
||||
|
||||
chan_pcal_info->pwr[2][2] =
|
||||
(val >> 4) & 0xf;
|
||||
chan_pcal_info->pddac[2][2] =
|
||||
(val >> 8) & 0x3f;
|
||||
pcinfo->pwr[2][2] = (val >> 4) & 0xf;
|
||||
pcinfo->pddac[2][2] = (val >> 8) & 0x3f;
|
||||
|
||||
chan_pcal_info->pwr[2][3] = 0;
|
||||
chan_pcal_info->pddac[2][3] = 0;
|
||||
pcinfo->pwr[2][3] = 0;
|
||||
pcinfo->pddac[2][3] = 0;
|
||||
} else if (pd_gains == 2) {
|
||||
chan_pcal_info->pwr[1][3] =
|
||||
(val >> 4) & 0xf;
|
||||
chan_pcal_info->pddac[1][3] =
|
||||
(val >> 8) & 0x3f;
|
||||
pcinfo->pwr[1][3] = (val >> 4) & 0xf;
|
||||
pcinfo->pddac[1][3] = (val >> 8) & 0x3f;
|
||||
}
|
||||
|
||||
if (pd_gains > 3) {
|
||||
chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3;
|
||||
pcinfo->pwr_i[3] = (val >> 14) & 0x3;
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2;
|
||||
pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2;
|
||||
|
||||
chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f;
|
||||
chan_pcal_info->pwr[3][0] =
|
||||
(val >> 10) & 0xf;
|
||||
chan_pcal_info->pddac[3][0] =
|
||||
(val >> 14) & 0x3;
|
||||
pcinfo->pddac_i[3] = (val >> 3) & 0x7f;
|
||||
pcinfo->pwr[3][0] = (val >> 10) & 0xf;
|
||||
pcinfo->pddac[3][0] = (val >> 14) & 0x3;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pddac[3][0] |=
|
||||
(val & 0xF) << 2;
|
||||
chan_pcal_info->pwr[3][1] =
|
||||
(val >> 4) & 0xf;
|
||||
chan_pcal_info->pddac[3][1] =
|
||||
(val >> 8) & 0x3f;
|
||||
pcinfo->pddac[3][0] |= (val & 0xF) << 2;
|
||||
pcinfo->pwr[3][1] = (val >> 4) & 0xf;
|
||||
pcinfo->pddac[3][1] = (val >> 8) & 0x3f;
|
||||
|
||||
chan_pcal_info->pwr[3][2] =
|
||||
(val >> 14) & 0x3;
|
||||
pcinfo->pwr[3][2] = (val >> 14) & 0x3;
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pwr[3][2] |=
|
||||
((val >> 0) & 0x3) << 2;
|
||||
pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2;
|
||||
|
||||
chan_pcal_info->pddac[3][2] =
|
||||
(val >> 2) & 0x3f;
|
||||
chan_pcal_info->pwr[3][3] =
|
||||
(val >> 8) & 0xf;
|
||||
pcinfo->pddac[3][2] = (val >> 2) & 0x3f;
|
||||
pcinfo->pwr[3][3] = (val >> 8) & 0xf;
|
||||
|
||||
chan_pcal_info->pddac[3][3] =
|
||||
(val >> 12) & 0xF;
|
||||
pcinfo->pddac[3][3] = (val >> 12) & 0xF;
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pddac[3][3] |=
|
||||
((val >> 0) & 0x3) << 4;
|
||||
pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4;
|
||||
} else if (pd_gains == 3) {
|
||||
chan_pcal_info->pwr[2][3] =
|
||||
(val >> 14) & 0x3;
|
||||
pcinfo->pwr[2][3] = (val >> 14) & 0x3;
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
chan_pcal_info->pwr[2][3] |=
|
||||
((val >> 0) & 0x3) << 2;
|
||||
pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2;
|
||||
|
||||
chan_pcal_info->pddac[2][3] =
|
||||
(val >> 2) & 0x3f;
|
||||
}
|
||||
|
||||
for (c = 0; c < pd_gains; c++) {
|
||||
/* Recreate pwr table for this channel using pwr steps */
|
||||
chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2;
|
||||
chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0];
|
||||
chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1];
|
||||
chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2];
|
||||
if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2])
|
||||
chan_pcal_info->pwr[c][3] = 0;
|
||||
|
||||
/* Recreate pddac table for this channel using pddac steps */
|
||||
chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c];
|
||||
chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0];
|
||||
chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1];
|
||||
chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2];
|
||||
if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2])
|
||||
chan_pcal_info->pddac[c][3] = 0;
|
||||
pcinfo->pddac[2][3] = (val >> 2) & 0x3f;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read per rate target power (this is the maximum tx power
|
||||
* supported by the card). This info is used when setting
|
||||
|
@ -1154,11 +1404,12 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
|
|||
*
|
||||
* This also works for v5 EEPROMs.
|
||||
*/
|
||||
static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
|
||||
static int
|
||||
ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct ath5k_rate_pcal_info *rate_pcal_info;
|
||||
u16 *rate_target_pwr_num;
|
||||
u8 *rate_target_pwr_num;
|
||||
u32 offset;
|
||||
u16 val;
|
||||
int ret, i;
|
||||
|
@ -1264,7 +1515,9 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
|
|||
else
|
||||
read_pcal = ath5k_eeprom_read_pcal_info_5111;
|
||||
|
||||
for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
|
||||
|
||||
for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G;
|
||||
mode++) {
|
||||
err = read_pcal(ah, mode);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -1277,6 +1530,62 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct ath5k_chan_pcal_info *chinfo;
|
||||
u8 pier, pdg;
|
||||
|
||||
switch (mode) {
|
||||
case AR5K_EEPROM_MODE_11A:
|
||||
if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
|
||||
return 0;
|
||||
chinfo = ee->ee_pwr_cal_a;
|
||||
break;
|
||||
case AR5K_EEPROM_MODE_11B:
|
||||
if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
|
||||
return 0;
|
||||
chinfo = ee->ee_pwr_cal_b;
|
||||
break;
|
||||
case AR5K_EEPROM_MODE_11G:
|
||||
if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
|
||||
return 0;
|
||||
chinfo = ee->ee_pwr_cal_g;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
|
||||
if (!chinfo[pier].pd_curves)
|
||||
continue;
|
||||
|
||||
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
|
||||
struct ath5k_pdgain_info *pd =
|
||||
&chinfo[pier].pd_curves[pdg];
|
||||
|
||||
if (pd != NULL) {
|
||||
kfree(pd->pd_step);
|
||||
kfree(pd->pd_pwr);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(chinfo[pier].pd_curves);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ath5k_eeprom_detach(struct ath5k_hw *ah)
|
||||
{
|
||||
u8 mode;
|
||||
|
||||
for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)
|
||||
ath5k_eeprom_free_pcal_info(ah, mode);
|
||||
}
|
||||
|
||||
/* Read conformance test limits used for regulatory control */
|
||||
static int
|
||||
ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
|
||||
|
@ -1457,3 +1766,4 @@ bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah)
|
|||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -173,6 +173,7 @@
|
|||
#define AR5K_EEPROM_N_5GHZ_CHAN 10
|
||||
#define AR5K_EEPROM_N_2GHZ_CHAN 3
|
||||
#define AR5K_EEPROM_N_2GHZ_CHAN_2413 4
|
||||
#define AR5K_EEPROM_N_2GHZ_CHAN_MAX 4
|
||||
#define AR5K_EEPROM_MAX_CHAN 10
|
||||
#define AR5K_EEPROM_N_PWR_POINTS_5111 11
|
||||
#define AR5K_EEPROM_N_PCDAC 11
|
||||
|
@ -193,7 +194,7 @@
|
|||
#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10)
|
||||
#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32)
|
||||
#define AR5K_EEPROM_MAX_CTLS 32
|
||||
#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4
|
||||
#define AR5K_EEPROM_N_PD_CURVES 4
|
||||
#define AR5K_EEPROM_N_XPD0_POINTS 4
|
||||
#define AR5K_EEPROM_N_XPD3_POINTS 3
|
||||
#define AR5K_EEPROM_N_PD_GAINS 4
|
||||
|
@ -232,7 +233,7 @@ enum ath5k_ctl_mode {
|
|||
AR5K_CTL_11B = 1,
|
||||
AR5K_CTL_11G = 2,
|
||||
AR5K_CTL_TURBO = 3,
|
||||
AR5K_CTL_108G = 4,
|
||||
AR5K_CTL_TURBOG = 4,
|
||||
AR5K_CTL_2GHT20 = 5,
|
||||
AR5K_CTL_5GHT20 = 6,
|
||||
AR5K_CTL_2GHT40 = 7,
|
||||
|
@ -240,6 +241,29 @@ enum ath5k_ctl_mode {
|
|||
AR5K_CTL_MODE_M = 15,
|
||||
};
|
||||
|
||||
/* Default CTL ids for the 3 main reg domains.
|
||||
* Atheros only uses these by default but vendors
|
||||
* can have up to 32 different CTLs for different
|
||||
* scenarios. Note that theese values are ORed with
|
||||
* the mode id (above) so we can have up to 24 CTL
|
||||
* datasets out of these 3 main regdomains. That leaves
|
||||
* 8 ids that can be used by vendors and since 0x20 is
|
||||
* missing from HAL sources i guess this is the set of
|
||||
* custom CTLs vendors can use. */
|
||||
#define AR5K_CTL_FCC 0x10
|
||||
#define AR5K_CTL_CUSTOM 0x20
|
||||
#define AR5K_CTL_ETSI 0x30
|
||||
#define AR5K_CTL_MKK 0x40
|
||||
|
||||
/* Indicates a CTL with only mode set and
|
||||
* no reg domain mapping, such CTLs are used
|
||||
* for world roaming domains or simply when
|
||||
* a reg domain is not set */
|
||||
#define AR5K_CTL_NO_REGDOMAIN 0xf0
|
||||
|
||||
/* Indicates an empty (invalid) CTL */
|
||||
#define AR5K_CTL_NO_CTL 0xff
|
||||
|
||||
/* Per channel calibration data, used for power table setup */
|
||||
struct ath5k_chan_pcal_info_rf5111 {
|
||||
/* Power levels in half dbm units
|
||||
|
@ -257,7 +281,7 @@ struct ath5k_chan_pcal_info_rf5111 {
|
|||
struct ath5k_chan_pcal_info_rf5112 {
|
||||
/* Power levels in quarter dBm units
|
||||
* for lower (0) and higher (3)
|
||||
* level curves */
|
||||
* level curves in 0.25dB units */
|
||||
s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
|
||||
s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
|
||||
/* PCDAC table steps
|
||||
|
@ -270,35 +294,61 @@ struct ath5k_chan_pcal_info_rf2413 {
|
|||
/* Starting pwr/pddac values */
|
||||
s8 pwr_i[AR5K_EEPROM_N_PD_GAINS];
|
||||
u8 pddac_i[AR5K_EEPROM_N_PD_GAINS];
|
||||
/* (pwr,pddac) points */
|
||||
/* (pwr,pddac) points
|
||||
* power levels in 0.5dB units */
|
||||
s8 pwr[AR5K_EEPROM_N_PD_GAINS]
|
||||
[AR5K_EEPROM_N_PD_POINTS];
|
||||
u8 pddac[AR5K_EEPROM_N_PD_GAINS]
|
||||
[AR5K_EEPROM_N_PD_POINTS];
|
||||
};
|
||||
|
||||
enum ath5k_powertable_type {
|
||||
AR5K_PWRTABLE_PWR_TO_PCDAC = 0,
|
||||
AR5K_PWRTABLE_LINEAR_PCDAC = 1,
|
||||
AR5K_PWRTABLE_PWR_TO_PDADC = 2,
|
||||
};
|
||||
|
||||
struct ath5k_pdgain_info {
|
||||
u8 pd_points;
|
||||
u8 *pd_step;
|
||||
/* Power values are in
|
||||
* 0.25dB units */
|
||||
s16 *pd_pwr;
|
||||
};
|
||||
|
||||
struct ath5k_chan_pcal_info {
|
||||
/* Frequency */
|
||||
u16 freq;
|
||||
/* Max available power */
|
||||
s8 max_pwr;
|
||||
/* Tx power boundaries */
|
||||
s16 max_pwr;
|
||||
s16 min_pwr;
|
||||
union {
|
||||
struct ath5k_chan_pcal_info_rf5111 rf5111_info;
|
||||
struct ath5k_chan_pcal_info_rf5112 rf5112_info;
|
||||
struct ath5k_chan_pcal_info_rf2413 rf2413_info;
|
||||
};
|
||||
/* Raw values used by phy code
|
||||
* Curves are stored in order from lower
|
||||
* gain to higher gain (max txpower -> min txpower) */
|
||||
struct ath5k_pdgain_info *pd_curves;
|
||||
};
|
||||
|
||||
/* Per rate calibration data for each mode, used for power table setup */
|
||||
/* Per rate calibration data for each mode,
|
||||
* used for rate power table setup.
|
||||
* Note: Values in 0.5dB units */
|
||||
struct ath5k_rate_pcal_info {
|
||||
u16 freq; /* Frequency */
|
||||
/* Power level for 6-24Mbit/s rates */
|
||||
/* Power level for 6-24Mbit/s rates or
|
||||
* 1Mb rate */
|
||||
u16 target_power_6to24;
|
||||
/* Power level for 36Mbit rate */
|
||||
/* Power level for 36Mbit rate or
|
||||
* 2Mb rate */
|
||||
u16 target_power_36;
|
||||
/* Power level for 48Mbit rate */
|
||||
/* Power level for 48Mbit rate or
|
||||
* 5.5Mbit rate */
|
||||
u16 target_power_48;
|
||||
/* Power level for 54Mbit rate */
|
||||
/* Power level for 54Mbit rate or
|
||||
* 11Mbit rate */
|
||||
u16 target_power_54;
|
||||
};
|
||||
|
||||
|
@ -330,12 +380,6 @@ struct ath5k_eeprom_info {
|
|||
u16 ee_cck_ofdm_power_delta;
|
||||
u16 ee_scaled_cck_delta;
|
||||
|
||||
/* Used for tx thermal adjustment (eeprom_init, rfregs) */
|
||||
u16 ee_tx_clip;
|
||||
u16 ee_pwd_84;
|
||||
u16 ee_pwd_90;
|
||||
u16 ee_gain_select;
|
||||
|
||||
/* RF Calibration settings (reset, rfregs) */
|
||||
u16 ee_i_cal[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_q_cal[AR5K_EEPROM_N_MODES];
|
||||
|
@ -363,23 +407,25 @@ struct ath5k_eeprom_info {
|
|||
/* Power calibration data */
|
||||
u16 ee_false_detect[AR5K_EEPROM_N_MODES];
|
||||
|
||||
/* Number of pd gain curves per mode (RF2413) */
|
||||
/* Number of pd gain curves per mode */
|
||||
u8 ee_pd_gains[AR5K_EEPROM_N_MODES];
|
||||
/* Back mapping pdcurve number -> pdcurve index in pd->pd_curves */
|
||||
u8 ee_pdc_to_idx[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PD_GAINS];
|
||||
|
||||
u8 ee_n_piers[AR5K_EEPROM_N_MODES];
|
||||
struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
|
||||
struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN];
|
||||
struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN];
|
||||
struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
|
||||
struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
|
||||
|
||||
/* Per rate target power levels */
|
||||
u16 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES];
|
||||
u8 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES];
|
||||
struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
|
||||
struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN];
|
||||
struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN];
|
||||
struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
|
||||
struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
|
||||
|
||||
/* Conformance test limits (Unused) */
|
||||
u16 ee_ctls;
|
||||
u16 ee_ctl[AR5K_EEPROM_MAX_CTLS];
|
||||
u8 ee_ctls;
|
||||
u8 ee_ctl[AR5K_EEPROM_MAX_CTLS];
|
||||
struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS];
|
||||
|
||||
/* Noise Floor Calibration settings */
|
||||
|
|
Loading…
Reference in a new issue