linux/drivers/net/wireless/ath/ath9k/eeprom.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008-2009 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 "hw.h"
  18
  19static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
  20{
  21        if (fbin == AR5416_BCHAN_UNUSED)
  22                return fbin;
  23
  24        return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
  25}
  26
  27void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
  28{
  29        REG_WRITE(ah, reg, val);
  30
  31        if (ah->config.analog_shiftreg)
  32                udelay(100);
  33}
  34
  35void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
  36                               u32 shift, u32 val)
  37{
  38        u32 regVal;
  39
  40        regVal = REG_READ(ah, reg) & ~mask;
  41        regVal |= (val << shift) & mask;
  42
  43        REG_WRITE(ah, reg, regVal);
  44
  45        if (ah->config.analog_shiftreg)
  46                udelay(100);
  47}
  48
  49int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
  50                             int16_t targetLeft, int16_t targetRight)
  51{
  52        int16_t rv;
  53
  54        if (srcRight == srcLeft) {
  55                rv = targetLeft;
  56        } else {
  57                rv = (int16_t) (((target - srcLeft) * targetRight +
  58                                 (srcRight - target) * targetLeft) /
  59                                (srcRight - srcLeft));
  60        }
  61        return rv;
  62}
  63
  64bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
  65                                    u16 *indexL, u16 *indexR)
  66{
  67        u16 i;
  68
  69        if (target <= pList[0]) {
  70                *indexL = *indexR = 0;
  71                return true;
  72        }
  73        if (target >= pList[listSize - 1]) {
  74                *indexL = *indexR = (u16) (listSize - 1);
  75                return true;
  76        }
  77
  78        for (i = 0; i < listSize - 1; i++) {
  79                if (pList[i] == target) {
  80                        *indexL = *indexR = i;
  81                        return true;
  82                }
  83                if (target < pList[i + 1]) {
  84                        *indexL = i;
  85                        *indexR = (u16) (i + 1);
  86                        return false;
  87                }
  88        }
  89        return false;
  90}
  91
  92bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data)
  93{
  94        return common->bus_ops->eeprom_read(common, off, data);
  95}
  96
  97void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
  98                             u8 *pVpdList, u16 numIntercepts,
  99                             u8 *pRetVpdList)
 100{
 101        u16 i, k;
 102        u8 currPwr = pwrMin;
 103        u16 idxL = 0, idxR = 0;
 104
 105        for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
 106                ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
 107                                               numIntercepts, &(idxL),
 108                                               &(idxR));
 109                if (idxR < 1)
 110                        idxR = 1;
 111                if (idxL == numIntercepts - 1)
 112                        idxL = (u16) (numIntercepts - 2);
 113                if (pPwrList[idxL] == pPwrList[idxR])
 114                        k = pVpdList[idxL];
 115                else
 116                        k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
 117                                   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
 118                                  (pPwrList[idxR] - pPwrList[idxL]));
 119                pRetVpdList[i] = (u8) k;
 120                currPwr += 2;
 121        }
 122}
 123
 124void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
 125                                       struct ath9k_channel *chan,
 126                                       struct cal_target_power_leg *powInfo,
 127                                       u16 numChannels,
 128                                       struct cal_target_power_leg *pNewPower,
 129                                       u16 numRates, bool isExtTarget)
 130{
 131        struct chan_centers centers;
 132        u16 clo, chi;
 133        int i;
 134        int matchIndex = -1, lowIndex = -1;
 135        u16 freq;
 136
 137        ath9k_hw_get_channel_centers(ah, chan, &centers);
 138        freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
 139
 140        if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
 141                                       IS_CHAN_2GHZ(chan))) {
 142                matchIndex = 0;
 143        } else {
 144                for (i = 0; (i < numChannels) &&
 145                             (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
 146                        if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
 147                                                       IS_CHAN_2GHZ(chan))) {
 148                                matchIndex = i;
 149                                break;
 150                        } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
 151                                                IS_CHAN_2GHZ(chan)) && i > 0 &&
 152                                   freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
 153                                                IS_CHAN_2GHZ(chan))) {
 154                                lowIndex = i - 1;
 155                                break;
 156                        }
 157                }
 158                if ((matchIndex == -1) && (lowIndex == -1))
 159                        matchIndex = i - 1;
 160        }
 161
 162        if (matchIndex != -1) {
 163                *pNewPower = powInfo[matchIndex];
 164        } else {
 165                clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
 166                                         IS_CHAN_2GHZ(chan));
 167                chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
 168                                         IS_CHAN_2GHZ(chan));
 169
 170                for (i = 0; i < numRates; i++) {
 171                        pNewPower->tPow2x[i] =
 172                                (u8)ath9k_hw_interpolate(freq, clo, chi,
 173                                                powInfo[lowIndex].tPow2x[i],
 174                                                powInfo[lowIndex + 1].tPow2x[i]);
 175                }
 176        }
 177}
 178
 179void ath9k_hw_get_target_powers(struct ath_hw *ah,
 180                                struct ath9k_channel *chan,
 181                                struct cal_target_power_ht *powInfo,
 182                                u16 numChannels,
 183                                struct cal_target_power_ht *pNewPower,
 184                                u16 numRates, bool isHt40Target)
 185{
 186        struct chan_centers centers;
 187        u16 clo, chi;
 188        int i;
 189        int matchIndex = -1, lowIndex = -1;
 190        u16 freq;
 191
 192        ath9k_hw_get_channel_centers(ah, chan, &centers);
 193        freq = isHt40Target ? centers.synth_center : centers.ctl_center;
 194
 195        if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
 196                matchIndex = 0;
 197        } else {
 198                for (i = 0; (i < numChannels) &&
 199                             (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
 200                        if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
 201                                                       IS_CHAN_2GHZ(chan))) {
 202                                matchIndex = i;
 203                                break;
 204                        } else
 205                                if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
 206                                                IS_CHAN_2GHZ(chan)) && i > 0 &&
 207                                    freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
 208                                                IS_CHAN_2GHZ(chan))) {
 209                                        lowIndex = i - 1;
 210                                        break;
 211                                }
 212                }
 213                if ((matchIndex == -1) && (lowIndex == -1))
 214                        matchIndex = i - 1;
 215        }
 216
 217        if (matchIndex != -1) {
 218                *pNewPower = powInfo[matchIndex];
 219        } else {
 220                clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
 221                                         IS_CHAN_2GHZ(chan));
 222                chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
 223                                         IS_CHAN_2GHZ(chan));
 224
 225                for (i = 0; i < numRates; i++) {
 226                        pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
 227                                                clo, chi,
 228                                                powInfo[lowIndex].tPow2x[i],
 229                                                powInfo[lowIndex + 1].tPow2x[i]);
 230                }
 231        }
 232}
 233
 234u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
 235                                bool is2GHz, int num_band_edges)
 236{
 237        u16 twiceMaxEdgePower = MAX_RATE_POWER;
 238        int i;
 239
 240        for (i = 0; (i < num_band_edges) &&
 241                     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
 242                if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
 243                        twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
 244                        break;
 245                } else if ((i > 0) &&
 246                           (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
 247                                                      is2GHz))) {
 248                        if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
 249                                               is2GHz) < freq &&
 250                            CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
 251                                twiceMaxEdgePower =
 252                                        CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
 253                        }
 254                        break;
 255                }
 256        }
 257
 258        return twiceMaxEdgePower;
 259}
 260
 261void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
 262{
 263        struct ath_common *common = ath9k_hw_common(ah);
 264        struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 265
 266        switch (ar5416_get_ntxchains(ah->txchainmask)) {
 267        case 1:
 268                break;
 269        case 2:
 270                regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
 271                break;
 272        case 3:
 273                regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
 274                break;
 275        default:
 276                ath_dbg(common, ATH_DBG_EEPROM,
 277                        "Invalid chainmask configuration\n");
 278                break;
 279        }
 280}
 281
 282void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
 283                                struct ath9k_channel *chan,
 284                                void *pRawDataSet,
 285                                u8 *bChans, u16 availPiers,
 286                                u16 tPdGainOverlap,
 287                                u16 *pPdGainBoundaries, u8 *pPDADCValues,
 288                                u16 numXpdGains)
 289{
 290        int i, j, k;
 291        int16_t ss;
 292        u16 idxL = 0, idxR = 0, numPiers;
 293        static u8 vpdTableL[AR5416_NUM_PD_GAINS]
 294                [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
 295        static u8 vpdTableR[AR5416_NUM_PD_GAINS]
 296                [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
 297        static u8 vpdTableI[AR5416_NUM_PD_GAINS]
 298                [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
 299
 300        u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
 301        u8 minPwrT4[AR5416_NUM_PD_GAINS];
 302        u8 maxPwrT4[AR5416_NUM_PD_GAINS];
 303        int16_t vpdStep;
 304        int16_t tmpVal;
 305        u16 sizeCurrVpdTable, maxIndex, tgtIndex;
 306        bool match;
 307        int16_t minDelta = 0;
 308        struct chan_centers centers;
 309        int pdgain_boundary_default;
 310        struct cal_data_per_freq *data_def = pRawDataSet;
 311        struct cal_data_per_freq_4k *data_4k = pRawDataSet;
 312        struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
 313        bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
 314        int intercepts;
 315
 316        if (AR_SREV_9287(ah))
 317                intercepts = AR9287_PD_GAIN_ICEPTS;
 318        else
 319                intercepts = AR5416_PD_GAIN_ICEPTS;
 320
 321        memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
 322        ath9k_hw_get_channel_centers(ah, chan, &centers);
 323
 324        for (numPiers = 0; numPiers < availPiers; numPiers++) {
 325                if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
 326                        break;
 327        }
 328
 329        match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
 330                                                             IS_CHAN_2GHZ(chan)),
 331                                               bChans, numPiers, &idxL, &idxR);
 332
 333        if (match) {
 334                if (AR_SREV_9287(ah)) {
 335                        /* FIXME: array overrun? */
 336                        for (i = 0; i < numXpdGains; i++) {
 337                                minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
 338                                maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4];
 339                                ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 340                                                data_9287[idxL].pwrPdg[i],
 341                                                data_9287[idxL].vpdPdg[i],
 342                                                intercepts,
 343                                                vpdTableI[i]);
 344                        }
 345                } else if (eeprom_4k) {
 346                        for (i = 0; i < numXpdGains; i++) {
 347                                minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
 348                                maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4];
 349                                ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 350                                                data_4k[idxL].pwrPdg[i],
 351                                                data_4k[idxL].vpdPdg[i],
 352                                                intercepts,
 353                                                vpdTableI[i]);
 354                        }
 355                } else {
 356                        for (i = 0; i < numXpdGains; i++) {
 357                                minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
 358                                maxPwrT4[i] = data_def[idxL].pwrPdg[i][4];
 359                                ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 360                                                data_def[idxL].pwrPdg[i],
 361                                                data_def[idxL].vpdPdg[i],
 362                                                intercepts,
 363                                                vpdTableI[i]);
 364                        }
 365                }
 366        } else {
 367                for (i = 0; i < numXpdGains; i++) {
 368                        if (AR_SREV_9287(ah)) {
 369                                pVpdL = data_9287[idxL].vpdPdg[i];
 370                                pPwrL = data_9287[idxL].pwrPdg[i];
 371                                pVpdR = data_9287[idxR].vpdPdg[i];
 372                                pPwrR = data_9287[idxR].pwrPdg[i];
 373                        } else if (eeprom_4k) {
 374                                pVpdL = data_4k[idxL].vpdPdg[i];
 375                                pPwrL = data_4k[idxL].pwrPdg[i];
 376                                pVpdR = data_4k[idxR].vpdPdg[i];
 377                                pPwrR = data_4k[idxR].pwrPdg[i];
 378                        } else {
 379                                pVpdL = data_def[idxL].vpdPdg[i];
 380                                pPwrL = data_def[idxL].pwrPdg[i];
 381                                pVpdR = data_def[idxR].vpdPdg[i];
 382                                pPwrR = data_def[idxR].pwrPdg[i];
 383                        }
 384
 385                        minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
 386
 387                        maxPwrT4[i] =
 388                                min(pPwrL[intercepts - 1],
 389                                    pPwrR[intercepts - 1]);
 390
 391
 392                        ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 393                                                pPwrL, pVpdL,
 394                                                intercepts,
 395                                                vpdTableL[i]);
 396                        ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 397                                                pPwrR, pVpdR,
 398                                                intercepts,
 399                                                vpdTableR[i]);
 400
 401                        for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
 402                                vpdTableI[i][j] =
 403                                        (u8)(ath9k_hw_interpolate((u16)
 404                                             FREQ2FBIN(centers.
 405                                                       synth_center,
 406                                                       IS_CHAN_2GHZ
 407                                                       (chan)),
 408                                             bChans[idxL], bChans[idxR],
 409                                             vpdTableL[i][j], vpdTableR[i][j]));
 410                        }
 411                }
 412        }
 413
 414        k = 0;
 415
 416        for (i = 0; i < numXpdGains; i++) {
 417                if (i == (numXpdGains - 1))
 418                        pPdGainBoundaries[i] =
 419                                (u16)(maxPwrT4[i] / 2);
 420                else
 421                        pPdGainBoundaries[i] =
 422                                (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
 423
 424                pPdGainBoundaries[i] =
 425                        min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
 426
 427                if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
 428                        minDelta = pPdGainBoundaries[0] - 23;
 429                        pPdGainBoundaries[0] = 23;
 430                } else {
 431                        minDelta = 0;
 432                }
 433
 434                if (i == 0) {
 435                        if (AR_SREV_9280_20_OR_LATER(ah))
 436                                ss = (int16_t)(0 - (minPwrT4[i] / 2));
 437                        else
 438                                ss = 0;
 439                } else {
 440                        ss = (int16_t)((pPdGainBoundaries[i - 1] -
 441                                        (minPwrT4[i] / 2)) -
 442                                       tPdGainOverlap + 1 + minDelta);
 443                }
 444                vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
 445                vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
 446
 447                while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
 448                        tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
 449                        pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
 450                        ss++;
 451                }
 452
 453                sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
 454                tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
 455                                (minPwrT4[i] / 2));
 456                maxIndex = (tgtIndex < sizeCurrVpdTable) ?
 457                        tgtIndex : sizeCurrVpdTable;
 458
 459                while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
 460                        pPDADCValues[k++] = vpdTableI[i][ss++];
 461                }
 462
 463                vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
 464                                    vpdTableI[i][sizeCurrVpdTable - 2]);
 465                vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
 466
 467                if (tgtIndex >= maxIndex) {
 468                        while ((ss <= tgtIndex) &&
 469                               (k < (AR5416_NUM_PDADC_VALUES - 1))) {
 470                                tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
 471                                                    (ss - maxIndex + 1) * vpdStep));
 472                                pPDADCValues[k++] = (u8)((tmpVal > 255) ?
 473                                                         255 : tmpVal);
 474                                ss++;
 475                        }
 476                }
 477        }
 478
 479        if (eeprom_4k)
 480                pdgain_boundary_default = 58;
 481        else
 482                pdgain_boundary_default = pPdGainBoundaries[i - 1];
 483
 484        while (i < AR5416_PD_GAINS_IN_MASK) {
 485                pPdGainBoundaries[i] = pdgain_boundary_default;
 486                i++;
 487        }
 488
 489        while (k < AR5416_NUM_PDADC_VALUES) {
 490                pPDADCValues[k] = pPDADCValues[k - 1];
 491                k++;
 492        }
 493}
 494
 495int ath9k_hw_eeprom_init(struct ath_hw *ah)
 496{
 497        int status;
 498
 499        if (AR_SREV_9300_20_OR_LATER(ah))
 500                ah->eep_ops = &eep_ar9300_ops;
 501        else if (AR_SREV_9287(ah)) {
 502                ah->eep_ops = &eep_ar9287_ops;
 503        } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
 504                ah->eep_ops = &eep_4k_ops;
 505        } else {
 506                ah->eep_ops = &eep_def_ops;
 507        }
 508
 509        if (!ah->eep_ops->fill_eeprom(ah))
 510                return -EIO;
 511
 512        status = ah->eep_ops->check_eeprom(ah);
 513
 514        return status;
 515}
 516