Commit df75dcdd authored by Nick Kossifidis's avatar Nick Kossifidis Committed by John W. Linville

ath5k: Reorder calibration calls during reset and update hw_set_power

 * Update ath5k_hw_reset and add some more documentation about PHY calibration
 * Fix ath5k_hw_set_power to use AR5K_SLEEP_CTL_SLE_ALLOW for Network sleep
 * Preserve sleep duration field while setting AR5K_SLEEP_CTL
   and reduce delays & checks for register's status (got this from
   decompiling & dumps, it works for me but it needs testing)

Changes-licensed-under: ISC
Signed-off-by: default avatarNick Kossifidis <mickflemm@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e2a0cceb
...@@ -1092,34 +1092,57 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, ...@@ -1092,34 +1092,57 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
data = 0; data = 0;
/* /*
* Enable calibration and wait until completion * Start automatic gain calibration
*
* During AGC calibration RX path is re-routed to
* a signal detector so we don't receive anything.
*
* This method is used to calibrate some static offsets
* used together with on-the fly I/Q calibration (the
* one performed via ath5k_hw_phy_calibrate), that doesn't
* interrupt rx path.
*
* If we are in a noisy environment AGC calibration may time
* out.
*/ */
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_CAL); AR5K_PHY_AGCCTL_CAL);
/* At the same time start I/Q calibration for QAM constellation
* -no need for CCK- */
ah->ah_calibration = false;
if (!(mode == AR5K_MODE_11B)) {
ah->ah_calibration = true;
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
AR5K_PHY_IQ_RUN);
}
/* Wait for gain calibration to finish (we check for I/Q calibration
* during ath5k_phy_calibrate) */
if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_CAL, 0, false)) { AR5K_PHY_AGCCTL_CAL, 0, false)) {
ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n", ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
channel->center_freq); channel->center_freq);
return -EAGAIN; return -EAGAIN;
} }
/*
* Start noise floor calibration
*
* If we run NF calibration before AGC, it always times out.
* Binary HAL starts NF and AGC calibration at the same time
* and only waits for AGC to finish. I believe that's wrong because
* during NF calibration, rx path is also routed to a detector, so if
* it doesn't finish we won't have RX.
*
* XXX: Find an interval that's OK for all cards...
*/
ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
if (ret) if (ret)
return ret; return ret;
ah->ah_calibration = false;
/* A and G modes can use QAM modulation which requires enabling
* I and Q calibration. Don't bother in B mode. */
if (!(mode == AR5K_MODE_11B)) {
ah->ah_calibration = true;
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
AR5K_PHY_IQ_RUN);
}
/* /*
* Reset queues and start beacon timers at the end of the reset routine * Reset queues and start beacon timers at the end of the reset routine
*/ */
...@@ -1247,7 +1270,7 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, ...@@ -1247,7 +1270,7 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
bool set_chip, u16 sleep_duration) bool set_chip, u16 sleep_duration)
{ {
unsigned int i; unsigned int i;
u32 staid; u32 staid, data;
ATH5K_TRACE(ah->ah_sc); ATH5K_TRACE(ah->ah_sc);
staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1); staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
...@@ -1259,7 +1282,8 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, ...@@ -1259,7 +1282,8 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
case AR5K_PM_NETWORK_SLEEP: case AR5K_PM_NETWORK_SLEEP:
if (set_chip) if (set_chip)
ath5k_hw_reg_write(ah, ath5k_hw_reg_write(ah,
AR5K_SLEEP_CTL_SLE | sleep_duration, AR5K_SLEEP_CTL_SLE_ALLOW |
sleep_duration,
AR5K_SLEEP_CTL); AR5K_SLEEP_CTL);
staid |= AR5K_STA_ID1_PWR_SV; staid |= AR5K_STA_ID1_PWR_SV;
...@@ -1274,13 +1298,24 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, ...@@ -1274,13 +1298,24 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
break; break;
case AR5K_PM_AWAKE: case AR5K_PM_AWAKE:
staid &= ~AR5K_STA_ID1_PWR_SV;
if (!set_chip) if (!set_chip)
goto commit; goto commit;
ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE, /* Preserve sleep duration */
AR5K_SLEEP_CTL); data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
if( data & 0xffc00000 ){
data = 0;
} else {
data = data & 0xfffcffff;
}
ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
udelay(15);
for (i = 5000; i > 0; i--) { for (i = 50; i > 0; i--) {
/* Check if the chip did wake up */ /* Check if the chip did wake up */
if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
AR5K_PCICFG_SPWR_DN) == 0) AR5K_PCICFG_SPWR_DN) == 0)
...@@ -1288,15 +1323,13 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, ...@@ -1288,15 +1323,13 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
/* Wait a bit and retry */ /* Wait a bit and retry */
udelay(200); udelay(200);
ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE, ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
AR5K_SLEEP_CTL);
} }
/* Fail if the chip didn't wake up */ /* Fail if the chip didn't wake up */
if (i <= 0) if (i <= 0)
return -EIO; return -EIO;
staid &= ~AR5K_STA_ID1_PWR_SV;
break; break;
default: default:
...@@ -1325,6 +1358,7 @@ void ath5k_hw_start_rx(struct ath5k_hw *ah) ...@@ -1325,6 +1358,7 @@ void ath5k_hw_start_rx(struct ath5k_hw *ah)
{ {
ATH5K_TRACE(ah->ah_sc); ATH5K_TRACE(ah->ah_sc);
ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
ath5k_hw_reg_read(ah, AR5K_CR);
} }
/* /*
...@@ -1411,6 +1445,7 @@ int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue) ...@@ -1411,6 +1445,7 @@ int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue)
} }
/* Start queue */ /* Start queue */
ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
ath5k_hw_reg_read(ah, AR5K_CR);
} else { } else {
/* Return if queue is disabled */ /* Return if queue is disabled */
if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue)) if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
...@@ -1708,6 +1743,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask) ...@@ -1708,6 +1743,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
* (they will be re-enabled afterwards). * (they will be re-enabled afterwards).
*/ */
ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
ath5k_hw_reg_read(ah, AR5K_IER);
old_mask = ah->ah_imr; old_mask = ah->ah_imr;
...@@ -3511,7 +3547,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) ...@@ -3511,7 +3547,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE) if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
AR5K_REG_ENABLE_BITS(ah, AR5K_REG_ENABLE_BITS(ah,
AR5K_QUEUE_MISC(queue), AR5K_QUEUE_MISC(queue),
AR5K_QCU_MISC_TXE); AR5K_QCU_MISC_RDY_VEOL_POLICY);
} }
if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment