Return-path: Received: from venema.h4ckr.net ([217.24.1.135]:56358 "EHLO venema.h4ckr.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751678AbZAaC2c (ORCPT ); Fri, 30 Jan 2009 21:28:32 -0500 Date: Sat, 31 Jan 2009 04:28:26 +0200 From: Nick Kossifidis To: ath5k-devel@lists.ath5k.org, linux-wireless@vger.kernel.org Cc: linville@tuxdriver.com, jirislaby@gmail.com, mcgrof@gmail.com, me@bobcopeland.com, nbd@openwrt.org Subject: [PATCH 3/5] ath5k: Update RF Buffer handling Message-ID: <20090131022826.GC3342@makis> (sfid-20090131_032836_580691_2EC1AB38) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Sender: linux-wireless-owner@vger.kernel.org List-ID: * Use the new way to modify rf buffer and put some rf buffer documentation on rfbufer.h * Merge all rf regs functions to one * Sync with legacy HAL and Sam's HAL * Set gain_F settings so that gain_F optimization engine works on RF5111/RF5112 (note that both HALs only use step 0 for RF5111 and they don't use gain_F optimization for this chip, code is there but is never used) Signed-Off-by: Nick Kossifidis --- drivers/net/wireless/ath5k/ath5k.h | 11 +- drivers/net/wireless/ath5k/phy.c | 571 +++++++++++++++++---------------- drivers/net/wireless/ath5k/reg.h | 24 -- drivers/net/wireless/ath5k/reset.c | 2 +- drivers/net/wireless/ath5k/rfbuffer.h | 88 +++++- 5 files changed, 379 insertions(+), 317 deletions(-) diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index c870e2a..5b2e0da 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -165,9 +165,6 @@ #define AR5K_INI_VAL_XR 0 #define AR5K_INI_VAL_MAX 5 -#define AR5K_RF5111_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS -#define AR5K_RF5112_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS - /* Used for BSSID etc manipulation */ #define AR5K_LOW_ID(_a)( \ (_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \ @@ -342,6 +339,7 @@ struct ath5k_srev_name { #define AR5K_SREV_PHY_5211 0x30 #define AR5K_SREV_PHY_5212 0x41 +#define AR5K_SREV_PHY_5212A 0x42 #define AR5K_SREV_PHY_2112B 0x43 #define AR5K_SREV_PHY_2413 0x45 #define AR5K_SREV_PHY_5413 0x61 @@ -1083,8 +1081,9 @@ struct ath5k_hw { u32 ah_txq_isr; u32 *ah_rf_banks; size_t ah_rf_banks_size; + size_t ah_rf_regs_count; struct ath5k_gain ah_gain; - u32 ah_offset[AR5K_MAX_RF_BANKS]; + u8 ah_offset[AR5K_MAX_RF_BANKS]; struct { u16 txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE]; @@ -1232,7 +1231,9 @@ extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah); extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel); /* Initialize RF */ -extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode); +extern int ath5k_hw_rfregs_init(struct ath5k_hw *ah, + struct ieee80211_channel *channel, + unsigned int mode); extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq); extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah); extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah); diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index 2543a71..81f5beb 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -32,48 +32,80 @@ /* * Used to modify RF Banks before writing them to AR5K_RF_BUFFER */ -static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits, - u32 first, u32 col, bool set) +static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah, + const struct ath5k_rf_reg *rf_regs, + u32 val, u8 reg_id, bool set) { - u32 mask, entry, last, data, shift, position; - s32 left; + const struct ath5k_rf_reg *rfreg = NULL; + u8 offset, bank, num_bits, col, position; + u16 entry; + u32 mask, data, last_bit, bits_shifted, first_bit; + u32 *rfb; + s32 bits_left; int i; data = 0; + rfb = ah->ah_rf_banks; - if (rf == NULL) + for (i = 0; i < ah->ah_rf_regs_count; i++) { + if (rf_regs[i].index == reg_id) { + rfreg = &rf_regs[i]; + break; + } + } + + if (rfb == NULL || rfreg == NULL) { + ATH5K_PRINTF("Rf register not found!\n"); /* should not happen */ return 0; + } + + bank = rfreg->bank; + num_bits = rfreg->field.len; + first_bit = rfreg->field.pos; + col = rfreg->field.col; + + /* first_bit is an offset from bank's + * start. Since we have all banks on + * the same array, we use this offset + * to mark each bank's start */ + offset = ah->ah_offset[bank]; - if (!(col <= 3 && bits <= 32 && first + bits <= 319)) { + /* Boundary check */ + if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) { ATH5K_PRINTF("invalid values at offset %u\n", offset); return 0; } - entry = ((first - 1) / 8) + offset; - position = (first - 1) % 8; + entry = ((first_bit - 1) / 8) + offset; + position = (first_bit - 1) % 8; if (set) - data = ath5k_hw_bitswap(reg, bits); + data = ath5k_hw_bitswap(val, num_bits); + + for (bits_shifted = 0, bits_left = num_bits; bits_left > 0; + position = 0, entry++) { + + last_bit = (position + bits_left > 8) ? 8 : + position + bits_left; - 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); + mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) << + (col * 8); if (set) { - rf[entry] &= ~mask; - rf[entry] |= ((data << position) << (col * 8)) & mask; + rfb[entry] &= ~mask; + rfb[entry] |= ((data << position) << (col * 8)) & mask; data >>= (8 - position); } else { - data = (((rf[entry] & mask) >> (col * 8)) >> position) - << shift; - shift += last - position; + data |= (((rfb[entry] & mask) >> (col * 8)) >> position) + << bits_shifted; + bits_shifted += last_bit - position; } - left -= 8 - position; + bits_left -= 8 - position; } - data = set ? 1 : ath5k_hw_bitswap(data, bits); + data = set ? 1 : ath5k_hw_bitswap(data, num_bits); return data; } @@ -167,6 +199,7 @@ static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) u32 *rf; const struct ath5k_gain_opt *go; const struct ath5k_gain_opt_step *g_step; + const struct ath5k_rf_reg *rf_regs; /* Only RF5112 Rev. 2 supports it */ if ((ah->ah_radio != AR5K_RF5112) || @@ -174,6 +207,8 @@ static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) return 0; go = &rfgain_opt_5112; + rf_regs = rf_regs_5112a; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a); g_step = &go->go_step[ah->ah_gain.g_step_idx]; @@ -184,11 +219,11 @@ static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) ah->ah_gain.g_f_corr = 0; /* No VGA (Variable Gain Amplifier) override, skip */ - if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1) + if (ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, false) != 1) return 0; /* Mix gain stepping */ - step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false); + step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXGAIN_STEP, false); /* Mix gain override */ mix = g_step->gos_param[0]; @@ -217,6 +252,7 @@ static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) * their detection window) so we must ignore it */ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) { + const struct ath5k_rf_reg *rf_regs; u32 step, mix_ovr, level[4]; u32 *rf; @@ -226,8 +262,13 @@ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) rf = ah->ah_rf_banks; if (ah->ah_radio == AR5K_RF5111) { - step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0, - false); + + rf_regs = rf_regs_5111; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111); + + step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_RFGAIN_STEP, + false); + level[0] = 0; level[1] = (step == 63) ? 50 : step + 4; level[2] = (step != 63) ? 64 : level[0]; @@ -238,8 +279,13 @@ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) ah->ah_gain.g_low = level[0] + (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); } else { - mix_ovr = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, - false); + + rf_regs = rf_regs_5112; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112); + + mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, + false); + level[0] = level[2] = 0; if (mix_ovr == 1) { @@ -451,341 +497,320 @@ int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq) * RF Registers setup * \********************/ + /* - * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111 + * Setup RF registers by writing rf buffer on hw */ -static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah, - struct ieee80211_channel *channel, unsigned int mode) +int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, + unsigned int mode) { + const struct ath5k_rf_reg *rf_regs; + const struct ath5k_ini_rfbuffer *ini_rfb; + const struct ath5k_gain_opt *go = NULL; + const struct ath5k_gain_opt_step *g_step; struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 *rf; - const unsigned int rf_size = ARRAY_SIZE(rfb_5111); - unsigned int i; - int obdb = -1, bank = -1; - u32 ee_mode; + u8 ee_mode = 0; + u32 *rfb; + int i, obdb = -1, bank = -1; - AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX); + switch (ah->ah_radio) { + case AR5K_RF5111: + rf_regs = rf_regs_5111; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111); + ini_rfb = rfb_5111; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111); + go = &rfgain_opt_5111; + break; + case AR5K_RF5112: + if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { + rf_regs = rf_regs_5112a; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a); + ini_rfb = rfb_5112a; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a); + } else { + rf_regs = rf_regs_5112; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112); + ini_rfb = rfb_5112; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112); + } + go = &rfgain_opt_5112; + break; + case AR5K_RF2413: + rf_regs = rf_regs_2413; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413); + ini_rfb = rfb_2413; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413); + break; + case AR5K_RF2316: + rf_regs = rf_regs_2316; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316); + ini_rfb = rfb_2316; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316); + break; + case AR5K_RF5413: + rf_regs = rf_regs_5413; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413); + ini_rfb = rfb_5413; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413); + break; + case AR5K_RF2317: + rf_regs = rf_regs_2425; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425); + ini_rfb = rfb_2317; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317); + break; + case AR5K_RF2425: + rf_regs = rf_regs_2425; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425); + if (ah->ah_mac_srev < AR5K_SREV_AR2417) { + ini_rfb = rfb_2425; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425); + } else { + ini_rfb = rfb_2417; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417); + } + break; + default: + return -EINVAL; + } - rf = ah->ah_rf_banks; + /* If it's the first time we set rf buffer, allocate + * ah->ah_rf_banks based on ah->ah_rf_banks_size + * we set above */ + if (ah->ah_rf_banks == NULL) { + ah->ah_rf_banks = kmalloc(sizeof(u32) * ah->ah_rf_banks_size, + GFP_KERNEL); + if (ah->ah_rf_banks == NULL) { + ATH5K_ERR(ah->ah_sc, "out of memory\n"); + return -ENOMEM; + } + } /* Copy values to modify them */ - for (i = 0; i < rf_size; i++) { - if (rfb_5111[i].rfb_bank >= AR5K_RF5111_INI_RF_MAX_BANKS) { + rfb = ah->ah_rf_banks; + + for (i = 0; i < ah->ah_rf_banks_size; i++) { + if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) { ATH5K_ERR(ah->ah_sc, "invalid bank\n"); return -EINVAL; } - if (bank != rfb_5111[i].rfb_bank) { - bank = rfb_5111[i].rfb_bank; + /* Bank changed, write down the offset */ + if (bank != ini_rfb[i].rfb_bank) { + bank = ini_rfb[i].rfb_bank; ah->ah_offset[bank] = i; } - rf[i] = rfb_5111[i].rfb_mode_data[mode]; + rfb[i] = ini_rfb[i].rfb_mode_data[mode]; } - /* Modify bank 0 */ + /* Set Output and Driver bias current (OB/DB) */ if (channel->hw_value & CHANNEL_2GHZ) { + if (channel->hw_value & CHANNEL_CCK) ee_mode = AR5K_EEPROM_MODE_11B; else ee_mode = AR5K_EEPROM_MODE_11G; - obdb = 0; - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0], - ee->ee_ob[ee_mode][obdb], 3, 119, 0, true)) - return -EINVAL; + /* For RF511X/RF211X combination we + * use b_OB and b_DB parameters stored + * in eeprom on ee->ee_ob[ee_mode][0] + * + * For all other chips we use OB/DB for 2Ghz + * stored in the b/g modal section just like + * 802.11a on ee->ee_ob[ee_mode][1] */ + if ((ah->ah_radio == AR5K_RF5111) || + (ah->ah_radio == AR5K_RF5112)) + obdb = 0; + else + obdb = 1; - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0], - ee->ee_ob[ee_mode][obdb], 3, 122, 0, true)) - return -EINVAL; + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb], + AR5K_RF_OB_2GHZ, true); - obdb = 1; - /* Modify bank 6 */ - } else { - /* For 11a, Turbo and XR */ + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb], + AR5K_RF_DB_2GHZ, true); + + /* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */ + } else if ((channel->hw_value & CHANNEL_5GHZ) || + (ah->ah_radio == AR5K_RF5111)) { + + /* For 11a, Turbo and XR we need to choose + * OB/DB based on frequency range */ ee_mode = AR5K_EEPROM_MODE_11A; obdb = channel->center_freq >= 5725 ? 3 : (channel->center_freq >= 5500 ? 2 : (channel->center_freq >= 5260 ? 1 : (channel->center_freq > 4000 ? 0 : -1))); - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - ee->ee_pwd_84, 1, 51, 3, true)) + if (obdb < 0) return -EINVAL; - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - ee->ee_pwd_90, 1, 45, 3, true)) - return -EINVAL; - } + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb], + AR5K_RF_OB_5GHZ, true); - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - !ee->ee_xpd[ee_mode], 1, 95, 0, true)) - return -EINVAL; + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb], + AR5K_RF_DB_5GHZ, true); + } - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - ee->ee_x_gain[ee_mode], 4, 96, 0, true)) - return -EINVAL; + g_step = &go->go_step[ah->ah_gain.g_step_idx]; - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ? - ee->ee_ob[ee_mode][obdb] : 0, 3, 104, 0, true)) - return -EINVAL; + /* Bank Modifications (chip-specific) */ + if (ah->ah_radio == AR5K_RF5111) { - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ? - ee->ee_db[ee_mode][obdb] : 0, 3, 107, 0, true)) - return -EINVAL; + /* Set gain_F settings according to current step */ + if (channel->hw_value & CHANNEL_OFDM) { - /* Modify bank 7 */ - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7], - ee->ee_i_gain[ee_mode], 6, 29, 0, true)) - return -EINVAL; + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, + AR5K_PHY_FRAME_CTL_TX_CLIP, + g_step->gos_param[0]); - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7], - ee->ee_xpd[ee_mode], 1, 4, 0, true)) - return -EINVAL; + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1], + AR5K_RF_PWD_90, true); - /* Write RF values */ - for (i = 0; i < rf_size; i++) { - AR5K_REG_WAIT(i); - ath5k_hw_reg_write(ah, rf[i], rfb_5111[i].rfb_ctrl_register); - } + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2], + AR5K_RF_PWD_84, true); - ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3], + AR5K_RF_RFGAIN_SEL, true); - return 0; -} + /* We programmed gain_F parameters, switch back + * to active state */ + ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; -/* - * Read EEPROM Calibration data, modify RF Banks and Initialize RF5112 - */ -static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, - struct ieee80211_channel *channel, unsigned int mode) -{ - const struct ath5k_ini_rfbuffer *rf_ini; - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 *rf; - unsigned int rf_size, i; - int obdb = -1, bank = -1; - u32 ee_mode; + } - AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX); + /* Bank 6/7 setup */ - rf = ah->ah_rf_banks; + ath5k_hw_rfb_op(ah, rf_regs, !ee->ee_xpd[ee_mode], + AR5K_RF_PWD_XPD, true); - if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { - rf_ini = rfb_5112a; - rf_size = ARRAY_SIZE(rfb_5112a); - } else { - rf_ini = rfb_5112; - rf_size = ARRAY_SIZE(rfb_5112); - } + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_x_gain[ee_mode], + AR5K_RF_XPD_GAIN, true); - /* Copy values to modify them */ - for (i = 0; i < rf_size; i++) { - if (rf_ini[i].rfb_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) { - ATH5K_ERR(ah->ah_sc, "invalid bank\n"); - return -EINVAL; - } + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode], + AR5K_RF_GAIN_I, true); - if (bank != rf_ini[i].rfb_bank) { - bank = rf_ini[i].rfb_bank; - ah->ah_offset[bank] = i; - } + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode], + AR5K_RF_PLO_SEL, true); - rf[i] = rf_ini[i].rfb_mode_data[mode]; + /* TODO: Half/quarter channel support */ } - /* Modify bank 6 */ - if (channel->hw_value & CHANNEL_2GHZ) { - if (channel->hw_value & CHANNEL_OFDM) - ee_mode = AR5K_EEPROM_MODE_11G; - else - ee_mode = AR5K_EEPROM_MODE_11B; - obdb = 0; + if (ah->ah_radio == AR5K_RF5112) { - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - ee->ee_ob[ee_mode][obdb], 3, 287, 0, true)) - return -EINVAL; + /* Set gain_F settings according to current step */ + if (channel->hw_value & CHANNEL_OFDM) { - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - ee->ee_ob[ee_mode][obdb], 3, 290, 0, true)) - return -EINVAL; - } else { - /* For 11a, Turbo and XR */ - ee_mode = AR5K_EEPROM_MODE_11A; - obdb = channel->center_freq >= 5725 ? 3 : - (channel->center_freq >= 5500 ? 2 : - (channel->center_freq >= 5260 ? 1 : - (channel->center_freq > 4000 ? 0 : -1))); + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0], + AR5K_RF_MIXGAIN_OVR, true); - if (obdb == -1) - return -EINVAL; + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1], + AR5K_RF_PWD_138, true); - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - ee->ee_ob[ee_mode][obdb], 3, 279, 0, true)) - return -EINVAL; + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2], + AR5K_RF_PWD_137, true); - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - ee->ee_ob[ee_mode][obdb], 3, 282, 0, true)) - return -EINVAL; - } + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3], + AR5K_RF_PWD_136, true); - ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - ee->ee_x_gain[ee_mode], 2, 270, 0, true); - ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - ee->ee_x_gain[ee_mode], 2, 257, 0, true); + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[4], + AR5K_RF_PWD_132, true); - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], - ee->ee_xpd[ee_mode], 1, 302, 0, true)) - return -EINVAL; + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[5], + AR5K_RF_PWD_131, true); - /* Modify bank 7 */ - if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7], - ee->ee_i_gain[ee_mode], 6, 14, 0, true)) - return -EINVAL; + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[6], + AR5K_RF_PWD_130, true); - /* Write RF values */ - for (i = 0; i < rf_size; i++) - ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rfb_ctrl_register); + /* We programmed gain_F parameters, switch back + * to active state */ + ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; + } + /* Bank 6/7 setup */ - ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode], + AR5K_RF_XPD_SEL, true); - return 0; -} + if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) { + /* Rev. 1 supports only one xpd */ + ath5k_hw_rfb_op(ah, rf_regs, + ee->ee_x_gain[ee_mode], + AR5K_RF_XPD_GAIN, true); -/* - * Initialize RF5413/5414 and future chips - * (until we come up with a better solution) - */ -static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah, - struct ieee80211_channel *channel, unsigned int mode) -{ - const struct ath5k_ini_rfbuffer *rf_ini; - u32 *rf; - unsigned int rf_size, i; - int bank = -1; + } else { + /* TODO: Set high and low gain bits */ + ath5k_hw_rfb_op(ah, rf_regs, + ee->ee_x_gain[ee_mode], + AR5K_RF_PD_GAIN_LO, true); + ath5k_hw_rfb_op(ah, rf_regs, + ee->ee_x_gain[ee_mode], + AR5K_RF_PD_GAIN_HI, true); - AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX); + /* Lower synth voltage on Rev 2 */ + ath5k_hw_rfb_op(ah, rf_regs, 2, + AR5K_RF_HIGH_VC_CP, true); - rf = ah->ah_rf_banks; + ath5k_hw_rfb_op(ah, rf_regs, 2, + AR5K_RF_MID_VC_CP, true); - switch (ah->ah_radio) { - case AR5K_RF5413: - rf_ini = rfb_5413; - rf_size = ARRAY_SIZE(rfb_5413); - break; - case AR5K_RF2413: - rf_ini = rfb_2413; - rf_size = ARRAY_SIZE(rfb_2413); + ath5k_hw_rfb_op(ah, rf_regs, 2, + AR5K_RF_LOW_VC_CP, true); - if (mode < 2) { - ATH5K_ERR(ah->ah_sc, - "invalid channel mode: %i\n", mode); - return -EINVAL; - } + ath5k_hw_rfb_op(ah, rf_regs, 2, + AR5K_RF_PUSH_UP, true); - break; - case AR5K_RF2425: - rf_ini = rfb_2425; - rf_size = ARRAY_SIZE(rfb_2425); + /* Decrease power consumption on 5213+ BaseBand */ + if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { + ath5k_hw_rfb_op(ah, rf_regs, 1, + AR5K_RF_PAD2GND, true); - if (mode < 2) { - ATH5K_ERR(ah->ah_sc, - "invalid channel mode: %i\n", mode); - return -EINVAL; - } + ath5k_hw_rfb_op(ah, rf_regs, 1, + AR5K_RF_XB2_LVL, true); - break; - default: - return -EINVAL; - } + ath5k_hw_rfb_op(ah, rf_regs, 1, + AR5K_RF_XB5_LVL, true); - /* Copy values to modify them */ - for (i = 0; i < rf_size; i++) { - if (rf_ini[i].rfb_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) { - ATH5K_ERR(ah->ah_sc, "invalid bank\n"); - return -EINVAL; - } + ath5k_hw_rfb_op(ah, rf_regs, 1, + AR5K_RF_PWD_167, true); - if (bank != rf_ini[i].rfb_bank) { - bank = rf_ini[i].rfb_bank; - ah->ah_offset[bank] = i; + ath5k_hw_rfb_op(ah, rf_regs, 1, + AR5K_RF_PWD_166, true); + } } - rf[i] = rf_ini[i].rfb_mode_data[mode]; - } + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode], + AR5K_RF_GAIN_I, true); - /* - * After compairing dumps from different cards - * we get the same RF_BUFFER settings (diff returns - * 0 lines). It seems that RF_BUFFER settings are static - * and are written unmodified (no EEPROM stuff - * is used because calibration data would be - * different between different cards and would result - * different RF_BUFFER settings) - */ + /* TODO: Half/quarter channel support */ - /* Write RF values */ - for (i = 0; i < rf_size; i++) - ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rfb_ctrl_register); + } - return 0; -} + if (ah->ah_radio == AR5K_RF5413 && + channel->hw_value & CHANNEL_2GHZ) { -/* - * Initialize RF - */ -int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, - unsigned int mode) -{ - int (*func)(struct ath5k_hw *, struct ieee80211_channel *, unsigned int); - int ret; + ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE, + true); - switch (ah->ah_radio) { - case AR5K_RF5111: - ah->ah_rf_banks_size = sizeof(rfb_5111); - func = ath5k_hw_rf5111_rfregs; - break; - case AR5K_RF5112: - if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) - ah->ah_rf_banks_size = sizeof(rfb_5112a); - else - ah->ah_rf_banks_size = sizeof(rfb_5112); - func = ath5k_hw_rf5112_rfregs; - break; - case AR5K_RF5413: - ah->ah_rf_banks_size = sizeof(rfb_5413); - func = ath5k_hw_rf5413_rfregs; - break; - case AR5K_RF2413: - ah->ah_rf_banks_size = sizeof(rfb_2413); - func = ath5k_hw_rf5413_rfregs; - break; - case AR5K_RF2425: - ah->ah_rf_banks_size = sizeof(rfb_2425); - func = ath5k_hw_rf5413_rfregs; - break; - default: - return -EINVAL; - } + /* Set optimum value for early revisions (on pci-e chips) */ + if (ah->ah_mac_srev >= AR5K_SREV_AR5424 && + ah->ah_mac_srev < AR5K_SREV_AR5413) + ath5k_hw_rfb_op(ah, rf_regs, ath5k_hw_bitswap(6, 3), + AR5K_RF_PWD_ICLOBUF_2G, true); - if (ah->ah_rf_banks == NULL) { - /* XXX do extra checks? */ - ah->ah_rf_banks = kmalloc(ah->ah_rf_banks_size, GFP_KERNEL); - if (ah->ah_rf_banks == NULL) { - ATH5K_ERR(ah->ah_sc, "out of memory\n"); - return -ENOMEM; - } } - ret = func(ah, channel, mode); + /* Write RF banks on hw */ + for (i = 0; i < ah->ah_rf_banks_size; i++) { + AR5K_REG_WAIT(i); + ath5k_hw_reg_write(ah, rfb[i], ini_rfb[i].rfb_ctrl_register); + } - return ret; + return 0; } - - /**************************\ PHY/RF channel functions \**************************/ diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 9189ab1..9aa22ef 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -2101,34 +2101,10 @@ /* * RF Buffer register * - * There are some special control registers on the RF chip - * that hold various operation settings related mostly to - * the analog parts (channel, gain adjustment etc). - * - * We don't write on those registers directly but - * we send a data packet on the buffer register and - * then write on another special register to notify hw - * to apply the settings. This is done so that control registers - * can be dynamicaly programmed during operation and the settings - * are applied faster on the hw. - * - * We sent such data packets during rf initialization and channel change - * through ath5k_hw_rf*_rfregs and ath5k_hw_rf*_channel functions. - * - * The data packets we send during initializadion are inside ath5k_ini_rf - * struct (see ath5k_hw.h) and each one is related to an "rf register bank". - * We use *rfregs functions to modify them acording to current operation - * mode and eeprom values and pass them all together to the chip. - * * It's obvious from the code that 0x989c is the buffer register but * for the other special registers that we write to after sending each * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers * for now. It's interesting that they are also used for some other operations. - * - * Also check out hw.h and U.S. Patent 6677779 B1 (about buffer - * registers and control registers): - * - * http://www.google.com/patents?id=qNURAAAAEBAJ */ #define AR5K_RF_BUFFER 0x989c diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index f7ce80e..40cf4c7 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -600,7 +600,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* * Write RF registers */ - ret = ath5k_hw_rfregs(ah, channel, mode); + ret = ath5k_hw_rfregs_init(ah, channel, mode); if (ret) return ret; diff --git a/drivers/net/wireless/ath5k/rfbuffer.h b/drivers/net/wireless/ath5k/rfbuffer.h index 28b3016..e50baff 100644 --- a/drivers/net/wireless/ath5k/rfbuffer.h +++ b/drivers/net/wireless/ath5k/rfbuffer.h @@ -17,6 +17,33 @@ * */ + +/* + * There are some special registers on the RF chip + * that control various operation settings related mostly to + * the analog parts (channel, gain adjustment etc). + * + * We don't write on those registers directly but + * we send a data packet on the chip, using a special register, + * that holds all the settings we need. After we 've sent the + * data packet, we write on another special register to notify hw + * to apply the settings. This is done so that control registers + * can be dynamicaly programmed during operation and the settings + * are applied faster on the hw. + * + * We call each data packet an "RF Bank" and all the data we write + * (all RF Banks) "RF Buffer". This file holds initial RF Buffer + * data for the different RF chips, and various info to match RF + * Buffer offsets with specific RF registers so that we can access + * them. We tweak these settings on rfregs_init function. + * + * Also check out reg.h and U.S. Patent 6677779 B1 (about buffer + * registers and control registers): + * + * http://www.google.com/patents?id=qNURAAAAEBAJ + */ + + /* * Struct to hold default mode specific RF * register values (RF Banks) @@ -72,15 +99,28 @@ enum ath5k_rf_regs_idx { AR5K_RF_XB2_LVL, AR5K_RF_XB5_LVL, AR5K_RF_PWD_ICLOBUF_2G, + AR5K_RF_PWD_84, + AR5K_RF_PWD_90, + AR5K_RF_PWD_130, + AR5K_RF_PWD_131, + AR5K_RF_PWD_132, + AR5K_RF_PWD_136, + AR5K_RF_PWD_137, + AR5K_RF_PWD_138, + AR5K_RF_PWD_166, + AR5K_RF_PWD_167, AR5K_RF_DERBY_CHAN_SEL_MODE, /* BANK 7 */ AR5K_RF_GAIN_I, AR5K_RF_PLO_SEL, AR5K_RF_RFGAIN_SEL, + AR5K_RF_RFGAIN_STEP, AR5K_RF_WAIT_S, AR5K_RF_WAIT_I, AR5K_RF_MAX_TIME, + AR5K_RF_MIXVGA_OVR, AR5K_RF_MIXGAIN_OVR, + AR5K_RF_MIXGAIN_STEP, AR5K_RF_PD_DELAY_A, AR5K_RF_PD_DELAY_B, AR5K_RF_PD_DELAY_XR, @@ -118,19 +158,21 @@ enum ath5k_rf_regs_idx { #define AR5K_RF5111_MAX_TIME { 2, 49, 0 } static const struct ath5k_rf_reg rf_regs_5111[] = { - {6, AR5K_RF_OB_2GHZ, AR5K_RF5111_OB_2GHZ}, - {6, AR5K_RF_DB_2GHZ, AR5K_RF5111_DB_2GHZ}, - {6, AR5K_RF_OB_5GHZ, AR5K_RF5111_OB_5GHZ}, - {6, AR5K_RF_DB_5GHZ, AR5K_RF5111_DB_5GHZ}, - {6, AR5K_RF_PWD_XPD, AR5K_RF5111_PWD_XPD}, - {6, AR5K_RF_XPD_GAIN, AR5K_RF5111_XPD_GAIN}, - {7, AR5K_RF_GAIN_I, AR5K_RF5111_GAIN_I}, - {7, AR5K_RF_PLO_SEL, AR5K_RF5111_PLO_SEL}, - {7, AR5K_RF_RFGAIN_SEL, AR5K_RF5111_RFGAIN_SEL}, - {7, AR5K_RF_WAIT_S, AR5K_RF5111_WAIT_S}, - {7, AR5K_RF_WAIT_I, AR5K_RF5111_WAIT_I}, - {7, AR5K_RF_MAX_TIME, AR5K_RF5111_MAX_TIME} - + {6, AR5K_RF_OB_2GHZ, AR5K_RF5111_OB_2GHZ}, + {6, AR5K_RF_DB_2GHZ, AR5K_RF5111_DB_2GHZ}, + {6, AR5K_RF_OB_5GHZ, AR5K_RF5111_OB_5GHZ}, + {6, AR5K_RF_DB_5GHZ, AR5K_RF5111_DB_5GHZ}, + {6, AR5K_RF_PWD_XPD, AR5K_RF5111_PWD_XPD}, + {6, AR5K_RF_XPD_GAIN, AR5K_RF5111_XPD_GAIN}, + {6, AR5K_RF_PWD_84, AR5K_RF5111_PWD(84)}, + {6, AR5K_RF_PWD_90, AR5K_RF5111_PWD(90)}, + {7, AR5K_RF_GAIN_I, AR5K_RF5111_GAIN_I}, + {7, AR5K_RF_PLO_SEL, AR5K_RF5111_PLO_SEL}, + {7, AR5K_RF_RFGAIN_SEL, AR5K_RF5111_RFGAIN_SEL}, + {7, AR5K_RF_RFGAIN_STEP, AR5K_RF5111_RFGAIN_STEP}, + {7, AR5K_RF_WAIT_S, AR5K_RF5111_WAIT_S}, + {7, AR5K_RF_WAIT_I, AR5K_RF5111_WAIT_I}, + {7, AR5K_RF_MAX_TIME, AR5K_RF5111_MAX_TIME} }; /* Default mode specific settings */ @@ -273,8 +315,16 @@ static const struct ath5k_rf_reg rf_regs_5112[] = { {6, AR5K_RF_FIXED_BIAS_B, AR5K_RF5112_FIXED_BIAS_B}, {6, AR5K_RF_XPD_SEL, AR5K_RF5112_XPD_SEL}, {6, AR5K_RF_XPD_GAIN, AR5K_RF5112_XPD_GAIN}, + {6, AR5K_RF_PWD_130, AR5K_RF5112_PWD(130)}, + {6, AR5K_RF_PWD_131, AR5K_RF5112_PWD(131)}, + {6, AR5K_RF_PWD_132, AR5K_RF5112_PWD(132)}, + {6, AR5K_RF_PWD_136, AR5K_RF5112_PWD(136)}, + {6, AR5K_RF_PWD_137, AR5K_RF5112_PWD(137)}, + {6, AR5K_RF_PWD_138, AR5K_RF5112_PWD(138)}, {7, AR5K_RF_GAIN_I, AR5K_RF5112X_GAIN_I}, + {7, AR5K_RF_MIXVGA_OVR, AR5K_RF5112X_MIXVGA_OVR}, {7, AR5K_RF_MIXGAIN_OVR, AR5K_RF5112X_MIXGAIN_OVR}, + {7, AR5K_RF_MIXGAIN_STEP, AR5K_RF5112X_MIXGAIN_STEP}, {7, AR5K_RF_PD_DELAY_A, AR5K_RF5112X_PD_DELAY_A}, {7, AR5K_RF_PD_DELAY_B, AR5K_RF5112X_PD_DELAY_B}, {7, AR5K_RF_PD_DELAY_XR, AR5K_RF5112X_PD_DELAY_XR}, @@ -419,7 +469,7 @@ static const struct ath5k_ini_rfbuffer rfb_5112[] = { #define AR5K_RF5112A_HIGH_VC_CP { 2, 90, 2 } #define AR5K_RF5112A_MID_VC_CP { 2, 92, 2 } #define AR5K_RF5112A_LOW_VC_CP { 2, 94, 2 } -#define AR5K_RF5112A_PUSH_UP { 2, 94, 2 } +#define AR5K_RF5112A_PUSH_UP { 1, 254, 2 } /* Power consumption */ #define AR5K_RF5112A_PAD2GND { 1, 281, 1 } @@ -436,6 +486,14 @@ static const struct ath5k_rf_reg rf_regs_5112a[] = { {6, AR5K_RF_XPD_SEL, AR5K_RF5112A_XPD_SEL}, {6, AR5K_RF_PD_GAIN_LO, AR5K_RF5112A_PDGAINLO}, {6, AR5K_RF_PD_GAIN_HI, AR5K_RF5112A_PDGAINHI}, + {6, AR5K_RF_PWD_130, AR5K_RF5112A_PWD(130)}, + {6, AR5K_RF_PWD_131, AR5K_RF5112A_PWD(131)}, + {6, AR5K_RF_PWD_132, AR5K_RF5112A_PWD(132)}, + {6, AR5K_RF_PWD_136, AR5K_RF5112A_PWD(136)}, + {6, AR5K_RF_PWD_137, AR5K_RF5112A_PWD(137)}, + {6, AR5K_RF_PWD_138, AR5K_RF5112A_PWD(138)}, + {6, AR5K_RF_PWD_166, AR5K_RF5112A_PWD(166)}, + {6, AR5K_RF_PWD_167, AR5K_RF5112A_PWD(167)}, {6, AR5K_RF_HIGH_VC_CP, AR5K_RF5112A_HIGH_VC_CP}, {6, AR5K_RF_MID_VC_CP, AR5K_RF5112A_MID_VC_CP}, {6, AR5K_RF_LOW_VC_CP, AR5K_RF5112A_LOW_VC_CP}, @@ -444,7 +502,9 @@ static const struct ath5k_rf_reg rf_regs_5112a[] = { {6, AR5K_RF_XB2_LVL, AR5K_RF5112A_XB2_LVL}, {6, AR5K_RF_XB5_LVL, AR5K_RF5112A_XB5_LVL}, {7, AR5K_RF_GAIN_I, AR5K_RF5112X_GAIN_I}, + {7, AR5K_RF_MIXVGA_OVR, AR5K_RF5112X_MIXVGA_OVR}, {7, AR5K_RF_MIXGAIN_OVR, AR5K_RF5112X_MIXGAIN_OVR}, + {7, AR5K_RF_MIXGAIN_STEP, AR5K_RF5112X_MIXGAIN_STEP}, {7, AR5K_RF_PD_DELAY_A, AR5K_RF5112X_PD_DELAY_A}, {7, AR5K_RF_PD_DELAY_B, AR5K_RF5112X_PD_DELAY_B}, {7, AR5K_RF_PD_DELAY_XR, AR5K_RF5112X_PD_DELAY_XR},