162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 462306a36Sopenharmony_ci * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "mt76x2.h" 862306a36Sopenharmony_ci#include "eeprom.h" 962306a36Sopenharmony_ci#include "../mt76x02_phy.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ciint mt76x2_set_sar_specs(struct ieee80211_hw *hw, 1262306a36Sopenharmony_ci const struct cfg80211_sar_specs *sar) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci int err = -EINVAL, power = hw->conf.power_level * 2; 1562306a36Sopenharmony_ci struct mt76x02_dev *dev = hw->priv; 1662306a36Sopenharmony_ci struct mt76_phy *mphy = &dev->mphy; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 1962306a36Sopenharmony_ci if (!cfg80211_chandef_valid(&mphy->chandef)) 2062306a36Sopenharmony_ci goto out; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci err = mt76_init_sar_power(hw, sar); 2362306a36Sopenharmony_ci if (err) 2462306a36Sopenharmony_ci goto out; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci dev->txpower_conf = mt76_get_sar_power(mphy, mphy->chandef.chan, 2762306a36Sopenharmony_ci power); 2862306a36Sopenharmony_ci /* convert to per-chain power for 2x2 devices */ 2962306a36Sopenharmony_ci dev->txpower_conf -= 6; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (test_bit(MT76_STATE_RUNNING, &mphy->state)) 3262306a36Sopenharmony_ci mt76x2_phy_set_txpower(dev); 3362306a36Sopenharmony_ciout: 3462306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return err; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_set_sar_specs); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void 4162306a36Sopenharmony_cimt76x2_set_wlan_state(struct mt76x02_dev *dev, bool enable) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci u32 val = mt76_rr(dev, MT_WLAN_FUN_CTRL); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (enable) 4662306a36Sopenharmony_ci val |= (MT_WLAN_FUN_CTRL_WLAN_EN | 4762306a36Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_CLK_EN); 4862306a36Sopenharmony_ci else 4962306a36Sopenharmony_ci val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN | 5062306a36Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_CLK_EN); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci mt76_wr(dev, MT_WLAN_FUN_CTRL, val); 5362306a36Sopenharmony_ci udelay(20); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_civoid mt76x2_reset_wlan(struct mt76x02_dev *dev, bool enable) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci u32 val; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (!enable) 6162306a36Sopenharmony_ci goto out; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci val = mt76_rr(dev, MT_WLAN_FUN_CTRL); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { 6862306a36Sopenharmony_ci val |= MT_WLAN_FUN_CTRL_WLAN_RESET_RF; 6962306a36Sopenharmony_ci mt76_wr(dev, MT_WLAN_FUN_CTRL, val); 7062306a36Sopenharmony_ci udelay(20); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci val &= ~MT_WLAN_FUN_CTRL_WLAN_RESET_RF; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci mt76_wr(dev, MT_WLAN_FUN_CTRL, val); 7662306a36Sopenharmony_ci udelay(20); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciout: 7962306a36Sopenharmony_ci mt76x2_set_wlan_state(dev, enable); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_reset_wlan); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_civoid mt76_write_mac_initvals(struct mt76x02_dev *dev) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci#define DEFAULT_PROT_CFG_CCK \ 8662306a36Sopenharmony_ci (FIELD_PREP(MT_PROT_CFG_RATE, 0x3) | \ 8762306a36Sopenharmony_ci FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ 8862306a36Sopenharmony_ci FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f) | \ 8962306a36Sopenharmony_ci MT_PROT_CFG_RTS_THRESH) 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define DEFAULT_PROT_CFG_OFDM \ 9262306a36Sopenharmony_ci (FIELD_PREP(MT_PROT_CFG_RATE, 0x2004) | \ 9362306a36Sopenharmony_ci FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ 9462306a36Sopenharmony_ci FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f) | \ 9562306a36Sopenharmony_ci MT_PROT_CFG_RTS_THRESH) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define DEFAULT_PROT_CFG_20 \ 9862306a36Sopenharmony_ci (FIELD_PREP(MT_PROT_CFG_RATE, 0x2004) | \ 9962306a36Sopenharmony_ci FIELD_PREP(MT_PROT_CFG_CTRL, 1) | \ 10062306a36Sopenharmony_ci FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ 10162306a36Sopenharmony_ci FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x17)) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define DEFAULT_PROT_CFG_40 \ 10462306a36Sopenharmony_ci (FIELD_PREP(MT_PROT_CFG_RATE, 0x2084) | \ 10562306a36Sopenharmony_ci FIELD_PREP(MT_PROT_CFG_CTRL, 1) | \ 10662306a36Sopenharmony_ci FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ 10762306a36Sopenharmony_ci FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f)) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci static const struct mt76_reg_pair vals[] = { 11062306a36Sopenharmony_ci /* Copied from MediaTek reference source */ 11162306a36Sopenharmony_ci { MT_PBF_SYS_CTRL, 0x00080c00 }, 11262306a36Sopenharmony_ci { MT_PBF_CFG, 0x1efebcff }, 11362306a36Sopenharmony_ci { MT_FCE_PSE_CTRL, 0x00000001 }, 11462306a36Sopenharmony_ci { MT_MAC_SYS_CTRL, 0x00000000 }, 11562306a36Sopenharmony_ci { MT_MAX_LEN_CFG, 0x003e3f00 }, 11662306a36Sopenharmony_ci { MT_AMPDU_MAX_LEN_20M1S, 0xaaa99887 }, 11762306a36Sopenharmony_ci { MT_AMPDU_MAX_LEN_20M2S, 0x000000aa }, 11862306a36Sopenharmony_ci { MT_XIFS_TIME_CFG, 0x33a40d0a }, 11962306a36Sopenharmony_ci { MT_BKOFF_SLOT_CFG, 0x00000209 }, 12062306a36Sopenharmony_ci { MT_TBTT_SYNC_CFG, 0x00422010 }, 12162306a36Sopenharmony_ci { MT_PWR_PIN_CFG, 0x00000000 }, 12262306a36Sopenharmony_ci { 0x1238, 0x001700c8 }, 12362306a36Sopenharmony_ci { MT_TX_SW_CFG0, 0x00101001 }, 12462306a36Sopenharmony_ci { MT_TX_SW_CFG1, 0x00010000 }, 12562306a36Sopenharmony_ci { MT_TX_SW_CFG2, 0x00000000 }, 12662306a36Sopenharmony_ci { MT_TXOP_CTRL_CFG, 0x0400583f }, 12762306a36Sopenharmony_ci { MT_TX_RTS_CFG, 0x00ffff20 }, 12862306a36Sopenharmony_ci { MT_TX_TIMEOUT_CFG, 0x000a2290 }, 12962306a36Sopenharmony_ci { MT_TX_RETRY_CFG, 0x47f01f0f }, 13062306a36Sopenharmony_ci { MT_EXP_ACK_TIME, 0x002c00dc }, 13162306a36Sopenharmony_ci { MT_TX_PROT_CFG6, 0xe3f42004 }, 13262306a36Sopenharmony_ci { MT_TX_PROT_CFG7, 0xe3f42084 }, 13362306a36Sopenharmony_ci { MT_TX_PROT_CFG8, 0xe3f42104 }, 13462306a36Sopenharmony_ci { MT_PIFS_TX_CFG, 0x00060fff }, 13562306a36Sopenharmony_ci { MT_RX_FILTR_CFG, 0x00015f97 }, 13662306a36Sopenharmony_ci { MT_LEGACY_BASIC_RATE, 0x0000017f }, 13762306a36Sopenharmony_ci { MT_HT_BASIC_RATE, 0x00004003 }, 13862306a36Sopenharmony_ci { MT_PN_PAD_MODE, 0x00000003 }, 13962306a36Sopenharmony_ci { MT_TXOP_HLDR_ET, 0x00000002 }, 14062306a36Sopenharmony_ci { 0xa44, 0x00000000 }, 14162306a36Sopenharmony_ci { MT_HEADER_TRANS_CTRL_REG, 0x00000000 }, 14262306a36Sopenharmony_ci { MT_TSO_CTRL, 0x00000000 }, 14362306a36Sopenharmony_ci { MT_AUX_CLK_CFG, 0x00000000 }, 14462306a36Sopenharmony_ci { MT_DACCLK_EN_DLY_CFG, 0x00000000 }, 14562306a36Sopenharmony_ci { MT_TX_ALC_CFG_4, 0x00000000 }, 14662306a36Sopenharmony_ci { MT_TX_ALC_VGA3, 0x00000000 }, 14762306a36Sopenharmony_ci { MT_TX_PWR_CFG_0, 0x3a3a3a3a }, 14862306a36Sopenharmony_ci { MT_TX_PWR_CFG_1, 0x3a3a3a3a }, 14962306a36Sopenharmony_ci { MT_TX_PWR_CFG_2, 0x3a3a3a3a }, 15062306a36Sopenharmony_ci { MT_TX_PWR_CFG_3, 0x3a3a3a3a }, 15162306a36Sopenharmony_ci { MT_TX_PWR_CFG_4, 0x3a3a3a3a }, 15262306a36Sopenharmony_ci { MT_TX_PWR_CFG_7, 0x3a3a3a3a }, 15362306a36Sopenharmony_ci { MT_TX_PWR_CFG_8, 0x0000003a }, 15462306a36Sopenharmony_ci { MT_TX_PWR_CFG_9, 0x0000003a }, 15562306a36Sopenharmony_ci { MT_EFUSE_CTRL, 0x0000d000 }, 15662306a36Sopenharmony_ci { MT_PAUSE_ENABLE_CONTROL1, 0x0000000a }, 15762306a36Sopenharmony_ci { MT_FCE_WLAN_FLOW_CONTROL1, 0x60401c18 }, 15862306a36Sopenharmony_ci { MT_WPDMA_DELAY_INT_CFG, 0x94ff0000 }, 15962306a36Sopenharmony_ci { MT_TX_SW_CFG3, 0x00000004 }, 16062306a36Sopenharmony_ci { MT_HT_FBK_TO_LEGACY, 0x00001818 }, 16162306a36Sopenharmony_ci { MT_VHT_HT_FBK_CFG1, 0xedcba980 }, 16262306a36Sopenharmony_ci { MT_PROT_AUTO_TX_CFG, 0x00830083 }, 16362306a36Sopenharmony_ci { MT_HT_CTRL_CFG, 0x000001ff }, 16462306a36Sopenharmony_ci { MT_TX_LINK_CFG, 0x00001020 }, 16562306a36Sopenharmony_ci }; 16662306a36Sopenharmony_ci struct mt76_reg_pair prot_vals[] = { 16762306a36Sopenharmony_ci { MT_CCK_PROT_CFG, DEFAULT_PROT_CFG_CCK }, 16862306a36Sopenharmony_ci { MT_OFDM_PROT_CFG, DEFAULT_PROT_CFG_OFDM }, 16962306a36Sopenharmony_ci { MT_MM20_PROT_CFG, DEFAULT_PROT_CFG_20 }, 17062306a36Sopenharmony_ci { MT_MM40_PROT_CFG, DEFAULT_PROT_CFG_40 }, 17162306a36Sopenharmony_ci { MT_GF20_PROT_CFG, DEFAULT_PROT_CFG_20 }, 17262306a36Sopenharmony_ci { MT_GF40_PROT_CFG, DEFAULT_PROT_CFG_40 }, 17362306a36Sopenharmony_ci }; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci mt76_wr_rp(dev, 0, vals, ARRAY_SIZE(vals)); 17662306a36Sopenharmony_ci mt76_wr_rp(dev, 0, prot_vals, ARRAY_SIZE(prot_vals)); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_write_mac_initvals); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_civoid mt76x2_init_txpower(struct mt76x02_dev *dev, 18162306a36Sopenharmony_ci struct ieee80211_supported_band *sband) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct ieee80211_channel *chan; 18462306a36Sopenharmony_ci struct mt76x2_tx_power_info txp; 18562306a36Sopenharmony_ci struct mt76x02_rate_power t = {}; 18662306a36Sopenharmony_ci int i; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 18962306a36Sopenharmony_ci chan = &sband->channels[i]; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci mt76x2_get_power_info(dev, &txp, chan); 19262306a36Sopenharmony_ci mt76x2_get_rate_power(dev, &t, chan); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci chan->orig_mpwr = mt76x02_get_max_rate_power(&t) + 19562306a36Sopenharmony_ci txp.target_power; 19662306a36Sopenharmony_ci chan->orig_mpwr = DIV_ROUND_UP(chan->orig_mpwr, 2); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* convert to combined output power on 2x2 devices */ 19962306a36Sopenharmony_ci chan->orig_mpwr += 3; 20062306a36Sopenharmony_ci chan->max_power = min_t(int, chan->max_reg_power, 20162306a36Sopenharmony_ci chan->orig_mpwr); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_init_txpower); 205