162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * (c) Copyright 2002-2010, Ralink Technology, Inc. 462306a36Sopenharmony_ci * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 562306a36Sopenharmony_ci * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "mt7601u.h" 962306a36Sopenharmony_ci#include "mcu.h" 1062306a36Sopenharmony_ci#include "eeprom.h" 1162306a36Sopenharmony_ci#include "trace.h" 1262306a36Sopenharmony_ci#include "initvals_phy.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/etherdevice.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic void mt7601u_agc_reset(struct mt7601u_dev *dev); 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int 1962306a36Sopenharmony_cimt7601u_rf_wr(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 value) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci int ret = 0; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || 2462306a36Sopenharmony_ci WARN_ON(offset > 63)) 2562306a36Sopenharmony_ci return -EINVAL; 2662306a36Sopenharmony_ci if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) 2762306a36Sopenharmony_ci return 0; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci mutex_lock(&dev->reg_atomic_mutex); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) { 3262306a36Sopenharmony_ci ret = -ETIMEDOUT; 3362306a36Sopenharmony_ci goto out; 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_CSR_CFG, 3762306a36Sopenharmony_ci FIELD_PREP(MT_RF_CSR_CFG_DATA, value) | 3862306a36Sopenharmony_ci FIELD_PREP(MT_RF_CSR_CFG_REG_BANK, bank) | 3962306a36Sopenharmony_ci FIELD_PREP(MT_RF_CSR_CFG_REG_ID, offset) | 4062306a36Sopenharmony_ci MT_RF_CSR_CFG_WR | 4162306a36Sopenharmony_ci MT_RF_CSR_CFG_KICK); 4262306a36Sopenharmony_ci trace_rf_write(dev, bank, offset, value); 4362306a36Sopenharmony_ciout: 4462306a36Sopenharmony_ci mutex_unlock(&dev->reg_atomic_mutex); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (ret < 0) 4762306a36Sopenharmony_ci dev_err(dev->dev, "Error: RF write %02hhx:%02hhx failed:%d!!\n", 4862306a36Sopenharmony_ci bank, offset, ret); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return ret; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int 5462306a36Sopenharmony_cimt7601u_rf_rr(struct mt7601u_dev *dev, u8 bank, u8 offset) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci int ret = -ETIMEDOUT; 5762306a36Sopenharmony_ci u32 val; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || 6062306a36Sopenharmony_ci WARN_ON(offset > 63)) 6162306a36Sopenharmony_ci return -EINVAL; 6262306a36Sopenharmony_ci if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) 6362306a36Sopenharmony_ci return 0xff; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci mutex_lock(&dev->reg_atomic_mutex); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) 6862306a36Sopenharmony_ci goto out; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_CSR_CFG, 7162306a36Sopenharmony_ci FIELD_PREP(MT_RF_CSR_CFG_REG_BANK, bank) | 7262306a36Sopenharmony_ci FIELD_PREP(MT_RF_CSR_CFG_REG_ID, offset) | 7362306a36Sopenharmony_ci MT_RF_CSR_CFG_KICK); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) 7662306a36Sopenharmony_ci goto out; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci val = mt7601u_rr(dev, MT_RF_CSR_CFG); 7962306a36Sopenharmony_ci if (FIELD_GET(MT_RF_CSR_CFG_REG_ID, val) == offset && 8062306a36Sopenharmony_ci FIELD_GET(MT_RF_CSR_CFG_REG_BANK, val) == bank) { 8162306a36Sopenharmony_ci ret = FIELD_GET(MT_RF_CSR_CFG_DATA, val); 8262306a36Sopenharmony_ci trace_rf_read(dev, bank, offset, ret); 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ciout: 8562306a36Sopenharmony_ci mutex_unlock(&dev->reg_atomic_mutex); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (ret < 0) 8862306a36Sopenharmony_ci dev_err(dev->dev, "Error: RF read %02hhx:%02hhx failed:%d!!\n", 8962306a36Sopenharmony_ci bank, offset, ret); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return ret; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int 9562306a36Sopenharmony_cimt7601u_rf_rmw(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask, u8 val) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci int ret; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci ret = mt7601u_rf_rr(dev, bank, offset); 10062306a36Sopenharmony_ci if (ret < 0) 10162306a36Sopenharmony_ci return ret; 10262306a36Sopenharmony_ci val |= ret & ~mask; 10362306a36Sopenharmony_ci ret = mt7601u_rf_wr(dev, bank, offset, val); 10462306a36Sopenharmony_ci if (ret) 10562306a36Sopenharmony_ci return ret; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return val; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int 11162306a36Sopenharmony_cimt7601u_rf_set(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 val) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci return mt7601u_rf_rmw(dev, bank, offset, 0, val); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int 11762306a36Sopenharmony_cimt7601u_rf_clear(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci return mt7601u_rf_rmw(dev, bank, offset, mask, 0); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void mt7601u_bbp_wr(struct mt7601u_dev *dev, u8 offset, u8 val) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || 12562306a36Sopenharmony_ci test_bit(MT7601U_STATE_REMOVED, &dev->state)) 12662306a36Sopenharmony_ci return; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci mutex_lock(&dev->reg_atomic_mutex); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) { 13162306a36Sopenharmony_ci dev_err(dev->dev, "Error: BBP write %02hhx failed!!\n", offset); 13262306a36Sopenharmony_ci goto out; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci mt7601u_wr(dev, MT_BBP_CSR_CFG, 13662306a36Sopenharmony_ci FIELD_PREP(MT_BBP_CSR_CFG_VAL, val) | 13762306a36Sopenharmony_ci FIELD_PREP(MT_BBP_CSR_CFG_REG_NUM, offset) | 13862306a36Sopenharmony_ci MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY); 13962306a36Sopenharmony_ci trace_bbp_write(dev, offset, val); 14062306a36Sopenharmony_ciout: 14162306a36Sopenharmony_ci mutex_unlock(&dev->reg_atomic_mutex); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int mt7601u_bbp_rr(struct mt7601u_dev *dev, u8 offset) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci u32 val; 14762306a36Sopenharmony_ci int ret = -ETIMEDOUT; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state))) 15062306a36Sopenharmony_ci return -EINVAL; 15162306a36Sopenharmony_ci if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) 15262306a36Sopenharmony_ci return 0xff; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci mutex_lock(&dev->reg_atomic_mutex); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) 15762306a36Sopenharmony_ci goto out; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci mt7601u_wr(dev, MT_BBP_CSR_CFG, 16062306a36Sopenharmony_ci FIELD_PREP(MT_BBP_CSR_CFG_REG_NUM, offset) | 16162306a36Sopenharmony_ci MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY | 16262306a36Sopenharmony_ci MT_BBP_CSR_CFG_READ); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) 16562306a36Sopenharmony_ci goto out; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci val = mt7601u_rr(dev, MT_BBP_CSR_CFG); 16862306a36Sopenharmony_ci if (FIELD_GET(MT_BBP_CSR_CFG_REG_NUM, val) == offset) { 16962306a36Sopenharmony_ci ret = FIELD_GET(MT_BBP_CSR_CFG_VAL, val); 17062306a36Sopenharmony_ci trace_bbp_read(dev, offset, ret); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ciout: 17362306a36Sopenharmony_ci mutex_unlock(&dev->reg_atomic_mutex); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (ret < 0) 17662306a36Sopenharmony_ci dev_err(dev->dev, "Error: BBP read %02hhx failed:%d!!\n", 17762306a36Sopenharmony_ci offset, ret); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return ret; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int mt7601u_bbp_rmw(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci int ret; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci ret = mt7601u_bbp_rr(dev, offset); 18762306a36Sopenharmony_ci if (ret < 0) 18862306a36Sopenharmony_ci return ret; 18962306a36Sopenharmony_ci val |= ret & ~mask; 19062306a36Sopenharmony_ci mt7601u_bbp_wr(dev, offset, val); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return val; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic u8 mt7601u_bbp_rmc(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci int ret; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci ret = mt7601u_bbp_rr(dev, offset); 20062306a36Sopenharmony_ci if (ret < 0) 20162306a36Sopenharmony_ci return ret; 20262306a36Sopenharmony_ci val |= ret & ~mask; 20362306a36Sopenharmony_ci if (ret != val) 20462306a36Sopenharmony_ci mt7601u_bbp_wr(dev, offset, val); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return val; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ciint mt7601u_wait_bbp_ready(struct mt7601u_dev *dev) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci int i = 20; 21262306a36Sopenharmony_ci u8 val; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci do { 21562306a36Sopenharmony_ci val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION); 21662306a36Sopenharmony_ci if (val && val != 0xff) 21762306a36Sopenharmony_ci break; 21862306a36Sopenharmony_ci } while (--i); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (!i) { 22162306a36Sopenharmony_ci dev_err(dev->dev, "Error: BBP is not ready\n"); 22262306a36Sopenharmony_ci return -EIO; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return 0; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ciu32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci return mt7601u_bbp_rmc(dev, 3, 0x20, below ? 0x20 : 0); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ciint mt7601u_phy_get_rssi(struct mt7601u_dev *dev, 23462306a36Sopenharmony_ci struct mt7601u_rxwi *rxwi, u16 rate) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci static const s8 lna[2][2][3] = { 23762306a36Sopenharmony_ci /* main LNA */ { 23862306a36Sopenharmony_ci /* bw20 */ { -2, 15, 33 }, 23962306a36Sopenharmony_ci /* bw40 */ { 0, 16, 34 } 24062306a36Sopenharmony_ci }, 24162306a36Sopenharmony_ci /* aux LNA */ { 24262306a36Sopenharmony_ci /* bw20 */ { -2, 15, 33 }, 24362306a36Sopenharmony_ci /* bw40 */ { -2, 16, 34 } 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci }; 24662306a36Sopenharmony_ci int bw = FIELD_GET(MT_RXWI_RATE_BW, rate); 24762306a36Sopenharmony_ci int aux_lna = FIELD_GET(MT_RXWI_ANT_AUX_LNA, rxwi->ant); 24862306a36Sopenharmony_ci int lna_id = FIELD_GET(MT_RXWI_GAIN_RSSI_LNA_ID, rxwi->gain); 24962306a36Sopenharmony_ci int val; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (lna_id) /* LNA id can be 0, 2, 3. */ 25262306a36Sopenharmony_ci lna_id--; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci val = 8; 25562306a36Sopenharmony_ci val -= lna[aux_lna][bw][lna_id]; 25662306a36Sopenharmony_ci val -= FIELD_GET(MT_RXWI_GAIN_RSSI_VAL, rxwi->gain); 25762306a36Sopenharmony_ci val -= dev->ee->lna_gain; 25862306a36Sopenharmony_ci val -= dev->ee->rssi_offset[0]; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return val; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic void mt7601u_vco_cal(struct mt7601u_dev *dev) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci mt7601u_rf_wr(dev, 0, 4, 0x0a); 26662306a36Sopenharmony_ci mt7601u_rf_wr(dev, 0, 5, 0x20); 26762306a36Sopenharmony_ci mt7601u_rf_set(dev, 0, 4, BIT(7)); 26862306a36Sopenharmony_ci msleep(2); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int mt7601u_set_bw_filter(struct mt7601u_dev *dev, bool cal) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci u32 filter = 0; 27462306a36Sopenharmony_ci int ret; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (!cal) 27762306a36Sopenharmony_ci filter |= 0x10000; 27862306a36Sopenharmony_ci if (dev->bw != MT_BW_20) 27962306a36Sopenharmony_ci filter |= 0x00100; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* TX */ 28262306a36Sopenharmony_ci ret = mt7601u_mcu_calibrate(dev, MCU_CAL_BW, filter | 1); 28362306a36Sopenharmony_ci if (ret) 28462306a36Sopenharmony_ci return ret; 28562306a36Sopenharmony_ci /* RX */ 28662306a36Sopenharmony_ci return mt7601u_mcu_calibrate(dev, MCU_CAL_BW, filter); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic int mt7601u_load_bbp_temp_table_bw(struct mt7601u_dev *dev) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci const struct reg_table *t; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (WARN_ON(dev->temp_mode > MT_TEMP_MODE_LOW)) 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci t = &bbp_mode_table[dev->temp_mode][dev->bw]; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, t->regs, t->n); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic int mt7601u_bbp_temp(struct mt7601u_dev *dev, int mode, const char *name) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci const struct reg_table *t; 30462306a36Sopenharmony_ci int ret; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (dev->temp_mode == mode) 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci dev->temp_mode = mode; 31062306a36Sopenharmony_ci trace_temp_mode(dev, mode); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci t = bbp_mode_table[dev->temp_mode]; 31362306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, 31462306a36Sopenharmony_ci t[2].regs, t[2].n); 31562306a36Sopenharmony_ci if (ret) 31662306a36Sopenharmony_ci return ret; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, 31962306a36Sopenharmony_ci t[dev->bw].regs, t[dev->bw].n); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void mt7601u_apply_ch14_fixup(struct mt7601u_dev *dev, int hw_chan) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct mt7601u_rate_power *t = &dev->ee->power_rate_table; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (hw_chan != 14 || dev->bw != MT_BW_20) { 32762306a36Sopenharmony_ci mt7601u_bbp_rmw(dev, 4, 0x20, 0); 32862306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 178, 0xff); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci t->cck[0].bw20 = dev->ee->real_cck_bw20[0]; 33162306a36Sopenharmony_ci t->cck[1].bw20 = dev->ee->real_cck_bw20[1]; 33262306a36Sopenharmony_ci } else { /* Apply CH14 OBW fixup */ 33362306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 4, 0x60); 33462306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 178, 0); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Note: vendor code is buggy here for negative values */ 33762306a36Sopenharmony_ci t->cck[0].bw20 = dev->ee->real_cck_bw20[0] - 2; 33862306a36Sopenharmony_ci t->cck[1].bw20 = dev->ee->real_cck_bw20[1] - 2; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int __mt7601u_phy_set_channel(struct mt7601u_dev *dev, 34362306a36Sopenharmony_ci struct cfg80211_chan_def *chandef) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci#define FREQ_PLAN_REGS 4 34662306a36Sopenharmony_ci static const u8 freq_plan[14][FREQ_PLAN_REGS] = { 34762306a36Sopenharmony_ci { 0x99, 0x99, 0x09, 0x50 }, 34862306a36Sopenharmony_ci { 0x46, 0x44, 0x0a, 0x50 }, 34962306a36Sopenharmony_ci { 0xec, 0xee, 0x0a, 0x50 }, 35062306a36Sopenharmony_ci { 0x99, 0x99, 0x0b, 0x50 }, 35162306a36Sopenharmony_ci { 0x46, 0x44, 0x08, 0x51 }, 35262306a36Sopenharmony_ci { 0xec, 0xee, 0x08, 0x51 }, 35362306a36Sopenharmony_ci { 0x99, 0x99, 0x09, 0x51 }, 35462306a36Sopenharmony_ci { 0x46, 0x44, 0x0a, 0x51 }, 35562306a36Sopenharmony_ci { 0xec, 0xee, 0x0a, 0x51 }, 35662306a36Sopenharmony_ci { 0x99, 0x99, 0x0b, 0x51 }, 35762306a36Sopenharmony_ci { 0x46, 0x44, 0x08, 0x52 }, 35862306a36Sopenharmony_ci { 0xec, 0xee, 0x08, 0x52 }, 35962306a36Sopenharmony_ci { 0x99, 0x99, 0x09, 0x52 }, 36062306a36Sopenharmony_ci { 0x33, 0x33, 0x0b, 0x52 }, 36162306a36Sopenharmony_ci }; 36262306a36Sopenharmony_ci struct mt76_reg_pair channel_freq_plan[FREQ_PLAN_REGS] = { 36362306a36Sopenharmony_ci { 17, 0 }, { 18, 0 }, { 19, 0 }, { 20, 0 }, 36462306a36Sopenharmony_ci }; 36562306a36Sopenharmony_ci struct mt76_reg_pair bbp_settings[3] = { 36662306a36Sopenharmony_ci { 62, 0x37 - dev->ee->lna_gain }, 36762306a36Sopenharmony_ci { 63, 0x37 - dev->ee->lna_gain }, 36862306a36Sopenharmony_ci { 64, 0x37 - dev->ee->lna_gain }, 36962306a36Sopenharmony_ci }; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci struct ieee80211_channel *chan = chandef->chan; 37262306a36Sopenharmony_ci enum nl80211_channel_type chan_type = 37362306a36Sopenharmony_ci cfg80211_get_chandef_type(chandef); 37462306a36Sopenharmony_ci struct mt7601u_rate_power *t = &dev->ee->power_rate_table; 37562306a36Sopenharmony_ci int chan_idx; 37662306a36Sopenharmony_ci bool chan_ext_below; 37762306a36Sopenharmony_ci u8 bw; 37862306a36Sopenharmony_ci int i, ret; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci bw = MT_BW_20; 38162306a36Sopenharmony_ci chan_ext_below = (chan_type == NL80211_CHAN_HT40MINUS); 38262306a36Sopenharmony_ci chan_idx = chan->hw_value - 1; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (chandef->width == NL80211_CHAN_WIDTH_40) { 38562306a36Sopenharmony_ci bw = MT_BW_40; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (chan_idx > 1 && chan_type == NL80211_CHAN_HT40MINUS) 38862306a36Sopenharmony_ci chan_idx -= 2; 38962306a36Sopenharmony_ci else if (chan_idx < 12 && chan_type == NL80211_CHAN_HT40PLUS) 39062306a36Sopenharmony_ci chan_idx += 2; 39162306a36Sopenharmony_ci else 39262306a36Sopenharmony_ci dev_err(dev->dev, "Error: invalid 40MHz channel!!\n"); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (bw != dev->bw || chan_ext_below != dev->chan_ext_below) { 39662306a36Sopenharmony_ci dev_dbg(dev->dev, "Info: switching HT mode bw:%d below:%d\n", 39762306a36Sopenharmony_ci bw, chan_ext_below); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci mt7601u_bbp_set_bw(dev, bw); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci mt7601u_bbp_set_ctrlch(dev, chan_ext_below); 40262306a36Sopenharmony_ci mt7601u_mac_set_ctrlch(dev, chan_ext_below); 40362306a36Sopenharmony_ci dev->chan_ext_below = chan_ext_below; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci for (i = 0; i < FREQ_PLAN_REGS; i++) 40762306a36Sopenharmony_ci channel_freq_plan[i].value = freq_plan[chan_idx][i]; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, 41062306a36Sopenharmony_ci channel_freq_plan, FREQ_PLAN_REGS); 41162306a36Sopenharmony_ci if (ret) 41262306a36Sopenharmony_ci return ret; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci mt7601u_rmw(dev, MT_TX_ALC_CFG_0, 0x3f3f, 41562306a36Sopenharmony_ci dev->ee->chan_pwr[chan_idx] & 0x3f); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, 41862306a36Sopenharmony_ci bbp_settings, ARRAY_SIZE(bbp_settings)); 41962306a36Sopenharmony_ci if (ret) 42062306a36Sopenharmony_ci return ret; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci mt7601u_vco_cal(dev); 42362306a36Sopenharmony_ci mt7601u_bbp_set_bw(dev, bw); 42462306a36Sopenharmony_ci ret = mt7601u_set_bw_filter(dev, false); 42562306a36Sopenharmony_ci if (ret) 42662306a36Sopenharmony_ci return ret; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci mt7601u_apply_ch14_fixup(dev, chan->hw_value); 42962306a36Sopenharmony_ci mt7601u_wr(dev, MT_TX_PWR_CFG_0, int_to_s6(t->ofdm[1].bw20) << 24 | 43062306a36Sopenharmony_ci int_to_s6(t->ofdm[0].bw20) << 16 | 43162306a36Sopenharmony_ci int_to_s6(t->cck[1].bw20) << 8 | 43262306a36Sopenharmony_ci int_to_s6(t->cck[0].bw20)); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) 43562306a36Sopenharmony_ci mt7601u_agc_reset(dev); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci dev->chandef = *chandef; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci return 0; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ciint mt7601u_phy_set_channel(struct mt7601u_dev *dev, 44362306a36Sopenharmony_ci struct cfg80211_chan_def *chandef) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci int ret; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci cancel_delayed_work_sync(&dev->cal_work); 44862306a36Sopenharmony_ci cancel_delayed_work_sync(&dev->freq_cal.work); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci mutex_lock(&dev->hw_atomic_mutex); 45162306a36Sopenharmony_ci ret = __mt7601u_phy_set_channel(dev, chandef); 45262306a36Sopenharmony_ci mutex_unlock(&dev->hw_atomic_mutex); 45362306a36Sopenharmony_ci if (ret) 45462306a36Sopenharmony_ci return ret; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) 45762306a36Sopenharmony_ci return 0; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci ieee80211_queue_delayed_work(dev->hw, &dev->cal_work, 46062306a36Sopenharmony_ci MT_CALIBRATE_INTERVAL); 46162306a36Sopenharmony_ci if (dev->freq_cal.enabled) 46262306a36Sopenharmony_ci ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, 46362306a36Sopenharmony_ci MT_FREQ_CAL_INIT_DELAY); 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci#define BBP_R47_FLAG GENMASK(2, 0) 46862306a36Sopenharmony_ci#define BBP_R47_F_TSSI 0 46962306a36Sopenharmony_ci#define BBP_R47_F_PKT_T 1 47062306a36Sopenharmony_ci#define BBP_R47_F_TX_RATE 2 47162306a36Sopenharmony_ci#define BBP_R47_F_TEMP 4 47262306a36Sopenharmony_ci/** 47362306a36Sopenharmony_ci * mt7601u_bbp_r47_get - read value through BBP R47/R49 pair 47462306a36Sopenharmony_ci * @dev: pointer to adapter structure 47562306a36Sopenharmony_ci * @reg: value of BBP R47 before the operation 47662306a36Sopenharmony_ci * @flag: one of the BBP_R47_F_* flags 47762306a36Sopenharmony_ci * 47862306a36Sopenharmony_ci * Convenience helper for reading values through BBP R47/R49 pair. 47962306a36Sopenharmony_ci * Takes old value of BBP R47 as @reg, because callers usually have it 48062306a36Sopenharmony_ci * cached already. 48162306a36Sopenharmony_ci * 48262306a36Sopenharmony_ci * Return: value of BBP R49. 48362306a36Sopenharmony_ci */ 48462306a36Sopenharmony_cistatic u8 mt7601u_bbp_r47_get(struct mt7601u_dev *dev, u8 reg, u8 flag) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci flag |= reg & ~BBP_R47_FLAG; 48762306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 47, flag); 48862306a36Sopenharmony_ci usleep_range(500, 700); 48962306a36Sopenharmony_ci return mt7601u_bbp_rr(dev, 49); 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic s8 mt7601u_read_bootup_temp(struct mt7601u_dev *dev) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci u8 bbp_val, temp; 49562306a36Sopenharmony_ci u32 rf_bp, rf_set; 49662306a36Sopenharmony_ci int i; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci rf_set = mt7601u_rr(dev, MT_RF_SETTING_0); 49962306a36Sopenharmony_ci rf_bp = mt7601u_rr(dev, MT_RF_BYPASS_0); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_BYPASS_0, 0); 50262306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_SETTING_0, 0x00000010); 50362306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_BYPASS_0, 0x00000010); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci bbp_val = mt7601u_bbp_rmw(dev, 47, 0, 0x10); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 22, 0x40); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci for (i = 100; i && (bbp_val & 0x10); i--) 51062306a36Sopenharmony_ci bbp_val = mt7601u_bbp_rr(dev, 47); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci temp = mt7601u_bbp_r47_get(dev, bbp_val, BBP_R47_F_TEMP); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 22, 0); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci bbp_val = mt7601u_bbp_rr(dev, 21); 51762306a36Sopenharmony_ci bbp_val |= 0x02; 51862306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 21, bbp_val); 51962306a36Sopenharmony_ci bbp_val &= ~0x02; 52062306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 21, bbp_val); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_BYPASS_0, 0); 52362306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_SETTING_0, rf_set); 52462306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_BYPASS_0, rf_bp); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci trace_read_temp(dev, temp); 52762306a36Sopenharmony_ci return temp; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic s8 mt7601u_read_temp(struct mt7601u_dev *dev) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci int i; 53362306a36Sopenharmony_ci u8 val; 53462306a36Sopenharmony_ci s8 temp; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci val = mt7601u_bbp_rmw(dev, 47, 0x7f, 0x10); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* Note: this rarely succeeds, temp can change even if it fails. */ 53962306a36Sopenharmony_ci for (i = 100; i && (val & 0x10); i--) 54062306a36Sopenharmony_ci val = mt7601u_bbp_rr(dev, 47); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci temp = mt7601u_bbp_r47_get(dev, val, BBP_R47_F_TEMP); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci trace_read_temp(dev, temp); 54562306a36Sopenharmony_ci return temp; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic void mt7601u_rxdc_cal(struct mt7601u_dev *dev) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci static const struct mt76_reg_pair intro[] = { 55162306a36Sopenharmony_ci { 158, 0x8d }, { 159, 0xfc }, 55262306a36Sopenharmony_ci { 158, 0x8c }, { 159, 0x4c }, 55362306a36Sopenharmony_ci }, outro[] = { 55462306a36Sopenharmony_ci { 158, 0x8d }, { 159, 0xe0 }, 55562306a36Sopenharmony_ci }; 55662306a36Sopenharmony_ci u32 mac_ctrl; 55762306a36Sopenharmony_ci int i, ret; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL); 56062306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, 56362306a36Sopenharmony_ci intro, ARRAY_SIZE(intro)); 56462306a36Sopenharmony_ci if (ret) 56562306a36Sopenharmony_ci dev_err(dev->dev, "%s intro failed:%d\n", __func__, ret); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci for (i = 20; i; i--) { 56862306a36Sopenharmony_ci usleep_range(300, 500); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 158, 0x8c); 57162306a36Sopenharmony_ci if (mt7601u_bbp_rr(dev, 159) == 0x0c) 57262306a36Sopenharmony_ci break; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci if (!i) 57562306a36Sopenharmony_ci dev_err(dev->dev, "%s timed out\n", __func__); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, 58062306a36Sopenharmony_ci outro, ARRAY_SIZE(outro)); 58162306a36Sopenharmony_ci if (ret) 58262306a36Sopenharmony_ci dev_err(dev->dev, "%s outro failed:%d\n", __func__, ret); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, mac_ctrl); 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_civoid mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) 59062306a36Sopenharmony_ci return; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->curr_temp); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci mt7601u_rxdc_cal(dev); 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci/* Note: function copied from vendor driver */ 59862306a36Sopenharmony_cistatic s16 lin2dBd(u16 linear) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci short exp = 0; 60162306a36Sopenharmony_ci unsigned int mantisa; 60262306a36Sopenharmony_ci int app, dBd; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (WARN_ON(!linear)) 60562306a36Sopenharmony_ci return -10000; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci mantisa = linear; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci exp = fls(mantisa) - 16; 61062306a36Sopenharmony_ci if (exp > 0) 61162306a36Sopenharmony_ci mantisa >>= exp; 61262306a36Sopenharmony_ci else 61362306a36Sopenharmony_ci mantisa <<= abs(exp); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (mantisa <= 0xb800) 61662306a36Sopenharmony_ci app = (mantisa + (mantisa >> 3) + (mantisa >> 4) - 0x9600); 61762306a36Sopenharmony_ci else 61862306a36Sopenharmony_ci app = (mantisa - (mantisa >> 3) - (mantisa >> 6) - 0x5a00); 61962306a36Sopenharmony_ci if (app < 0) 62062306a36Sopenharmony_ci app = 0; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci dBd = ((15 + exp) << 15) + app; 62362306a36Sopenharmony_ci dBd = (dBd << 2) + (dBd << 1) + (dBd >> 6) + (dBd >> 7); 62462306a36Sopenharmony_ci dBd = (dBd >> 10); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci return dBd; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic void 63062306a36Sopenharmony_cimt7601u_set_initial_tssi(struct mt7601u_dev *dev, s16 tssi_db, s16 tssi_hvga_db) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci struct tssi_data *d = &dev->ee->tssi_data; 63362306a36Sopenharmony_ci int init_offset; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci init_offset = -((tssi_db * d->slope + d->offset[1]) / 4096) + 10; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci mt76_rmw(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, 63862306a36Sopenharmony_ci int_to_s6(init_offset) & MT_TX_ALC_CFG_1_TEMP_COMP); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic void mt7601u_tssi_dc_gain_cal(struct mt7601u_dev *dev) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci u8 rf_vga, rf_mixer, bbp_r47; 64462306a36Sopenharmony_ci int i, j; 64562306a36Sopenharmony_ci s8 res[4]; 64662306a36Sopenharmony_ci s16 tssi_init_db, tssi_init_hvga_db; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_SETTING_0, 0x00000030); 64962306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_BYPASS_0, 0x000c0030); 65062306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 58, 0); 65362306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 241, 0x2); 65462306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 23, 0x8); 65562306a36Sopenharmony_ci bbp_r47 = mt7601u_bbp_rr(dev, 47); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Set VGA gain */ 65862306a36Sopenharmony_ci rf_vga = mt7601u_rf_rr(dev, 5, 3); 65962306a36Sopenharmony_ci mt7601u_rf_wr(dev, 5, 3, 8); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci /* Mixer disable */ 66262306a36Sopenharmony_ci rf_mixer = mt7601u_rf_rr(dev, 4, 39); 66362306a36Sopenharmony_ci mt7601u_rf_wr(dev, 4, 39, 0); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 66662306a36Sopenharmony_ci mt7601u_rf_wr(dev, 4, 39, (i & 1) ? rf_mixer : 0); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 23, (i < 2) ? 0x08 : 0x02); 66962306a36Sopenharmony_ci mt7601u_rf_wr(dev, 5, 3, (i < 2) ? 0x08 : 0x11); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* BBP TSSI initial and soft reset */ 67262306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 22, 0); 67362306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 244, 0); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 21, 1); 67662306a36Sopenharmony_ci udelay(1); 67762306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 21, 0); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* TSSI measurement */ 68062306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 47, 0x50); 68162306a36Sopenharmony_ci mt7601u_bbp_wr(dev, (i & 1) ? 244 : 22, (i & 1) ? 0x31 : 0x40); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci for (j = 20; j; j--) 68462306a36Sopenharmony_ci if (!(mt7601u_bbp_rr(dev, 47) & 0x10)) 68562306a36Sopenharmony_ci break; 68662306a36Sopenharmony_ci if (!j) 68762306a36Sopenharmony_ci dev_err(dev->dev, "%s timed out\n", __func__); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* TSSI read */ 69062306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 47, 0x40); 69162306a36Sopenharmony_ci res[i] = mt7601u_bbp_rr(dev, 49); 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci tssi_init_db = lin2dBd((short)res[1] - res[0]); 69562306a36Sopenharmony_ci tssi_init_hvga_db = lin2dBd(((short)res[3] - res[2]) * 4); 69662306a36Sopenharmony_ci dev->tssi_init = res[0]; 69762306a36Sopenharmony_ci dev->tssi_init_hvga = res[2]; 69862306a36Sopenharmony_ci dev->tssi_init_hvga_offset_db = tssi_init_hvga_db - tssi_init_db; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci dev_dbg(dev->dev, 70162306a36Sopenharmony_ci "TSSI_init:%hhx db:%hx hvga:%hhx hvga_db:%hx off_db:%hx\n", 70262306a36Sopenharmony_ci dev->tssi_init, tssi_init_db, dev->tssi_init_hvga, 70362306a36Sopenharmony_ci tssi_init_hvga_db, dev->tssi_init_hvga_offset_db); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 22, 0); 70662306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 244, 0); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 21, 1); 70962306a36Sopenharmony_ci udelay(1); 71062306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 21, 0); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_BYPASS_0, 0); 71362306a36Sopenharmony_ci mt7601u_wr(dev, MT_RF_SETTING_0, 0); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci mt7601u_rf_wr(dev, 5, 3, rf_vga); 71662306a36Sopenharmony_ci mt7601u_rf_wr(dev, 4, 39, rf_mixer); 71762306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 47, bbp_r47); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci mt7601u_set_initial_tssi(dev, tssi_init_db, tssi_init_hvga_db); 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic int mt7601u_temp_comp(struct mt7601u_dev *dev, bool on) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci int ret, temp, hi_temp = 400, lo_temp = -200; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci temp = (dev->raw_temp - dev->ee->ref_temp) * MT_EE_TEMPERATURE_SLOPE; 72762306a36Sopenharmony_ci dev->curr_temp = temp; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* DPD Calibration */ 73062306a36Sopenharmony_ci if (temp - dev->dpd_temp > 450 || temp - dev->dpd_temp < -450) { 73162306a36Sopenharmony_ci dev->dpd_temp = temp; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp); 73462306a36Sopenharmony_ci if (ret) 73562306a36Sopenharmony_ci return ret; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci mt7601u_vco_cal(dev); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci dev_dbg(dev->dev, "Recalibrate DPD\n"); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* PLL Lock Protect */ 74362306a36Sopenharmony_ci if (temp < -50 && !dev->pll_lock_protect) { /* < 20C */ 74462306a36Sopenharmony_ci dev->pll_lock_protect = true; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci mt7601u_rf_wr(dev, 4, 4, 6); 74762306a36Sopenharmony_ci mt7601u_rf_clear(dev, 4, 10, 0x30); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci dev_dbg(dev->dev, "PLL lock protect on - too cold\n"); 75062306a36Sopenharmony_ci } else if (temp > 50 && dev->pll_lock_protect) { /* > 30C */ 75162306a36Sopenharmony_ci dev->pll_lock_protect = false; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci mt7601u_rf_wr(dev, 4, 4, 0); 75462306a36Sopenharmony_ci mt7601u_rf_rmw(dev, 4, 10, 0x30, 0x10); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci dev_dbg(dev->dev, "PLL lock protect off\n"); 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (on) { 76062306a36Sopenharmony_ci hi_temp -= 50; 76162306a36Sopenharmony_ci lo_temp -= 50; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci /* BBP CR for H, L, N temperature */ 76562306a36Sopenharmony_ci if (temp > hi_temp) 76662306a36Sopenharmony_ci return mt7601u_bbp_temp(dev, MT_TEMP_MODE_HIGH, "high"); 76762306a36Sopenharmony_ci else if (temp > lo_temp) 76862306a36Sopenharmony_ci return mt7601u_bbp_temp(dev, MT_TEMP_MODE_NORMAL, "normal"); 76962306a36Sopenharmony_ci else 77062306a36Sopenharmony_ci return mt7601u_bbp_temp(dev, MT_TEMP_MODE_LOW, "low"); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci/* Note: this is used only with TSSI, we can just use trgt_pwr from eeprom. */ 77462306a36Sopenharmony_cistatic int mt7601u_current_tx_power(struct mt7601u_dev *dev) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci return dev->ee->chan_pwr[dev->chandef.chan->hw_value - 1]; 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic bool mt7601u_use_hvga(struct mt7601u_dev *dev) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci return !(mt7601u_current_tx_power(dev) > 20); 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic s16 78562306a36Sopenharmony_cimt7601u_phy_rf_pa_mode_val(struct mt7601u_dev *dev, int phy_mode, int tx_rate) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci static const s16 decode_tb[] = { 0, 8847, -5734, -5734 }; 78862306a36Sopenharmony_ci u32 reg; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci switch (phy_mode) { 79162306a36Sopenharmony_ci case MT_PHY_TYPE_OFDM: 79262306a36Sopenharmony_ci tx_rate += 4; 79362306a36Sopenharmony_ci fallthrough; 79462306a36Sopenharmony_ci case MT_PHY_TYPE_CCK: 79562306a36Sopenharmony_ci reg = dev->rf_pa_mode[0]; 79662306a36Sopenharmony_ci break; 79762306a36Sopenharmony_ci default: 79862306a36Sopenharmony_ci reg = dev->rf_pa_mode[1]; 79962306a36Sopenharmony_ci break; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return decode_tb[(reg >> (tx_rate * 2)) & 0x3]; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic struct mt7601u_tssi_params 80662306a36Sopenharmony_cimt7601u_tssi_params_get(struct mt7601u_dev *dev) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci static const u8 ofdm_pkt2rate[8] = { 6, 4, 2, 0, 7, 5, 3, 1 }; 80962306a36Sopenharmony_ci static const int static_power[4] = { 0, -49152, -98304, 49152 }; 81062306a36Sopenharmony_ci struct mt7601u_tssi_params p; 81162306a36Sopenharmony_ci u8 bbp_r47, pkt_type, tx_rate; 81262306a36Sopenharmony_ci struct power_per_rate *rate_table; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci bbp_r47 = mt7601u_bbp_rr(dev, 47); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci p.tssi0 = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TSSI); 81762306a36Sopenharmony_ci dev->raw_temp = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TEMP); 81862306a36Sopenharmony_ci pkt_type = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_PKT_T); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci p.trgt_power = mt7601u_current_tx_power(dev); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci switch (pkt_type & 0x03) { 82362306a36Sopenharmony_ci case MT_PHY_TYPE_CCK: 82462306a36Sopenharmony_ci tx_rate = (pkt_type >> 4) & 0x03; 82562306a36Sopenharmony_ci rate_table = dev->ee->power_rate_table.cck; 82662306a36Sopenharmony_ci break; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci case MT_PHY_TYPE_OFDM: 82962306a36Sopenharmony_ci tx_rate = ofdm_pkt2rate[(pkt_type >> 4) & 0x07]; 83062306a36Sopenharmony_ci rate_table = dev->ee->power_rate_table.ofdm; 83162306a36Sopenharmony_ci break; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci default: 83462306a36Sopenharmony_ci tx_rate = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TX_RATE); 83562306a36Sopenharmony_ci tx_rate &= 0x7f; 83662306a36Sopenharmony_ci rate_table = dev->ee->power_rate_table.ht; 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (dev->bw == MT_BW_20) 84162306a36Sopenharmony_ci p.trgt_power += rate_table[tx_rate / 2].bw20; 84262306a36Sopenharmony_ci else 84362306a36Sopenharmony_ci p.trgt_power += rate_table[tx_rate / 2].bw40; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci p.trgt_power <<= 12; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci dev_dbg(dev->dev, "tx_rate:%02hhx pwr:%08x\n", tx_rate, p.trgt_power); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci p.trgt_power += mt7601u_phy_rf_pa_mode_val(dev, pkt_type & 0x03, 85062306a36Sopenharmony_ci tx_rate); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci /* Channel 14, cck, bw20 */ 85362306a36Sopenharmony_ci if ((pkt_type & 0x03) == MT_PHY_TYPE_CCK) { 85462306a36Sopenharmony_ci if (mt7601u_bbp_rr(dev, 4) & 0x20) 85562306a36Sopenharmony_ci p.trgt_power += mt7601u_bbp_rr(dev, 178) ? 18022 : 9830; 85662306a36Sopenharmony_ci else 85762306a36Sopenharmony_ci p.trgt_power += mt7601u_bbp_rr(dev, 178) ? 819 : 24576; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci p.trgt_power += static_power[mt7601u_bbp_rr(dev, 1) & 0x03]; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci p.trgt_power += dev->ee->tssi_data.tx0_delta_offset; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci dev_dbg(dev->dev, 86562306a36Sopenharmony_ci "tssi:%02hhx t_power:%08x temp:%02hhx pkt_type:%02hhx\n", 86662306a36Sopenharmony_ci p.tssi0, p.trgt_power, dev->raw_temp, pkt_type); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci return p; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic bool mt7601u_tssi_read_ready(struct mt7601u_dev *dev) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci return !(mt7601u_bbp_rr(dev, 47) & 0x10); 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic int mt7601u_tssi_cal(struct mt7601u_dev *dev) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci struct mt7601u_tssi_params params; 87962306a36Sopenharmony_ci int curr_pwr, diff_pwr; 88062306a36Sopenharmony_ci char tssi_offset; 88162306a36Sopenharmony_ci s8 tssi_init; 88262306a36Sopenharmony_ci s16 tssi_m_dc, tssi_db; 88362306a36Sopenharmony_ci bool hvga; 88462306a36Sopenharmony_ci u32 val; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (!dev->ee->tssi_enabled) 88762306a36Sopenharmony_ci return 0; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci hvga = mt7601u_use_hvga(dev); 89062306a36Sopenharmony_ci if (!dev->tssi_read_trig) 89162306a36Sopenharmony_ci return mt7601u_mcu_tssi_read_kick(dev, hvga); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (!mt7601u_tssi_read_ready(dev)) 89462306a36Sopenharmony_ci return 0; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci params = mt7601u_tssi_params_get(dev); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci tssi_init = (hvga ? dev->tssi_init_hvga : dev->tssi_init); 89962306a36Sopenharmony_ci tssi_m_dc = params.tssi0 - tssi_init; 90062306a36Sopenharmony_ci tssi_db = lin2dBd(tssi_m_dc); 90162306a36Sopenharmony_ci dev_dbg(dev->dev, "tssi dc:%04hx db:%04hx hvga:%d\n", 90262306a36Sopenharmony_ci tssi_m_dc, tssi_db, hvga); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (dev->chandef.chan->hw_value < 5) 90562306a36Sopenharmony_ci tssi_offset = dev->ee->tssi_data.offset[0]; 90662306a36Sopenharmony_ci else if (dev->chandef.chan->hw_value < 9) 90762306a36Sopenharmony_ci tssi_offset = dev->ee->tssi_data.offset[1]; 90862306a36Sopenharmony_ci else 90962306a36Sopenharmony_ci tssi_offset = dev->ee->tssi_data.offset[2]; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (hvga) 91262306a36Sopenharmony_ci tssi_db -= dev->tssi_init_hvga_offset_db; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci curr_pwr = tssi_db * dev->ee->tssi_data.slope + (tssi_offset << 9); 91562306a36Sopenharmony_ci diff_pwr = params.trgt_power - curr_pwr; 91662306a36Sopenharmony_ci dev_dbg(dev->dev, "Power curr:%08x diff:%08x\n", curr_pwr, diff_pwr); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (params.tssi0 > 126 && diff_pwr > 0) { 91962306a36Sopenharmony_ci dev_err(dev->dev, "Error: TSSI upper saturation\n"); 92062306a36Sopenharmony_ci diff_pwr = 0; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci if (params.tssi0 - tssi_init < 1 && diff_pwr < 0) { 92362306a36Sopenharmony_ci dev_err(dev->dev, "Error: TSSI lower saturation\n"); 92462306a36Sopenharmony_ci diff_pwr = 0; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if ((dev->prev_pwr_diff ^ diff_pwr) < 0 && abs(diff_pwr) < 4096 && 92862306a36Sopenharmony_ci (abs(diff_pwr) > abs(dev->prev_pwr_diff) || 92962306a36Sopenharmony_ci (diff_pwr > 0 && diff_pwr == -dev->prev_pwr_diff))) 93062306a36Sopenharmony_ci diff_pwr = 0; 93162306a36Sopenharmony_ci else 93262306a36Sopenharmony_ci dev->prev_pwr_diff = diff_pwr; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci diff_pwr += (diff_pwr > 0) ? 2048 : -2048; 93562306a36Sopenharmony_ci diff_pwr /= 4096; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci dev_dbg(dev->dev, "final diff: %08x\n", diff_pwr); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci val = mt7601u_rr(dev, MT_TX_ALC_CFG_1); 94062306a36Sopenharmony_ci curr_pwr = s6_to_int(FIELD_GET(MT_TX_ALC_CFG_1_TEMP_COMP, val)); 94162306a36Sopenharmony_ci diff_pwr += curr_pwr; 94262306a36Sopenharmony_ci val = (val & ~MT_TX_ALC_CFG_1_TEMP_COMP) | int_to_s6(diff_pwr); 94362306a36Sopenharmony_ci mt7601u_wr(dev, MT_TX_ALC_CFG_1, val); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci return mt7601u_mcu_tssi_read_kick(dev, hvga); 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic u8 mt7601u_agc_default(struct mt7601u_dev *dev) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci return (dev->ee->lna_gain - 8) * 2 + 0x34; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_cistatic void mt7601u_agc_reset(struct mt7601u_dev *dev) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci u8 agc = mt7601u_agc_default(dev); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 66, agc); 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_civoid mt7601u_agc_save(struct mt7601u_dev *dev) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci dev->agc_save = mt7601u_bbp_rr(dev, 66); 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_civoid mt7601u_agc_restore(struct mt7601u_dev *dev) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 66, dev->agc_save); 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_cistatic void mt7601u_agc_tune(struct mt7601u_dev *dev) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci u8 val = mt7601u_agc_default(dev); 97362306a36Sopenharmony_ci long avg_rssi; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) 97662306a36Sopenharmony_ci return; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* Note: only in STA mode and not dozing; perhaps do this only if 97962306a36Sopenharmony_ci * there is enough rssi updates since last run? 98062306a36Sopenharmony_ci * Rssi updates are only on beacons and U2M so should work... 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_ci spin_lock_bh(&dev->con_mon_lock); 98362306a36Sopenharmony_ci avg_rssi = ewma_rssi_read(&dev->avg_rssi); 98462306a36Sopenharmony_ci spin_unlock_bh(&dev->con_mon_lock); 98562306a36Sopenharmony_ci if (avg_rssi == 0) 98662306a36Sopenharmony_ci return; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci avg_rssi = -avg_rssi; 98962306a36Sopenharmony_ci if (avg_rssi <= -70) 99062306a36Sopenharmony_ci val -= 0x20; 99162306a36Sopenharmony_ci else if (avg_rssi <= -60) 99262306a36Sopenharmony_ci val -= 0x10; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (val != mt7601u_bbp_rr(dev, 66)) 99562306a36Sopenharmony_ci mt7601u_bbp_wr(dev, 66, val); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* TODO: also if lost a lot of beacons try resetting 99862306a36Sopenharmony_ci * (see RTMPSetAGCInitValue() call in mlme.c). 99962306a36Sopenharmony_ci */ 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic void mt7601u_phy_calibrate(struct work_struct *work) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, 100562306a36Sopenharmony_ci cal_work.work); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci mt7601u_agc_tune(dev); 100862306a36Sopenharmony_ci mt7601u_tssi_cal(dev); 100962306a36Sopenharmony_ci /* If TSSI calibration was run it already updated temperature. */ 101062306a36Sopenharmony_ci if (!dev->ee->tssi_enabled) 101162306a36Sopenharmony_ci dev->raw_temp = mt7601u_read_temp(dev); 101262306a36Sopenharmony_ci mt7601u_temp_comp(dev, true); /* TODO: find right value for @on */ 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci ieee80211_queue_delayed_work(dev->hw, &dev->cal_work, 101562306a36Sopenharmony_ci MT_CALIBRATE_INTERVAL); 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic unsigned long 101962306a36Sopenharmony_ci__mt7601u_phy_freq_cal(struct mt7601u_dev *dev, s8 last_offset, u8 phy_mode) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci u8 activate_threshold, deactivate_threshold; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci trace_freq_cal_offset(dev, phy_mode, last_offset); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* No beacons received - reschedule soon */ 102662306a36Sopenharmony_ci if (last_offset == MT_FREQ_OFFSET_INVALID) 102762306a36Sopenharmony_ci return MT_FREQ_CAL_ADJ_INTERVAL; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci switch (phy_mode) { 103062306a36Sopenharmony_ci case MT_PHY_TYPE_CCK: 103162306a36Sopenharmony_ci activate_threshold = 19; 103262306a36Sopenharmony_ci deactivate_threshold = 5; 103362306a36Sopenharmony_ci break; 103462306a36Sopenharmony_ci case MT_PHY_TYPE_OFDM: 103562306a36Sopenharmony_ci activate_threshold = 102; 103662306a36Sopenharmony_ci deactivate_threshold = 32; 103762306a36Sopenharmony_ci break; 103862306a36Sopenharmony_ci case MT_PHY_TYPE_HT: 103962306a36Sopenharmony_ci case MT_PHY_TYPE_HT_GF: 104062306a36Sopenharmony_ci activate_threshold = 82; 104162306a36Sopenharmony_ci deactivate_threshold = 20; 104262306a36Sopenharmony_ci break; 104362306a36Sopenharmony_ci default: 104462306a36Sopenharmony_ci WARN_ON(1); 104562306a36Sopenharmony_ci return MT_FREQ_CAL_CHECK_INTERVAL; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (abs(last_offset) >= activate_threshold) 104962306a36Sopenharmony_ci dev->freq_cal.adjusting = true; 105062306a36Sopenharmony_ci else if (abs(last_offset) <= deactivate_threshold) 105162306a36Sopenharmony_ci dev->freq_cal.adjusting = false; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (!dev->freq_cal.adjusting) 105462306a36Sopenharmony_ci return MT_FREQ_CAL_CHECK_INTERVAL; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if (last_offset > deactivate_threshold) { 105762306a36Sopenharmony_ci if (dev->freq_cal.freq > 0) 105862306a36Sopenharmony_ci dev->freq_cal.freq--; 105962306a36Sopenharmony_ci else 106062306a36Sopenharmony_ci dev->freq_cal.adjusting = false; 106162306a36Sopenharmony_ci } else if (last_offset < -deactivate_threshold) { 106262306a36Sopenharmony_ci if (dev->freq_cal.freq < 0xbf) 106362306a36Sopenharmony_ci dev->freq_cal.freq++; 106462306a36Sopenharmony_ci else 106562306a36Sopenharmony_ci dev->freq_cal.adjusting = false; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci trace_freq_cal_adjust(dev, dev->freq_cal.freq); 106962306a36Sopenharmony_ci mt7601u_rf_wr(dev, 0, 12, dev->freq_cal.freq); 107062306a36Sopenharmony_ci mt7601u_vco_cal(dev); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci return dev->freq_cal.adjusting ? MT_FREQ_CAL_ADJ_INTERVAL : 107362306a36Sopenharmony_ci MT_FREQ_CAL_CHECK_INTERVAL; 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic void mt7601u_phy_freq_cal(struct work_struct *work) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, 107962306a36Sopenharmony_ci freq_cal.work.work); 108062306a36Sopenharmony_ci s8 last_offset; 108162306a36Sopenharmony_ci u8 phy_mode; 108262306a36Sopenharmony_ci unsigned long delay; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci spin_lock_bh(&dev->con_mon_lock); 108562306a36Sopenharmony_ci last_offset = dev->bcn_freq_off; 108662306a36Sopenharmony_ci phy_mode = dev->bcn_phy_mode; 108762306a36Sopenharmony_ci spin_unlock_bh(&dev->con_mon_lock); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci delay = __mt7601u_phy_freq_cal(dev, last_offset, phy_mode); 109062306a36Sopenharmony_ci ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, delay); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci spin_lock_bh(&dev->con_mon_lock); 109362306a36Sopenharmony_ci dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID; 109462306a36Sopenharmony_ci spin_unlock_bh(&dev->con_mon_lock); 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_civoid mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, 109862306a36Sopenharmony_ci struct ieee80211_bss_conf *info) 109962306a36Sopenharmony_ci{ 110062306a36Sopenharmony_ci struct ieee80211_vif *vif = container_of(info, struct ieee80211_vif, 110162306a36Sopenharmony_ci bss_conf); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (!vif->cfg.assoc) 110462306a36Sopenharmony_ci cancel_delayed_work_sync(&dev->freq_cal.work); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* Start/stop collecting beacon data */ 110762306a36Sopenharmony_ci spin_lock_bh(&dev->con_mon_lock); 110862306a36Sopenharmony_ci ether_addr_copy(dev->ap_bssid, info->bssid); 110962306a36Sopenharmony_ci ewma_rssi_init(&dev->avg_rssi); 111062306a36Sopenharmony_ci dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID; 111162306a36Sopenharmony_ci spin_unlock_bh(&dev->con_mon_lock); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci dev->freq_cal.freq = dev->ee->rf_freq_off; 111462306a36Sopenharmony_ci dev->freq_cal.enabled = vif->cfg.assoc; 111562306a36Sopenharmony_ci dev->freq_cal.adjusting = false; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (vif->cfg.assoc) 111862306a36Sopenharmony_ci ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, 111962306a36Sopenharmony_ci MT_FREQ_CAL_INIT_DELAY); 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic int mt7601u_init_cal(struct mt7601u_dev *dev) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci u32 mac_ctrl; 112562306a36Sopenharmony_ci int ret; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci dev->raw_temp = mt7601u_read_bootup_temp(dev); 112862306a36Sopenharmony_ci dev->curr_temp = (dev->raw_temp - dev->ee->ref_temp) * 112962306a36Sopenharmony_ci MT_EE_TEMPERATURE_SLOPE; 113062306a36Sopenharmony_ci dev->dpd_temp = dev->curr_temp; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci ret = mt7601u_mcu_calibrate(dev, MCU_CAL_R, 0); 113562306a36Sopenharmony_ci if (ret) 113662306a36Sopenharmony_ci return ret; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci ret = mt7601u_rf_rr(dev, 0, 4); 113962306a36Sopenharmony_ci if (ret < 0) 114062306a36Sopenharmony_ci return ret; 114162306a36Sopenharmony_ci ret |= 0x80; 114262306a36Sopenharmony_ci ret = mt7601u_rf_wr(dev, 0, 4, ret); 114362306a36Sopenharmony_ci if (ret) 114462306a36Sopenharmony_ci return ret; 114562306a36Sopenharmony_ci msleep(2); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci ret = mt7601u_mcu_calibrate(dev, MCU_CAL_TXDCOC, 0); 114862306a36Sopenharmony_ci if (ret) 114962306a36Sopenharmony_ci return ret; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci mt7601u_rxdc_cal(dev); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci ret = mt7601u_set_bw_filter(dev, true); 115462306a36Sopenharmony_ci if (ret) 115562306a36Sopenharmony_ci return ret; 115662306a36Sopenharmony_ci ret = mt7601u_mcu_calibrate(dev, MCU_CAL_LOFT, 0); 115762306a36Sopenharmony_ci if (ret) 115862306a36Sopenharmony_ci return ret; 115962306a36Sopenharmony_ci ret = mt7601u_mcu_calibrate(dev, MCU_CAL_TXIQ, 0); 116062306a36Sopenharmony_ci if (ret) 116162306a36Sopenharmony_ci return ret; 116262306a36Sopenharmony_ci ret = mt7601u_mcu_calibrate(dev, MCU_CAL_RXIQ, 0); 116362306a36Sopenharmony_ci if (ret) 116462306a36Sopenharmony_ci return ret; 116562306a36Sopenharmony_ci ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp); 116662306a36Sopenharmony_ci if (ret) 116762306a36Sopenharmony_ci return ret; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci mt7601u_rxdc_cal(dev); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci mt7601u_tssi_dc_gain_cal(dev); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, mac_ctrl); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci mt7601u_temp_comp(dev, true); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci return 0; 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ciint mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci u32 val, old; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (bw == dev->bw) { 118562306a36Sopenharmony_ci /* Vendor driver does the rmc even when no change is needed. */ 118662306a36Sopenharmony_ci mt7601u_bbp_rmc(dev, 4, 0x18, bw == MT_BW_20 ? 0 : 0x10); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci return 0; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci dev->bw = bw; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci /* Stop MAC for the time of bw change */ 119362306a36Sopenharmony_ci old = mt7601u_rr(dev, MT_MAC_SYS_CTRL); 119462306a36Sopenharmony_ci val = old & ~(MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); 119562306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, val); 119662306a36Sopenharmony_ci mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 119762306a36Sopenharmony_ci 0, 500000); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci mt7601u_bbp_rmc(dev, 4, 0x18, bw == MT_BW_20 ? 0 : 0x10); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, old); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci return mt7601u_load_bbp_temp_table_bw(dev); 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci/** 120762306a36Sopenharmony_ci * mt7601u_set_rx_path - set rx path in BBP 120862306a36Sopenharmony_ci * @dev: pointer to adapter structure 120962306a36Sopenharmony_ci * @path: rx path to set values are 0-based 121062306a36Sopenharmony_ci */ 121162306a36Sopenharmony_civoid mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci mt7601u_bbp_rmw(dev, 3, 0x18, path << 3); 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci/** 121762306a36Sopenharmony_ci * mt7601u_set_tx_dac - set which tx DAC to use 121862306a36Sopenharmony_ci * @dev: pointer to adapter structure 121962306a36Sopenharmony_ci * @dac: DAC index, values are 0-based 122062306a36Sopenharmony_ci */ 122162306a36Sopenharmony_civoid mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 dac) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci mt7601u_bbp_rmc(dev, 1, 0x18, dac << 3); 122462306a36Sopenharmony_ci} 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ciint mt7601u_phy_init(struct mt7601u_dev *dev) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci int ret; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci dev->rf_pa_mode[0] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG0); 123162306a36Sopenharmony_ci dev->rf_pa_mode[1] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG1); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci ret = mt7601u_rf_wr(dev, 0, 12, dev->ee->rf_freq_off); 123462306a36Sopenharmony_ci if (ret) 123562306a36Sopenharmony_ci return ret; 123662306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, 0, rf_central, 123762306a36Sopenharmony_ci ARRAY_SIZE(rf_central)); 123862306a36Sopenharmony_ci if (ret) 123962306a36Sopenharmony_ci return ret; 124062306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, 0, rf_channel, 124162306a36Sopenharmony_ci ARRAY_SIZE(rf_channel)); 124262306a36Sopenharmony_ci if (ret) 124362306a36Sopenharmony_ci return ret; 124462306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, 0, rf_vga, ARRAY_SIZE(rf_vga)); 124562306a36Sopenharmony_ci if (ret) 124662306a36Sopenharmony_ci return ret; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci ret = mt7601u_init_cal(dev); 124962306a36Sopenharmony_ci if (ret) 125062306a36Sopenharmony_ci return ret; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci dev->prev_pwr_diff = 100; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci INIT_DELAYED_WORK(&dev->cal_work, mt7601u_phy_calibrate); 125562306a36Sopenharmony_ci INIT_DELAYED_WORK(&dev->freq_cal.work, mt7601u_phy_freq_cal); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci return 0; 125862306a36Sopenharmony_ci} 1259