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
  92void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
  93                                  int eep_start_loc, int size)
  94{
  95        int i = 0, j, addr;
  96        u32 addrdata[8];
  97        u32 data[8];
  98
  99        for (addr = 0; addr < size; addr++) {
 100                addrdata[i] = AR5416_EEPROM_OFFSET +
 101                        ((addr + eep_start_loc) << AR5416_EEPROM_S);
 102                i++;
 103                if (i == 8) {
 104                        REG_READ_MULTI(ah, addrdata, data, i);
 105
 106                        for (j = 0; j < i; j++) {
 107                                *eep_data = data[j];
 108                                eep_data++;
 109                        }
 110                        i = 0;
 111                }
 112        }
 113
 114        if (i != 0) {
 115                REG_READ_MULTI(ah, addrdata, data, i);
 116
 117                for (j = 0; j < i; j++) {
 118                        *eep_data = data[j];
 119                        eep_data++;
 120                }
 121        }
 122}
 123
 124bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data)
 125{
 126        return common->bus_ops->eeprom_read(common, off, data);
 127}
 128
 129void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
 130                             u8 *pVpdList, u16 numIntercepts,
 131                             u8 *pRetVpdList)
 132{
 133        u16 i, k;
 134        u8 currPwr = pwrMin;
 135        u16 idxL = 0, idxR = 0;
 136
 137        for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
 138                ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
 139                                               numIntercepts, &(idxL),
 140                                               &(idxR));
 141                if (idxR < 1)
 142                        idxR = 1;
 143                if (idxL == numIntercepts - 1)
 144                        idxL = (u16) (numIntercepts - 2);
 145                if (pPwrList[idxL] == pPwrList[idxR])
 146                        k = pVpdList[idxL];
 147                else
 148                        k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
 149                                   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
 150                                  (pPwrList[idxR] - pPwrList[idxL]));
 151                pRetVpdList[i] = (u8) k;
 152                currPwr += 2;
 153        }
 154}
 155
 156void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
 157                                       struct ath9k_channel *chan,
 158                                       struct cal_target_power_leg *powInfo,
 159                                       u16 numChannels,
 160                                       struct cal_target_power_leg *pNewPower,
 161                                       u16 numRates, bool isExtTarget)
 162{
 163        struct chan_centers centers;
 164        u16 clo, chi;
 165        int i;
 166        int matchIndex = -1, lowIndex = -1;
 167        u16 freq;
 168
 169        ath9k_hw_get_channel_centers(ah, chan, &centers);
 170        freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
 171
 172        if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
 173                                       IS_CHAN_2GHZ(chan))) {
 174                matchIndex = 0;
 175        } else {
 176                for (i = 0; (i < numChannels) &&
 177                             (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
 178                        if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
 179                                                       IS_CHAN_2GHZ(chan))) {
 180                                matchIndex = i;
 181                                break;
 182                        } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
 183                                                IS_CHAN_2GHZ(chan)) && i > 0 &&
 184                                   freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
 185                                                IS_CHAN_2GHZ(chan))) {
 186                                lowIndex = i - 1;
 187                                break;
 188                        }
 189                }
 190                if ((matchIndex == -1) && (lowIndex == -1))
 191                        matchIndex = i - 1;
 192        }
 193
 194        if (matchIndex != -1) {
 195                *pNewPower = powInfo[matchIndex];
 196        } else {
 197                clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
 198                                         IS_CHAN_2GHZ(chan));
 199                chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
 200                                         IS_CHAN_2GHZ(chan));
 201
 202                for (i = 0; i < numRates; i++) {
 203                        pNewPower->tPow2x[i] =
 204                                (u8)ath9k_hw_interpolate(freq, clo, chi,
 205                                                powInfo[lowIndex].tPow2x[i],
 206                                                powInfo[lowIndex + 1].tPow2x[i]);
 207                }
 208        }
 209}
 210
 211void ath9k_hw_get_target_powers(struct ath_hw *ah,
 212                                struct ath9k_channel *chan,
 213                                struct cal_target_power_ht *powInfo,
 214                                u16 numChannels,
 215                                struct cal_target_power_ht *pNewPower,
 216                                u16 numRates, bool isHt40Target)
 217{
 218        struct chan_centers centers;
 219        u16 clo, chi;
 220        int i;
 221        int matchIndex = -1, lowIndex = -1;
 222        u16 freq;
 223
 224        ath9k_hw_get_channel_centers(ah, chan, &centers);
 225        freq = isHt40Target ? centers.synth_center : centers.ctl_center;
 226
 227        if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
 228                matchIndex = 0;
 229        } else {
 230                for (i = 0; (i < numChannels) &&
 231                             (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
 232                        if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
 233                                                       IS_CHAN_2GHZ(chan))) {
 234                                matchIndex = i;
 235                                break;
 236                        } else
 237                                if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
 238                                                IS_CHAN_2GHZ(chan)) && i > 0 &&
 239                                    freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
 240                                                IS_CHAN_2GHZ(chan))) {
 241                                        lowIndex = i - 1;
 242                                        break;
 243                                }
 244                }
 245                if ((matchIndex == -1) && (lowIndex == -1))
 246                        matchIndex = i - 1;
 247        }
 248
 249        if (matchIndex != -1) {
 250                *pNewPower = powInfo[matchIndex];
 251        } else {
 252                clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
 253                                         IS_CHAN_2GHZ(chan));
 254                chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
 255                                         IS_CHAN_2GHZ(chan));
 256
 257                for (i = 0; i < numRates; i++) {
 258                        pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
 259                                                clo, chi,
 260                                                powInfo[lowIndex].tPow2x[i],
 261                                                powInfo[lowIndex + 1].tPow2x[i]);
 262                }
 263        }
 264}
 265
 266u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
 267                                bool is2GHz, int num_band_edges)
 268{
 269        u16 twiceMaxEdgePower = MAX_RATE_POWER;
 270        int i;
 271
 272        for (i = 0; (i < num_band_edges) &&
 273                     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
 274                if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
 275                        twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
 276                        break;
 277                } else if ((i > 0) &&
 278                           (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
 279                                                      is2GHz))) {
 280                        if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
 281                                               is2GHz) < freq &&
 282                            CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
 283                                twiceMaxEdgePower =
 284                                        CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
 285                        }
 286                        break;
 287                }
 288        }
 289
 290        return twiceMaxEdgePower;
 291}
 292
 293void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
 294{
 295        struct ath_common *common = ath9k_hw_common(ah);
 296        struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 297
 298        switch (ar5416_get_ntxchains(ah->txchainmask)) {
 299        case 1:
 300                break;
 301        case 2:
 302                regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
 303                break;
 304        case 3:
 305                regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
 306                break;
 307        default:
 308                ath_dbg(common, ATH_DBG_EEPROM,
 309                        "Invalid chainmask configuration\n");
 310                break;
 311        }
 312}
 313
 314void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
 315                                struct ath9k_channel *chan,
 316                                void *pRawDataSet,
 317                                u8 *bChans, u16 availPiers,
 318                                u16 tPdGainOverlap,
 319                                u16 *pPdGainBoundaries, u8 *pPDADCValues,
 320                                u16 numXpdGains)
 321{
 322        int i, j, k;
 323        int16_t ss;
 324        u16 idxL = 0, idxR = 0, numPiers;
 325        static u8 vpdTableL[AR5416_NUM_PD_GAINS]
 326                [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
 327        static u8 vpdTableR[AR5416_NUM_PD_GAINS]
 328                [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
 329        static u8 vpdTableI[AR5416_NUM_PD_GAINS]
 330                [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
 331
 332        u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
 333        u8 minPwrT4[AR5416_NUM_PD_GAINS];
 334        u8 maxPwrT4[AR5416_NUM_PD_GAINS];
 335        int16_t vpdStep;
 336        int16_t tmpVal;
 337        u16 sizeCurrVpdTable, maxIndex, tgtIndex;
 338        bool match;
 339        int16_t minDelta = 0;
 340        struct chan_centers centers;
 341        int pdgain_boundary_default;
 342        struct cal_data_per_freq *data_def = pRawDataSet;
 343        struct cal_data_per_freq_4k *data_4k = pRawDataSet;
 344        struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
 345        bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
 346        int intercepts;
 347
 348        if (AR_SREV_9287(ah))
 349                intercepts = AR9287_PD_GAIN_ICEPTS;
 350        else
 351                intercepts = AR5416_PD_GAIN_ICEPTS;
 352
 353        memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
 354        ath9k_hw_get_channel_centers(ah, chan, &centers);
 355
 356        for (numPiers = 0; numPiers < availPiers; numPiers++) {
 357                if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
 358                        break;
 359        }
 360
 361        match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
 362                                                             IS_CHAN_2GHZ(chan)),
 363                                               bChans, numPiers, &idxL, &idxR);
 364
 365        if (match) {
 366                if (AR_SREV_9287(ah)) {
 367                        /* FIXME: array overrun? */
 368                        for (i = 0; i < numXpdGains; i++) {
 369                                minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
 370                                maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4];
 371                                ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 372                                                data_9287[idxL].pwrPdg[i],
 373                                                data_9287[idxL].vpdPdg[i],
 374                                                intercepts,
 375                                                vpdTableI[i]);
 376                        }
 377                } else if (eeprom_4k) {
 378                        for (i = 0; i < numXpdGains; i++) {
 379                                minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
 380                                maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4];
 381                                ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 382                                                data_4k[idxL].pwrPdg[i],
 383                                                data_4k[idxL].vpdPdg[i],
 384                                                intercepts,
 385                                                vpdTableI[i]);
 386                        }
 387                } else {
 388                        for (i = 0; i < numXpdGains; i++) {
 389                                minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
 390                                maxPwrT4[i] = data_def[idxL].pwrPdg[i][4];
 391                                ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 392                                                data_def[idxL].pwrPdg[i],
 393                                                data_def[idxL].vpdPdg[i],
 394                                                intercepts,
 395                                                vpdTableI[i]);
 396                        }
 397                }
 398        } else {
 399                for (i = 0; i < numXpdGains; i++) {
 400                        if (AR_SREV_9287(ah)) {
 401                                pVpdL = data_9287[idxL].vpdPdg[i];
 402                                pPwrL = data_9287[idxL].pwrPdg[i];
 403                                pVpdR = data_9287[idxR].vpdPdg[i];
 404                                pPwrR = data_9287[idxR].pwrPdg[i];
 405                        } else if (eeprom_4k) {
 406                                pVpdL = data_4k[idxL].vpdPdg[i];
 407                                pPwrL = data_4k[idxL].pwrPdg[i];
 408                                pVpdR = data_4k[idxR].vpdPdg[i];
 409                                pPwrR = data_4k[idxR].pwrPdg[i];
 410                        } else {
 411                                pVpdL = data_def[idxL].vpdPdg[i];
 412                                pPwrL = data_def[idxL].pwrPdg[i];
 413                                pVpdR = data_def[idxR].vpdPdg[i];
 414                                pPwrR = data_def[idxR].pwrPdg[i];
 415                        }
 416
 417                        minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
 418
 419                        maxPwrT4[i] =
 420                                min(pPwrL[intercepts - 1],
 421                                    pPwrR[intercepts - 1]);
 422
 423
 424                        ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 425                                                pPwrL, pVpdL,
 426                                                intercepts,
 427                                                vpdTableL[i]);
 428                        ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
 429                                                pPwrR, pVpdR,
 430                                                intercepts,
 431                                                vpdTableR[i]);
 432
 433                        for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
 434                                vpdTableI[i][j] =
 435                                        (u8)(ath9k_hw_interpolate((u16)
 436                                             FREQ2FBIN(centers.
 437                                                       synth_center,
 438                                                       IS_CHAN_2GHZ
 439                                                       (chan)),
 440                                             bChans[idxL], bChans[idxR],
 441                                             vpdTableL[i][j], vpdTableR[i][j]));
 442                        }
 443                }
 444        }
 445
 446        k = 0;
 447
 448        for (i = 0; i < numXpdGains; i++) {
 449                if (i == (numXpdGains - 1))
 450                        pPdGainBoundaries[i] =
 451                                (u16)(maxPwrT4[i] / 2);
 452                else
 453                        pPdGainBoundaries[i] =
 454                                (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
 455
 456                pPdGainBoundaries[i] =
 457                        min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
 458
 459                if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
 460                        minDelta = pPdGainBoundaries[0] - 23;
 461                        pPdGainBoundaries[0] = 23;
 462                } else {
 463                        minDelta = 0;
 464                }
 465
 466                if (i == 0) {
 467                        if (AR_SREV_9280_20_OR_LATER(ah))
 468                                ss = (int16_t)(0 - (minPwrT4[i] / 2));
 469                        else
 470                                ss = 0;
 471                } else {
 472                        ss = (int16_t)((pPdGainBoundaries[i - 1] -
 473                                        (minPwrT4[i] / 2)) -
 474                                       tPdGainOverlap + 1 + minDelta);
 475                }
 476                vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
 477                vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
 478
 479                while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
 480                        tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
 481                        pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
 482                        ss++;
 483                }
 484
 485                sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
 486                tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
 487                                (minPwrT4[i] / 2));
 488                maxIndex = (tgtIndex < sizeCurrVpdTable) ?
 489                        tgtIndex : sizeCurrVpdTable;
 490
 491                while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
 492                        pPDADCValues[k++] = vpdTableI[i][ss++];
 493                }
 494
 495                vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
 496                                    vpdTableI[i][sizeCurrVpdTable - 2]);
 497                vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
 498
 499                if (tgtIndex >= maxIndex) {
 500                        while ((ss <= tgtIndex) &&
 501                               (k < (AR5416_NUM_PDADC_VALUES - 1))) {
 502                                tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
 503                                                    (ss - maxIndex + 1) * vpdStep));
 504                                pPDADCValues[k++] = (u8)((tmpVal > 255) ?
 505                                                         255 : tmpVal);
 506                                ss++;
 507                        }
 508                }
 509        }
 510
 511        if (eeprom_4k)
 512                pdgain_boundary_default = 58;
 513        else
 514                pdgain_boundary_default = pPdGainBoundaries[i - 1];
 515
 516        while (i < AR5416_PD_GAINS_IN_MASK) {
 517                pPdGainBoundaries[i] = pdgain_boundary_default;
 518                i++;
 519        }
 520
 521        while (k < AR5416_NUM_PDADC_VALUES) {
 522                pPDADCValues[k] = pPDADCValues[k - 1];
 523                k++;
 524        }
 525}
 526
 527int ath9k_hw_eeprom_init(struct ath_hw *ah)
 528{
 529        int status;
 530
 531        if (AR_SREV_9300_20_OR_LATER(ah))
 532                ah->eep_ops = &eep_ar9300_ops;
 533        else if (AR_SREV_9287(ah)) {
 534                ah->eep_ops = &eep_ar9287_ops;
 535        } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
 536                ah->eep_ops = &eep_4k_ops;
 537        } else {
 538                ah->eep_ops = &eep_def_ops;
 539        }
 540
 541        if (!ah->eep_ops->fill_eeprom(ah))
 542                return -EIO;
 543
 544        status = ah->eep_ops->check_eeprom(ah);
 545
 546        return status;
 547}
 548