Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2010 Broadcom Corporation
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
0011  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
0013  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
0014  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include <net/mac80211.h>
0018 
0019 #include "types.h"
0020 #include "d11.h"
0021 #include "rate.h"
0022 #include "phy/phy_hal.h"
0023 #include "channel.h"
0024 #include "main.h"
0025 #include "stf.h"
0026 #include "debug.h"
0027 
0028 #define MIN_SPATIAL_EXPANSION   0
0029 #define MAX_SPATIAL_EXPANSION   1
0030 
0031 #define BRCMS_STF_SS_STBC_RX(wlc) (BRCMS_ISNPHY(wlc->band) && \
0032     NREV_GT(wlc->band->phyrev, 3) && NREV_LE(wlc->band->phyrev, 6))
0033 
0034 #define NSTS_1  1
0035 #define NSTS_2  2
0036 #define NSTS_3  3
0037 #define NSTS_4  4
0038 
0039 static const u8 txcore_default[5] = {
0040     (0),            /* bitmap of the core enabled */
0041     (0x01),         /* For Nsts = 1, enable core 1 */
0042     (0x03),         /* For Nsts = 2, enable core 1 & 2 */
0043     (0x07),         /* For Nsts = 3, enable core 1, 2 & 3 */
0044     (0x0f)          /* For Nsts = 4, enable all cores */
0045 };
0046 
0047 static void brcms_c_stf_stbc_rx_ht_update(struct brcms_c_info *wlc, int val)
0048 {
0049     /* MIMOPHYs rev3-6 cannot receive STBC with only one rx core active */
0050     if (BRCMS_STF_SS_STBC_RX(wlc)) {
0051         if ((wlc->stf->rxstreams == 1) && (val != HT_CAP_RX_STBC_NO))
0052             return;
0053     }
0054 
0055     if (wlc->pub->up) {
0056         brcms_c_update_beacon(wlc);
0057         brcms_c_update_probe_resp(wlc, true);
0058     }
0059 }
0060 
0061 /*
0062  * every WLC_TEMPSENSE_PERIOD seconds temperature check to decide whether to
0063  * turn on/off txchain.
0064  */
0065 void brcms_c_tempsense_upd(struct brcms_c_info *wlc)
0066 {
0067     struct brcms_phy_pub *pi = wlc->band->pi;
0068     uint active_chains, txchain;
0069 
0070     /* Check if the chip is too hot. Disable one Tx chain, if it is */
0071     /* high 4 bits are for Rx chain, low 4 bits are  for Tx chain */
0072     active_chains = wlc_phy_stf_chain_active_get(pi);
0073     txchain = active_chains & 0xf;
0074 
0075     if (wlc->stf->txchain == wlc->stf->hw_txchain) {
0076         if (txchain && (txchain < wlc->stf->hw_txchain))
0077             /* turn off 1 tx chain */
0078             brcms_c_stf_txchain_set(wlc, txchain, true);
0079     } else if (wlc->stf->txchain < wlc->stf->hw_txchain) {
0080         if (txchain == wlc->stf->hw_txchain)
0081             /* turn back on txchain */
0082             brcms_c_stf_txchain_set(wlc, txchain, true);
0083     }
0084 }
0085 
0086 void
0087 brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel,
0088                 u16 chanspec)
0089 {
0090     struct tx_power power = { };
0091     u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id;
0092 
0093     /* Clear previous settings */
0094     *ss_algo_channel = 0;
0095 
0096     if (!wlc->pub->up) {
0097         *ss_algo_channel = (u16) -1;
0098         return;
0099     }
0100 
0101     wlc_phy_txpower_get_current(wlc->band->pi, &power,
0102                     CHSPEC_CHANNEL(chanspec));
0103 
0104     siso_mcs_id = (CHSPEC_IS40(chanspec)) ?
0105         WL_TX_POWER_MCS40_SISO_FIRST : WL_TX_POWER_MCS20_SISO_FIRST;
0106     cdd_mcs_id = (CHSPEC_IS40(chanspec)) ?
0107         WL_TX_POWER_MCS40_CDD_FIRST : WL_TX_POWER_MCS20_CDD_FIRST;
0108     stbc_mcs_id = (CHSPEC_IS40(chanspec)) ?
0109         WL_TX_POWER_MCS40_STBC_FIRST : WL_TX_POWER_MCS20_STBC_FIRST;
0110 
0111     /* criteria to choose stf mode */
0112 
0113     /*
0114      * the "+3dbm (12 0.25db units)" is to account for the fact that with
0115      * CDD, tx occurs on both chains
0116      */
0117     if (power.target[siso_mcs_id] > (power.target[cdd_mcs_id] + 12))
0118         setbit(ss_algo_channel, PHY_TXC1_MODE_SISO);
0119     else
0120         setbit(ss_algo_channel, PHY_TXC1_MODE_CDD);
0121 
0122     /*
0123      * STBC is ORed into to algo channel as STBC requires per-packet SCB
0124      * capability check so cannot be default mode of operation. One of
0125      * SISO, CDD have to be set
0126      */
0127     if (power.target[siso_mcs_id] <= (power.target[stbc_mcs_id] + 12))
0128         setbit(ss_algo_channel, PHY_TXC1_MODE_STBC);
0129 }
0130 
0131 static bool brcms_c_stf_stbc_tx_set(struct brcms_c_info *wlc, s32 int_val)
0132 {
0133     if ((int_val != AUTO) && (int_val != OFF) && (int_val != ON))
0134         return false;
0135 
0136     if ((int_val == ON) && (wlc->stf->txstreams == 1))
0137         return false;
0138 
0139     wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = (s8) int_val;
0140     wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = (s8) int_val;
0141 
0142     return true;
0143 }
0144 
0145 bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val)
0146 {
0147     if ((int_val != HT_CAP_RX_STBC_NO)
0148         && (int_val != HT_CAP_RX_STBC_ONE_STREAM))
0149         return false;
0150 
0151     if (BRCMS_STF_SS_STBC_RX(wlc)) {
0152         if ((int_val != HT_CAP_RX_STBC_NO)
0153             && (wlc->stf->rxstreams == 1))
0154             return false;
0155     }
0156 
0157     brcms_c_stf_stbc_rx_ht_update(wlc, int_val);
0158     return true;
0159 }
0160 
0161 static int brcms_c_stf_txcore_set(struct brcms_c_info *wlc, u8 Nsts,
0162                   u8 core_mask)
0163 {
0164     brcms_dbg_ht(wlc->hw->d11core, "wl%d: Nsts %d core_mask %x\n",
0165              wlc->pub->unit, Nsts, core_mask);
0166 
0167     if (hweight8(core_mask) > wlc->stf->txstreams)
0168         core_mask = 0;
0169 
0170     if ((hweight8(core_mask) == wlc->stf->txstreams) &&
0171         ((core_mask & ~wlc->stf->txchain)
0172          || !(core_mask & wlc->stf->txchain)))
0173         core_mask = wlc->stf->txchain;
0174 
0175     wlc->stf->txcore[Nsts] = core_mask;
0176     /* Nsts = 1..4, txcore index = 1..4 */
0177     if (Nsts == 1) {
0178         /* Needs to update beacon and ucode generated response
0179          * frames when 1 stream core map changed
0180          */
0181         wlc->stf->phytxant = core_mask << PHY_TXC_ANT_SHIFT;
0182         brcms_b_txant_set(wlc->hw, wlc->stf->phytxant);
0183         if (wlc->clk) {
0184             brcms_c_suspend_mac_and_wait(wlc);
0185             brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec);
0186             brcms_c_enable_mac(wlc);
0187         }
0188     }
0189 
0190     return 0;
0191 }
0192 
0193 static int brcms_c_stf_spatial_policy_set(struct brcms_c_info *wlc, int val)
0194 {
0195     int i;
0196     u8 core_mask = 0;
0197 
0198     brcms_dbg_ht(wlc->hw->d11core, "wl%d: val %x\n", wlc->pub->unit,
0199              val);
0200 
0201     wlc->stf->spatial_policy = (s8) val;
0202     for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) {
0203         core_mask = (val == MAX_SPATIAL_EXPANSION) ?
0204             wlc->stf->txchain : txcore_default[i];
0205         brcms_c_stf_txcore_set(wlc, (u8) i, core_mask);
0206     }
0207     return 0;
0208 }
0209 
0210 /*
0211  * Centralized txant update function. call it whenever wlc->stf->txant and/or
0212  * wlc->stf->txchain change.
0213  *
0214  * Antennas are controlled by ucode indirectly, which drives PHY or GPIO to
0215  * achieve various tx/rx antenna selection schemes
0216  *
0217  * legacy phy, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7
0218  * means auto(last rx).
0219  * for NREV<3, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7
0220  * means last rx and do tx-antenna selection for SISO transmissions
0221  * for NREV=3, bit 6 and bit _8_ means antenna 0 and 1 respectively, bit6+bit7
0222  * means last rx and do tx-antenna selection for SISO transmissions
0223  * for NREV>=7, bit 6 and bit 7 mean antenna 0 and 1 respectively, nit6+bit7
0224  * means both cores active
0225 */
0226 static void _brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
0227 {
0228     s8 txant;
0229 
0230     txant = (s8) wlc->stf->txant;
0231     if (BRCMS_PHY_11N_CAP(wlc->band)) {
0232         if (txant == ANT_TX_FORCE_0) {
0233             wlc->stf->phytxant = PHY_TXC_ANT_0;
0234         } else if (txant == ANT_TX_FORCE_1) {
0235             wlc->stf->phytxant = PHY_TXC_ANT_1;
0236 
0237             if (BRCMS_ISNPHY(wlc->band) &&
0238                 NREV_GE(wlc->band->phyrev, 3)
0239                 && NREV_LT(wlc->band->phyrev, 7))
0240                 wlc->stf->phytxant = PHY_TXC_ANT_2;
0241         } else {
0242             if (BRCMS_ISLCNPHY(wlc->band) ||
0243                 BRCMS_ISSSLPNPHY(wlc->band))
0244                 wlc->stf->phytxant = PHY_TXC_LCNPHY_ANT_LAST;
0245             else {
0246                 /* catch out of sync wlc->stf->txcore */
0247                 WARN_ON(wlc->stf->txchain <= 0);
0248                 wlc->stf->phytxant =
0249                     wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
0250             }
0251         }
0252     } else {
0253         if (txant == ANT_TX_FORCE_0)
0254             wlc->stf->phytxant = PHY_TXC_OLD_ANT_0;
0255         else if (txant == ANT_TX_FORCE_1)
0256             wlc->stf->phytxant = PHY_TXC_OLD_ANT_1;
0257         else
0258             wlc->stf->phytxant = PHY_TXC_OLD_ANT_LAST;
0259     }
0260 
0261     brcms_b_txant_set(wlc->hw, wlc->stf->phytxant);
0262 }
0263 
0264 int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force)
0265 {
0266     u8 txchain = (u8) int_val;
0267     u8 txstreams;
0268     uint i;
0269 
0270     if (wlc->stf->txchain == txchain)
0271         return 0;
0272 
0273     if ((txchain & ~wlc->stf->hw_txchain)
0274         || !(txchain & wlc->stf->hw_txchain))
0275         return -EINVAL;
0276 
0277     /*
0278      * if nrate override is configured to be non-SISO STF mode, reject
0279      * reducing txchain to 1
0280      */
0281     txstreams = (u8) hweight8(txchain);
0282     if (txstreams > MAX_STREAMS_SUPPORTED)
0283         return -EINVAL;
0284 
0285     wlc->stf->txchain = txchain;
0286     wlc->stf->txstreams = txstreams;
0287     brcms_c_stf_stbc_tx_set(wlc, wlc->band->band_stf_stbc_tx);
0288     brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
0289     brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
0290     wlc->stf->txant =
0291         (wlc->stf->txstreams == 1) ? ANT_TX_FORCE_0 : ANT_TX_DEF;
0292     _brcms_c_stf_phy_txant_upd(wlc);
0293 
0294     wlc_phy_stf_chain_set(wlc->band->pi, wlc->stf->txchain,
0295                   wlc->stf->rxchain);
0296 
0297     for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++)
0298         brcms_c_stf_txcore_set(wlc, (u8) i, txcore_default[i]);
0299 
0300     return 0;
0301 }
0302 
0303 /*
0304  * update wlc->stf->ss_opmode which represents the operational stf_ss mode
0305  * we're using
0306  */
0307 void brcms_c_stf_ss_update(struct brcms_c_info *wlc, struct brcms_band *band)
0308 {
0309     u8 prev_stf_ss;
0310     u8 upd_stf_ss;
0311 
0312     prev_stf_ss = wlc->stf->ss_opmode;
0313 
0314     /*
0315      * NOTE: opmode can only be SISO or CDD as STBC is decided on a
0316      * per-packet basis
0317      */
0318     if (BRCMS_STBC_CAP_PHY(wlc) &&
0319         wlc->stf->ss_algosel_auto
0320         && (wlc->stf->ss_algo_channel != (u16) -1)) {
0321         upd_stf_ss = (wlc->stf->txstreams == 1 ||
0322                   isset(&wlc->stf->ss_algo_channel,
0323                     PHY_TXC1_MODE_SISO)) ?
0324                     PHY_TXC1_MODE_SISO : PHY_TXC1_MODE_CDD;
0325     } else {
0326         if (wlc->band != band)
0327             return;
0328         upd_stf_ss = (wlc->stf->txstreams == 1) ?
0329                 PHY_TXC1_MODE_SISO : band->band_stf_ss_mode;
0330     }
0331     if (prev_stf_ss != upd_stf_ss) {
0332         wlc->stf->ss_opmode = upd_stf_ss;
0333         brcms_b_band_stf_ss_set(wlc->hw, upd_stf_ss);
0334     }
0335 }
0336 
0337 int brcms_c_stf_attach(struct brcms_c_info *wlc)
0338 {
0339     wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_SISO;
0340     wlc->bandstate[BAND_5G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_CDD;
0341 
0342     if (BRCMS_ISNPHY(wlc->band) &&
0343         (wlc_phy_txpower_hw_ctrl_get(wlc->band->pi) != PHY_TPC_HW_ON))
0344         wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode =
0345             PHY_TXC1_MODE_CDD;
0346     brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
0347     brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
0348 
0349     brcms_c_stf_stbc_rx_ht_update(wlc, HT_CAP_RX_STBC_NO);
0350     wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = OFF;
0351     wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = OFF;
0352 
0353     if (BRCMS_STBC_CAP_PHY(wlc)) {
0354         wlc->stf->ss_algosel_auto = true;
0355         /* Init the default value */
0356         wlc->stf->ss_algo_channel = (u16) -1;
0357     }
0358     return 0;
0359 }
0360 
0361 void brcms_c_stf_detach(struct brcms_c_info *wlc)
0362 {
0363 }
0364 
0365 void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
0366 {
0367     _brcms_c_stf_phy_txant_upd(wlc);
0368 }
0369 
0370 void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc)
0371 {
0372     struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
0373 
0374     /* get available rx/tx chains */
0375     wlc->stf->hw_txchain = sprom->txchain;
0376     wlc->stf->hw_rxchain = sprom->rxchain;
0377 
0378     /* these parameter are intended to be used for all PHY types */
0379     if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) {
0380         if (BRCMS_ISNPHY(wlc->band))
0381             wlc->stf->hw_txchain = TXCHAIN_DEF_NPHY;
0382         else
0383             wlc->stf->hw_txchain = TXCHAIN_DEF;
0384     }
0385 
0386     wlc->stf->txchain = wlc->stf->hw_txchain;
0387     wlc->stf->txstreams = (u8) hweight8(wlc->stf->hw_txchain);
0388 
0389     if (wlc->stf->hw_rxchain == 0 || wlc->stf->hw_rxchain == 0xf) {
0390         if (BRCMS_ISNPHY(wlc->band))
0391             wlc->stf->hw_rxchain = RXCHAIN_DEF_NPHY;
0392         else
0393             wlc->stf->hw_rxchain = RXCHAIN_DEF;
0394     }
0395 
0396     wlc->stf->rxchain = wlc->stf->hw_rxchain;
0397     wlc->stf->rxstreams = (u8) hweight8(wlc->stf->hw_rxchain);
0398 
0399     /* initialize the txcore table */
0400     memcpy(wlc->stf->txcore, txcore_default, sizeof(wlc->stf->txcore));
0401 
0402     /* default spatial_policy */
0403     wlc->stf->spatial_policy = MIN_SPATIAL_EXPANSION;
0404     brcms_c_stf_spatial_policy_set(wlc, MIN_SPATIAL_EXPANSION);
0405 }
0406 
0407 static u16 _brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc,
0408                        u32 rspec)
0409 {
0410     u16 phytxant = wlc->stf->phytxant;
0411 
0412     if (rspec_stf(rspec) != PHY_TXC1_MODE_SISO)
0413         phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
0414     else if (wlc->stf->txant == ANT_TX_DEF)
0415         phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
0416     phytxant &= PHY_TXC_ANT_MASK;
0417     return phytxant;
0418 }
0419 
0420 u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, u32 rspec)
0421 {
0422     return _brcms_c_stf_phytxchain_sel(wlc, rspec);
0423 }
0424 
0425 u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, u32 rspec)
0426 {
0427     u16 phytxant = wlc->stf->phytxant;
0428     u16 mask = PHY_TXC_ANT_MASK;
0429 
0430     /* for non-siso rates or default setting, use the available chains */
0431     if (BRCMS_ISNPHY(wlc->band)) {
0432         phytxant = _brcms_c_stf_phytxchain_sel(wlc, rspec);
0433         mask = PHY_TXC_HTANT_MASK;
0434     }
0435     phytxant |= phytxant & mask;
0436     return phytxant;
0437 }