summaryrefslogtreecommitdiff
path: root/sys/dev/ic/ar5xxx.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ic/ar5xxx.c')
-rw-r--r--sys/dev/ic/ar5xxx.c307
1 files changed, 241 insertions, 66 deletions
diff --git a/sys/dev/ic/ar5xxx.c b/sys/dev/ic/ar5xxx.c
index 1c3ccfd023e..6532bed0be6 100644
--- a/sys/dev/ic/ar5xxx.c
+++ b/sys/dev/ic/ar5xxx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar5xxx.c,v 1.17 2005/03/10 08:30:56 reyk Exp $ */
+/* $OpenBSD: ar5xxx.c,v 1.18 2005/03/18 20:46:32 reyk Exp $ */
/*
* Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net>
@@ -29,12 +29,6 @@ extern ar5k_attach_t ar5k_ar5210_attach;
extern ar5k_attach_t ar5k_ar5211_attach;
extern ar5k_attach_t ar5k_ar5212_attach;
-static const struct
-ieee80211_regchannel ar5k_5ghz_channels[] = IEEE80211_CHANNELS_5GHZ;
-
-static const struct
-ieee80211_regchannel ar5k_2ghz_channels[] = IEEE80211_CHANNELS_2GHZ;
-
static const struct {
u_int16_t vendor;
u_int16_t device;
@@ -86,18 +80,29 @@ HAL_BOOL ar5k_check_channel(struct ath_hal *, u_int16_t, u_int flags);
HAL_BOOL ar5k_ar5111_rfregs(struct ath_hal *, HAL_CHANNEL *, u_int);
HAL_BOOL ar5k_ar5112_rfregs(struct ath_hal *, HAL_CHANNEL *, u_int);
-int ar5k_rfregs_set(u_int32_t *, u_int32_t, u_int32_t, u_int32_t,
- u_int32_t, u_int32_t);
+int ar5k_rfregs_op(u_int32_t *, u_int32_t, u_int32_t, u_int32_t,
+ u_int32_t, u_int32_t, HAL_BOOL);
+
+/*
+ * Supported channels
+ */
+static const struct
+ieee80211_regchannel ar5k_5ghz_channels[] = IEEE80211_CHANNELS_5GHZ;
+static const struct
+ieee80211_regchannel ar5k_2ghz_channels[] = IEEE80211_CHANNELS_2GHZ;
+
+/*
+ * Initial gain optimization values
+ */
+static const struct ar5k_gain_opt ar5111_gain_opt = AR5K_AR5111_GAIN_OPT;
+static const struct ar5k_gain_opt ar5112_gain_opt = AR5K_AR5112_GAIN_OPT;
/*
* Initial register for the radio chipsets
*/
-static const struct ar5k_ini_rf ar5111_rf[] =
- AR5K_AR5111_INI_RF;
-static const struct ar5k_ini_rf ar5112_rf[] =
- AR5K_AR5112_INI_RF;
-static const struct ar5k_ini_rfgain ar5k_rfg[] =
- AR5K_INI_RFGAIN;
+static const struct ar5k_ini_rf ar5111_rf[] = AR5K_AR5111_INI_RF;
+static const struct ar5k_ini_rf ar5112_rf[] = AR5K_AR5112_INI_RF;
+static const struct ar5k_ini_rfgain ar5k_rfg[] = AR5K_INI_RFGAIN;
/*
* Enable to overwrite the country code (use "00" for debug)
@@ -144,6 +149,7 @@ ath_hal_attach(device, sc, st, sh, status)
HAL_RATE_TABLE rt_11b = AR5K_RATES_11B;
HAL_RATE_TABLE rt_11g = AR5K_RATES_11G;
HAL_RATE_TABLE rt_turbo = AR5K_RATES_TURBO;
+ HAL_RATE_TABLE rt_xr = AR5K_RATES_XR;
u_int16_t regdomain;
struct ath_hal *hal = NULL;
ar5k_attach_t *attach = NULL;
@@ -256,6 +262,25 @@ ath_hal_attach(device, sc, st, sh, status)
ar5k_rt_copy(&hal->ah_rt_11g, &rt_11g);
if (hal->ah_capabilities.cap_mode & HAL_MODE_TURBO)
ar5k_rt_copy(&hal->ah_rt_turbo, &rt_turbo);
+ if (hal->ah_capabilities.cap_mode & HAL_MODE_XR)
+ ar5k_rt_copy(&hal->ah_rt_xr, &rt_xr);
+
+ /* Initialize the gain optimization values */
+ if (hal->ah_radio == AR5K_AR5111) {
+ hal->ah_gain.g_step_idx = ar5111_gain_opt.go_default;
+ hal->ah_gain.g_step =
+ &ar5111_gain_opt.go_step[hal->ah_gain.g_step_idx];
+ hal->ah_gain.g_low = 20;
+ hal->ah_gain.g_high = 35;
+ hal->ah_gain.g_active = 1;
+ } else if (hal->ah_radio == AR5K_AR5112) {
+ hal->ah_gain.g_step_idx = ar5112_gain_opt.go_default;
+ hal->ah_gain.g_step =
+ &ar5111_gain_opt.go_step[hal->ah_gain.g_step_idx];
+ hal->ah_gain.g_low = 20;
+ hal->ah_gain.g_high = 85;
+ hal->ah_gain.g_active = 1;
+ }
*status = HAL_OK;
@@ -1273,34 +1298,174 @@ ar5k_ar5112_channel(hal, channel)
}
int
-ar5k_rfregs_set(rf, offset, reg, bits, first, col)
+ar5k_rfregs_op(rf, offset, reg, bits, first, col, set)
u_int32_t *rf;
u_int32_t offset, reg, bits, first, col;
+ HAL_BOOL set;
{
- u_int32_t tmp, mask, entry, last;
- int32_t position, left;
+ u_int32_t mask, entry, last, data, shift, position;
+ int32_t left;
int i;
if (!(col <= 3 && bits <= 32 && first + bits <= 319)) {
AR5K_PRINTF("invalid values at offset %u\n", offset);
- return (-1);
+ return (0);
}
- tmp = ar5k_bitswap(reg, bits);
entry = ((first - 1) / 8) + offset;
position = (first - 1) % 8;
- for (i = 0, left = bits; left > 0; position = 0, entry++, i++) {
+ if (set == AH_TRUE)
+ data = ar5k_bitswap(reg, bits);
+
+ for (i = shift = 0, left = bits; left > 0; position = 0, entry++, i++) {
last = (position + left > 8) ? 8 : position + left;
mask = (((1 << last) - 1) ^ ((1 << position) - 1)) <<
(col * 8);
- rf[entry] &= ~mask;
- rf[entry] |= ((tmp << position) << (col * 8)) & mask;
+
+ if (set == AH_TRUE) {
+ rf[entry] &= ~mask;
+ rf[entry] |= ((data << position) << (col * 8)) & mask;
+ data >>= (8 - position);
+ } else {
+ data = (((rf[entry] & mask) >> (col * 8)) >>
+ position) << shift;
+ shift += last - position;
+ }
+
left -= 8 - position;
- tmp >>= (8 - position);
}
- return (i);
+ data = set == AH_TRUE ? 1 : ar5k_bitswap(data, bits);
+
+ return (data);
+}
+
+u_int32_t
+ar5k_rfregs_gainf_corr(hal)
+ struct ath_hal *hal;
+{
+ u_int32_t mix, step;
+
+ hal->ah_gain.g_f_corr = 0;
+
+ if (ar5k_rfregs_op(NULL, hal->ah_offset[7], 0, 1, 36, 0, AH_FALSE) != 1)
+ return (0);
+
+ step = ar5k_rfregs_op(NULL, hal->ah_offset[7], 0, 4, 32, 0, AH_FALSE);
+ mix = hal->ah_gain.g_step->gos_param[0];
+
+ switch (mix) {
+ case 3:
+ hal->ah_gain.g_f_corr = step * 2;
+ break;
+ case 2:
+ hal->ah_gain.g_f_corr = (step - 5) * 2;
+ break;
+ case 1:
+ hal->ah_gain.g_f_corr = step;
+ break;
+ default:
+ hal->ah_gain.g_f_corr = 0;
+ break;
+ }
+
+ return (hal->ah_gain.g_f_corr);
+}
+
+HAL_BOOL
+ar5k_rfregs_gain_readback(hal)
+ struct ath_hal *hal;
+{
+ u_int32_t step, mix, level[4];
+
+ if (hal->ah_radio == AR5K_AR5111) {
+ step = ar5k_rfregs_op(NULL, hal->ah_offset[7],
+ 0, 6, 37, 0, AH_FALSE);
+ level[0] = 0;
+ level[1] = (step == 0x3f) ? 0x32 : step + 4;
+ level[2] = (step != 0x3f) ? 0x40 : level[0];
+ level[3] = level[2] + 0x32;
+
+ hal->ah_gain.g_high = level[3] -
+ (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
+ hal->ah_gain.g_low = level[0] +
+ (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
+ } else {
+ mix = ar5k_rfregs_op(NULL, hal->ah_offset[7],
+ 0, 1, 36, 0, AH_FALSE);
+ level[0] = level[2] = 0;
+
+ if (mix == 1) {
+ level[1] = level[3] = 83;
+ } else {
+ level[1] = level[3] = 107;
+ hal->ah_gain.g_high = 55;
+ }
+ }
+
+ return ((hal->ah_gain.g_current >= level[0] &&
+ hal->ah_gain.g_current <= level[1]) ||
+ (hal->ah_gain.g_current >= level[2] &&
+ hal->ah_gain.g_current <= level[3]));
+}
+
+int32_t
+ar5k_rfregs_gain_adjust(hal)
+ struct ath_hal *hal;
+{
+ int ret = 0;
+ const struct ar5k_gain_opt *go;
+
+ go = hal->ah_radio == AR5K_AR5111 ?
+ &ar5111_gain_opt : &ar5112_gain_opt;
+
+ hal->ah_gain.g_step = &go->go_step[hal->ah_gain.g_step_idx];
+
+ if (hal->ah_gain.g_current >= hal->ah_gain.g_high) {
+ if (hal->ah_gain.g_step_idx == 0)
+ return (-1);
+ for (hal->ah_gain.g_target = hal->ah_gain.g_current;
+ hal->ah_gain.g_target >= hal->ah_gain.g_high &&
+ hal->ah_gain.g_step_idx > 0;
+ hal->ah_gain.g_step =
+ &go->go_step[hal->ah_gain.g_step_idx]) {
+ hal->ah_gain.g_target -= 2 *
+ (go->go_step[--(hal->ah_gain.g_step_idx)].gos_gain -
+ hal->ah_gain.g_step->gos_gain);
+ }
+
+ ret = 1;
+ goto done;
+ }
+
+ if (hal->ah_gain.g_current <= hal->ah_gain.g_low) {
+ if (hal->ah_gain.g_step_idx == (go->go_steps_count - 1))
+ return (-2);
+ for (hal->ah_gain.g_target = hal->ah_gain.g_current;
+ hal->ah_gain.g_target <= hal->ah_gain.g_low &&
+ hal->ah_gain.g_step_idx < (go->go_steps_count - 1);
+ hal->ah_gain.g_step =
+ &go->go_step[hal->ah_gain.g_step_idx]) {
+ hal->ah_gain.g_target -= 2 *
+ (go->go_step[++(hal->ah_gain.g_step_idx)].gos_gain -
+ hal->ah_gain.g_step->gos_gain);
+ }
+
+ ret = 2;
+ goto done;
+ }
+
+ done:
+#ifdef AR5K_DEBUG
+ AR5K_PRINTF("ret %d, gain step %u, current gain %u, target gain %u\n",
+ g,
+ hal->ah_gain.g_step_idx,
+ hal->ah_gain.g_current,
+ hal->ah_gain.g_target);
+#endif
+
+ return (ret);
}
HAL_BOOL
@@ -1309,12 +1474,20 @@ ar5k_rfregs(hal, channel, mode)
HAL_CHANNEL *channel;
u_int mode;
{
+ HAL_BOOL ret;
+
if (hal->ah_radio < AR5K_AR5111)
return (AH_FALSE);
- else if (hal->ah_radio < AR5K_AR5112)
- return (ar5k_ar5111_rfregs(hal, channel, mode));
- return (ar5k_ar5112_rfregs(hal, channel, mode));
+ if (hal->ah_radio == AR5K_AR5111)
+ ret = ar5k_ar5111_rfregs(hal, channel, mode);
+ else
+ ret = ar5k_ar5112_rfregs(hal, channel, mode);
+
+ if (ret == AH_TRUE)
+ hal->ah_rf_gain = HAL_RFGAIN_INACTIVE;
+
+ return (ret);
}
HAL_BOOL
@@ -1327,7 +1500,7 @@ ar5k_ar5111_rfregs(hal, channel, mode)
const u_int rf_size = AR5K_ELEMENTS(ar5111_rf);
u_int32_t rf[rf_size];
int i, obdb = -1, bank = -1;
- u_int32_t ee_mode, offset[AR5K_AR5111_INI_RF_MAX_BANKS];
+ u_int32_t ee_mode;
AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
@@ -1341,7 +1514,7 @@ ar5k_ar5111_rfregs(hal, channel, mode)
if (bank != ar5111_rf[i].rf_bank) {
bank = ar5111_rf[i].rf_bank;
- offset[bank] = i;
+ hal->ah_offset[bank] = i;
}
rf[i] = ar5111_rf[i].rf_value[mode];
@@ -1354,12 +1527,12 @@ ar5k_ar5111_rfregs(hal, channel, mode)
ee_mode = AR5K_EEPROM_MODE_11G;
obdb = 0;
- if (ar5k_rfregs_set(rf, offset[0],
- ee->ee_ob[ee_mode][obdb], 3, 119, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[0],
+ ee->ee_ob[ee_mode][obdb], 3, 119, 0, AH_TRUE))
return (AH_FALSE);
- if (ar5k_rfregs_set(rf, offset[0],
- ee->ee_ob[ee_mode][obdb], 3, 122, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[0],
+ ee->ee_ob[ee_mode][obdb], 3, 122, 0, AH_TRUE))
return (AH_FALSE);
obdb = 1;
@@ -1371,37 +1544,37 @@ ar5k_ar5111_rfregs(hal, channel, mode)
(channel->c_channel >= 5260 ? 1 :
(channel->c_channel > 4000 ? 0 : -1)));
- if (ar5k_rfregs_set(rf, offset[6],
- ee->ee_pwd_84, 1, 51, 3) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ ee->ee_pwd_84, 1, 51, 3, AH_TRUE))
return (AH_FALSE);
- if (ar5k_rfregs_set(rf, offset[6],
- ee->ee_pwd_90, 1, 45, 3) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ ee->ee_pwd_90, 1, 45, 3, AH_TRUE))
return (AH_FALSE);
}
- if (ar5k_rfregs_set(rf, offset[6],
- !ee->ee_xpd[ee_mode], 1, 95, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ !ee->ee_xpd[ee_mode], 1, 95, 0, AH_TRUE))
return (AH_FALSE);
- if (ar5k_rfregs_set(rf, offset[6],
- ee->ee_x_gain[ee_mode], 4, 96, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ ee->ee_x_gain[ee_mode], 4, 96, 0, AH_TRUE))
return (AH_FALSE);
- if (ar5k_rfregs_set(rf, offset[6],
- obdb >= 0 ? ee->ee_ob[ee_mode][obdb] : 0, 3, 104, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ obdb >= 0 ? ee->ee_ob[ee_mode][obdb] : 0, 3, 104, 0, AH_TRUE))
return (AH_FALSE);
- if (ar5k_rfregs_set(rf, offset[6],
- obdb >= 0 ? ee->ee_db[ee_mode][obdb] : 0, 3, 107, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ obdb >= 0 ? ee->ee_db[ee_mode][obdb] : 0, 3, 107, 0, AH_TRUE))
return (AH_FALSE);
- if (ar5k_rfregs_set(rf, offset[7],
- ee->ee_i_gain[ee_mode], 6, 29, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[7],
+ ee->ee_i_gain[ee_mode], 6, 29, 0, AH_TRUE))
return (AH_FALSE);
- if (ar5k_rfregs_set(rf, offset[7],
- ee->ee_xpd[ee_mode], 1, 4, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[7],
+ ee->ee_xpd[ee_mode], 1, 4, 0, AH_TRUE))
return (AH_FALSE);
/* Write RF values */
@@ -1423,7 +1596,7 @@ ar5k_ar5112_rfregs(hal, channel, mode)
const u_int rf_size = AR5K_ELEMENTS(ar5112_rf);
u_int32_t rf[rf_size];
int i, obdb = -1, bank = -1;
- u_int32_t ee_mode, offset[AR5K_AR5112_INI_RF_MAX_BANKS];
+ u_int32_t ee_mode;
AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
@@ -1437,7 +1610,7 @@ ar5k_ar5112_rfregs(hal, channel, mode)
if (bank != ar5112_rf[i].rf_bank) {
bank = ar5112_rf[i].rf_bank;
- offset[bank] = i;
+ hal->ah_offset[bank] = i;
}
rf[i] = ar5112_rf[i].rf_value[mode];
@@ -1450,12 +1623,12 @@ ar5k_ar5112_rfregs(hal, channel, mode)
ee_mode = AR5K_EEPROM_MODE_11G;
obdb = 0;
- if (ar5k_rfregs_set(rf, offset[6],
- ee->ee_ob[ee_mode][obdb], 3, 287, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ ee->ee_ob[ee_mode][obdb], 3, 287, 0, AH_TRUE))
return (AH_FALSE);
- if (ar5k_rfregs_set(rf, offset[6],
- ee->ee_ob[ee_mode][obdb], 3, 290, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ ee->ee_ob[ee_mode][obdb], 3, 290, 0, AH_TRUE))
return (AH_FALSE);
} else {
/* For 11a, Turbo and XR */
@@ -1465,26 +1638,28 @@ ar5k_ar5112_rfregs(hal, channel, mode)
(channel->c_channel >= 5260 ? 1 :
(channel->c_channel > 4000 ? 0 : -1)));
- if (ar5k_rfregs_set(rf, offset[6],
- ee->ee_ob[ee_mode][obdb], 3, 279, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ ee->ee_ob[ee_mode][obdb], 3, 279, 0, AH_TRUE))
return (AH_FALSE);
- if (ar5k_rfregs_set(rf, offset[6],
- ee->ee_ob[ee_mode][obdb], 3, 282, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ ee->ee_ob[ee_mode][obdb], 3, 282, 0, AH_TRUE))
return (AH_FALSE);
}
#ifdef notyet
- ar5k_rfregs_set(rf, offset[6], ee->ee_x_gain[ee_mode], 2, 270, 0);
- ar5k_rfregs_set(rf, offset[6], ee->ee_x_gain[ee_mode], 2, 257, 0);
+ ar5k_rfregs_op(rf, hal->ah_offset[6],
+ ee->ee_x_gain[ee_mode], 2, 270, 0, AH_TRUE);
+ ar5k_rfregs_op(rf, hal->ah_offset[6],
+ ee->ee_x_gain[ee_mode], 2, 257, 0, AH_TRUE);
#endif
- if (ar5k_rfregs_set(rf, offset[6],
- ee->ee_xpd[ee_mode], 1, 302, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
+ ee->ee_xpd[ee_mode], 1, 302, 0, AH_TRUE))
return (AH_FALSE);
- if (ar5k_rfregs_set(rf, offset[7],
- ee->ee_i_gain[ee_mode], 6, 14, 0) < 0)
+ if (!ar5k_rfregs_op(rf, hal->ah_offset[7],
+ ee->ee_i_gain[ee_mode], 6, 14, 0, AH_TRUE))
return (AH_FALSE);
/* Write RF values */