xref: /freebsd/sys/contrib/dev/mediatek/mt76/mt76x02_phy.c (revision cbb3ec25236ba72f91cbdf23f8b78b9d1af0cedf)
16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb /*
36c92544dSBjoern A. Zeeb  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
46c92544dSBjoern A. Zeeb  * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
56c92544dSBjoern A. Zeeb  */
66c92544dSBjoern A. Zeeb 
76c92544dSBjoern A. Zeeb #include <linux/kernel.h>
86c92544dSBjoern A. Zeeb 
96c92544dSBjoern A. Zeeb #include "mt76x02.h"
106c92544dSBjoern A. Zeeb #include "mt76x02_phy.h"
116c92544dSBjoern A. Zeeb 
mt76x02_phy_set_rxpath(struct mt76x02_dev * dev)126c92544dSBjoern A. Zeeb void mt76x02_phy_set_rxpath(struct mt76x02_dev *dev)
136c92544dSBjoern A. Zeeb {
146c92544dSBjoern A. Zeeb 	u32 val;
156c92544dSBjoern A. Zeeb 
166c92544dSBjoern A. Zeeb 	val = mt76_rr(dev, MT_BBP(AGC, 0));
176c92544dSBjoern A. Zeeb 	val &= ~BIT(4);
186c92544dSBjoern A. Zeeb 
196c92544dSBjoern A. Zeeb 	switch (dev->mphy.chainmask & 0xf) {
206c92544dSBjoern A. Zeeb 	case 2:
216c92544dSBjoern A. Zeeb 		val |= BIT(3);
226c92544dSBjoern A. Zeeb 		break;
236c92544dSBjoern A. Zeeb 	default:
246c92544dSBjoern A. Zeeb 		val &= ~BIT(3);
256c92544dSBjoern A. Zeeb 		break;
266c92544dSBjoern A. Zeeb 	}
276c92544dSBjoern A. Zeeb 
286c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_BBP(AGC, 0), val);
296c92544dSBjoern A. Zeeb 	mb();
306c92544dSBjoern A. Zeeb 	val = mt76_rr(dev, MT_BBP(AGC, 0));
316c92544dSBjoern A. Zeeb }
326c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_phy_set_rxpath);
336c92544dSBjoern A. Zeeb 
mt76x02_phy_set_txdac(struct mt76x02_dev * dev)346c92544dSBjoern A. Zeeb void mt76x02_phy_set_txdac(struct mt76x02_dev *dev)
356c92544dSBjoern A. Zeeb {
366c92544dSBjoern A. Zeeb 	int txpath;
376c92544dSBjoern A. Zeeb 
386c92544dSBjoern A. Zeeb 	txpath = (dev->mphy.chainmask >> 8) & 0xf;
396c92544dSBjoern A. Zeeb 	switch (txpath) {
406c92544dSBjoern A. Zeeb 	case 2:
416c92544dSBjoern A. Zeeb 		mt76_set(dev, MT_BBP(TXBE, 5), 0x3);
426c92544dSBjoern A. Zeeb 		break;
436c92544dSBjoern A. Zeeb 	default:
446c92544dSBjoern A. Zeeb 		mt76_clear(dev, MT_BBP(TXBE, 5), 0x3);
456c92544dSBjoern A. Zeeb 		break;
466c92544dSBjoern A. Zeeb 	}
476c92544dSBjoern A. Zeeb }
486c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_phy_set_txdac);
496c92544dSBjoern A. Zeeb 
506c92544dSBjoern A. Zeeb static u32
mt76x02_tx_power_mask(u8 v1,u8 v2,u8 v3,u8 v4)516c92544dSBjoern A. Zeeb mt76x02_tx_power_mask(u8 v1, u8 v2, u8 v3, u8 v4)
526c92544dSBjoern A. Zeeb {
536c92544dSBjoern A. Zeeb 	u32 val = 0;
546c92544dSBjoern A. Zeeb 
556c92544dSBjoern A. Zeeb 	val |= (v1 & (BIT(6) - 1)) << 0;
566c92544dSBjoern A. Zeeb 	val |= (v2 & (BIT(6) - 1)) << 8;
576c92544dSBjoern A. Zeeb 	val |= (v3 & (BIT(6) - 1)) << 16;
586c92544dSBjoern A. Zeeb 	val |= (v4 & (BIT(6) - 1)) << 24;
596c92544dSBjoern A. Zeeb 	return val;
606c92544dSBjoern A. Zeeb }
616c92544dSBjoern A. Zeeb 
mt76x02_get_max_rate_power(struct mt76x02_rate_power * r)62*cbb3ec25SBjoern A. Zeeb int mt76x02_get_max_rate_power(struct mt76x02_rate_power *r)
636c92544dSBjoern A. Zeeb {
646c92544dSBjoern A. Zeeb 	s8 ret = 0;
656c92544dSBjoern A. Zeeb 	int i;
666c92544dSBjoern A. Zeeb 
676c92544dSBjoern A. Zeeb 	for (i = 0; i < sizeof(r->all); i++)
686c92544dSBjoern A. Zeeb 		ret = max(ret, r->all[i]);
696c92544dSBjoern A. Zeeb 
706c92544dSBjoern A. Zeeb 	return ret;
716c92544dSBjoern A. Zeeb }
726c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_get_max_rate_power);
736c92544dSBjoern A. Zeeb 
mt76x02_limit_rate_power(struct mt76x02_rate_power * r,int limit)74*cbb3ec25SBjoern A. Zeeb void mt76x02_limit_rate_power(struct mt76x02_rate_power *r, int limit)
756c92544dSBjoern A. Zeeb {
766c92544dSBjoern A. Zeeb 	int i;
776c92544dSBjoern A. Zeeb 
786c92544dSBjoern A. Zeeb 	for (i = 0; i < sizeof(r->all); i++)
796c92544dSBjoern A. Zeeb 		if (r->all[i] > limit)
806c92544dSBjoern A. Zeeb 			r->all[i] = limit;
816c92544dSBjoern A. Zeeb }
826c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_limit_rate_power);
836c92544dSBjoern A. Zeeb 
mt76x02_add_rate_power_offset(struct mt76x02_rate_power * r,int offset)84*cbb3ec25SBjoern A. Zeeb void mt76x02_add_rate_power_offset(struct mt76x02_rate_power *r, int offset)
856c92544dSBjoern A. Zeeb {
866c92544dSBjoern A. Zeeb 	int i;
876c92544dSBjoern A. Zeeb 
886c92544dSBjoern A. Zeeb 	for (i = 0; i < sizeof(r->all); i++)
896c92544dSBjoern A. Zeeb 		r->all[i] += offset;
906c92544dSBjoern A. Zeeb }
916c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_add_rate_power_offset);
926c92544dSBjoern A. Zeeb 
mt76x02_phy_set_txpower(struct mt76x02_dev * dev,int txp_0,int txp_1)936c92544dSBjoern A. Zeeb void mt76x02_phy_set_txpower(struct mt76x02_dev *dev, int txp_0, int txp_1)
946c92544dSBjoern A. Zeeb {
95*cbb3ec25SBjoern A. Zeeb 	struct mt76x02_rate_power *t = &dev->rate_power;
966c92544dSBjoern A. Zeeb 
976c92544dSBjoern A. Zeeb 	mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, txp_0);
986c92544dSBjoern A. Zeeb 	mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, txp_1);
996c92544dSBjoern A. Zeeb 
1006c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TX_PWR_CFG_0,
1016c92544dSBjoern A. Zeeb 		mt76x02_tx_power_mask(t->cck[0], t->cck[2], t->ofdm[0],
1026c92544dSBjoern A. Zeeb 				      t->ofdm[2]));
1036c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TX_PWR_CFG_1,
1046c92544dSBjoern A. Zeeb 		mt76x02_tx_power_mask(t->ofdm[4], t->ofdm[6], t->ht[0],
1056c92544dSBjoern A. Zeeb 				      t->ht[2]));
1066c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TX_PWR_CFG_2,
1076c92544dSBjoern A. Zeeb 		mt76x02_tx_power_mask(t->ht[4], t->ht[6], t->ht[8],
1086c92544dSBjoern A. Zeeb 				      t->ht[10]));
1096c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TX_PWR_CFG_3,
110*cbb3ec25SBjoern A. Zeeb 		mt76x02_tx_power_mask(t->ht[12], t->ht[14], t->ht[0],
111*cbb3ec25SBjoern A. Zeeb 				      t->ht[2]));
1126c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TX_PWR_CFG_4,
113*cbb3ec25SBjoern A. Zeeb 		mt76x02_tx_power_mask(t->ht[4], t->ht[6], 0, 0));
1146c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TX_PWR_CFG_7,
115*cbb3ec25SBjoern A. Zeeb 		mt76x02_tx_power_mask(t->ofdm[7], t->vht[0], t->ht[7],
116*cbb3ec25SBjoern A. Zeeb 				      t->vht[1]));
1176c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TX_PWR_CFG_8,
118*cbb3ec25SBjoern A. Zeeb 		mt76x02_tx_power_mask(t->ht[14], 0, t->vht[0], t->vht[1]));
1196c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TX_PWR_CFG_9,
120*cbb3ec25SBjoern A. Zeeb 		mt76x02_tx_power_mask(t->ht[7], 0, t->vht[0], t->vht[1]));
1216c92544dSBjoern A. Zeeb }
1226c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_phy_set_txpower);
1236c92544dSBjoern A. Zeeb 
mt76x02_phy_set_bw(struct mt76x02_dev * dev,int width,u8 ctrl)1246c92544dSBjoern A. Zeeb void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl)
1256c92544dSBjoern A. Zeeb {
1266c92544dSBjoern A. Zeeb 	int core_val, agc_val;
1276c92544dSBjoern A. Zeeb 
1286c92544dSBjoern A. Zeeb 	switch (width) {
1296c92544dSBjoern A. Zeeb 	case NL80211_CHAN_WIDTH_80:
1306c92544dSBjoern A. Zeeb 		core_val = 3;
1316c92544dSBjoern A. Zeeb 		agc_val = 7;
1326c92544dSBjoern A. Zeeb 		break;
1336c92544dSBjoern A. Zeeb 	case NL80211_CHAN_WIDTH_40:
1346c92544dSBjoern A. Zeeb 		core_val = 2;
1356c92544dSBjoern A. Zeeb 		agc_val = 3;
1366c92544dSBjoern A. Zeeb 		break;
1376c92544dSBjoern A. Zeeb 	default:
1386c92544dSBjoern A. Zeeb 		core_val = 0;
1396c92544dSBjoern A. Zeeb 		agc_val = 1;
1406c92544dSBjoern A. Zeeb 		break;
1416c92544dSBjoern A. Zeeb 	}
1426c92544dSBjoern A. Zeeb 
1436c92544dSBjoern A. Zeeb 	mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val);
1446c92544dSBjoern A. Zeeb 	mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val);
1456c92544dSBjoern A. Zeeb 	mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl);
1466c92544dSBjoern A. Zeeb 	mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl);
1476c92544dSBjoern A. Zeeb }
1486c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_phy_set_bw);
1496c92544dSBjoern A. Zeeb 
mt76x02_phy_set_band(struct mt76x02_dev * dev,int band,bool primary_upper)1506c92544dSBjoern A. Zeeb void mt76x02_phy_set_band(struct mt76x02_dev *dev, int band,
1516c92544dSBjoern A. Zeeb 			  bool primary_upper)
1526c92544dSBjoern A. Zeeb {
1536c92544dSBjoern A. Zeeb 	switch (band) {
1546c92544dSBjoern A. Zeeb 	case NL80211_BAND_2GHZ:
1556c92544dSBjoern A. Zeeb 		mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G);
1566c92544dSBjoern A. Zeeb 		mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G);
1576c92544dSBjoern A. Zeeb 		break;
1586c92544dSBjoern A. Zeeb 	case NL80211_BAND_5GHZ:
1596c92544dSBjoern A. Zeeb 		mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G);
1606c92544dSBjoern A. Zeeb 		mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G);
1616c92544dSBjoern A. Zeeb 		break;
1626c92544dSBjoern A. Zeeb 	}
1636c92544dSBjoern A. Zeeb 
1646c92544dSBjoern A. Zeeb 	mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M,
1656c92544dSBjoern A. Zeeb 		       primary_upper);
1666c92544dSBjoern A. Zeeb }
1676c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_phy_set_band);
1686c92544dSBjoern A. Zeeb 
mt76x02_phy_adjust_vga_gain(struct mt76x02_dev * dev)1696c92544dSBjoern A. Zeeb bool mt76x02_phy_adjust_vga_gain(struct mt76x02_dev *dev)
1706c92544dSBjoern A. Zeeb {
1716c92544dSBjoern A. Zeeb 	u8 limit = dev->cal.low_gain > 0 ? 16 : 4;
1726c92544dSBjoern A. Zeeb 	bool ret = false;
1736c92544dSBjoern A. Zeeb 	u32 false_cca;
1746c92544dSBjoern A. Zeeb 
1756c92544dSBjoern A. Zeeb 	false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS,
1766c92544dSBjoern A. Zeeb 			      mt76_rr(dev, MT_RX_STAT_1));
1776c92544dSBjoern A. Zeeb 	dev->cal.false_cca = false_cca;
1786c92544dSBjoern A. Zeeb 	if (false_cca > 800 && dev->cal.agc_gain_adjust < limit) {
1796c92544dSBjoern A. Zeeb 		dev->cal.agc_gain_adjust += 2;
1806c92544dSBjoern A. Zeeb 		ret = true;
1816c92544dSBjoern A. Zeeb 	} else if ((false_cca < 10 && dev->cal.agc_gain_adjust > 0) ||
1826c92544dSBjoern A. Zeeb 		   (dev->cal.agc_gain_adjust >= limit && false_cca < 500)) {
1836c92544dSBjoern A. Zeeb 		dev->cal.agc_gain_adjust -= 2;
1846c92544dSBjoern A. Zeeb 		ret = true;
1856c92544dSBjoern A. Zeeb 	}
1866c92544dSBjoern A. Zeeb 
1876c92544dSBjoern A. Zeeb 	dev->cal.agc_lowest_gain = dev->cal.agc_gain_adjust >= limit;
1886c92544dSBjoern A. Zeeb 
1896c92544dSBjoern A. Zeeb 	return ret;
1906c92544dSBjoern A. Zeeb }
1916c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_phy_adjust_vga_gain);
1926c92544dSBjoern A. Zeeb 
mt76x02_init_agc_gain(struct mt76x02_dev * dev)1936c92544dSBjoern A. Zeeb void mt76x02_init_agc_gain(struct mt76x02_dev *dev)
1946c92544dSBjoern A. Zeeb {
1956c92544dSBjoern A. Zeeb 	dev->cal.agc_gain_init[0] = mt76_get_field(dev, MT_BBP(AGC, 8),
1966c92544dSBjoern A. Zeeb 						   MT_BBP_AGC_GAIN);
1976c92544dSBjoern A. Zeeb 	dev->cal.agc_gain_init[1] = mt76_get_field(dev, MT_BBP(AGC, 9),
1986c92544dSBjoern A. Zeeb 						   MT_BBP_AGC_GAIN);
1996c92544dSBjoern A. Zeeb 	memcpy(dev->cal.agc_gain_cur, dev->cal.agc_gain_init,
2006c92544dSBjoern A. Zeeb 	       sizeof(dev->cal.agc_gain_cur));
2016c92544dSBjoern A. Zeeb 	dev->cal.low_gain = -1;
2026c92544dSBjoern A. Zeeb 	dev->cal.gain_init_done = true;
2036c92544dSBjoern A. Zeeb }
2046c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_init_agc_gain);
205