11590Srgrimes// SPDX-License-Identifier: ISC
21590Srgrimes/*
31590Srgrimes * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
41590Srgrimes * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
51590Srgrimes */
61590Srgrimes
71590Srgrimes#include "mt76x2.h"
81590Srgrimes#include "eeprom.h"
91590Srgrimes#include "mcu.h"
101590Srgrimes#include "../mt76x02_phy.h"
111590Srgrimes
121590Srgrimesstatic void
131590Srgrimesmt76x2_adjust_high_lna_gain(struct mt76x02_dev *dev, int reg, s8 offset)
141590Srgrimes{
151590Srgrimes	s8 gain;
161590Srgrimes
171590Srgrimes	gain = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN,
181590Srgrimes			 mt76_rr(dev, MT_BBP(AGC, reg)));
191590Srgrimes	gain -= offset / 2;
201590Srgrimes	mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_LNA_HIGH_GAIN, gain);
211590Srgrimes}
221590Srgrimes
231590Srgrimesstatic void
241590Srgrimesmt76x2_adjust_agc_gain(struct mt76x02_dev *dev, int reg, s8 offset)
251590Srgrimes{
261590Srgrimes	s8 gain;
271590Srgrimes
281590Srgrimes	gain = FIELD_GET(MT_BBP_AGC_GAIN, mt76_rr(dev, MT_BBP(AGC, reg)));
291590Srgrimes	gain += offset;
301590Srgrimes	mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_GAIN, gain);
3174769Smikeh}
321590Srgrimes
3374769Smikehvoid mt76x2_apply_gain_adj(struct mt76x02_dev *dev)
341590Srgrimes{
3599112Sobrien	s8 *gain_adj = dev->cal.rx.high_gain;
3699112Sobrien
371590Srgrimes	mt76x2_adjust_high_lna_gain(dev, 4, gain_adj[0]);
381590Srgrimes	mt76x2_adjust_high_lna_gain(dev, 5, gain_adj[1]);
391590Srgrimes
401590Srgrimes	mt76x2_adjust_agc_gain(dev, 8, gain_adj[0]);
411590Srgrimes	mt76x2_adjust_agc_gain(dev, 9, gain_adj[1]);
421590Srgrimes}
431590SrgrimesEXPORT_SYMBOL_GPL(mt76x2_apply_gain_adj);
441590Srgrimes
451590Srgrimesvoid mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev,
461590Srgrimes				 enum nl80211_band band)
471590Srgrimes{
481590Srgrimes	u32 pa_mode[2];
491590Srgrimes	u32 pa_mode_adj;
501590Srgrimes
511590Srgrimes	if (band == NL80211_BAND_2GHZ) {
521590Srgrimes		pa_mode[0] = 0x010055ff;
531590Srgrimes		pa_mode[1] = 0x00550055;
541590Srgrimes
55216564Scharnier		mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00);
56216564Scharnier		mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06);
571590Srgrimes
581590Srgrimes		if (mt76x02_ext_pa_enabled(dev, band)) {
5977274Smikeh			mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00);
6077274Smikeh			mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00);
611590Srgrimes		} else {
6277274Smikeh			mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0xf4000200);
631590Srgrimes			mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0xfa000200);
641590Srgrimes		}
651590Srgrimes	} else {
661590Srgrimes		pa_mode[0] = 0x0000ffff;
6777274Smikeh		pa_mode[1] = 0x00ff00ff;
681590Srgrimes
6977274Smikeh		if (mt76x02_ext_pa_enabled(dev, band)) {
701590Srgrimes			mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400);
711590Srgrimes			mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476);
7277274Smikeh		} else {
731590Srgrimes			mt76_wr(dev, MT_TX_ALC_CFG_2, 0x1b0f0400);
741590Srgrimes			mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476);
751590Srgrimes		}
761590Srgrimes
771590Srgrimes		if (mt76x02_ext_pa_enabled(dev, band))
781590Srgrimes			pa_mode_adj = 0x04000000;
791590Srgrimes		else
801590Srgrimes			pa_mode_adj = 0;
811590Srgrimes
821590Srgrimes		mt76_wr(dev, MT_RF_PA_MODE_ADJ0, pa_mode_adj);
831590Srgrimes		mt76_wr(dev, MT_RF_PA_MODE_ADJ1, pa_mode_adj);
8474769Smikeh	}
851590Srgrimes
861590Srgrimes	mt76_wr(dev, MT_BB_PA_MODE_CFG0, pa_mode[0]);
871590Srgrimes	mt76_wr(dev, MT_BB_PA_MODE_CFG1, pa_mode[1]);
888874Srgrimes	mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]);
891590Srgrimes	mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]);
901590Srgrimes
911590Srgrimes	if (mt76x02_ext_pa_enabled(dev, band)) {
921590Srgrimes		u32 val;
931590Srgrimes
941590Srgrimes		if (band == NL80211_BAND_2GHZ)
951590Srgrimes			val = 0x3c3c023c;
961590Srgrimes		else
971590Srgrimes			val = 0x363c023c;
981590Srgrimes
991590Srgrimes		mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val);
1001590Srgrimes		mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val);
1011590Srgrimes		mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00001818);
1021590Srgrimes	} else {
1031590Srgrimes		if (band == NL80211_BAND_2GHZ) {
1041590Srgrimes			u32 val = 0x0f3c3c3c;
1051590Srgrimes
1061590Srgrimes			mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val);
1071590Srgrimes			mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val);
1081590Srgrimes			mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00000606);
1091590Srgrimes		} else {
1101590Srgrimes			mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x383c023c);
1111590Srgrimes			mt76_wr(dev, MT_TX1_RF_GAIN_CORR, 0x24282e28);
1121590Srgrimes			mt76_wr(dev, MT_TX_ALC_CFG_4, 0);
1131590Srgrimes		}
1141590Srgrimes	}
1151590Srgrimes}
1161590SrgrimesEXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower_regs);
1171590Srgrimes
11877274Smikehstatic int
11988227Sachemt76x2_get_min_rate_power(struct mt76x02_rate_power *r)
1201590Srgrimes{
1211590Srgrimes	int i;
12288227Sache	s8 ret = 0;
1231590Srgrimes
1241590Srgrimes	for (i = 0; i < sizeof(r->all); i++) {
1251590Srgrimes		if (!r->all[i])
1261590Srgrimes			continue;
1271590Srgrimes
1281590Srgrimes		if (ret)
1291590Srgrimes			ret = min(ret, r->all[i]);
1301590Srgrimes		else
1311590Srgrimes			ret = r->all[i];
1321590Srgrimes	}
1331590Srgrimes
1341590Srgrimes	return ret;
1351590Srgrimes}
13677274Smikeh
1371590Srgrimesvoid mt76x2_phy_set_txpower(struct mt76x02_dev *dev)
1381590Srgrimes{
1391590Srgrimes	enum nl80211_chan_width width = dev->mphy.chandef.width;
1401590Srgrimes	struct ieee80211_channel *chan = dev->mphy.chandef.chan;
1411590Srgrimes	struct mt76x2_tx_power_info txp;
1421590Srgrimes	int txp_0, txp_1, delta = 0;
1431590Srgrimes	struct mt76x02_rate_power t = {};
14477274Smikeh	int base_power, gain;
1451590Srgrimes
1461590Srgrimes	mt76x2_get_power_info(dev, &txp, chan);
1471590Srgrimes
1481590Srgrimes	if (width == NL80211_CHAN_WIDTH_40)
1491590Srgrimes		delta = txp.delta_bw40;
1501590Srgrimes	else if (width == NL80211_CHAN_WIDTH_80)
1511590Srgrimes		delta = txp.delta_bw80;
1521590Srgrimes
1531590Srgrimes	mt76x2_get_rate_power(dev, &t, chan);
1541590Srgrimes	mt76x02_add_rate_power_offset(&t, txp.target_power + delta);
1551590Srgrimes	mt76x02_limit_rate_power(&t, dev->txpower_conf);
1561590Srgrimes	dev->mphy.txpower_cur = mt76x02_get_max_rate_power(&t);
1571590Srgrimes
1581590Srgrimes	base_power = mt76x2_get_min_rate_power(&t);
1591590Srgrimes	delta = base_power - txp.target_power;
1601590Srgrimes	txp_0 = txp.chain[0].target_power + txp.chain[0].delta + delta;
1611590Srgrimes	txp_1 = txp.chain[1].target_power + txp.chain[1].delta + delta;
1621590Srgrimes
1631590Srgrimes	gain = min(txp_0, txp_1);
1641590Srgrimes	if (gain < 0) {
1651590Srgrimes		base_power -= gain;
1661590Srgrimes		txp_0 -= gain;
1671590Srgrimes		txp_1 -= gain;
1681590Srgrimes	} else if (gain > 0x2f) {
1691590Srgrimes		base_power -= gain - 0x2f;
17077274Smikeh		txp_0 = 0x2f;
1711590Srgrimes		txp_1 = 0x2f;
1721590Srgrimes	}
1731590Srgrimes
17477274Smikeh	mt76x02_add_rate_power_offset(&t, -base_power);
17577274Smikeh	dev->target_power = txp.target_power;
17674769Smikeh	dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power;
17777274Smikeh	dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power;
1781590Srgrimes	dev->rate_power = t;
17977274Smikeh
1801590Srgrimes	mt76x02_phy_set_txpower(dev, txp_0, txp_1);
1811590Srgrimes}
1821590SrgrimesEXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower);
1831590Srgrimes
1841590Srgrimesvoid mt76x2_configure_tx_delay(struct mt76x02_dev *dev,
1851590Srgrimes			       enum nl80211_band band, u8 bw)
1861590Srgrimes{
18777274Smikeh	u32 cfg0, cfg1;
1881590Srgrimes
18974769Smikeh	if (mt76x02_ext_pa_enabled(dev, band)) {
1901590Srgrimes		cfg0 = bw ? 0x000b0c01 : 0x00101101;
1911590Srgrimes		cfg1 = 0x00011414;
1921590Srgrimes	} else {
1931590Srgrimes		cfg0 = bw ? 0x000b0b01 : 0x00101001;
1941590Srgrimes		cfg1 = 0x00021414;
1951590Srgrimes	}
1961590Srgrimes	mt76_wr(dev, MT_TX_SW_CFG0, cfg0);
1971590Srgrimes	mt76_wr(dev, MT_TX_SW_CFG1, cfg1);
1981590Srgrimes
1991590Srgrimes	mt76_rmw_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_OFDM_SIFS, 15);
2001590Srgrimes}
20177274SmikehEXPORT_SYMBOL_GPL(mt76x2_configure_tx_delay);
20277274Smikeh
20377274Smikehvoid mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev)
2041590Srgrimes{
20577274Smikeh	struct ieee80211_channel *chan = dev->mphy.chandef.chan;
2061590Srgrimes	struct mt76x2_tx_power_info txp;
2071590Srgrimes	struct mt76x2_tssi_comp t = {};
2081590Srgrimes
2091590Srgrimes	if (!dev->cal.tssi_cal_done)
21077274Smikeh		return;
2111590Srgrimes
2121590Srgrimes	if (!dev->cal.tssi_comp_pending) {
21377274Smikeh		/* TSSI trigger */
21477274Smikeh		t.cal_mode = BIT(0);
2151590Srgrimes		mt76x2_mcu_tssi_comp(dev, &t);
2161590Srgrimes		dev->cal.tssi_comp_pending = true;
2171590Srgrimes	} else {
2181590Srgrimes		if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4))
21977274Smikeh			return;
22077274Smikeh
2211590Srgrimes		dev->cal.tssi_comp_pending = false;
2221590Srgrimes		mt76x2_get_power_info(dev, &txp, chan);
2231590Srgrimes
2241590Srgrimes		if (mt76x02_ext_pa_enabled(dev, chan->band))
2251590Srgrimes			t.pa_mode = 1;
2261590Srgrimes
227216564Scharnier		t.cal_mode = BIT(1);
2281590Srgrimes		t.slope0 = txp.chain[0].tssi_slope;
2291590Srgrimes		t.offset0 = txp.chain[0].tssi_offset;
23077274Smikeh		t.slope1 = txp.chain[1].tssi_slope;
2311590Srgrimes		t.offset1 = txp.chain[1].tssi_offset;
2321590Srgrimes		mt76x2_mcu_tssi_comp(dev, &t);
2331590Srgrimes
2341590Srgrimes		if (t.pa_mode || dev->cal.dpd_cal_done || dev->ed_tx_blocked)
2351590Srgrimes			return;
23677274Smikeh
23777274Smikeh		usleep_range(10000, 20000);
2381590Srgrimes		mt76x02_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value);
23977274Smikeh		dev->cal.dpd_cal_done = true;
2401590Srgrimes	}
2411590Srgrimes}
2421590SrgrimesEXPORT_SYMBOL_GPL(mt76x2_phy_tssi_compensate);
2431590Srgrimes
2441590Srgrimesstatic void
2451590Srgrimesmt76x2_phy_set_gain_val(struct mt76x02_dev *dev)
2461590Srgrimes{
247216564Scharnier	u32 val;
248216564Scharnier	u8 gain_val[2];
2491590Srgrimes
2501590Srgrimes	gain_val[0] = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust;
2511590Srgrimes	gain_val[1] = dev->cal.agc_gain_cur[1] - dev->cal.agc_gain_adjust;
2521590Srgrimes
2531590Srgrimes	val = 0x1836 << 16;
2541590Srgrimes	if (!mt76x2_has_ext_lna(dev) &&
2551590Srgrimes	    dev->mphy.chandef.width >= NL80211_CHAN_WIDTH_40)
2561590Srgrimes		val = 0x1e42 << 16;
25732189Sjoerg
25877274Smikeh	if (mt76x2_has_ext_lna(dev) &&
2591590Srgrimes	    dev->mphy.chandef.chan->band == NL80211_BAND_2GHZ &&
26077274Smikeh	    dev->mphy.chandef.width < NL80211_CHAN_WIDTH_40)
2611590Srgrimes		val = 0x0f36 << 16;
2621590Srgrimes
2631590Srgrimes	val |= 0xf8;
2641590Srgrimes
2651590Srgrimes	mt76_wr(dev, MT_BBP(AGC, 8),
2661590Srgrimes		val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[0]));
2671590Srgrimes	mt76_wr(dev, MT_BBP(AGC, 9),
2681590Srgrimes		val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[1]));
269216564Scharnier
2701590Srgrimes	if (dev->mphy.chandef.chan->flags & IEEE80211_CHAN_RADAR)
2711590Srgrimes		mt76x02_phy_dfs_adjust_agc(dev);
2721590Srgrimes}
2731590Srgrimes
27477274Smikehvoid mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev)
27577274Smikeh{
27677274Smikeh	u8 *gain = dev->cal.agc_gain_init;
27777274Smikeh	u8 low_gain_delta, gain_delta;
27878193Smikeh	u32 agc_35, agc_37;
27977274Smikeh	bool gain_change;
2801590Srgrimes	int low_gain;
28177274Smikeh	u32 val;
2821590Srgrimes
2831590Srgrimes	dev->cal.avg_rssi_all = mt76_get_min_avg_rssi(&dev->mt76, false);
2841590Srgrimes	if (!dev->cal.avg_rssi_all)
2851590Srgrimes		dev->cal.avg_rssi_all = -75;
2861590Srgrimes
2871590Srgrimes	low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) +
2881590Srgrimes		(dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev));
289216564Scharnier
2901590Srgrimes	gain_change = dev->cal.low_gain < 0 ||
2911590Srgrimes		      (dev->cal.low_gain & 2) ^ (low_gain & 2);
292126415Smikeh	dev->cal.low_gain = low_gain;
2931590Srgrimes
2941590Srgrimes	if (!gain_change) {
295126415Smikeh		if (mt76x02_phy_adjust_vga_gain(dev))
2961590Srgrimes			mt76x2_phy_set_gain_val(dev);
2971590Srgrimes		return;
2981590Srgrimes	}
2991590Srgrimes
3001590Srgrimes	if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_80) {
3011590Srgrimes		mt76_wr(dev, MT_BBP(RXO, 14), 0x00560211);
3021590Srgrimes		val = mt76_rr(dev, MT_BBP(AGC, 26)) & ~0xf;
3031590Srgrimes		if (low_gain == 2)
30477274Smikeh			val |= 0x3;
30588150Smikeh		else
30688150Smikeh			val |= 0x5;
30788150Smikeh		mt76_wr(dev, MT_BBP(AGC, 26), val);
30888150Smikeh	} else {
30988150Smikeh		mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423);
31088150Smikeh	}
3111590Srgrimes
31277274Smikeh	if (mt76x2_has_ext_lna(dev))
3131590Srgrimes		low_gain_delta = 10;
31474769Smikeh	else
31574769Smikeh		low_gain_delta = 14;
31678904Smikeh
31778904Smikeh	agc_37 = 0x2121262c;
31877274Smikeh	if (dev->mphy.chandef.chan->band == NL80211_BAND_2GHZ)
3191590Srgrimes		agc_35 = 0x11111516;
3201590Srgrimes	else if (low_gain == 2)
3211590Srgrimes		agc_35 = agc_37 = 0x08080808;
32274769Smikeh	else if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_80)
3231590Srgrimes		agc_35 = 0x10101014;
3241590Srgrimes	else
3251590Srgrimes		agc_35 = 0x11111116;
3261590Srgrimes
3271590Srgrimes	if (low_gain == 2) {
3281590Srgrimes		mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990);
3291590Srgrimes		mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808);
33077274Smikeh		mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808);
3311590Srgrimes		gain_delta = low_gain_delta;
3321590Srgrimes		dev->cal.agc_gain_adjust = 0;
3331590Srgrimes	} else {
3341590Srgrimes		mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991);
3351590Srgrimes		gain_delta = 0;
3361590Srgrimes		dev->cal.agc_gain_adjust = low_gain_delta;
3371590Srgrimes	}
3381590Srgrimes
3391590Srgrimes	mt76_wr(dev, MT_BBP(AGC, 35), agc_35);
3401590Srgrimes	mt76_wr(dev, MT_BBP(AGC, 37), agc_37);
3411590Srgrimes
3421590Srgrimes	dev->cal.agc_gain_cur[0] = gain[0] - gain_delta;
3431590Srgrimes	dev->cal.agc_gain_cur[1] = gain[1] - gain_delta;
344126415Smikeh	mt76x2_phy_set_gain_val(dev);
345126415Smikeh
346126415Smikeh	/* clear false CCA counters */
347126415Smikeh	mt76_rr(dev, MT_RX_STAT_1);
348126415Smikeh}
349126415SmikehEXPORT_SYMBOL_GPL(mt76x2_phy_update_channel_gain);
350126415Smikeh