LCOV - code coverage report
Current view: top level - dev/ic - ar9287.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 311 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: ar9287.c,v 1.25 2017/01/12 16:32:28 stsp Exp $        */
       2             : 
       3             : /*-
       4             :  * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
       5             :  * Copyright (c) 2008-2009 Atheros Communications Inc.
       6             :  *
       7             :  * Permission to use, copy, modify, and/or distribute this software for any
       8             :  * purpose with or without fee is hereby granted, provided that the above
       9             :  * copyright notice and this permission notice appear in all copies.
      10             :  *
      11             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18             :  */
      19             : 
      20             : /*
      21             :  * Driver for Atheros 802.11a/g/n chipsets.
      22             :  * Routines for AR9227 and AR9287 chipsets.
      23             :  */
      24             : 
      25             : #include "bpfilter.h"
      26             : 
      27             : #include <sys/param.h>
      28             : #include <sys/sockio.h>
      29             : #include <sys/mbuf.h>
      30             : #include <sys/kernel.h>
      31             : #include <sys/socket.h>
      32             : #include <sys/systm.h>
      33             : #include <sys/malloc.h>
      34             : #include <sys/queue.h>
      35             : #include <sys/timeout.h>
      36             : #include <sys/conf.h>
      37             : #include <sys/device.h>
      38             : #include <sys/endian.h>
      39             : 
      40             : #include <machine/bus.h>
      41             : #include <machine/intr.h>
      42             : 
      43             : #if NBPFILTER > 0
      44             : #include <net/bpf.h>
      45             : #endif
      46             : #include <net/if.h>
      47             : #include <net/if_media.h>
      48             : 
      49             : #include <netinet/in.h>
      50             : #include <netinet/if_ether.h>
      51             : 
      52             : #include <net80211/ieee80211_var.h>
      53             : #include <net80211/ieee80211_amrr.h>
      54             : #include <net80211/ieee80211_mira.h>
      55             : #include <net80211/ieee80211_radiotap.h>
      56             : 
      57             : #include <dev/ic/athnreg.h>
      58             : #include <dev/ic/athnvar.h>
      59             : 
      60             : #include <dev/ic/ar5008reg.h>
      61             : #include <dev/ic/ar9280reg.h>
      62             : #include <dev/ic/ar9287reg.h>
      63             : 
      64             : int     ar9287_attach(struct athn_softc *);
      65             : void    ar9287_setup(struct athn_softc *);
      66             : void    ar9287_swap_rom(struct athn_softc *);
      67             : const   struct ar_spur_chan *ar9287_get_spur_chans(struct athn_softc *, int);
      68             : void    ar9287_init_from_rom(struct athn_softc *, struct ieee80211_channel *,
      69             :             struct ieee80211_channel *);
      70             : void    ar9287_get_pdadcs(struct athn_softc *, struct ieee80211_channel *,
      71             :             int, int, uint8_t, uint8_t *, uint8_t *);
      72             : void    ar9287_olpc_get_pdgain(struct athn_softc *, struct ieee80211_channel *,
      73             :             int, int8_t *);
      74             : void    ar9287_set_power_calib(struct athn_softc *,
      75             :             struct ieee80211_channel *);
      76             : void    ar9287_set_txpower(struct athn_softc *, struct ieee80211_channel *,
      77             :             struct ieee80211_channel *);
      78             : void    ar9287_olpc_init(struct athn_softc *);
      79             : void    ar9287_olpc_temp_compensation(struct athn_softc *);
      80             : void    ar9287_1_3_enable_async_fifo(struct athn_softc *);
      81             : void    ar9287_1_3_setup_async_fifo(struct athn_softc *);
      82             : 
      83             : /* Extern functions. */
      84             : uint8_t athn_chan2fbin(struct ieee80211_channel *);
      85             : void    athn_get_pier_ival(uint8_t, const uint8_t *, int, int *, int *);
      86             : int     ar5008_attach(struct athn_softc *);
      87             : void    ar5008_write_txpower(struct athn_softc *, int16_t power[]);
      88             : void    ar5008_get_pdadcs(struct athn_softc *, uint8_t, struct athn_pier *,
      89             :             struct athn_pier *, int, int, uint8_t, uint8_t *, uint8_t *);
      90             : void    ar5008_get_lg_tpow(struct athn_softc *, struct ieee80211_channel *,
      91             :             uint8_t, const struct ar_cal_target_power_leg *, int, uint8_t[]);
      92             : void    ar5008_get_ht_tpow(struct athn_softc *, struct ieee80211_channel *,
      93             :             uint8_t, const struct ar_cal_target_power_ht *, int, uint8_t[]);
      94             : int     ar9280_set_synth(struct athn_softc *, struct ieee80211_channel *,
      95             :             struct ieee80211_channel *);
      96             : void    ar9280_spur_mitigate(struct athn_softc *, struct ieee80211_channel *,
      97             :             struct ieee80211_channel *);
      98             : 
      99             : 
     100             : int
     101           0 : ar9287_attach(struct athn_softc *sc)
     102             : {
     103           0 :         sc->eep_base = AR9287_EEP_START_LOC;
     104           0 :         sc->eep_size = sizeof(struct ar9287_eeprom);
     105           0 :         sc->def_nf = AR9287_PHY_CCA_MAX_GOOD_VALUE;
     106           0 :         sc->ngpiopins = (sc->flags & ATHN_FLAG_USB) ? 16 : 11;
     107           0 :         sc->led_pin = 8;
     108           0 :         sc->workaround = AR9285_WA_DEFAULT;
     109           0 :         sc->ops.setup = ar9287_setup;
     110           0 :         sc->ops.swap_rom = ar9287_swap_rom;
     111           0 :         sc->ops.init_from_rom = ar9287_init_from_rom;
     112           0 :         sc->ops.set_txpower = ar9287_set_txpower;
     113           0 :         sc->ops.set_synth = ar9280_set_synth;
     114           0 :         sc->ops.spur_mitigate = ar9280_spur_mitigate;
     115           0 :         sc->ops.get_spur_chans = ar9287_get_spur_chans;
     116           0 :         sc->ops.olpc_init = ar9287_olpc_init;
     117           0 :         sc->ops.olpc_temp_compensation = ar9287_olpc_temp_compensation;
     118           0 :         sc->ini = &ar9287_1_1_ini;
     119           0 :         sc->serdes = &ar9280_2_0_serdes;
     120             : 
     121           0 :         return (ar5008_attach(sc));
     122             : }
     123             : 
     124             : void
     125           0 : ar9287_setup(struct athn_softc *sc)
     126             : {
     127           0 :         const struct ar9287_eeprom *eep = sc->eep;
     128             : 
     129             :         /* Determine if open loop power control should be used. */
     130           0 :         if (eep->baseEepHeader.openLoopPwrCntl)
     131           0 :                 sc->flags |= ATHN_FLAG_OLPC;
     132             : 
     133           0 :         sc->rx_gain = &ar9287_1_1_rx_gain;
     134           0 :         sc->tx_gain = &ar9287_1_1_tx_gain;
     135           0 : }
     136             : 
     137             : void
     138           0 : ar9287_swap_rom(struct athn_softc *sc)
     139             : {
     140           0 :         struct ar9287_eeprom *eep = sc->eep;
     141             :         int i;
     142             : 
     143           0 :         eep->modalHeader.antCtrlCommon =
     144           0 :             swap32(eep->modalHeader.antCtrlCommon);
     145             : 
     146           0 :         for (i = 0; i < AR9287_MAX_CHAINS; i++) {
     147           0 :                 eep->modalHeader.antCtrlChain[i] =
     148           0 :                     swap32(eep->modalHeader.antCtrlChain[i]);
     149             :         }
     150           0 :         for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
     151           0 :                 eep->modalHeader.spurChans[i].spurChan =
     152           0 :                     swap16(eep->modalHeader.spurChans[i].spurChan);
     153             :         }
     154           0 : }
     155             : 
     156             : const struct ar_spur_chan *
     157           0 : ar9287_get_spur_chans(struct athn_softc *sc, int is2ghz)
     158             : {
     159           0 :         const struct ar9287_eeprom *eep = sc->eep;
     160             : 
     161           0 :         KASSERT(is2ghz);
     162           0 :         return (eep->modalHeader.spurChans);
     163             : }
     164             : 
     165             : void
     166           0 : ar9287_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c,
     167             :     struct ieee80211_channel *extc)
     168             : {
     169           0 :         const struct ar9287_eeprom *eep = sc->eep;
     170           0 :         const struct ar9287_modal_eep_header *modal = &eep->modalHeader;
     171             :         uint32_t reg, offset;
     172             :         int i;
     173             : 
     174           0 :         AR_WRITE(sc, AR_PHY_SWITCH_COM, modal->antCtrlCommon);
     175             : 
     176           0 :         for (i = 0; i < AR9287_MAX_CHAINS; i++) {
     177           0 :                 offset = i * 0x1000;
     178             : 
     179           0 :                 AR_WRITE(sc, AR_PHY_SWITCH_CHAIN_0 + offset,
     180             :                     modal->antCtrlChain[i]);
     181             : 
     182           0 :                 reg = AR_READ(sc, AR_PHY_TIMING_CTRL4_0 + offset);
     183           0 :                 reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
     184             :                     modal->iqCalICh[i]);
     185           0 :                 reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
     186             :                     modal->iqCalQCh[i]);
     187           0 :                 AR_WRITE(sc, AR_PHY_TIMING_CTRL4_0 + offset, reg);
     188             : 
     189           0 :                 reg = AR_READ(sc, AR_PHY_GAIN_2GHZ + offset);
     190           0 :                 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
     191             :                     modal->bswMargin[i]);
     192           0 :                 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_DB,
     193             :                     modal->bswAtten[i]);
     194           0 :                 AR_WRITE(sc, AR_PHY_GAIN_2GHZ + offset, reg);
     195             : 
     196           0 :                 reg = AR_READ(sc, AR_PHY_RXGAIN + offset);
     197           0 :                 reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_MARGIN,
     198             :                     modal->rxTxMarginCh[i]);
     199           0 :                 reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_ATTEN,
     200             :                     modal->txRxAttenCh[i]);
     201           0 :                 AR_WRITE(sc, AR_PHY_RXGAIN + offset, reg);
     202             :         }
     203             : 
     204           0 :         reg = AR_READ(sc, AR_PHY_SETTLING);
     205           0 :         if (extc != NULL)
     206           0 :                 reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->swSettleHt40);
     207             :         else
     208           0 :                 reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->switchSettling);
     209           0 :         AR_WRITE(sc, AR_PHY_SETTLING, reg);
     210             : 
     211           0 :         reg = AR_READ(sc, AR_PHY_DESIRED_SZ);
     212           0 :         reg = RW(reg, AR_PHY_DESIRED_SZ_ADC, modal->adcDesiredSize);
     213           0 :         AR_WRITE(sc, AR_PHY_DESIRED_SZ, reg);
     214             : 
     215           0 :         reg  = SM(AR_PHY_RF_CTL4_TX_END_XPAA_OFF, modal->txEndToXpaOff);
     216           0 :         reg |= SM(AR_PHY_RF_CTL4_TX_END_XPAB_OFF, modal->txEndToXpaOff);
     217           0 :         reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAA_ON, modal->txFrameToXpaOn);
     218           0 :         reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAB_ON, modal->txFrameToXpaOn);
     219           0 :         AR_WRITE(sc, AR_PHY_RF_CTL4, reg);
     220             : 
     221           0 :         reg = AR_READ(sc, AR_PHY_RF_CTL3);
     222           0 :         reg = RW(reg, AR_PHY_TX_END_TO_A2_RX_ON, modal->txEndToRxOn);
     223           0 :         AR_WRITE(sc, AR_PHY_RF_CTL3, reg);
     224             : 
     225           0 :         reg = AR_READ(sc, AR_PHY_CCA(0));
     226           0 :         reg = RW(reg, AR9280_PHY_CCA_THRESH62, modal->thresh62);
     227           0 :         AR_WRITE(sc, AR_PHY_CCA(0), reg);
     228             : 
     229           0 :         reg = AR_READ(sc, AR_PHY_EXT_CCA0);
     230           0 :         reg = RW(reg, AR_PHY_EXT_CCA0_THRESH62, modal->thresh62);
     231           0 :         AR_WRITE(sc, AR_PHY_EXT_CCA0, reg);
     232             : 
     233           0 :         reg = AR_READ(sc, AR9287_AN_RF2G3_CH0);
     234           0 :         reg = RW(reg, AR9287_AN_RF2G3_DB1, modal->db1);
     235           0 :         reg = RW(reg, AR9287_AN_RF2G3_DB2, modal->db2);
     236           0 :         reg = RW(reg, AR9287_AN_RF2G3_OB_CCK, modal->ob_cck);
     237           0 :         reg = RW(reg, AR9287_AN_RF2G3_OB_PSK, modal->ob_psk);
     238           0 :         reg = RW(reg, AR9287_AN_RF2G3_OB_QAM, modal->ob_qam);
     239           0 :         reg = RW(reg, AR9287_AN_RF2G3_OB_PAL_OFF, modal->ob_pal_off);
     240           0 :         AR_WRITE(sc, AR9287_AN_RF2G3_CH0, reg);
     241           0 :         AR_WRITE_BARRIER(sc);
     242           0 :         DELAY(100);
     243             : 
     244           0 :         reg = AR_READ(sc, AR9287_AN_RF2G3_CH1);
     245           0 :         reg = RW(reg, AR9287_AN_RF2G3_DB1, modal->db1);
     246           0 :         reg = RW(reg, AR9287_AN_RF2G3_DB2, modal->db2);
     247           0 :         reg = RW(reg, AR9287_AN_RF2G3_OB_CCK, modal->ob_cck);
     248           0 :         reg = RW(reg, AR9287_AN_RF2G3_OB_PSK, modal->ob_psk);
     249           0 :         reg = RW(reg, AR9287_AN_RF2G3_OB_QAM, modal->ob_qam);
     250           0 :         reg = RW(reg, AR9287_AN_RF2G3_OB_PAL_OFF, modal->ob_pal_off);
     251           0 :         AR_WRITE(sc, AR9287_AN_RF2G3_CH1, reg);
     252           0 :         AR_WRITE_BARRIER(sc);
     253           0 :         DELAY(100);
     254             : 
     255           0 :         reg = AR_READ(sc, AR_PHY_RF_CTL2);
     256           0 :         reg = RW(reg, AR_PHY_TX_END_DATA_START, modal->txFrameToDataStart);
     257           0 :         reg = RW(reg, AR_PHY_TX_END_PA_ON, modal->txFrameToPaOn);
     258           0 :         AR_WRITE(sc, AR_PHY_RF_CTL2, reg);
     259             : 
     260           0 :         reg = AR_READ(sc, AR9287_AN_TOP2);
     261           0 :         reg = RW(reg, AR9287_AN_TOP2_XPABIAS_LVL, modal->xpaBiasLvl);
     262           0 :         AR_WRITE(sc, AR9287_AN_TOP2, reg);
     263           0 :         AR_WRITE_BARRIER(sc);
     264           0 :         DELAY(100);
     265           0 : }
     266             : 
     267             : void
     268           0 : ar9287_get_pdadcs(struct athn_softc *sc, struct ieee80211_channel *c,
     269             :     int chain, int nxpdgains, uint8_t overlap, uint8_t *boundaries,
     270             :     uint8_t *pdadcs)
     271             : {
     272           0 :         const struct ar9287_eeprom *eep = sc->eep;
     273             :         const struct ar9287_cal_data_per_freq *pierdata;
     274             :         const uint8_t *pierfreq;
     275           0 :         struct athn_pier lopier, hipier;
     276             :         int16_t delta;
     277             :         uint8_t fbin;
     278           0 :         int i, lo, hi, npiers;
     279             : 
     280           0 :         pierfreq = eep->calFreqPier2G;
     281           0 :         pierdata = (const struct ar9287_cal_data_per_freq *)
     282           0 :             eep->calPierData2G[chain];
     283             :         npiers = AR9287_NUM_2G_CAL_PIERS;
     284             : 
     285             :         /* Find channel in ROM pier table. */
     286           0 :         fbin = athn_chan2fbin(c);
     287           0 :         athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi);
     288             : 
     289           0 :         lopier.fbin = pierfreq[lo];
     290           0 :         hipier.fbin = pierfreq[hi];
     291           0 :         for (i = 0; i < nxpdgains; i++) {
     292           0 :                 lopier.pwr[i] = pierdata[lo].pwrPdg[i];
     293           0 :                 lopier.vpd[i] = pierdata[lo].vpdPdg[i];
     294           0 :                 hipier.pwr[i] = pierdata[lo].pwrPdg[i];
     295           0 :                 hipier.vpd[i] = pierdata[lo].vpdPdg[i];
     296             :         }
     297           0 :         ar5008_get_pdadcs(sc, fbin, &lopier, &hipier, nxpdgains,
     298             :             AR9287_PD_GAIN_ICEPTS, overlap, boundaries, pdadcs);
     299             : 
     300           0 :         delta = (eep->baseEepHeader.pwrTableOffset -
     301           0 :             AR_PWR_TABLE_OFFSET_DB) * 2;        /* In half dB. */
     302           0 :         if (delta != 0) {
     303             :                 /* Shift the PDADC table to start at the new offset. */
     304             :                 /* XXX Our padding value differs from Linux. */
     305           0 :                 for (i = 0; i < AR_NUM_PDADC_VALUES; i++)
     306           0 :                         pdadcs[i] = pdadcs[MIN(i + delta,
     307             :                             AR_NUM_PDADC_VALUES - 1)];
     308             :         }
     309           0 : }
     310             : 
     311             : void
     312           0 : ar9287_olpc_get_pdgain(struct athn_softc *sc, struct ieee80211_channel *c,
     313             :     int chain, int8_t *pwr)
     314             : {
     315           0 :         const struct ar9287_eeprom *eep = sc->eep;
     316             :         const struct ar_cal_data_per_freq_olpc *pierdata;
     317             :         const uint8_t *pierfreq;
     318             :         uint8_t fbin;
     319           0 :         int lo, hi, npiers;
     320             : 
     321           0 :         pierfreq = eep->calFreqPier2G;
     322           0 :         pierdata = (const struct ar_cal_data_per_freq_olpc *)
     323           0 :             eep->calPierData2G[chain];
     324             :         npiers = AR9287_NUM_2G_CAL_PIERS;
     325             : 
     326             :         /* Find channel in ROM pier table. */
     327           0 :         fbin = athn_chan2fbin(c);
     328           0 :         athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi);
     329             : 
     330             : #if 0
     331             :         *pwr = athn_interpolate(fbin,
     332             :             pierfreq[lo], pierdata[lo].pwrPdg[0][0],
     333             :             pierfreq[hi], pierdata[hi].pwrPdg[0][0]);
     334             : #else
     335           0 :         *pwr = (pierdata[lo].pwrPdg[0][0] + pierdata[hi].pwrPdg[0][0]) / 2;
     336             : #endif
     337           0 : }
     338             : 
     339             : void
     340           0 : ar9287_set_power_calib(struct athn_softc *sc, struct ieee80211_channel *c)
     341             : {
     342           0 :         const struct ar9287_eeprom *eep = sc->eep;
     343           0 :         uint8_t boundaries[AR_PD_GAINS_IN_MASK];
     344           0 :         uint8_t pdadcs[AR_NUM_PDADC_VALUES];
     345           0 :         uint8_t xpdgains[AR9287_NUM_PD_GAINS];
     346           0 :         int8_t txpower;
     347             :         uint8_t overlap;
     348             :         uint32_t reg, offset;
     349             :         int i, j, nxpdgains;
     350             : 
     351           0 :         if (sc->eep_rev < AR_EEP_MINOR_VER_2) {
     352           0 :                 overlap = MS(AR_READ(sc, AR_PHY_TPCRG5),
     353             :                     AR_PHY_TPCRG5_PD_GAIN_OVERLAP);
     354           0 :         } else
     355           0 :                 overlap = eep->modalHeader.pdGainOverlap;
     356             : 
     357           0 :         if (sc->flags & ATHN_FLAG_OLPC) {
     358             :                 /* XXX not here. */
     359           0 :                 sc->pdadc =
     360           0 :                     ((const struct ar_cal_data_per_freq_olpc *)
     361           0 :                      eep->calPierData2G[0])->vpdPdg[0][0];
     362           0 :         }
     363             : 
     364             :         nxpdgains = 0;
     365           0 :         memset(xpdgains, 0, sizeof(xpdgains));
     366           0 :         for (i = AR9287_PD_GAINS_IN_MASK - 1; i >= 0; i--) {
     367           0 :                 if (nxpdgains >= AR9287_NUM_PD_GAINS)
     368             :                         break;          /* Can't happen. */
     369           0 :                 if (eep->modalHeader.xpdGain & (1 << i))
     370           0 :                         xpdgains[nxpdgains++] = i;
     371             :         }
     372           0 :         reg = AR_READ(sc, AR_PHY_TPCRG1);
     373           0 :         reg = RW(reg, AR_PHY_TPCRG1_NUM_PD_GAIN, nxpdgains - 1);
     374           0 :         reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_1, xpdgains[0]);
     375           0 :         reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_2, xpdgains[1]);
     376           0 :         AR_WRITE(sc, AR_PHY_TPCRG1, reg);
     377           0 :         AR_WRITE_BARRIER(sc);
     378             : 
     379           0 :         for (i = 0; i < AR9287_MAX_CHAINS; i++)      {
     380           0 :                 if (!(sc->txchainmask & (1 << i)))
     381             :                         continue;
     382             : 
     383           0 :                 offset = i * 0x1000;
     384             : 
     385           0 :                 if (sc->flags & ATHN_FLAG_OLPC) {
     386           0 :                         ar9287_olpc_get_pdgain(sc, c, i, &txpower);
     387             : 
     388           0 :                         reg = AR_READ(sc, AR_PHY_TX_PWRCTRL6_0);
     389           0 :                         reg = RW(reg, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
     390           0 :                         AR_WRITE(sc, AR_PHY_TX_PWRCTRL6_0, reg);
     391             : 
     392           0 :                         reg = AR_READ(sc, AR_PHY_TX_PWRCTRL6_1);
     393           0 :                         reg = RW(reg, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
     394           0 :                         AR_WRITE(sc, AR_PHY_TX_PWRCTRL6_1, reg);
     395             : 
     396             :                         /* NB: txpower is in half dB. */
     397           0 :                         reg = AR_READ(sc, AR_PHY_CH0_TX_PWRCTRL11 + offset);
     398           0 :                         reg = RW(reg, AR_PHY_TX_PWRCTRL_OLPC_PWR, txpower);
     399           0 :                         AR_WRITE(sc, AR_PHY_CH0_TX_PWRCTRL11 + offset, reg);
     400             : 
     401           0 :                         AR_WRITE_BARRIER(sc);
     402           0 :                         continue;       /* That's it for open loop mode. */
     403             :                 }
     404             : 
     405             :                 /* Closed loop power control. */
     406           0 :                 ar9287_get_pdadcs(sc, c, i, nxpdgains, overlap,
     407           0 :                     boundaries, pdadcs);
     408             : 
     409             :                 /* Write boundaries. */
     410           0 :                 if (i == 0) {
     411           0 :                         reg  = SM(AR_PHY_TPCRG5_PD_GAIN_OVERLAP,
     412             :                             overlap);
     413           0 :                         reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1,
     414             :                             boundaries[0]);
     415           0 :                         reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2,
     416             :                             boundaries[1]);
     417           0 :                         reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3,
     418             :                             boundaries[2]);
     419           0 :                         reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4,
     420             :                             boundaries[3]);
     421           0 :                         AR_WRITE(sc, AR_PHY_TPCRG5 + offset, reg);
     422           0 :                 }
     423             :                 /* Write PDADC values. */
     424           0 :                 for (j = 0; j < AR_NUM_PDADC_VALUES; j += 4) {
     425           0 :                         AR_WRITE(sc, AR_PHY_PDADC_TBL_BASE + offset + j,
     426             :                             pdadcs[j + 0] <<  0 |
     427             :                             pdadcs[j + 1] <<  8 |
     428             :                             pdadcs[j + 2] << 16 |
     429             :                             pdadcs[j + 3] << 24);
     430             :                 }
     431           0 :                 AR_WRITE_BARRIER(sc);
     432           0 :         }
     433           0 : }
     434             : 
     435             : void
     436           0 : ar9287_set_txpower(struct athn_softc *sc, struct ieee80211_channel *c,
     437             :     struct ieee80211_channel *extc)
     438             : {
     439           0 :         const struct ar9287_eeprom *eep = sc->eep;
     440           0 :         const struct ar9287_modal_eep_header *modal = &eep->modalHeader;
     441           0 :         uint8_t tpow_cck[4], tpow_ofdm[4];
     442           0 :         uint8_t tpow_cck_ext[4], tpow_ofdm_ext[4];
     443           0 :         uint8_t tpow_ht20[8], tpow_ht40[8];
     444             :         uint8_t ht40inc;
     445           0 :         int16_t pwr = 0, max_ant_gain, power[ATHN_POWER_COUNT];
     446             :         int i;
     447             : 
     448           0 :         ar9287_set_power_calib(sc, c);
     449             : 
     450             :         /* Compute transmit power reduction due to antenna gain. */
     451           0 :         max_ant_gain = MAX(modal->antennaGainCh[0], modal->antennaGainCh[1]);
     452             :         /* XXX */
     453             : 
     454             :         /*
     455             :          * Reduce scaled power by number of active chains to get per-chain
     456             :          * transmit power level.
     457             :          */
     458           0 :         if (sc->ntxchains == 2)
     459           0 :                 pwr -= AR_PWR_DECREASE_FOR_2_CHAIN;
     460           0 :         if (pwr < 0)
     461           0 :                 pwr = 0;
     462             : 
     463             :         /* Get CCK target powers. */
     464           0 :         ar5008_get_lg_tpow(sc, c, AR_CTL_11B, eep->calTargetPowerCck,
     465           0 :             AR9287_NUM_2G_CCK_TARGET_POWERS, tpow_cck);
     466             : 
     467             :         /* Get OFDM target powers. */
     468           0 :         ar5008_get_lg_tpow(sc, c, AR_CTL_11G, eep->calTargetPower2G,
     469           0 :             AR9287_NUM_2G_20_TARGET_POWERS, tpow_ofdm);
     470             : 
     471             :         /* Get HT-20 target powers. */
     472           0 :         ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT20, eep->calTargetPower2GHT20,
     473           0 :             AR9287_NUM_2G_20_TARGET_POWERS, tpow_ht20);
     474             : 
     475           0 :         if (extc != NULL) {
     476             :                 /* Get HT-40 target powers. */
     477           0 :                 ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT40,
     478           0 :                     eep->calTargetPower2GHT40, AR9287_NUM_2G_40_TARGET_POWERS,
     479           0 :                     tpow_ht40);
     480             : 
     481             :                 /* Get secondary channel CCK target powers. */
     482           0 :                 ar5008_get_lg_tpow(sc, extc, AR_CTL_11B,
     483             :                     eep->calTargetPowerCck, AR9287_NUM_2G_CCK_TARGET_POWERS,
     484           0 :                     tpow_cck_ext);
     485             : 
     486             :                 /* Get secondary channel OFDM target powers. */
     487           0 :                 ar5008_get_lg_tpow(sc, extc, AR_CTL_11G,
     488             :                     eep->calTargetPower2G, AR9287_NUM_2G_20_TARGET_POWERS,
     489           0 :                     tpow_ofdm_ext);
     490           0 :         }
     491             : 
     492           0 :         memset(power, 0, sizeof(power));
     493             :         /* Shuffle target powers accross transmit rates. */
     494           0 :         power[ATHN_POWER_OFDM6   ] =
     495           0 :         power[ATHN_POWER_OFDM9   ] =
     496           0 :         power[ATHN_POWER_OFDM12  ] =
     497           0 :         power[ATHN_POWER_OFDM18  ] =
     498           0 :         power[ATHN_POWER_OFDM24  ] = tpow_ofdm[0];
     499           0 :         power[ATHN_POWER_OFDM36  ] = tpow_ofdm[1];
     500           0 :         power[ATHN_POWER_OFDM48  ] = tpow_ofdm[2];
     501           0 :         power[ATHN_POWER_OFDM54  ] = tpow_ofdm[3];
     502           0 :         power[ATHN_POWER_XR      ] = tpow_ofdm[0];
     503           0 :         power[ATHN_POWER_CCK1_LP ] = tpow_cck[0];
     504           0 :         power[ATHN_POWER_CCK2_LP ] =
     505           0 :         power[ATHN_POWER_CCK2_SP ] = tpow_cck[1];
     506           0 :         power[ATHN_POWER_CCK55_LP] =
     507           0 :         power[ATHN_POWER_CCK55_SP] = tpow_cck[2];
     508           0 :         power[ATHN_POWER_CCK11_LP] =
     509           0 :         power[ATHN_POWER_CCK11_SP] = tpow_cck[3];
     510           0 :         for (i = 0; i < nitems(tpow_ht20); i++)
     511           0 :                 power[ATHN_POWER_HT20(i)] = tpow_ht20[i];
     512           0 :         if (extc != NULL) {
     513             :                 /* Correct PAR difference between HT40 and HT20/Legacy. */
     514           0 :                 if (sc->eep_rev >= AR_EEP_MINOR_VER_2)
     515           0 :                         ht40inc = modal->ht40PowerIncForPdadc;
     516             :                 else
     517             :                         ht40inc = AR_HT40_POWER_INC_FOR_PDADC;
     518           0 :                 for (i = 0; i < nitems(tpow_ht40); i++)
     519           0 :                         power[ATHN_POWER_HT40(i)] = tpow_ht40[i] + ht40inc;
     520           0 :                 power[ATHN_POWER_OFDM_DUP] = tpow_ht40[0];
     521           0 :                 power[ATHN_POWER_CCK_DUP ] = tpow_ht40[0];
     522           0 :                 power[ATHN_POWER_OFDM_EXT] = tpow_ofdm_ext[0];
     523           0 :                 if (IEEE80211_IS_CHAN_2GHZ(c))
     524           0 :                         power[ATHN_POWER_CCK_EXT] = tpow_cck_ext[0];
     525             :         }
     526             : 
     527           0 :         for (i = 0; i < ATHN_POWER_COUNT; i++) {
     528           0 :                 power[i] -= AR_PWR_TABLE_OFFSET_DB * 2; /* In half dB. */
     529           0 :                 if (power[i] > AR_MAX_RATE_POWER)
     530           0 :                         power[i] = AR_MAX_RATE_POWER;
     531             :         }
     532             :         /* Commit transmit power values to hardware. */
     533           0 :         ar5008_write_txpower(sc, power);
     534           0 : }
     535             : 
     536             : void
     537           0 : ar9287_olpc_init(struct athn_softc *sc)
     538             : {
     539             :         uint32_t reg;
     540             : 
     541           0 :         AR_SETBITS(sc, AR_PHY_TX_PWRCTRL9, AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL);
     542             : 
     543           0 :         reg = AR_READ(sc, AR9287_AN_TXPC0);
     544           0 :         reg = RW(reg, AR9287_AN_TXPC0_TXPCMODE,
     545             :             AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE);
     546           0 :         AR_WRITE(sc, AR9287_AN_TXPC0, reg);
     547           0 :         AR_WRITE_BARRIER(sc);
     548           0 :         DELAY(100);
     549           0 : }
     550             : 
     551             : void
     552           0 : ar9287_olpc_temp_compensation(struct athn_softc *sc)
     553             : {
     554           0 :         const struct ar9287_eeprom *eep = sc->eep;
     555             :         int8_t pdadc, slope, tcomp;
     556             :         uint32_t reg;
     557             : 
     558           0 :         reg = AR_READ(sc, AR_PHY_TX_PWRCTRL4);
     559           0 :         pdadc = MS(reg, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
     560             :         DPRINTFN(3, ("PD Avg Out=%d\n", pdadc));
     561             : 
     562           0 :         if (sc->pdadc == 0 || pdadc == 0)
     563           0 :                 return; /* No frames transmitted yet. */
     564             : 
     565             :         /* Compute Tx gain temperature compensation. */
     566           0 :         if (sc->eep_rev >= AR_EEP_MINOR_VER_2)
     567           0 :                 slope = eep->baseEepHeader.tempSensSlope;
     568             :         else
     569             :                 slope = 0;
     570           0 :         if (slope != 0) /* Prevents division by zero. */
     571           0 :                 tcomp = ((pdadc - sc->pdadc) * 4) / slope;
     572             :         else
     573             :                 tcomp = 0;
     574             :         DPRINTFN(3, ("OLPC temp compensation=%d\n", tcomp));
     575             : 
     576             :         /* Write compensation value for both Tx chains. */
     577           0 :         reg = AR_READ(sc, AR_PHY_CH0_TX_PWRCTRL11);
     578           0 :         reg = RW(reg, AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, tcomp);
     579           0 :         AR_WRITE(sc, AR_PHY_CH0_TX_PWRCTRL11, reg);
     580             : 
     581           0 :         reg = AR_READ(sc, AR_PHY_CH1_TX_PWRCTRL11);
     582           0 :         reg = RW(reg, AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, tcomp);
     583           0 :         AR_WRITE(sc, AR_PHY_CH1_TX_PWRCTRL11, reg);
     584           0 :         AR_WRITE_BARRIER(sc);
     585           0 : }
     586             : 
     587             : void
     588           0 : ar9287_1_3_enable_async_fifo(struct athn_softc *sc)
     589             : {
     590             :         /* Enable ASYNC FIFO. */
     591           0 :         AR_SETBITS(sc, AR_MAC_PCU_ASYNC_FIFO_REG3,
     592             :             AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
     593           0 :         AR_SETBITS(sc, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
     594           0 :         AR_CLRBITS(sc, AR_MAC_PCU_ASYNC_FIFO_REG3,
     595             :             AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
     596           0 :         AR_SETBITS(sc, AR_MAC_PCU_ASYNC_FIFO_REG3,
     597             :             AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
     598           0 :         AR_WRITE_BARRIER(sc);
     599           0 : }
     600             : 
     601             : void
     602           0 : ar9287_1_3_setup_async_fifo(struct athn_softc *sc)
     603             : {
     604             :         uint32_t reg;
     605             : 
     606             :         /*
     607             :          * MAC runs at 117MHz (instead of 88/44MHz) when ASYNC FIFO is
     608             :          * enabled, so the following counters have to be changed.
     609             :          */
     610           0 :         AR_WRITE(sc, AR_D_GBL_IFS_SIFS, AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
     611           0 :         AR_WRITE(sc, AR_D_GBL_IFS_SLOT, AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
     612           0 :         AR_WRITE(sc, AR_D_GBL_IFS_EIFS, AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
     613             : 
     614           0 :         AR_WRITE(sc, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
     615           0 :         AR_WRITE(sc, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
     616             : 
     617           0 :         AR_SETBITS(sc, AR_MAC_PCU_LOGIC_ANALYZER,
     618             :             AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
     619             : 
     620           0 :         reg = AR_READ(sc, AR_AHB_MODE);
     621           0 :         reg = RW(reg, AR_AHB_CUSTOM_BURST, AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
     622           0 :         AR_WRITE(sc, AR_AHB_MODE, reg);
     623             : 
     624           0 :         AR_SETBITS(sc, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
     625           0 :         AR_WRITE_BARRIER(sc);
     626           0 : }

Generated by: LCOV version 1.13