linux/drivers/net/wireless/ath/ath9k/ar9002_hw.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008-2011 Atheros Communications Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include <linux/moduleparam.h>
  18#include "hw.h"
  19#include "ar5008_initvals.h"
  20#include "ar9001_initvals.h"
  21#include "ar9002_initvals.h"
  22#include "ar9002_phy.h"
  23
  24/* General hardware code for the A5008/AR9001/AR9002 hadware families */
  25
  26static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
  27{
  28        if (AR_SREV_9271(ah)) {
  29                INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271);
  30                INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271);
  31                INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg);
  32                return 0;
  33        }
  34
  35        INIT_INI_ARRAY(&ah->iniPcieSerdes,
  36                       ar9280PciePhy_clkreq_always_on_L1_9280);
  37
  38        if (AR_SREV_9287_11_OR_LATER(ah)) {
  39                INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1);
  40                INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1);
  41        } else if (AR_SREV_9285_12_OR_LATER(ah)) {
  42                INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2);
  43                INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2);
  44        } else if (AR_SREV_9280_20_OR_LATER(ah)) {
  45                INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2);
  46                INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2);
  47
  48                INIT_INI_ARRAY(&ah->iniModesFastClock,
  49                               ar9280Modes_fast_clock_9280_2);
  50        } else if (AR_SREV_9160_10_OR_LATER(ah)) {
  51                INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160);
  52                INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160);
  53                if (AR_SREV_9160_11(ah)) {
  54                        INIT_INI_ARRAY(&ah->iniAddac,
  55                                       ar5416Addac_9160_1_1);
  56                } else {
  57                        INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160);
  58                }
  59        } else if (AR_SREV_9100_OR_LATER(ah)) {
  60                INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100);
  61                INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100);
  62                INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100);
  63        } else {
  64                INIT_INI_ARRAY(&ah->iniModes, ar5416Modes);
  65                INIT_INI_ARRAY(&ah->iniCommon, ar5416Common);
  66                INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac);
  67        }
  68
  69        if (!AR_SREV_9280_20_OR_LATER(ah)) {
  70                /* Common for AR5416, AR913x, AR9160 */
  71                INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain);
  72
  73                /* Common for AR913x, AR9160 */
  74                if (!AR_SREV_5416(ah))
  75                        INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6TPC_9100);
  76                else
  77                        INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6TPC);
  78        }
  79
  80        /* iniAddac needs to be modified for these chips */
  81        if (AR_SREV_9160(ah) || !AR_SREV_5416_22_OR_LATER(ah)) {
  82                struct ar5416IniArray *addac = &ah->iniAddac;
  83                u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns;
  84                u32 *data;
  85
  86                data = devm_kzalloc(ah->dev, size, GFP_KERNEL);
  87                if (!data)
  88                        return -ENOMEM;
  89
  90                memcpy(data, addac->ia_array, size);
  91                addac->ia_array = data;
  92
  93                if (!AR_SREV_5416_22_OR_LATER(ah)) {
  94                        /* override CLKDRV value */
  95                        INI_RA(addac, 31,1) = 0;
  96                }
  97        }
  98        if (AR_SREV_9287_11_OR_LATER(ah)) {
  99                INIT_INI_ARRAY(&ah->iniCckfirNormal,
 100                       ar9287Common_normal_cck_fir_coeff_9287_1_1);
 101                INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
 102                       ar9287Common_japan_2484_cck_fir_coeff_9287_1_1);
 103        }
 104        return 0;
 105}
 106
 107static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah)
 108{
 109        u32 rxgain_type;
 110
 111        if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >=
 112            AR5416_EEP_MINOR_VER_17) {
 113                rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE);
 114
 115                if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
 116                        INIT_INI_ARRAY(&ah->iniModesRxGain,
 117                                       ar9280Modes_backoff_13db_rxgain_9280_2);
 118                else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
 119                        INIT_INI_ARRAY(&ah->iniModesRxGain,
 120                                       ar9280Modes_backoff_23db_rxgain_9280_2);
 121                else
 122                        INIT_INI_ARRAY(&ah->iniModesRxGain,
 123                                       ar9280Modes_original_rxgain_9280_2);
 124        } else {
 125                INIT_INI_ARRAY(&ah->iniModesRxGain,
 126                               ar9280Modes_original_rxgain_9280_2);
 127        }
 128}
 129
 130static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type)
 131{
 132        if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >=
 133            AR5416_EEP_MINOR_VER_19) {
 134                if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
 135                        INIT_INI_ARRAY(&ah->iniModesTxGain,
 136                                       ar9280Modes_high_power_tx_gain_9280_2);
 137                else
 138                        INIT_INI_ARRAY(&ah->iniModesTxGain,
 139                                       ar9280Modes_original_tx_gain_9280_2);
 140        } else {
 141                INIT_INI_ARRAY(&ah->iniModesTxGain,
 142                               ar9280Modes_original_tx_gain_9280_2);
 143        }
 144}
 145
 146static void ar9271_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type)
 147{
 148        if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
 149                INIT_INI_ARRAY(&ah->iniModesTxGain,
 150                               ar9271Modes_high_power_tx_gain_9271);
 151        else
 152                INIT_INI_ARRAY(&ah->iniModesTxGain,
 153                               ar9271Modes_normal_power_tx_gain_9271);
 154}
 155
 156static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
 157{
 158        u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
 159
 160        if (AR_SREV_9287_11_OR_LATER(ah))
 161                INIT_INI_ARRAY(&ah->iniModesRxGain,
 162                               ar9287Modes_rx_gain_9287_1_1);
 163        else if (AR_SREV_9280_20(ah))
 164                ar9280_20_hw_init_rxgain_ini(ah);
 165
 166        if (AR_SREV_9271(ah)) {
 167                ar9271_hw_init_txgain_ini(ah, txgain_type);
 168        } else if (AR_SREV_9287_11_OR_LATER(ah)) {
 169                INIT_INI_ARRAY(&ah->iniModesTxGain,
 170                               ar9287Modes_tx_gain_9287_1_1);
 171        } else if (AR_SREV_9280_20(ah)) {
 172                ar9280_20_hw_init_txgain_ini(ah, txgain_type);
 173        } else if (AR_SREV_9285_12_OR_LATER(ah)) {
 174                /* txgain table */
 175                if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) {
 176                        if (AR_SREV_9285E_20(ah)) {
 177                                INIT_INI_ARRAY(&ah->iniModesTxGain,
 178                                               ar9285Modes_XE2_0_high_power);
 179                        } else {
 180                                INIT_INI_ARRAY(&ah->iniModesTxGain,
 181                                        ar9285Modes_high_power_tx_gain_9285_1_2);
 182                        }
 183                } else {
 184                        if (AR_SREV_9285E_20(ah)) {
 185                                INIT_INI_ARRAY(&ah->iniModesTxGain,
 186                                               ar9285Modes_XE2_0_normal_power);
 187                        } else {
 188                                INIT_INI_ARRAY(&ah->iniModesTxGain,
 189                                        ar9285Modes_original_tx_gain_9285_1_2);
 190                        }
 191                }
 192        }
 193}
 194
 195/*
 196 * Helper for ASPM support.
 197 *
 198 * Disable PLL when in L0s as well as receiver clock when in L1.
 199 * This power saving option must be enabled through the SerDes.
 200 *
 201 * Programming the SerDes must go through the same 288 bit serial shift
 202 * register as the other analog registers.  Hence the 9 writes.
 203 */
 204static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
 205                                         bool power_off)
 206{
 207        u8 i;
 208        u32 val;
 209
 210        /* Nothing to do on restore for 11N */
 211        if (!power_off /* !restore */) {
 212                if (AR_SREV_9280_20_OR_LATER(ah)) {
 213                        /*
 214                         * AR9280 2.0 or later chips use SerDes values from the
 215                         * initvals.h initialized depending on chipset during
 216                         * __ath9k_hw_init()
 217                         */
 218                        for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
 219                                REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
 220                                          INI_RA(&ah->iniPcieSerdes, i, 1));
 221                        }
 222                } else {
 223                        ENABLE_REGWRITE_BUFFER(ah);
 224
 225                        REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
 226                        REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
 227
 228                        /* RX shut off when elecidle is asserted */
 229                        REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
 230                        REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
 231                        REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
 232
 233                        /*
 234                         * Ignore ah->ah_config.pcie_clock_req setting for
 235                         * pre-AR9280 11n
 236                         */
 237                        REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
 238
 239                        REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
 240                        REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
 241                        REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
 242
 243                        /* Load the new settings */
 244                        REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 245
 246                        REGWRITE_BUFFER_FLUSH(ah);
 247                }
 248
 249                udelay(1000);
 250        }
 251
 252        if (power_off) {
 253                /* clear bit 19 to disable L1 */
 254                REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
 255
 256                val = REG_READ(ah, AR_WA);
 257
 258                /*
 259                 * Set PCIe workaround bits
 260                 * In AR9280 and AR9285, bit 14 in WA register (disable L1)
 261                 * should only  be set when device enters D3 and be
 262                 * cleared when device comes back to D0.
 263                 */
 264                if (ah->config.pcie_waen) {
 265                        if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
 266                                val |= AR_WA_D3_L1_DISABLE;
 267                } else {
 268                        if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) {
 269                                if (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)
 270                                        val |= AR_WA_D3_L1_DISABLE;
 271                        } else if (AR_SREV_9280(ah)) {
 272                                if (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE)
 273                                        val |= AR_WA_D3_L1_DISABLE;
 274                        }
 275                }
 276
 277                if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
 278                        /*
 279                         * Disable bit 6 and 7 before entering D3 to
 280                         * prevent system hang.
 281                         */
 282                        val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
 283                }
 284
 285                if (AR_SREV_9280(ah))
 286                        val |= AR_WA_BIT22;
 287
 288                if (AR_SREV_9285E_20(ah))
 289                        val |= AR_WA_BIT23;
 290
 291                REG_WRITE(ah, AR_WA, val);
 292        } else {
 293                if (ah->config.pcie_waen) {
 294                        val = ah->config.pcie_waen;
 295                        val &= (~AR_WA_D3_L1_DISABLE);
 296                } else {
 297                        if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) {
 298                                val = AR9285_WA_DEFAULT;
 299                                val &= (~AR_WA_D3_L1_DISABLE);
 300                        } else if (AR_SREV_9280(ah)) {
 301                                /*
 302                                 * For AR9280 chips, bit 22 of 0x4004
 303                                 * needs to be set.
 304                                 */
 305                                val = AR9280_WA_DEFAULT;
 306                                val &= (~AR_WA_D3_L1_DISABLE);
 307                        } else {
 308                                val = AR_WA_DEFAULT;
 309                        }
 310                }
 311
 312                /* WAR for ASPM system hang */
 313                if (AR_SREV_9285(ah) || AR_SREV_9287(ah))
 314                        val |= (AR_WA_BIT6 | AR_WA_BIT7);
 315
 316                if (AR_SREV_9285E_20(ah))
 317                        val |= AR_WA_BIT23;
 318
 319                REG_WRITE(ah, AR_WA, val);
 320
 321                /* set bit 19 to allow forcing of pcie core into L1 state */
 322                REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
 323        }
 324}
 325
 326static int ar9002_hw_get_radiorev(struct ath_hw *ah)
 327{
 328        u32 val;
 329        int i;
 330
 331        ENABLE_REGWRITE_BUFFER(ah);
 332
 333        REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
 334        for (i = 0; i < 8; i++)
 335                REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
 336
 337        REGWRITE_BUFFER_FLUSH(ah);
 338
 339        val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
 340        val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
 341
 342        return ath9k_hw_reverse_bits(val, 8);
 343}
 344
 345int ar9002_hw_rf_claim(struct ath_hw *ah)
 346{
 347        u32 val;
 348
 349        REG_WRITE(ah, AR_PHY(0), 0x00000007);
 350
 351        val = ar9002_hw_get_radiorev(ah);
 352        switch (val & AR_RADIO_SREV_MAJOR) {
 353        case 0:
 354                val = AR_RAD5133_SREV_MAJOR;
 355                break;
 356        case AR_RAD5133_SREV_MAJOR:
 357        case AR_RAD5122_SREV_MAJOR:
 358        case AR_RAD2133_SREV_MAJOR:
 359        case AR_RAD2122_SREV_MAJOR:
 360                break;
 361        default:
 362                ath_err(ath9k_hw_common(ah),
 363                        "Radio Chip Rev 0x%02X not supported\n",
 364                        val & AR_RADIO_SREV_MAJOR);
 365                return -EOPNOTSUPP;
 366        }
 367
 368        ah->hw_version.analog5GhzRev = val;
 369
 370        return 0;
 371}
 372
 373void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
 374{
 375        if (AR_SREV_9287_13_OR_LATER(ah)) {
 376                REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
 377                                AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
 378                REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
 379                REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
 380                                AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
 381                REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
 382                                AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
 383        }
 384}
 385
 386static void ar9002_hw_init_hang_checks(struct ath_hw *ah)
 387{
 388        if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) {
 389                ah->config.hw_hang_checks |= HW_BB_RIFS_HANG;
 390                ah->config.hw_hang_checks |= HW_BB_DFS_HANG;
 391        }
 392
 393        if (AR_SREV_9280(ah))
 394                ah->config.hw_hang_checks |= HW_BB_RX_CLEAR_STUCK_HANG;
 395
 396        if (AR_SREV_5416(ah) || AR_SREV_9100(ah) || AR_SREV_9160(ah))
 397                ah->config.hw_hang_checks |= HW_MAC_HANG;
 398}
 399
 400/* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
 401int ar9002_hw_attach_ops(struct ath_hw *ah)
 402{
 403        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 404        struct ath_hw_ops *ops = ath9k_hw_ops(ah);
 405        int ret;
 406
 407        ret = ar9002_hw_init_mode_regs(ah);
 408        if (ret)
 409                return ret;
 410
 411        priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
 412        priv_ops->init_hang_checks = ar9002_hw_init_hang_checks;
 413
 414        ops->config_pci_powersave = ar9002_hw_configpcipowersave;
 415
 416        ret = ar5008_hw_attach_phy_ops(ah);
 417        if (ret)
 418                return ret;
 419
 420        if (AR_SREV_9280_20_OR_LATER(ah))
 421                ar9002_hw_attach_phy_ops(ah);
 422
 423        ar9002_hw_attach_calib_ops(ah);
 424        ar9002_hw_attach_mac_ops(ah);
 425        return 0;
 426}
 427
 428void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
 429{
 430        u32 modesIndex;
 431        int i;
 432
 433        if (IS_CHAN_5GHZ(chan))
 434                modesIndex = IS_CHAN_HT40(chan) ? 2 : 1;
 435        else
 436                modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;
 437
 438        ENABLE_REGWRITE_BUFFER(ah);
 439
 440        for (i = 0; i < ah->iniModes_9271_ANI_reg.ia_rows; i++) {
 441                u32 reg = INI_RA(&ah->iniModes_9271_ANI_reg, i, 0);
 442                u32 val = INI_RA(&ah->iniModes_9271_ANI_reg, i, modesIndex);
 443                u32 val_orig;
 444
 445                if (reg == AR_PHY_CCK_DETECT) {
 446                        val_orig = REG_READ(ah, reg);
 447                        val &= AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
 448                        val_orig &= ~AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
 449
 450                        REG_WRITE(ah, reg, val|val_orig);
 451                } else
 452                        REG_WRITE(ah, reg, val);
 453        }
 454
 455        REGWRITE_BUFFER_FLUSH(ah);
 456}
 457