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_rev(ah) >= AR5416_EEP_MINOR_VER_17) {
 112                rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE);
 113
 114                if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
 115                        INIT_INI_ARRAY(&ah->iniModesRxGain,
 116                                       ar9280Modes_backoff_13db_rxgain_9280_2);
 117                else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
 118                        INIT_INI_ARRAY(&ah->iniModesRxGain,
 119                                       ar9280Modes_backoff_23db_rxgain_9280_2);
 120                else
 121                        INIT_INI_ARRAY(&ah->iniModesRxGain,
 122                                       ar9280Modes_original_rxgain_9280_2);
 123        } else {
 124                INIT_INI_ARRAY(&ah->iniModesRxGain,
 125                               ar9280Modes_original_rxgain_9280_2);
 126        }
 127}
 128
 129static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type)
 130{
 131        if (ah->eep_ops->get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_19) {
 132                if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
 133                        INIT_INI_ARRAY(&ah->iniModesTxGain,
 134                                       ar9280Modes_high_power_tx_gain_9280_2);
 135                else
 136                        INIT_INI_ARRAY(&ah->iniModesTxGain,
 137                                       ar9280Modes_original_tx_gain_9280_2);
 138        } else {
 139                INIT_INI_ARRAY(&ah->iniModesTxGain,
 140                               ar9280Modes_original_tx_gain_9280_2);
 141        }
 142}
 143
 144static void ar9271_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type)
 145{
 146        if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
 147                INIT_INI_ARRAY(&ah->iniModesTxGain,
 148                               ar9271Modes_high_power_tx_gain_9271);
 149        else
 150                INIT_INI_ARRAY(&ah->iniModesTxGain,
 151                               ar9271Modes_normal_power_tx_gain_9271);
 152}
 153
 154static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
 155{
 156        u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
 157
 158        if (AR_SREV_9287_11_OR_LATER(ah))
 159                INIT_INI_ARRAY(&ah->iniModesRxGain,
 160                               ar9287Modes_rx_gain_9287_1_1);
 161        else if (AR_SREV_9280_20(ah))
 162                ar9280_20_hw_init_rxgain_ini(ah);
 163
 164        if (AR_SREV_9271(ah)) {
 165                ar9271_hw_init_txgain_ini(ah, txgain_type);
 166        } else if (AR_SREV_9287_11_OR_LATER(ah)) {
 167                INIT_INI_ARRAY(&ah->iniModesTxGain,
 168                               ar9287Modes_tx_gain_9287_1_1);
 169        } else if (AR_SREV_9280_20(ah)) {
 170                ar9280_20_hw_init_txgain_ini(ah, txgain_type);
 171        } else if (AR_SREV_9285_12_OR_LATER(ah)) {
 172                /* txgain table */
 173                if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) {
 174                        if (AR_SREV_9285E_20(ah)) {
 175                                INIT_INI_ARRAY(&ah->iniModesTxGain,
 176                                               ar9285Modes_XE2_0_high_power);
 177                        } else {
 178                                INIT_INI_ARRAY(&ah->iniModesTxGain,
 179                                        ar9285Modes_high_power_tx_gain_9285_1_2);
 180                        }
 181                } else {
 182                        if (AR_SREV_9285E_20(ah)) {
 183                                INIT_INI_ARRAY(&ah->iniModesTxGain,
 184                                               ar9285Modes_XE2_0_normal_power);
 185                        } else {
 186                                INIT_INI_ARRAY(&ah->iniModesTxGain,
 187                                        ar9285Modes_original_tx_gain_9285_1_2);
 188                        }
 189                }
 190        }
 191}
 192
 193/*
 194 * Helper for ASPM support.
 195 *
 196 * Disable PLL when in L0s as well as receiver clock when in L1.
 197 * This power saving option must be enabled through the SerDes.
 198 *
 199 * Programming the SerDes must go through the same 288 bit serial shift
 200 * register as the other analog registers.  Hence the 9 writes.
 201 */
 202static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
 203                                         bool power_off)
 204{
 205        u8 i;
 206        u32 val;
 207
 208        /* Nothing to do on restore for 11N */
 209        if (!power_off /* !restore */) {
 210                if (AR_SREV_9280_20_OR_LATER(ah)) {
 211                        /*
 212                         * AR9280 2.0 or later chips use SerDes values from the
 213                         * initvals.h initialized depending on chipset during
 214                         * __ath9k_hw_init()
 215                         */
 216                        for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
 217                                REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
 218                                          INI_RA(&ah->iniPcieSerdes, i, 1));
 219                        }
 220                } else {
 221                        ENABLE_REGWRITE_BUFFER(ah);
 222
 223                        REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
 224                        REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
 225
 226                        /* RX shut off when elecidle is asserted */
 227                        REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
 228                        REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
 229                        REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
 230
 231                        /*
 232                         * Ignore ah->ah_config.pcie_clock_req setting for
 233                         * pre-AR9280 11n
 234                         */
 235                        REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
 236
 237                        REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
 238                        REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
 239                        REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
 240
 241                        /* Load the new settings */
 242                        REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 243
 244                        REGWRITE_BUFFER_FLUSH(ah);
 245                }
 246
 247                udelay(1000);
 248        }
 249
 250        if (power_off) {
 251                /* clear bit 19 to disable L1 */
 252                REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
 253
 254                val = REG_READ(ah, AR_WA);
 255
 256                /*
 257                 * Set PCIe workaround bits
 258                 * In AR9280 and AR9285, bit 14 in WA register (disable L1)
 259                 * should only  be set when device enters D3 and be
 260                 * cleared when device comes back to D0.
 261                 */
 262                if (ah->config.pcie_waen) {
 263                        if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
 264                                val |= AR_WA_D3_L1_DISABLE;
 265                } else {
 266                        if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) {
 267                                if (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)
 268                                        val |= AR_WA_D3_L1_DISABLE;
 269                        } else if (AR_SREV_9280(ah)) {
 270                                if (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE)
 271                                        val |= AR_WA_D3_L1_DISABLE;
 272                        }
 273                }
 274
 275                if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
 276                        /*
 277                         * Disable bit 6 and 7 before entering D3 to
 278                         * prevent system hang.
 279                         */
 280                        val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
 281                }
 282
 283                if (AR_SREV_9280(ah))
 284                        val |= AR_WA_BIT22;
 285
 286                if (AR_SREV_9285E_20(ah))
 287                        val |= AR_WA_BIT23;
 288
 289                REG_WRITE(ah, AR_WA, val);
 290        } else {
 291                if (ah->config.pcie_waen) {
 292                        val = ah->config.pcie_waen;
 293                        val &= (~AR_WA_D3_L1_DISABLE);
 294                } else {
 295                        if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) {
 296                                val = AR9285_WA_DEFAULT;
 297                                val &= (~AR_WA_D3_L1_DISABLE);
 298                        } else if (AR_SREV_9280(ah)) {
 299                                /*
 300                                 * For AR9280 chips, bit 22 of 0x4004
 301                                 * needs to be set.
 302                                 */
 303                                val = AR9280_WA_DEFAULT;
 304                                val &= (~AR_WA_D3_L1_DISABLE);
 305                        } else {
 306                                val = AR_WA_DEFAULT;
 307                        }
 308                }
 309
 310                /* WAR for ASPM system hang */
 311                if (AR_SREV_9285(ah) || AR_SREV_9287(ah))
 312                        val |= (AR_WA_BIT6 | AR_WA_BIT7);
 313
 314                if (AR_SREV_9285E_20(ah))
 315                        val |= AR_WA_BIT23;
 316
 317                REG_WRITE(ah, AR_WA, val);
 318
 319                /* set bit 19 to allow forcing of pcie core into L1 state */
 320                REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
 321        }
 322}
 323
 324static int ar9002_hw_get_radiorev(struct ath_hw *ah)
 325{
 326        u32 val;
 327        int i;
 328
 329        ENABLE_REGWRITE_BUFFER(ah);
 330
 331        REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
 332        for (i = 0; i < 8; i++)
 333                REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
 334
 335        REGWRITE_BUFFER_FLUSH(ah);
 336
 337        val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
 338        val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
 339
 340        return ath9k_hw_reverse_bits(val, 8);
 341}
 342
 343int ar9002_hw_rf_claim(struct ath_hw *ah)
 344{
 345        u32 val;
 346
 347        REG_WRITE(ah, AR_PHY(0), 0x00000007);
 348
 349        val = ar9002_hw_get_radiorev(ah);
 350        switch (val & AR_RADIO_SREV_MAJOR) {
 351        case 0:
 352                val = AR_RAD5133_SREV_MAJOR;
 353                break;
 354        case AR_RAD5133_SREV_MAJOR:
 355        case AR_RAD5122_SREV_MAJOR:
 356        case AR_RAD2133_SREV_MAJOR:
 357        case AR_RAD2122_SREV_MAJOR:
 358                break;
 359        default:
 360                ath_err(ath9k_hw_common(ah),
 361                        "Radio Chip Rev 0x%02X not supported\n",
 362                        val & AR_RADIO_SREV_MAJOR);
 363                return -EOPNOTSUPP;
 364        }
 365
 366        ah->hw_version.analog5GhzRev = val;
 367
 368        return 0;
 369}
 370
 371void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
 372{
 373        if (AR_SREV_9287_13_OR_LATER(ah)) {
 374                REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
 375                                AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
 376                REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
 377                REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
 378                                AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
 379                REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
 380                                AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
 381        }
 382}
 383
 384static void ar9002_hw_init_hang_checks(struct ath_hw *ah)
 385{
 386        if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) {
 387                ah->config.hw_hang_checks |= HW_BB_RIFS_HANG;
 388                ah->config.hw_hang_checks |= HW_BB_DFS_HANG;
 389        }
 390
 391        if (AR_SREV_9280(ah))
 392                ah->config.hw_hang_checks |= HW_BB_RX_CLEAR_STUCK_HANG;
 393
 394        if (AR_SREV_5416(ah) || AR_SREV_9100(ah) || AR_SREV_9160(ah))
 395                ah->config.hw_hang_checks |= HW_MAC_HANG;
 396}
 397
 398/* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
 399int ar9002_hw_attach_ops(struct ath_hw *ah)
 400{
 401        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 402        struct ath_hw_ops *ops = ath9k_hw_ops(ah);
 403        int ret;
 404
 405        ret = ar9002_hw_init_mode_regs(ah);
 406        if (ret)
 407                return ret;
 408
 409        priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
 410        priv_ops->init_hang_checks = ar9002_hw_init_hang_checks;
 411
 412        ops->config_pci_powersave = ar9002_hw_configpcipowersave;
 413
 414        ret = ar5008_hw_attach_phy_ops(ah);
 415        if (ret)
 416                return ret;
 417
 418        if (AR_SREV_9280_20_OR_LATER(ah))
 419                ar9002_hw_attach_phy_ops(ah);
 420
 421        ar9002_hw_attach_calib_ops(ah);
 422        ar9002_hw_attach_mac_ops(ah);
 423        return 0;
 424}
 425
 426void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
 427{
 428        u32 modesIndex;
 429        int i;
 430
 431        if (IS_CHAN_5GHZ(chan))
 432                modesIndex = IS_CHAN_HT40(chan) ? 2 : 1;
 433        else
 434                modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;
 435
 436        ENABLE_REGWRITE_BUFFER(ah);
 437
 438        for (i = 0; i < ah->iniModes_9271_ANI_reg.ia_rows; i++) {
 439                u32 reg = INI_RA(&ah->iniModes_9271_ANI_reg, i, 0);
 440                u32 val = INI_RA(&ah->iniModes_9271_ANI_reg, i, modesIndex);
 441                u32 val_orig;
 442
 443                if (reg == AR_PHY_CCK_DETECT) {
 444                        val_orig = REG_READ(ah, reg);
 445                        val &= AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
 446                        val_orig &= ~AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
 447
 448                        REG_WRITE(ah, reg, val|val_orig);
 449                } else
 450                        REG_WRITE(ah, reg, val);
 451        }
 452
 453        REGWRITE_BUFFER_FLUSH(ah);
 454}
 455