Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> |
| 3 | * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> |
| 4 | * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu> |
| 5 | * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org> |
| 6 | * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> |
| 7 | * |
| 8 | * Permission to use, copy, modify, and distribute this software for any |
| 9 | * purpose with or without fee is hereby granted, provided that the above |
| 10 | * copyright notice and this permission notice appear in all copies. |
| 11 | * |
| 12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 19 | * |
| 20 | */ |
| 21 | |
| 22 | #define _ATH5K_RESET |
| 23 | |
| 24 | /*****************************\ |
| 25 | Reset functions and helpers |
| 26 | \*****************************/ |
| 27 | |
| 28 | #include <linux/pci.h> |
| 29 | #include "ath5k.h" |
| 30 | #include "reg.h" |
| 31 | #include "base.h" |
| 32 | #include "debug.h" |
| 33 | |
| 34 | /** |
| 35 | * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212 |
| 36 | * |
| 37 | * @ah: the &struct ath5k_hw |
| 38 | * @channel: the currently set channel upon reset |
| 39 | * |
| 40 | * Write the OFDM timings for the AR5212 upon reset. This is a helper for |
| 41 | * ath5k_hw_reset(). This seems to tune the PLL a specified frequency |
| 42 | * depending on the bandwidth of the channel. |
| 43 | * |
| 44 | */ |
| 45 | static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, |
| 46 | struct ieee80211_channel *channel) |
| 47 | { |
| 48 | /* Get exponent and mantissa and set it */ |
| 49 | u32 coef_scaled, coef_exp, coef_man, |
| 50 | ds_coef_exp, ds_coef_man, clock; |
| 51 | |
| 52 | if (!(ah->ah_version == AR5K_AR5212) || |
| 53 | !(channel->hw_value & CHANNEL_OFDM)) |
| 54 | BUG(); |
| 55 | |
| 56 | /* Seems there are two PLLs, one for baseband sampling and one |
| 57 | * for tuning. Tuning basebands are 40 MHz or 80MHz when in |
| 58 | * turbo. */ |
| 59 | clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40; |
| 60 | coef_scaled = ((5 * (clock << 24)) / 2) / |
| 61 | channel->center_freq; |
| 62 | |
| 63 | for (coef_exp = 31; coef_exp > 0; coef_exp--) |
| 64 | if ((coef_scaled >> coef_exp) & 0x1) |
| 65 | break; |
| 66 | |
| 67 | if (!coef_exp) |
| 68 | return -EINVAL; |
| 69 | |
| 70 | coef_exp = 14 - (coef_exp - 24); |
| 71 | coef_man = coef_scaled + |
| 72 | (1 << (24 - coef_exp - 1)); |
| 73 | ds_coef_man = coef_man >> (24 - coef_exp); |
| 74 | ds_coef_exp = coef_exp - 16; |
| 75 | |
| 76 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, |
| 77 | AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man); |
| 78 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, |
| 79 | AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp); |
| 80 | |
| 81 | return 0; |
| 82 | } |
| 83 | |
| 84 | |
| 85 | /* |
| 86 | * index into rates for control rates, we can set it up like this because |
| 87 | * this is only used for AR5212 and we know it supports G mode |
| 88 | */ |
| 89 | static int control_rates[] = |
| 90 | { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 }; |
| 91 | |
| 92 | /** |
| 93 | * ath5k_hw_write_rate_duration - set rate duration during hw resets |
| 94 | * |
| 95 | * @ah: the &struct ath5k_hw |
| 96 | * @mode: one of enum ath5k_driver_mode |
| 97 | * |
| 98 | * Write the rate duration table upon hw reset. This is a helper for |
| 99 | * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout for |
| 100 | * the hardware for the current mode for each rate. The rates which are capable |
| 101 | * of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have another |
| 102 | * register for the short preamble ACK timeout calculation. |
| 103 | */ |
| 104 | static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, |
| 105 | unsigned int mode) |
| 106 | { |
| 107 | struct ath5k_softc *sc = ah->ah_sc; |
| 108 | struct ieee80211_rate *rate; |
| 109 | unsigned int i; |
| 110 | |
| 111 | /* Write rate duration table */ |
| 112 | for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) { |
| 113 | u32 reg; |
| 114 | u16 tx_time; |
| 115 | |
| 116 | rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]]; |
| 117 | |
| 118 | /* Set ACK timeout */ |
| 119 | reg = AR5K_RATE_DUR(rate->hw_value); |
| 120 | |
| 121 | /* An ACK frame consists of 10 bytes. If you add the FCS, |
| 122 | * which ieee80211_generic_frame_duration() adds, |
| 123 | * its 14 bytes. Note we use the control rate and not the |
| 124 | * actual rate for this rate. See mac80211 tx.c |
| 125 | * ieee80211_duration() for a brief description of |
| 126 | * what rate we should choose to TX ACKs. */ |
| 127 | tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, |
| 128 | sc->vif, 10, rate)); |
| 129 | |
| 130 | ath5k_hw_reg_write(ah, tx_time, reg); |
| 131 | |
| 132 | if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) |
| 133 | continue; |
| 134 | |
| 135 | /* |
| 136 | * We're not distinguishing short preamble here, |
| 137 | * This is true, all we'll get is a longer value here |
| 138 | * which is not necessarilly bad. We could use |
| 139 | * export ieee80211_frame_duration() but that needs to be |
| 140 | * fixed first to be properly used by mac802111 drivers: |
| 141 | * |
| 142 | * - remove erp stuff and let the routine figure ofdm |
| 143 | * erp rates |
| 144 | * - remove passing argument ieee80211_local as |
| 145 | * drivers don't have access to it |
| 146 | * - move drivers using ieee80211_generic_frame_duration() |
| 147 | * to this |
| 148 | */ |
| 149 | ath5k_hw_reg_write(ah, tx_time, |
| 150 | reg + (AR5K_SET_SHORT_PREAMBLE << 2)); |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | /* |
| 155 | * Reset chipset |
| 156 | */ |
| 157 | static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) |
| 158 | { |
| 159 | int ret; |
| 160 | u32 mask = val ? val : ~0U; |
| 161 | |
| 162 | ATH5K_TRACE(ah->ah_sc); |
| 163 | |
| 164 | /* Read-and-clear RX Descriptor Pointer*/ |
| 165 | ath5k_hw_reg_read(ah, AR5K_RXDP); |
| 166 | |
| 167 | /* |
| 168 | * Reset the device and wait until success |
| 169 | */ |
| 170 | ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL); |
| 171 | |
| 172 | /* Wait at least 128 PCI clocks */ |
| 173 | udelay(15); |
| 174 | |
| 175 | if (ah->ah_version == AR5K_AR5210) { |
Nick Kossifidis | 84e463f | 2008-09-17 03:33:19 +0300 | [diff] [blame] | 176 | val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA |
| 177 | | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY; |
| 178 | mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA |
| 179 | | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY; |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 180 | } else { |
| 181 | val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; |
| 182 | mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; |
| 183 | } |
| 184 | |
| 185 | ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false); |
| 186 | |
| 187 | /* |
| 188 | * Reset configuration register (for hw byte-swap). Note that this |
| 189 | * is only set for big endian. We do the necessary magic in |
| 190 | * AR5K_INIT_CFG. |
| 191 | */ |
| 192 | if ((val & AR5K_RESET_CTL_PCU) == 0) |
| 193 | ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG); |
| 194 | |
| 195 | return ret; |
| 196 | } |
| 197 | |
| 198 | /* |
| 199 | * Sleep control |
| 200 | */ |
| 201 | int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, |
| 202 | bool set_chip, u16 sleep_duration) |
| 203 | { |
| 204 | unsigned int i; |
| 205 | u32 staid, data; |
| 206 | |
| 207 | ATH5K_TRACE(ah->ah_sc); |
| 208 | staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1); |
| 209 | |
| 210 | switch (mode) { |
| 211 | case AR5K_PM_AUTO: |
| 212 | staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA; |
| 213 | /* fallthrough */ |
| 214 | case AR5K_PM_NETWORK_SLEEP: |
| 215 | if (set_chip) |
| 216 | ath5k_hw_reg_write(ah, |
| 217 | AR5K_SLEEP_CTL_SLE_ALLOW | |
| 218 | sleep_duration, |
| 219 | AR5K_SLEEP_CTL); |
| 220 | |
| 221 | staid |= AR5K_STA_ID1_PWR_SV; |
| 222 | break; |
| 223 | |
| 224 | case AR5K_PM_FULL_SLEEP: |
| 225 | if (set_chip) |
| 226 | ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP, |
| 227 | AR5K_SLEEP_CTL); |
| 228 | |
| 229 | staid |= AR5K_STA_ID1_PWR_SV; |
| 230 | break; |
| 231 | |
| 232 | case AR5K_PM_AWAKE: |
| 233 | |
| 234 | staid &= ~AR5K_STA_ID1_PWR_SV; |
| 235 | |
| 236 | if (!set_chip) |
| 237 | goto commit; |
| 238 | |
| 239 | /* Preserve sleep duration */ |
| 240 | data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); |
| 241 | if (data & 0xffc00000) |
| 242 | data = 0; |
| 243 | else |
| 244 | data = data & 0xfffcffff; |
| 245 | |
| 246 | ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); |
| 247 | udelay(15); |
| 248 | |
| 249 | for (i = 50; i > 0; i--) { |
| 250 | /* Check if the chip did wake up */ |
| 251 | if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & |
| 252 | AR5K_PCICFG_SPWR_DN) == 0) |
| 253 | break; |
| 254 | |
| 255 | /* Wait a bit and retry */ |
| 256 | udelay(200); |
| 257 | ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); |
| 258 | } |
| 259 | |
| 260 | /* Fail if the chip didn't wake up */ |
| 261 | if (i <= 0) |
| 262 | return -EIO; |
| 263 | |
| 264 | break; |
| 265 | |
| 266 | default: |
| 267 | return -EINVAL; |
| 268 | } |
| 269 | |
| 270 | commit: |
| 271 | ah->ah_power_mode = mode; |
| 272 | ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1); |
| 273 | |
| 274 | return 0; |
| 275 | } |
| 276 | |
| 277 | /* |
| 278 | * Bring up MAC + PHY Chips |
| 279 | */ |
| 280 | int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) |
| 281 | { |
| 282 | struct pci_dev *pdev = ah->ah_sc->pdev; |
| 283 | u32 turbo, mode, clock, bus_flags; |
| 284 | int ret; |
| 285 | |
| 286 | turbo = 0; |
| 287 | mode = 0; |
| 288 | clock = 0; |
| 289 | |
| 290 | ATH5K_TRACE(ah->ah_sc); |
| 291 | |
| 292 | /* Wakeup the device */ |
| 293 | ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); |
| 294 | if (ret) { |
| 295 | ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n"); |
| 296 | return ret; |
| 297 | } |
| 298 | |
| 299 | if (ah->ah_version != AR5K_AR5210) { |
| 300 | /* |
| 301 | * Get channel mode flags |
| 302 | */ |
| 303 | |
| 304 | if (ah->ah_radio >= AR5K_RF5112) { |
| 305 | mode = AR5K_PHY_MODE_RAD_RF5112; |
| 306 | clock = AR5K_PHY_PLL_RF5112; |
| 307 | } else { |
| 308 | mode = AR5K_PHY_MODE_RAD_RF5111; /*Zero*/ |
| 309 | clock = AR5K_PHY_PLL_RF5111; /*Zero*/ |
| 310 | } |
| 311 | |
| 312 | if (flags & CHANNEL_2GHZ) { |
| 313 | mode |= AR5K_PHY_MODE_FREQ_2GHZ; |
| 314 | clock |= AR5K_PHY_PLL_44MHZ; |
| 315 | |
| 316 | if (flags & CHANNEL_CCK) { |
| 317 | mode |= AR5K_PHY_MODE_MOD_CCK; |
| 318 | } else if (flags & CHANNEL_OFDM) { |
| 319 | /* XXX Dynamic OFDM/CCK is not supported by the |
| 320 | * AR5211 so we set MOD_OFDM for plain g (no |
| 321 | * CCK headers) operation. We need to test |
| 322 | * this, 5211 might support ofdm-only g after |
| 323 | * all, there are also initial register values |
| 324 | * in the code for g mode (see initvals.c). */ |
| 325 | if (ah->ah_version == AR5K_AR5211) |
| 326 | mode |= AR5K_PHY_MODE_MOD_OFDM; |
| 327 | else |
| 328 | mode |= AR5K_PHY_MODE_MOD_DYN; |
| 329 | } else { |
| 330 | ATH5K_ERR(ah->ah_sc, |
| 331 | "invalid radio modulation mode\n"); |
| 332 | return -EINVAL; |
| 333 | } |
| 334 | } else if (flags & CHANNEL_5GHZ) { |
| 335 | mode |= AR5K_PHY_MODE_FREQ_5GHZ; |
| 336 | clock |= AR5K_PHY_PLL_40MHZ; |
| 337 | |
| 338 | if (flags & CHANNEL_OFDM) |
| 339 | mode |= AR5K_PHY_MODE_MOD_OFDM; |
| 340 | else { |
| 341 | ATH5K_ERR(ah->ah_sc, |
| 342 | "invalid radio modulation mode\n"); |
| 343 | return -EINVAL; |
| 344 | } |
| 345 | } else { |
| 346 | ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n"); |
| 347 | return -EINVAL; |
| 348 | } |
| 349 | |
| 350 | if (flags & CHANNEL_TURBO) |
| 351 | turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT; |
| 352 | } else { /* Reset the device */ |
| 353 | |
| 354 | /* ...enable Atheros turbo mode if requested */ |
| 355 | if (flags & CHANNEL_TURBO) |
| 356 | ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE, |
| 357 | AR5K_PHY_TURBO); |
| 358 | } |
| 359 | |
| 360 | /* reseting PCI on PCI-E cards results card to hang |
| 361 | * and always return 0xffff... so we ingore that flag |
| 362 | * for PCI-E cards */ |
| 363 | bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; |
| 364 | |
| 365 | /* Reset chipset */ |
Nick Kossifidis | 84e463f | 2008-09-17 03:33:19 +0300 | [diff] [blame] | 366 | if (ah->ah_version == AR5K_AR5210) { |
| 367 | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | |
| 368 | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | |
| 369 | AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); |
| 370 | mdelay(2); |
| 371 | } else { |
| 372 | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | |
| 373 | AR5K_RESET_CTL_BASEBAND | bus_flags); |
| 374 | } |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 375 | if (ret) { |
| 376 | ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); |
| 377 | return -EIO; |
| 378 | } |
| 379 | |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 380 | /* ...wakeup again!*/ |
| 381 | ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); |
| 382 | if (ret) { |
| 383 | ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); |
| 384 | return ret; |
| 385 | } |
| 386 | |
| 387 | /* ...final warm reset */ |
| 388 | if (ath5k_hw_nic_reset(ah, 0)) { |
| 389 | ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); |
| 390 | return -EIO; |
| 391 | } |
| 392 | |
| 393 | if (ah->ah_version != AR5K_AR5210) { |
| 394 | /* ...set the PHY operating mode */ |
| 395 | ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); |
| 396 | udelay(300); |
| 397 | |
| 398 | ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE); |
| 399 | ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO); |
| 400 | } |
| 401 | |
| 402 | return 0; |
| 403 | } |
| 404 | |
| 405 | /* |
| 406 | * Main reset function |
| 407 | */ |
Johannes Berg | 05c914f | 2008-09-11 00:01:58 +0200 | [diff] [blame] | 408 | int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 409 | struct ieee80211_channel *channel, bool change_channel) |
| 410 | { |
| 411 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
| 412 | struct pci_dev *pdev = ah->ah_sc->pdev; |
| 413 | u32 data, s_seq, s_ant, s_led[3], dma_size; |
| 414 | unsigned int i, mode, freq, ee_mode, ant[2]; |
| 415 | int ret; |
| 416 | |
| 417 | ATH5K_TRACE(ah->ah_sc); |
| 418 | |
| 419 | s_seq = 0; |
| 420 | s_ant = 0; |
| 421 | ee_mode = 0; |
| 422 | freq = 0; |
| 423 | mode = 0; |
| 424 | |
| 425 | /* |
| 426 | * Save some registers before a reset |
| 427 | */ |
| 428 | /*DCU/Antenna selection not available on 5210*/ |
| 429 | if (ah->ah_version != AR5K_AR5210) { |
| 430 | if (change_channel) { |
| 431 | /* Seq number for queue 0 -do this for all queues ? */ |
| 432 | s_seq = ath5k_hw_reg_read(ah, |
| 433 | AR5K_QUEUE_DFS_SEQNUM(0)); |
| 434 | /*Default antenna*/ |
| 435 | s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); |
| 436 | } |
| 437 | } |
| 438 | |
| 439 | /*GPIOs*/ |
| 440 | s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE; |
| 441 | s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR); |
| 442 | s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO); |
| 443 | |
| 444 | if (change_channel && ah->ah_rf_banks != NULL) |
| 445 | ath5k_hw_get_rf_gain(ah); |
| 446 | |
| 447 | |
| 448 | /*Wakeup the device*/ |
| 449 | ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false); |
| 450 | if (ret) |
| 451 | return ret; |
| 452 | |
| 453 | /* |
| 454 | * Initialize operating mode |
| 455 | */ |
| 456 | ah->ah_op_mode = op_mode; |
| 457 | |
| 458 | /* |
| 459 | * 5111/5112 Settings |
| 460 | * 5210 only comes with RF5110 |
| 461 | */ |
| 462 | if (ah->ah_version != AR5K_AR5210) { |
| 463 | if (ah->ah_radio != AR5K_RF5111 && |
| 464 | ah->ah_radio != AR5K_RF5112 && |
| 465 | ah->ah_radio != AR5K_RF5413 && |
| 466 | ah->ah_radio != AR5K_RF2413 && |
| 467 | ah->ah_radio != AR5K_RF2425) { |
| 468 | ATH5K_ERR(ah->ah_sc, |
| 469 | "invalid phy radio: %u\n", ah->ah_radio); |
| 470 | return -EINVAL; |
| 471 | } |
| 472 | |
| 473 | switch (channel->hw_value & CHANNEL_MODES) { |
| 474 | case CHANNEL_A: |
| 475 | mode = AR5K_MODE_11A; |
| 476 | freq = AR5K_INI_RFGAIN_5GHZ; |
| 477 | ee_mode = AR5K_EEPROM_MODE_11A; |
| 478 | break; |
| 479 | case CHANNEL_G: |
| 480 | mode = AR5K_MODE_11G; |
| 481 | freq = AR5K_INI_RFGAIN_2GHZ; |
| 482 | ee_mode = AR5K_EEPROM_MODE_11G; |
| 483 | break; |
| 484 | case CHANNEL_B: |
| 485 | mode = AR5K_MODE_11B; |
| 486 | freq = AR5K_INI_RFGAIN_2GHZ; |
| 487 | ee_mode = AR5K_EEPROM_MODE_11B; |
| 488 | break; |
| 489 | case CHANNEL_T: |
| 490 | mode = AR5K_MODE_11A_TURBO; |
| 491 | freq = AR5K_INI_RFGAIN_5GHZ; |
| 492 | ee_mode = AR5K_EEPROM_MODE_11A; |
| 493 | break; |
| 494 | /*Is this ok on 5211 too ?*/ |
| 495 | case CHANNEL_TG: |
| 496 | mode = AR5K_MODE_11G_TURBO; |
| 497 | freq = AR5K_INI_RFGAIN_2GHZ; |
| 498 | ee_mode = AR5K_EEPROM_MODE_11G; |
| 499 | break; |
| 500 | case CHANNEL_XR: |
| 501 | if (ah->ah_version == AR5K_AR5211) { |
| 502 | ATH5K_ERR(ah->ah_sc, |
| 503 | "XR mode not available on 5211"); |
| 504 | return -EINVAL; |
| 505 | } |
| 506 | mode = AR5K_MODE_XR; |
| 507 | freq = AR5K_INI_RFGAIN_5GHZ; |
| 508 | ee_mode = AR5K_EEPROM_MODE_11A; |
| 509 | break; |
| 510 | default: |
| 511 | ATH5K_ERR(ah->ah_sc, |
| 512 | "invalid channel: %d\n", channel->center_freq); |
| 513 | return -EINVAL; |
| 514 | } |
| 515 | |
| 516 | /* PHY access enable */ |
| 517 | ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); |
| 518 | |
| 519 | } |
| 520 | |
| 521 | ret = ath5k_hw_write_initvals(ah, mode, change_channel); |
| 522 | if (ret) |
| 523 | return ret; |
| 524 | |
| 525 | /* |
| 526 | * 5211/5212 Specific |
| 527 | */ |
| 528 | if (ah->ah_version != AR5K_AR5210) { |
| 529 | /* |
| 530 | * Write initial RF gain settings |
| 531 | * This should work for both 5111/5112 |
| 532 | */ |
| 533 | ret = ath5k_hw_rfgain(ah, freq); |
| 534 | if (ret) |
| 535 | return ret; |
| 536 | |
| 537 | mdelay(1); |
| 538 | |
| 539 | /* |
Elias Oltmanns | 7d19267 | 2008-10-29 14:25:42 +0100 | [diff] [blame] | 540 | * Write some more initial register settings for revised chips |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 541 | */ |
Elias Oltmanns | 7d19267 | 2008-10-29 14:25:42 +0100 | [diff] [blame] | 542 | if (ah->ah_version == AR5K_AR5212 && |
| 543 | ah->ah_phy_revision > 0x41) { |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 544 | ath5k_hw_reg_write(ah, 0x0002a002, 0x982c); |
| 545 | |
| 546 | if (channel->hw_value == CHANNEL_G) |
Nick Kossifidis | 1bef016 | 2008-09-29 02:09:09 +0300 | [diff] [blame] | 547 | if (ah->ah_mac_srev < AR5K_SREV_AR2413) |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 548 | ath5k_hw_reg_write(ah, 0x00f80d80, |
| 549 | 0x994c); |
Nick Kossifidis | 1bef016 | 2008-09-29 02:09:09 +0300 | [diff] [blame] | 550 | else if (ah->ah_mac_srev < AR5K_SREV_AR5424) |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 551 | ath5k_hw_reg_write(ah, 0x00380140, |
| 552 | 0x994c); |
Nick Kossifidis | 1bef016 | 2008-09-29 02:09:09 +0300 | [diff] [blame] | 553 | else if (ah->ah_mac_srev < AR5K_SREV_AR2425) |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 554 | ath5k_hw_reg_write(ah, 0x00fc0ec0, |
| 555 | 0x994c); |
| 556 | else /* 2425 */ |
| 557 | ath5k_hw_reg_write(ah, 0x00fc0fc0, |
| 558 | 0x994c); |
| 559 | else |
| 560 | ath5k_hw_reg_write(ah, 0x00000000, 0x994c); |
| 561 | |
Elias Oltmanns | 7d19267 | 2008-10-29 14:25:42 +0100 | [diff] [blame] | 562 | /* Got this from legacy-hal */ |
| 563 | AR5K_REG_DISABLE_BITS(ah, 0xa228, 0x200); |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 564 | |
Elias Oltmanns | 7d19267 | 2008-10-29 14:25:42 +0100 | [diff] [blame] | 565 | AR5K_REG_MASKED_BITS(ah, 0xa228, 0x800, 0xfffe03ff); |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 566 | |
| 567 | /* Just write 0x9b5 ? */ |
| 568 | /* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */ |
| 569 | ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK); |
| 570 | ath5k_hw_reg_write(ah, 0x00000000, 0xa254); |
| 571 | ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL); |
| 572 | } |
| 573 | |
| 574 | /* Fix for first revision of the RF5112 RF chipset */ |
| 575 | if (ah->ah_radio >= AR5K_RF5112 && |
| 576 | ah->ah_radio_5ghz_revision < |
| 577 | AR5K_SREV_RAD_5112A) { |
| 578 | ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, |
| 579 | AR5K_PHY_CCKTXCTL); |
| 580 | if (channel->hw_value & CHANNEL_5GHZ) |
| 581 | data = 0xffb81020; |
| 582 | else |
| 583 | data = 0xffb80d20; |
| 584 | ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL); |
| 585 | data = 0; |
| 586 | } |
| 587 | |
| 588 | /* |
| 589 | * Set TX power (FIXME) |
| 590 | */ |
| 591 | ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER); |
| 592 | if (ret) |
| 593 | return ret; |
| 594 | |
| 595 | /* Write rate duration table only on AR5212 and if |
| 596 | * virtual interface has already been brought up |
| 597 | * XXX: rethink this after new mode changes to |
| 598 | * mac80211 are integrated */ |
| 599 | if (ah->ah_version == AR5K_AR5212 && |
| 600 | ah->ah_sc->vif != NULL) |
| 601 | ath5k_hw_write_rate_duration(ah, mode); |
| 602 | |
| 603 | /* |
| 604 | * Write RF registers |
| 605 | */ |
| 606 | ret = ath5k_hw_rfregs(ah, channel, mode); |
| 607 | if (ret) |
| 608 | return ret; |
| 609 | |
| 610 | /* |
| 611 | * Configure additional registers |
| 612 | */ |
| 613 | |
| 614 | /* Write OFDM timings on 5212*/ |
| 615 | if (ah->ah_version == AR5K_AR5212 && |
| 616 | channel->hw_value & CHANNEL_OFDM) { |
| 617 | ret = ath5k_hw_write_ofdm_timings(ah, channel); |
| 618 | if (ret) |
| 619 | return ret; |
| 620 | } |
| 621 | |
| 622 | /*Enable/disable 802.11b mode on 5111 |
| 623 | (enable 2111 frequency converter + CCK)*/ |
| 624 | if (ah->ah_radio == AR5K_RF5111) { |
| 625 | if (mode == AR5K_MODE_11B) |
| 626 | AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, |
| 627 | AR5K_TXCFG_B_MODE); |
| 628 | else |
| 629 | AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG, |
| 630 | AR5K_TXCFG_B_MODE); |
| 631 | } |
| 632 | |
| 633 | /* |
| 634 | * Set channel and calibrate the PHY |
| 635 | */ |
| 636 | ret = ath5k_hw_channel(ah, channel); |
| 637 | if (ret) |
| 638 | return ret; |
| 639 | |
| 640 | /* Set antenna mode */ |
| 641 | AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL, |
| 642 | ah->ah_antenna[ee_mode][0], 0xfffffc06); |
| 643 | |
| 644 | /* |
| 645 | * In case a fixed antenna was set as default |
| 646 | * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE |
| 647 | * registers. |
| 648 | */ |
| 649 | if (s_ant != 0) { |
| 650 | if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */ |
| 651 | ant[0] = ant[1] = AR5K_ANT_FIXED_A; |
| 652 | else /* 2 - Aux */ |
| 653 | ant[0] = ant[1] = AR5K_ANT_FIXED_B; |
| 654 | } else { |
| 655 | ant[0] = AR5K_ANT_FIXED_A; |
| 656 | ant[1] = AR5K_ANT_FIXED_B; |
| 657 | } |
| 658 | |
| 659 | ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]], |
| 660 | AR5K_PHY_ANT_SWITCH_TABLE_0); |
| 661 | ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]], |
| 662 | AR5K_PHY_ANT_SWITCH_TABLE_1); |
| 663 | |
| 664 | /* Commit values from EEPROM */ |
| 665 | if (ah->ah_radio == AR5K_RF5111) |
| 666 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, |
| 667 | AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip); |
| 668 | |
| 669 | ath5k_hw_reg_write(ah, |
| 670 | AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]), |
| 671 | AR5K_PHY_NFTHRES); |
| 672 | |
| 673 | AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING, |
| 674 | (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80, |
| 675 | 0xffffc07f); |
| 676 | AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN, |
| 677 | (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000, |
| 678 | 0xfffc0fff); |
| 679 | AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, |
| 680 | (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | |
| 681 | ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00), |
| 682 | 0xffff0000); |
| 683 | |
| 684 | ath5k_hw_reg_write(ah, |
| 685 | (ee->ee_tx_end2xpa_disable[ee_mode] << 24) | |
| 686 | (ee->ee_tx_end2xpa_disable[ee_mode] << 16) | |
| 687 | (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) | |
| 688 | (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4); |
| 689 | |
| 690 | AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3, |
| 691 | ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff); |
| 692 | AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF, |
| 693 | (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff); |
| 694 | AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01); |
| 695 | |
| 696 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, |
| 697 | AR5K_PHY_IQ_CORR_ENABLE | |
| 698 | (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) | |
| 699 | ee->ee_q_cal[ee_mode]); |
| 700 | |
| 701 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) |
| 702 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ, |
| 703 | AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX, |
| 704 | ee->ee_margin_tx_rx[ee_mode]); |
| 705 | |
| 706 | } else { |
| 707 | mdelay(1); |
| 708 | /* Disable phy and wait */ |
| 709 | ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); |
| 710 | mdelay(1); |
| 711 | } |
| 712 | |
| 713 | /* |
| 714 | * Restore saved values |
| 715 | */ |
| 716 | /*DCU/Antenna selection not available on 5210*/ |
| 717 | if (ah->ah_version != AR5K_AR5210) { |
| 718 | ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0)); |
| 719 | ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA); |
| 720 | } |
| 721 | AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]); |
| 722 | ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR); |
| 723 | ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); |
| 724 | |
| 725 | /* |
| 726 | * Misc |
| 727 | */ |
| 728 | /* XXX: add ah->aid once mac80211 gives this to us */ |
| 729 | ath5k_hw_set_associd(ah, ah->ah_bssid, 0); |
| 730 | |
| 731 | ath5k_hw_set_opmode(ah); |
| 732 | /*PISR/SISR Not available on 5210*/ |
| 733 | if (ah->ah_version != AR5K_AR5210) { |
| 734 | ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); |
| 735 | /* If we later allow tuning for this, store into sc structure */ |
| 736 | data = AR5K_TUNE_RSSI_THRES | |
| 737 | AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S; |
| 738 | ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR); |
| 739 | } |
| 740 | |
| 741 | /* |
| 742 | * Set Rx/Tx DMA Configuration |
| 743 | * |
| 744 | * Set maximum DMA size (512) except for PCI-E cards since |
| 745 | * it causes rx overruns and tx errors (tested on 5424 but since |
| 746 | * rx overruns also occur on 5416/5418 with madwifi we set 128 |
| 747 | * for all PCI-E cards to be safe). |
| 748 | * |
| 749 | * In dumps this is 128 for allchips. |
| 750 | * |
| 751 | * XXX: need to check 5210 for this |
| 752 | * TODO: Check out tx triger level, it's always 64 on dumps but I |
| 753 | * guess we can tweak it and see how it goes ;-) |
| 754 | */ |
| 755 | dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B; |
| 756 | if (ah->ah_version != AR5K_AR5210) { |
| 757 | AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, |
| 758 | AR5K_TXCFG_SDMAMR, dma_size); |
| 759 | AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, |
| 760 | AR5K_RXCFG_SDMAMW, dma_size); |
| 761 | } |
| 762 | |
| 763 | /* |
| 764 | * Enable the PHY and wait until completion |
| 765 | */ |
| 766 | ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); |
| 767 | |
| 768 | /* |
| 769 | * On 5211+ read activation -> rx delay |
| 770 | * and use it. |
| 771 | */ |
| 772 | if (ah->ah_version != AR5K_AR5210) { |
| 773 | data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & |
| 774 | AR5K_PHY_RX_DELAY_M; |
| 775 | data = (channel->hw_value & CHANNEL_CCK) ? |
| 776 | ((data << 2) / 22) : (data / 10); |
| 777 | |
| 778 | udelay(100 + (2 * data)); |
| 779 | data = 0; |
| 780 | } else { |
| 781 | mdelay(1); |
| 782 | } |
| 783 | |
| 784 | /* |
| 785 | * Perform ADC test (?) |
| 786 | */ |
| 787 | data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); |
| 788 | ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); |
| 789 | for (i = 0; i <= 20; i++) { |
| 790 | if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) |
| 791 | break; |
| 792 | udelay(200); |
| 793 | } |
| 794 | ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1); |
| 795 | data = 0; |
| 796 | |
| 797 | /* |
| 798 | * Start automatic gain calibration |
| 799 | * |
| 800 | * During AGC calibration RX path is re-routed to |
| 801 | * a signal detector so we don't receive anything. |
| 802 | * |
| 803 | * This method is used to calibrate some static offsets |
| 804 | * used together with on-the fly I/Q calibration (the |
| 805 | * one performed via ath5k_hw_phy_calibrate), that doesn't |
| 806 | * interrupt rx path. |
| 807 | * |
| 808 | * If we are in a noisy environment AGC calibration may time |
| 809 | * out. |
| 810 | */ |
| 811 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, |
| 812 | AR5K_PHY_AGCCTL_CAL); |
| 813 | |
| 814 | /* At the same time start I/Q calibration for QAM constellation |
| 815 | * -no need for CCK- */ |
| 816 | ah->ah_calibration = false; |
| 817 | if (!(mode == AR5K_MODE_11B)) { |
| 818 | ah->ah_calibration = true; |
| 819 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, |
| 820 | AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); |
| 821 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, |
| 822 | AR5K_PHY_IQ_RUN); |
| 823 | } |
| 824 | |
| 825 | /* Wait for gain calibration to finish (we check for I/Q calibration |
| 826 | * during ath5k_phy_calibrate) */ |
| 827 | if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, |
| 828 | AR5K_PHY_AGCCTL_CAL, 0, false)) { |
| 829 | ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n", |
| 830 | channel->center_freq); |
| 831 | return -EAGAIN; |
| 832 | } |
| 833 | |
| 834 | /* |
| 835 | * Start noise floor calibration |
| 836 | * |
| 837 | * If we run NF calibration before AGC, it always times out. |
| 838 | * Binary HAL starts NF and AGC calibration at the same time |
| 839 | * and only waits for AGC to finish. I believe that's wrong because |
| 840 | * during NF calibration, rx path is also routed to a detector, so if |
| 841 | * it doesn't finish we won't have RX. |
| 842 | * |
| 843 | * XXX: Find an interval that's OK for all cards... |
| 844 | */ |
| 845 | ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); |
| 846 | if (ret) |
| 847 | return ret; |
| 848 | |
| 849 | /* |
| 850 | * Reset queues and start beacon timers at the end of the reset routine |
| 851 | */ |
| 852 | for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) { |
| 853 | /*No QCU on 5210*/ |
| 854 | if (ah->ah_version != AR5K_AR5210) |
| 855 | AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i); |
| 856 | |
| 857 | ret = ath5k_hw_reset_tx_queue(ah, i); |
| 858 | if (ret) { |
| 859 | ATH5K_ERR(ah->ah_sc, |
| 860 | "failed to reset TX queue #%d\n", i); |
| 861 | return ret; |
| 862 | } |
| 863 | } |
| 864 | |
| 865 | /* Pre-enable interrupts on 5211/5212*/ |
| 866 | if (ah->ah_version != AR5K_AR5210) |
Nick Kossifidis | 4c674c6 | 2008-10-26 20:40:25 +0200 | [diff] [blame^] | 867 | ath5k_hw_set_imr(ah, ah->ah_imr); |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 868 | |
| 869 | /* |
| 870 | * Set RF kill flags if supported by the device (read from the EEPROM) |
| 871 | * Disable gpio_intr for now since it results system hang. |
| 872 | * TODO: Handle this in ath5k_intr |
| 873 | */ |
| 874 | #if 0 |
| 875 | if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { |
| 876 | ath5k_hw_set_gpio_input(ah, 0); |
| 877 | ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0); |
| 878 | if (ah->ah_gpio[0] == 0) |
| 879 | ath5k_hw_set_gpio_intr(ah, 0, 1); |
| 880 | else |
| 881 | ath5k_hw_set_gpio_intr(ah, 0, 0); |
| 882 | } |
| 883 | #endif |
| 884 | |
| 885 | /* |
| 886 | * Set the 32MHz reference clock on 5212 phy clock sleep register |
| 887 | * |
| 888 | * TODO: Find out how to switch to external 32Khz clock to save power |
| 889 | */ |
| 890 | if (ah->ah_version == AR5K_AR5212) { |
| 891 | ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR); |
| 892 | ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT); |
| 893 | ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL); |
| 894 | ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK); |
| 895 | ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY); |
| 896 | ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING); |
| 897 | |
| 898 | data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ; |
| 899 | data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ? |
| 900 | 0x00000f80 : 0x00001380 ; |
| 901 | ath5k_hw_reg_write(ah, data, AR5K_USEC_5211); |
| 902 | data = 0; |
| 903 | } |
| 904 | |
| 905 | if (ah->ah_version == AR5K_AR5212) { |
| 906 | ath5k_hw_reg_write(ah, 0x000100aa, 0x8118); |
| 907 | ath5k_hw_reg_write(ah, 0x00003210, 0x811c); |
| 908 | ath5k_hw_reg_write(ah, 0x00000052, 0x8108); |
Nick Kossifidis | 1bef016 | 2008-09-29 02:09:09 +0300 | [diff] [blame] | 909 | if (ah->ah_mac_srev >= AR5K_SREV_AR2413) |
Nick Kossifidis | c6e387a | 2008-08-29 22:45:39 +0300 | [diff] [blame] | 910 | ath5k_hw_reg_write(ah, 0x00000004, 0x8120); |
| 911 | } |
| 912 | |
| 913 | /* |
| 914 | * Disable beacons and reset the register |
| 915 | */ |
| 916 | AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE | |
| 917 | AR5K_BEACON_RESET_TSF); |
| 918 | |
| 919 | return 0; |
| 920 | } |
| 921 | |
| 922 | #undef _ATH5K_RESET |