18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2010 Broadcom Corporation 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 118c2ecf20Sopenharmony_ci * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 138c2ecf20Sopenharmony_ci * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 148c2ecf20Sopenharmony_ci * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <net/mac80211.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "types.h" 208c2ecf20Sopenharmony_ci#include "d11.h" 218c2ecf20Sopenharmony_ci#include "rate.h" 228c2ecf20Sopenharmony_ci#include "phy/phy_hal.h" 238c2ecf20Sopenharmony_ci#include "channel.h" 248c2ecf20Sopenharmony_ci#include "main.h" 258c2ecf20Sopenharmony_ci#include "stf.h" 268c2ecf20Sopenharmony_ci#include "debug.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define MIN_SPATIAL_EXPANSION 0 298c2ecf20Sopenharmony_ci#define MAX_SPATIAL_EXPANSION 1 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define BRCMS_STF_SS_STBC_RX(wlc) (BRCMS_ISNPHY(wlc->band) && \ 328c2ecf20Sopenharmony_ci NREV_GT(wlc->band->phyrev, 3) && NREV_LE(wlc->band->phyrev, 6)) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define NSTS_1 1 358c2ecf20Sopenharmony_ci#define NSTS_2 2 368c2ecf20Sopenharmony_ci#define NSTS_3 3 378c2ecf20Sopenharmony_ci#define NSTS_4 4 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const u8 txcore_default[5] = { 408c2ecf20Sopenharmony_ci (0), /* bitmap of the core enabled */ 418c2ecf20Sopenharmony_ci (0x01), /* For Nsts = 1, enable core 1 */ 428c2ecf20Sopenharmony_ci (0x03), /* For Nsts = 2, enable core 1 & 2 */ 438c2ecf20Sopenharmony_ci (0x07), /* For Nsts = 3, enable core 1, 2 & 3 */ 448c2ecf20Sopenharmony_ci (0x0f) /* For Nsts = 4, enable all cores */ 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void brcms_c_stf_stbc_rx_ht_update(struct brcms_c_info *wlc, int val) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci /* MIMOPHYs rev3-6 cannot receive STBC with only one rx core active */ 508c2ecf20Sopenharmony_ci if (BRCMS_STF_SS_STBC_RX(wlc)) { 518c2ecf20Sopenharmony_ci if ((wlc->stf->rxstreams == 1) && (val != HT_CAP_RX_STBC_NO)) 528c2ecf20Sopenharmony_ci return; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (wlc->pub->up) { 568c2ecf20Sopenharmony_ci brcms_c_update_beacon(wlc); 578c2ecf20Sopenharmony_ci brcms_c_update_probe_resp(wlc, true); 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * every WLC_TEMPSENSE_PERIOD seconds temperature check to decide whether to 638c2ecf20Sopenharmony_ci * turn on/off txchain. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_civoid brcms_c_tempsense_upd(struct brcms_c_info *wlc) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct brcms_phy_pub *pi = wlc->band->pi; 688c2ecf20Sopenharmony_ci uint active_chains, txchain; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Check if the chip is too hot. Disable one Tx chain, if it is */ 718c2ecf20Sopenharmony_ci /* high 4 bits are for Rx chain, low 4 bits are for Tx chain */ 728c2ecf20Sopenharmony_ci active_chains = wlc_phy_stf_chain_active_get(pi); 738c2ecf20Sopenharmony_ci txchain = active_chains & 0xf; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (wlc->stf->txchain == wlc->stf->hw_txchain) { 768c2ecf20Sopenharmony_ci if (txchain && (txchain < wlc->stf->hw_txchain)) 778c2ecf20Sopenharmony_ci /* turn off 1 tx chain */ 788c2ecf20Sopenharmony_ci brcms_c_stf_txchain_set(wlc, txchain, true); 798c2ecf20Sopenharmony_ci } else if (wlc->stf->txchain < wlc->stf->hw_txchain) { 808c2ecf20Sopenharmony_ci if (txchain == wlc->stf->hw_txchain) 818c2ecf20Sopenharmony_ci /* turn back on txchain */ 828c2ecf20Sopenharmony_ci brcms_c_stf_txchain_set(wlc, txchain, true); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_civoid 878c2ecf20Sopenharmony_cibrcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel, 888c2ecf20Sopenharmony_ci u16 chanspec) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct tx_power power = { }; 918c2ecf20Sopenharmony_ci u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* Clear previous settings */ 948c2ecf20Sopenharmony_ci *ss_algo_channel = 0; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!wlc->pub->up) { 978c2ecf20Sopenharmony_ci *ss_algo_channel = (u16) -1; 988c2ecf20Sopenharmony_ci return; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci wlc_phy_txpower_get_current(wlc->band->pi, &power, 1028c2ecf20Sopenharmony_ci CHSPEC_CHANNEL(chanspec)); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci siso_mcs_id = (CHSPEC_IS40(chanspec)) ? 1058c2ecf20Sopenharmony_ci WL_TX_POWER_MCS40_SISO_FIRST : WL_TX_POWER_MCS20_SISO_FIRST; 1068c2ecf20Sopenharmony_ci cdd_mcs_id = (CHSPEC_IS40(chanspec)) ? 1078c2ecf20Sopenharmony_ci WL_TX_POWER_MCS40_CDD_FIRST : WL_TX_POWER_MCS20_CDD_FIRST; 1088c2ecf20Sopenharmony_ci stbc_mcs_id = (CHSPEC_IS40(chanspec)) ? 1098c2ecf20Sopenharmony_ci WL_TX_POWER_MCS40_STBC_FIRST : WL_TX_POWER_MCS20_STBC_FIRST; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* criteria to choose stf mode */ 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* 1148c2ecf20Sopenharmony_ci * the "+3dbm (12 0.25db units)" is to account for the fact that with 1158c2ecf20Sopenharmony_ci * CDD, tx occurs on both chains 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci if (power.target[siso_mcs_id] > (power.target[cdd_mcs_id] + 12)) 1188c2ecf20Sopenharmony_ci setbit(ss_algo_channel, PHY_TXC1_MODE_SISO); 1198c2ecf20Sopenharmony_ci else 1208c2ecf20Sopenharmony_ci setbit(ss_algo_channel, PHY_TXC1_MODE_CDD); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * STBC is ORed into to algo channel as STBC requires per-packet SCB 1248c2ecf20Sopenharmony_ci * capability check so cannot be default mode of operation. One of 1258c2ecf20Sopenharmony_ci * SISO, CDD have to be set 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci if (power.target[siso_mcs_id] <= (power.target[stbc_mcs_id] + 12)) 1288c2ecf20Sopenharmony_ci setbit(ss_algo_channel, PHY_TXC1_MODE_STBC); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic bool brcms_c_stf_stbc_tx_set(struct brcms_c_info *wlc, s32 int_val) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci if ((int_val != AUTO) && (int_val != OFF) && (int_val != ON)) 1348c2ecf20Sopenharmony_ci return false; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if ((int_val == ON) && (wlc->stf->txstreams == 1)) 1378c2ecf20Sopenharmony_ci return false; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = (s8) int_val; 1408c2ecf20Sopenharmony_ci wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = (s8) int_val; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return true; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cibool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci if ((int_val != HT_CAP_RX_STBC_NO) 1488c2ecf20Sopenharmony_ci && (int_val != HT_CAP_RX_STBC_ONE_STREAM)) 1498c2ecf20Sopenharmony_ci return false; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (BRCMS_STF_SS_STBC_RX(wlc)) { 1528c2ecf20Sopenharmony_ci if ((int_val != HT_CAP_RX_STBC_NO) 1538c2ecf20Sopenharmony_ci && (wlc->stf->rxstreams == 1)) 1548c2ecf20Sopenharmony_ci return false; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci brcms_c_stf_stbc_rx_ht_update(wlc, int_val); 1588c2ecf20Sopenharmony_ci return true; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int brcms_c_stf_txcore_set(struct brcms_c_info *wlc, u8 Nsts, 1628c2ecf20Sopenharmony_ci u8 core_mask) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci brcms_dbg_ht(wlc->hw->d11core, "wl%d: Nsts %d core_mask %x\n", 1658c2ecf20Sopenharmony_ci wlc->pub->unit, Nsts, core_mask); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (hweight8(core_mask) > wlc->stf->txstreams) 1688c2ecf20Sopenharmony_ci core_mask = 0; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if ((hweight8(core_mask) == wlc->stf->txstreams) && 1718c2ecf20Sopenharmony_ci ((core_mask & ~wlc->stf->txchain) 1728c2ecf20Sopenharmony_ci || !(core_mask & wlc->stf->txchain))) 1738c2ecf20Sopenharmony_ci core_mask = wlc->stf->txchain; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci wlc->stf->txcore[Nsts] = core_mask; 1768c2ecf20Sopenharmony_ci /* Nsts = 1..4, txcore index = 1..4 */ 1778c2ecf20Sopenharmony_ci if (Nsts == 1) { 1788c2ecf20Sopenharmony_ci /* Needs to update beacon and ucode generated response 1798c2ecf20Sopenharmony_ci * frames when 1 stream core map changed 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci wlc->stf->phytxant = core_mask << PHY_TXC_ANT_SHIFT; 1828c2ecf20Sopenharmony_ci brcms_b_txant_set(wlc->hw, wlc->stf->phytxant); 1838c2ecf20Sopenharmony_ci if (wlc->clk) { 1848c2ecf20Sopenharmony_ci brcms_c_suspend_mac_and_wait(wlc); 1858c2ecf20Sopenharmony_ci brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec); 1868c2ecf20Sopenharmony_ci brcms_c_enable_mac(wlc); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int brcms_c_stf_spatial_policy_set(struct brcms_c_info *wlc, int val) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci int i; 1968c2ecf20Sopenharmony_ci u8 core_mask = 0; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci brcms_dbg_ht(wlc->hw->d11core, "wl%d: val %x\n", wlc->pub->unit, 1998c2ecf20Sopenharmony_ci val); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci wlc->stf->spatial_policy = (s8) val; 2028c2ecf20Sopenharmony_ci for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) { 2038c2ecf20Sopenharmony_ci core_mask = (val == MAX_SPATIAL_EXPANSION) ? 2048c2ecf20Sopenharmony_ci wlc->stf->txchain : txcore_default[i]; 2058c2ecf20Sopenharmony_ci brcms_c_stf_txcore_set(wlc, (u8) i, core_mask); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/* 2118c2ecf20Sopenharmony_ci * Centralized txant update function. call it whenever wlc->stf->txant and/or 2128c2ecf20Sopenharmony_ci * wlc->stf->txchain change. 2138c2ecf20Sopenharmony_ci * 2148c2ecf20Sopenharmony_ci * Antennas are controlled by ucode indirectly, which drives PHY or GPIO to 2158c2ecf20Sopenharmony_ci * achieve various tx/rx antenna selection schemes 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * legacy phy, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7 2188c2ecf20Sopenharmony_ci * means auto(last rx). 2198c2ecf20Sopenharmony_ci * for NREV<3, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7 2208c2ecf20Sopenharmony_ci * means last rx and do tx-antenna selection for SISO transmissions 2218c2ecf20Sopenharmony_ci * for NREV=3, bit 6 and bit _8_ means antenna 0 and 1 respectively, bit6+bit7 2228c2ecf20Sopenharmony_ci * means last rx and do tx-antenna selection for SISO transmissions 2238c2ecf20Sopenharmony_ci * for NREV>=7, bit 6 and bit 7 mean antenna 0 and 1 respectively, nit6+bit7 2248c2ecf20Sopenharmony_ci * means both cores active 2258c2ecf20Sopenharmony_ci*/ 2268c2ecf20Sopenharmony_cistatic void _brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci s8 txant; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci txant = (s8) wlc->stf->txant; 2318c2ecf20Sopenharmony_ci if (BRCMS_PHY_11N_CAP(wlc->band)) { 2328c2ecf20Sopenharmony_ci if (txant == ANT_TX_FORCE_0) { 2338c2ecf20Sopenharmony_ci wlc->stf->phytxant = PHY_TXC_ANT_0; 2348c2ecf20Sopenharmony_ci } else if (txant == ANT_TX_FORCE_1) { 2358c2ecf20Sopenharmony_ci wlc->stf->phytxant = PHY_TXC_ANT_1; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (BRCMS_ISNPHY(wlc->band) && 2388c2ecf20Sopenharmony_ci NREV_GE(wlc->band->phyrev, 3) 2398c2ecf20Sopenharmony_ci && NREV_LT(wlc->band->phyrev, 7)) 2408c2ecf20Sopenharmony_ci wlc->stf->phytxant = PHY_TXC_ANT_2; 2418c2ecf20Sopenharmony_ci } else { 2428c2ecf20Sopenharmony_ci if (BRCMS_ISLCNPHY(wlc->band) || 2438c2ecf20Sopenharmony_ci BRCMS_ISSSLPNPHY(wlc->band)) 2448c2ecf20Sopenharmony_ci wlc->stf->phytxant = PHY_TXC_LCNPHY_ANT_LAST; 2458c2ecf20Sopenharmony_ci else { 2468c2ecf20Sopenharmony_ci /* catch out of sync wlc->stf->txcore */ 2478c2ecf20Sopenharmony_ci WARN_ON(wlc->stf->txchain <= 0); 2488c2ecf20Sopenharmony_ci wlc->stf->phytxant = 2498c2ecf20Sopenharmony_ci wlc->stf->txchain << PHY_TXC_ANT_SHIFT; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci } else { 2538c2ecf20Sopenharmony_ci if (txant == ANT_TX_FORCE_0) 2548c2ecf20Sopenharmony_ci wlc->stf->phytxant = PHY_TXC_OLD_ANT_0; 2558c2ecf20Sopenharmony_ci else if (txant == ANT_TX_FORCE_1) 2568c2ecf20Sopenharmony_ci wlc->stf->phytxant = PHY_TXC_OLD_ANT_1; 2578c2ecf20Sopenharmony_ci else 2588c2ecf20Sopenharmony_ci wlc->stf->phytxant = PHY_TXC_OLD_ANT_LAST; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci brcms_b_txant_set(wlc->hw, wlc->stf->phytxant); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciint brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci u8 txchain = (u8) int_val; 2678c2ecf20Sopenharmony_ci u8 txstreams; 2688c2ecf20Sopenharmony_ci uint i; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (wlc->stf->txchain == txchain) 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if ((txchain & ~wlc->stf->hw_txchain) 2748c2ecf20Sopenharmony_ci || !(txchain & wlc->stf->hw_txchain)) 2758c2ecf20Sopenharmony_ci return -EINVAL; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* 2788c2ecf20Sopenharmony_ci * if nrate override is configured to be non-SISO STF mode, reject 2798c2ecf20Sopenharmony_ci * reducing txchain to 1 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci txstreams = (u8) hweight8(txchain); 2828c2ecf20Sopenharmony_ci if (txstreams > MAX_STREAMS_SUPPORTED) 2838c2ecf20Sopenharmony_ci return -EINVAL; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci wlc->stf->txchain = txchain; 2868c2ecf20Sopenharmony_ci wlc->stf->txstreams = txstreams; 2878c2ecf20Sopenharmony_ci brcms_c_stf_stbc_tx_set(wlc, wlc->band->band_stf_stbc_tx); 2888c2ecf20Sopenharmony_ci brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]); 2898c2ecf20Sopenharmony_ci brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]); 2908c2ecf20Sopenharmony_ci wlc->stf->txant = 2918c2ecf20Sopenharmony_ci (wlc->stf->txstreams == 1) ? ANT_TX_FORCE_0 : ANT_TX_DEF; 2928c2ecf20Sopenharmony_ci _brcms_c_stf_phy_txant_upd(wlc); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci wlc_phy_stf_chain_set(wlc->band->pi, wlc->stf->txchain, 2958c2ecf20Sopenharmony_ci wlc->stf->rxchain); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) 2988c2ecf20Sopenharmony_ci brcms_c_stf_txcore_set(wlc, (u8) i, txcore_default[i]); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/* 3048c2ecf20Sopenharmony_ci * update wlc->stf->ss_opmode which represents the operational stf_ss mode 3058c2ecf20Sopenharmony_ci * we're using 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_civoid brcms_c_stf_ss_update(struct brcms_c_info *wlc, struct brcms_band *band) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci u8 prev_stf_ss; 3108c2ecf20Sopenharmony_ci u8 upd_stf_ss; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci prev_stf_ss = wlc->stf->ss_opmode; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* 3158c2ecf20Sopenharmony_ci * NOTE: opmode can only be SISO or CDD as STBC is decided on a 3168c2ecf20Sopenharmony_ci * per-packet basis 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci if (BRCMS_STBC_CAP_PHY(wlc) && 3198c2ecf20Sopenharmony_ci wlc->stf->ss_algosel_auto 3208c2ecf20Sopenharmony_ci && (wlc->stf->ss_algo_channel != (u16) -1)) { 3218c2ecf20Sopenharmony_ci upd_stf_ss = (wlc->stf->txstreams == 1 || 3228c2ecf20Sopenharmony_ci isset(&wlc->stf->ss_algo_channel, 3238c2ecf20Sopenharmony_ci PHY_TXC1_MODE_SISO)) ? 3248c2ecf20Sopenharmony_ci PHY_TXC1_MODE_SISO : PHY_TXC1_MODE_CDD; 3258c2ecf20Sopenharmony_ci } else { 3268c2ecf20Sopenharmony_ci if (wlc->band != band) 3278c2ecf20Sopenharmony_ci return; 3288c2ecf20Sopenharmony_ci upd_stf_ss = (wlc->stf->txstreams == 1) ? 3298c2ecf20Sopenharmony_ci PHY_TXC1_MODE_SISO : band->band_stf_ss_mode; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci if (prev_stf_ss != upd_stf_ss) { 3328c2ecf20Sopenharmony_ci wlc->stf->ss_opmode = upd_stf_ss; 3338c2ecf20Sopenharmony_ci brcms_b_band_stf_ss_set(wlc->hw, upd_stf_ss); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ciint brcms_c_stf_attach(struct brcms_c_info *wlc) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_SISO; 3408c2ecf20Sopenharmony_ci wlc->bandstate[BAND_5G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_CDD; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (BRCMS_ISNPHY(wlc->band) && 3438c2ecf20Sopenharmony_ci (wlc_phy_txpower_hw_ctrl_get(wlc->band->pi) != PHY_TPC_HW_ON)) 3448c2ecf20Sopenharmony_ci wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = 3458c2ecf20Sopenharmony_ci PHY_TXC1_MODE_CDD; 3468c2ecf20Sopenharmony_ci brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]); 3478c2ecf20Sopenharmony_ci brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci brcms_c_stf_stbc_rx_ht_update(wlc, HT_CAP_RX_STBC_NO); 3508c2ecf20Sopenharmony_ci wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = OFF; 3518c2ecf20Sopenharmony_ci wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = OFF; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (BRCMS_STBC_CAP_PHY(wlc)) { 3548c2ecf20Sopenharmony_ci wlc->stf->ss_algosel_auto = true; 3558c2ecf20Sopenharmony_ci /* Init the default value */ 3568c2ecf20Sopenharmony_ci wlc->stf->ss_algo_channel = (u16) -1; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci return 0; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_civoid brcms_c_stf_detach(struct brcms_c_info *wlc) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_civoid brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci _brcms_c_stf_phy_txant_upd(wlc); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_civoid brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* get available rx/tx chains */ 3758c2ecf20Sopenharmony_ci wlc->stf->hw_txchain = sprom->txchain; 3768c2ecf20Sopenharmony_ci wlc->stf->hw_rxchain = sprom->rxchain; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* these parameter are intended to be used for all PHY types */ 3798c2ecf20Sopenharmony_ci if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) { 3808c2ecf20Sopenharmony_ci if (BRCMS_ISNPHY(wlc->band)) 3818c2ecf20Sopenharmony_ci wlc->stf->hw_txchain = TXCHAIN_DEF_NPHY; 3828c2ecf20Sopenharmony_ci else 3838c2ecf20Sopenharmony_ci wlc->stf->hw_txchain = TXCHAIN_DEF; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci wlc->stf->txchain = wlc->stf->hw_txchain; 3878c2ecf20Sopenharmony_ci wlc->stf->txstreams = (u8) hweight8(wlc->stf->hw_txchain); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (wlc->stf->hw_rxchain == 0 || wlc->stf->hw_rxchain == 0xf) { 3908c2ecf20Sopenharmony_ci if (BRCMS_ISNPHY(wlc->band)) 3918c2ecf20Sopenharmony_ci wlc->stf->hw_rxchain = RXCHAIN_DEF_NPHY; 3928c2ecf20Sopenharmony_ci else 3938c2ecf20Sopenharmony_ci wlc->stf->hw_rxchain = RXCHAIN_DEF; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci wlc->stf->rxchain = wlc->stf->hw_rxchain; 3978c2ecf20Sopenharmony_ci wlc->stf->rxstreams = (u8) hweight8(wlc->stf->hw_rxchain); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* initialize the txcore table */ 4008c2ecf20Sopenharmony_ci memcpy(wlc->stf->txcore, txcore_default, sizeof(wlc->stf->txcore)); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* default spatial_policy */ 4038c2ecf20Sopenharmony_ci wlc->stf->spatial_policy = MIN_SPATIAL_EXPANSION; 4048c2ecf20Sopenharmony_ci brcms_c_stf_spatial_policy_set(wlc, MIN_SPATIAL_EXPANSION); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic u16 _brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, 4088c2ecf20Sopenharmony_ci u32 rspec) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci u16 phytxant = wlc->stf->phytxant; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (rspec_stf(rspec) != PHY_TXC1_MODE_SISO) 4138c2ecf20Sopenharmony_ci phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT; 4148c2ecf20Sopenharmony_ci else if (wlc->stf->txant == ANT_TX_DEF) 4158c2ecf20Sopenharmony_ci phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT; 4168c2ecf20Sopenharmony_ci phytxant &= PHY_TXC_ANT_MASK; 4178c2ecf20Sopenharmony_ci return phytxant; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ciu16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, u32 rspec) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci return _brcms_c_stf_phytxchain_sel(wlc, rspec); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ciu16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, u32 rspec) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci u16 phytxant = wlc->stf->phytxant; 4288c2ecf20Sopenharmony_ci u16 mask = PHY_TXC_ANT_MASK; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* for non-siso rates or default setting, use the available chains */ 4318c2ecf20Sopenharmony_ci if (BRCMS_ISNPHY(wlc->band)) { 4328c2ecf20Sopenharmony_ci phytxant = _brcms_c_stf_phytxchain_sel(wlc, rspec); 4338c2ecf20Sopenharmony_ci mask = PHY_TXC_HTANT_MASK; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci phytxant |= phytxant & mask; 4368c2ecf20Sopenharmony_ci return phytxant; 4378c2ecf20Sopenharmony_ci} 438