xref: /freebsd/sys/contrib/dev/rtw89/phy.c (revision 118d0ff54d4f7cffe6a13a1e0cdb2fe23fbfce74)
18e93258fSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
28e93258fSBjoern A. Zeeb /* Copyright(c) 2019-2020  Realtek Corporation
38e93258fSBjoern A. Zeeb  */
48e93258fSBjoern A. Zeeb 
5e2340276SBjoern A. Zeeb #include "coex.h"
68e93258fSBjoern A. Zeeb #include "debug.h"
78e93258fSBjoern A. Zeeb #include "fw.h"
88e93258fSBjoern A. Zeeb #include "mac.h"
98e93258fSBjoern A. Zeeb #include "phy.h"
108e93258fSBjoern A. Zeeb #include "ps.h"
118e93258fSBjoern A. Zeeb #include "reg.h"
128e93258fSBjoern A. Zeeb #include "sar.h"
13e2340276SBjoern A. Zeeb #include "txrx.h"
14e2340276SBjoern A. Zeeb #include "util.h"
158e93258fSBjoern A. Zeeb 
168e93258fSBjoern A. Zeeb static u16 get_max_amsdu_len(struct rtw89_dev *rtwdev,
178e93258fSBjoern A. Zeeb 			     const struct rtw89_ra_report *report)
188e93258fSBjoern A. Zeeb {
198e93258fSBjoern A. Zeeb 	u32 bit_rate = report->bit_rate;
208e93258fSBjoern A. Zeeb 
218e93258fSBjoern A. Zeeb 	/* lower than ofdm, do not aggregate */
228e93258fSBjoern A. Zeeb 	if (bit_rate < 550)
238e93258fSBjoern A. Zeeb 		return 1;
248e93258fSBjoern A. Zeeb 
258e93258fSBjoern A. Zeeb 	/* avoid AMSDU for legacy rate */
268e93258fSBjoern A. Zeeb 	if (report->might_fallback_legacy)
278e93258fSBjoern A. Zeeb 		return 1;
288e93258fSBjoern A. Zeeb 
298e93258fSBjoern A. Zeeb 	/* lower than 20M vht 2ss mcs8, make it small */
308e93258fSBjoern A. Zeeb 	if (bit_rate < 1800)
318e93258fSBjoern A. Zeeb 		return 1200;
328e93258fSBjoern A. Zeeb 
338e93258fSBjoern A. Zeeb 	/* lower than 40M vht 2ss mcs9, make it medium */
348e93258fSBjoern A. Zeeb 	if (bit_rate < 4000)
358e93258fSBjoern A. Zeeb 		return 2600;
368e93258fSBjoern A. Zeeb 
378e93258fSBjoern A. Zeeb 	/* not yet 80M vht 2ss mcs8/9, make it twice regular packet size */
388e93258fSBjoern A. Zeeb 	if (bit_rate < 7000)
398e93258fSBjoern A. Zeeb 		return 3500;
408e93258fSBjoern A. Zeeb 
418e93258fSBjoern A. Zeeb 	return rtwdev->chip->max_amsdu_limit;
428e93258fSBjoern A. Zeeb }
438e93258fSBjoern A. Zeeb 
448e93258fSBjoern A. Zeeb static u64 get_mcs_ra_mask(u16 mcs_map, u8 highest_mcs, u8 gap)
458e93258fSBjoern A. Zeeb {
468e93258fSBjoern A. Zeeb 	u64 ra_mask = 0;
478e93258fSBjoern A. Zeeb 	u8 mcs_cap;
488e93258fSBjoern A. Zeeb 	int i, nss;
498e93258fSBjoern A. Zeeb 
508e93258fSBjoern A. Zeeb 	for (i = 0, nss = 12; i < 4; i++, mcs_map >>= 2, nss += 12) {
518e93258fSBjoern A. Zeeb 		mcs_cap = mcs_map & 0x3;
528e93258fSBjoern A. Zeeb 		switch (mcs_cap) {
538e93258fSBjoern A. Zeeb 		case 2:
548e93258fSBjoern A. Zeeb 			ra_mask |= GENMASK_ULL(highest_mcs, 0) << nss;
558e93258fSBjoern A. Zeeb 			break;
568e93258fSBjoern A. Zeeb 		case 1:
578e93258fSBjoern A. Zeeb 			ra_mask |= GENMASK_ULL(highest_mcs - gap, 0) << nss;
588e93258fSBjoern A. Zeeb 			break;
598e93258fSBjoern A. Zeeb 		case 0:
608e93258fSBjoern A. Zeeb 			ra_mask |= GENMASK_ULL(highest_mcs - gap * 2, 0) << nss;
618e93258fSBjoern A. Zeeb 			break;
628e93258fSBjoern A. Zeeb 		default:
638e93258fSBjoern A. Zeeb 			break;
648e93258fSBjoern A. Zeeb 		}
658e93258fSBjoern A. Zeeb 	}
668e93258fSBjoern A. Zeeb 
678e93258fSBjoern A. Zeeb 	return ra_mask;
688e93258fSBjoern A. Zeeb }
698e93258fSBjoern A. Zeeb 
708e93258fSBjoern A. Zeeb static u64 get_he_ra_mask(struct ieee80211_sta *sta)
718e93258fSBjoern A. Zeeb {
728e93258fSBjoern A. Zeeb 	struct ieee80211_sta_he_cap cap = sta->deflink.he_cap;
738e93258fSBjoern A. Zeeb 	u16 mcs_map;
748e93258fSBjoern A. Zeeb 
758e93258fSBjoern A. Zeeb 	switch (sta->deflink.bandwidth) {
768e93258fSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_160:
778e93258fSBjoern A. Zeeb 		if (cap.he_cap_elem.phy_cap_info[0] &
788e93258fSBjoern A. Zeeb 		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
798e93258fSBjoern A. Zeeb 			mcs_map = le16_to_cpu(cap.he_mcs_nss_supp.rx_mcs_80p80);
808e93258fSBjoern A. Zeeb 		else
818e93258fSBjoern A. Zeeb 			mcs_map = le16_to_cpu(cap.he_mcs_nss_supp.rx_mcs_160);
828e93258fSBjoern A. Zeeb 		break;
838e93258fSBjoern A. Zeeb 	default:
848e93258fSBjoern A. Zeeb 		mcs_map = le16_to_cpu(cap.he_mcs_nss_supp.rx_mcs_80);
858e93258fSBjoern A. Zeeb 	}
868e93258fSBjoern A. Zeeb 
878e93258fSBjoern A. Zeeb 	/* MCS11, MCS9, MCS7 */
888e93258fSBjoern A. Zeeb 	return get_mcs_ra_mask(mcs_map, 11, 2);
898e93258fSBjoern A. Zeeb }
908e93258fSBjoern A. Zeeb 
918e93258fSBjoern A. Zeeb #define RA_FLOOR_TABLE_SIZE	7
928e93258fSBjoern A. Zeeb #define RA_FLOOR_UP_GAP		3
938e93258fSBjoern A. Zeeb static u64 rtw89_phy_ra_mask_rssi(struct rtw89_dev *rtwdev, u8 rssi,
948e93258fSBjoern A. Zeeb 				  u8 ratr_state)
958e93258fSBjoern A. Zeeb {
968e93258fSBjoern A. Zeeb 	u8 rssi_lv_t[RA_FLOOR_TABLE_SIZE] = {30, 44, 48, 52, 56, 60, 100};
978e93258fSBjoern A. Zeeb 	u8 rssi_lv = 0;
988e93258fSBjoern A. Zeeb 	u8 i;
998e93258fSBjoern A. Zeeb 
1008e93258fSBjoern A. Zeeb 	rssi >>= 1;
1018e93258fSBjoern A. Zeeb 	for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++) {
1028e93258fSBjoern A. Zeeb 		if (i >= ratr_state)
1038e93258fSBjoern A. Zeeb 			rssi_lv_t[i] += RA_FLOOR_UP_GAP;
1048e93258fSBjoern A. Zeeb 		if (rssi < rssi_lv_t[i]) {
1058e93258fSBjoern A. Zeeb 			rssi_lv = i;
1068e93258fSBjoern A. Zeeb 			break;
1078e93258fSBjoern A. Zeeb 		}
1088e93258fSBjoern A. Zeeb 	}
1098e93258fSBjoern A. Zeeb 	if (rssi_lv == 0)
1108e93258fSBjoern A. Zeeb 		return 0xffffffffffffffffULL;
1118e93258fSBjoern A. Zeeb 	else if (rssi_lv == 1)
1128e93258fSBjoern A. Zeeb 		return 0xfffffffffffffff0ULL;
1138e93258fSBjoern A. Zeeb 	else if (rssi_lv == 2)
1148e93258fSBjoern A. Zeeb 		return 0xffffffffffffefe0ULL;
1158e93258fSBjoern A. Zeeb 	else if (rssi_lv == 3)
1168e93258fSBjoern A. Zeeb 		return 0xffffffffffffcfc0ULL;
1178e93258fSBjoern A. Zeeb 	else if (rssi_lv == 4)
1188e93258fSBjoern A. Zeeb 		return 0xffffffffffff8f80ULL;
1198e93258fSBjoern A. Zeeb 	else if (rssi_lv >= 5)
1208e93258fSBjoern A. Zeeb 		return 0xffffffffffff0f00ULL;
1218e93258fSBjoern A. Zeeb 
1228e93258fSBjoern A. Zeeb 	return 0xffffffffffffffffULL;
1238e93258fSBjoern A. Zeeb }
1248e93258fSBjoern A. Zeeb 
1258e93258fSBjoern A. Zeeb static u64 rtw89_phy_ra_mask_recover(u64 ra_mask, u64 ra_mask_bak)
1268e93258fSBjoern A. Zeeb {
1278e93258fSBjoern A. Zeeb 	if ((ra_mask & ~(RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES)) == 0)
1288e93258fSBjoern A. Zeeb 		ra_mask |= (ra_mask_bak & ~(RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES));
1298e93258fSBjoern A. Zeeb 
1308e93258fSBjoern A. Zeeb 	if (ra_mask == 0)
1318e93258fSBjoern A. Zeeb 		ra_mask |= (ra_mask_bak & (RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES));
1328e93258fSBjoern A. Zeeb 
1338e93258fSBjoern A. Zeeb 	return ra_mask;
1348e93258fSBjoern A. Zeeb }
1358e93258fSBjoern A. Zeeb 
1368e93258fSBjoern A. Zeeb static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta)
1378e93258fSBjoern A. Zeeb {
1388e93258fSBjoern A. Zeeb 	struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
1398e93258fSBjoern A. Zeeb 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
1408e93258fSBjoern A. Zeeb 	struct cfg80211_bitrate_mask *mask = &rtwsta->mask;
1418e93258fSBjoern A. Zeeb 	enum nl80211_band band;
1428e93258fSBjoern A. Zeeb 	u64 cfg_mask;
1438e93258fSBjoern A. Zeeb 
1448e93258fSBjoern A. Zeeb 	if (!rtwsta->use_cfg_mask)
1458e93258fSBjoern A. Zeeb 		return -1;
1468e93258fSBjoern A. Zeeb 
1478e93258fSBjoern A. Zeeb 	switch (chan->band_type) {
1488e93258fSBjoern A. Zeeb 	case RTW89_BAND_2G:
1498e93258fSBjoern A. Zeeb 		band = NL80211_BAND_2GHZ;
1508e93258fSBjoern A. Zeeb 		cfg_mask = u64_encode_bits(mask->control[NL80211_BAND_2GHZ].legacy,
1518e93258fSBjoern A. Zeeb 					   RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES);
1528e93258fSBjoern A. Zeeb 		break;
1538e93258fSBjoern A. Zeeb 	case RTW89_BAND_5G:
1548e93258fSBjoern A. Zeeb 		band = NL80211_BAND_5GHZ;
1558e93258fSBjoern A. Zeeb 		cfg_mask = u64_encode_bits(mask->control[NL80211_BAND_5GHZ].legacy,
1568e93258fSBjoern A. Zeeb 					   RA_MASK_OFDM_RATES);
1578e93258fSBjoern A. Zeeb 		break;
1588e93258fSBjoern A. Zeeb 	case RTW89_BAND_6G:
1598e93258fSBjoern A. Zeeb 		band = NL80211_BAND_6GHZ;
1608e93258fSBjoern A. Zeeb 		cfg_mask = u64_encode_bits(mask->control[NL80211_BAND_6GHZ].legacy,
1618e93258fSBjoern A. Zeeb 					   RA_MASK_OFDM_RATES);
1628e93258fSBjoern A. Zeeb 		break;
1638e93258fSBjoern A. Zeeb 	default:
1648e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "unhandled band type %d\n", chan->band_type);
1658e93258fSBjoern A. Zeeb 		return -1;
1668e93258fSBjoern A. Zeeb 	}
1678e93258fSBjoern A. Zeeb 
1688e93258fSBjoern A. Zeeb 	if (sta->deflink.he_cap.has_he) {
1698e93258fSBjoern A. Zeeb 		cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[0],
1708e93258fSBjoern A. Zeeb 					    RA_MASK_HE_1SS_RATES);
1718e93258fSBjoern A. Zeeb 		cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[1],
1728e93258fSBjoern A. Zeeb 					    RA_MASK_HE_2SS_RATES);
1738e93258fSBjoern A. Zeeb 	} else if (sta->deflink.vht_cap.vht_supported) {
1748e93258fSBjoern A. Zeeb 		cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0],
1758e93258fSBjoern A. Zeeb 					    RA_MASK_VHT_1SS_RATES);
1768e93258fSBjoern A. Zeeb 		cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1],
1778e93258fSBjoern A. Zeeb 					    RA_MASK_VHT_2SS_RATES);
1788e93258fSBjoern A. Zeeb 	} else if (sta->deflink.ht_cap.ht_supported) {
1798e93258fSBjoern A. Zeeb 		cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0],
1808e93258fSBjoern A. Zeeb 					    RA_MASK_HT_1SS_RATES);
1818e93258fSBjoern A. Zeeb 		cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1],
1828e93258fSBjoern A. Zeeb 					    RA_MASK_HT_2SS_RATES);
1838e93258fSBjoern A. Zeeb 	}
1848e93258fSBjoern A. Zeeb 
1858e93258fSBjoern A. Zeeb 	return cfg_mask;
1868e93258fSBjoern A. Zeeb }
1878e93258fSBjoern A. Zeeb 
1888e93258fSBjoern A. Zeeb static const u64
1898e93258fSBjoern A. Zeeb rtw89_ra_mask_ht_rates[4] = {RA_MASK_HT_1SS_RATES, RA_MASK_HT_2SS_RATES,
1908e93258fSBjoern A. Zeeb 			     RA_MASK_HT_3SS_RATES, RA_MASK_HT_4SS_RATES};
1918e93258fSBjoern A. Zeeb static const u64
1928e93258fSBjoern A. Zeeb rtw89_ra_mask_vht_rates[4] = {RA_MASK_VHT_1SS_RATES, RA_MASK_VHT_2SS_RATES,
1938e93258fSBjoern A. Zeeb 			      RA_MASK_VHT_3SS_RATES, RA_MASK_VHT_4SS_RATES};
1948e93258fSBjoern A. Zeeb static const u64
1958e93258fSBjoern A. Zeeb rtw89_ra_mask_he_rates[4] = {RA_MASK_HE_1SS_RATES, RA_MASK_HE_2SS_RATES,
1968e93258fSBjoern A. Zeeb 			     RA_MASK_HE_3SS_RATES, RA_MASK_HE_4SS_RATES};
1978e93258fSBjoern A. Zeeb 
198e2340276SBjoern A. Zeeb static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev,
199e2340276SBjoern A. Zeeb 				struct rtw89_sta *rtwsta,
200e2340276SBjoern A. Zeeb 				bool *fix_giltf_en, u8 *fix_giltf)
201e2340276SBjoern A. Zeeb {
202e2340276SBjoern A. Zeeb 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
203e2340276SBjoern A. Zeeb 	struct cfg80211_bitrate_mask *mask = &rtwsta->mask;
204e2340276SBjoern A. Zeeb 	u8 band = chan->band_type;
205e2340276SBjoern A. Zeeb 	enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
206e2340276SBjoern A. Zeeb 	u8 he_gi = mask->control[nl_band].he_gi;
207e2340276SBjoern A. Zeeb 	u8 he_ltf = mask->control[nl_band].he_ltf;
208e2340276SBjoern A. Zeeb 
209e2340276SBjoern A. Zeeb 	if (!rtwsta->use_cfg_mask)
210e2340276SBjoern A. Zeeb 		return;
211e2340276SBjoern A. Zeeb 
212e2340276SBjoern A. Zeeb 	if (he_ltf == 2 && he_gi == 2) {
213e2340276SBjoern A. Zeeb 		*fix_giltf = RTW89_GILTF_LGI_4XHE32;
214e2340276SBjoern A. Zeeb 	} else if (he_ltf == 2 && he_gi == 0) {
215e2340276SBjoern A. Zeeb 		*fix_giltf = RTW89_GILTF_SGI_4XHE08;
216e2340276SBjoern A. Zeeb 	} else if (he_ltf == 1 && he_gi == 1) {
217e2340276SBjoern A. Zeeb 		*fix_giltf = RTW89_GILTF_2XHE16;
218e2340276SBjoern A. Zeeb 	} else if (he_ltf == 1 && he_gi == 0) {
219e2340276SBjoern A. Zeeb 		*fix_giltf = RTW89_GILTF_2XHE08;
220e2340276SBjoern A. Zeeb 	} else if (he_ltf == 0 && he_gi == 1) {
221e2340276SBjoern A. Zeeb 		*fix_giltf = RTW89_GILTF_1XHE16;
222e2340276SBjoern A. Zeeb 	} else if (he_ltf == 0 && he_gi == 0) {
223e2340276SBjoern A. Zeeb 		*fix_giltf = RTW89_GILTF_1XHE08;
224e2340276SBjoern A. Zeeb 	} else {
225e2340276SBjoern A. Zeeb 		*fix_giltf_en = false;
226e2340276SBjoern A. Zeeb 		return;
227e2340276SBjoern A. Zeeb 	}
228e2340276SBjoern A. Zeeb 
229e2340276SBjoern A. Zeeb 	*fix_giltf_en = true;
230e2340276SBjoern A. Zeeb }
231e2340276SBjoern A. Zeeb 
2328e93258fSBjoern A. Zeeb static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
2338e93258fSBjoern A. Zeeb 				    struct ieee80211_sta *sta, bool csi)
2348e93258fSBjoern A. Zeeb {
2358e93258fSBjoern A. Zeeb 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
2368e93258fSBjoern A. Zeeb 	struct rtw89_vif *rtwvif = rtwsta->rtwvif;
2378e93258fSBjoern A. Zeeb 	struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern;
2388e93258fSBjoern A. Zeeb 	struct rtw89_ra_info *ra = &rtwsta->ra;
2398e93258fSBjoern A. Zeeb 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
240e2340276SBjoern A. Zeeb 	struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif);
2418e93258fSBjoern A. Zeeb 	const u64 *high_rate_masks = rtw89_ra_mask_ht_rates;
2428e93258fSBjoern A. Zeeb 	u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi);
2438e93258fSBjoern A. Zeeb 	u64 ra_mask = 0;
2448e93258fSBjoern A. Zeeb 	u64 ra_mask_bak;
2458e93258fSBjoern A. Zeeb 	u8 mode = 0;
2468e93258fSBjoern A. Zeeb 	u8 csi_mode = RTW89_RA_RPT_MODE_LEGACY;
2478e93258fSBjoern A. Zeeb 	u8 bw_mode = 0;
2488e93258fSBjoern A. Zeeb 	u8 stbc_en = 0;
2498e93258fSBjoern A. Zeeb 	u8 ldpc_en = 0;
250e2340276SBjoern A. Zeeb 	u8 fix_giltf = 0;
2518e93258fSBjoern A. Zeeb 	u8 i;
2528e93258fSBjoern A. Zeeb 	bool sgi = false;
253e2340276SBjoern A. Zeeb 	bool fix_giltf_en = false;
2548e93258fSBjoern A. Zeeb 
2558e93258fSBjoern A. Zeeb 	memset(ra, 0, sizeof(*ra));
2568e93258fSBjoern A. Zeeb 	/* Set the ra mask from sta's capability */
2578e93258fSBjoern A. Zeeb 	if (sta->deflink.he_cap.has_he) {
2588e93258fSBjoern A. Zeeb 		mode |= RTW89_RA_MODE_HE;
2598e93258fSBjoern A. Zeeb 		csi_mode = RTW89_RA_RPT_MODE_HE;
2608e93258fSBjoern A. Zeeb 		ra_mask |= get_he_ra_mask(sta);
2618e93258fSBjoern A. Zeeb 		high_rate_masks = rtw89_ra_mask_he_rates;
2628e93258fSBjoern A. Zeeb 		if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[2] &
2638e93258fSBjoern A. Zeeb 		    IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
2648e93258fSBjoern A. Zeeb 			stbc_en = 1;
2658e93258fSBjoern A. Zeeb 		if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[1] &
2668e93258fSBjoern A. Zeeb 		    IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)
2678e93258fSBjoern A. Zeeb 			ldpc_en = 1;
268e2340276SBjoern A. Zeeb 		rtw89_phy_ra_gi_ltf(rtwdev, rtwsta, &fix_giltf_en, &fix_giltf);
2698e93258fSBjoern A. Zeeb 	} else if (sta->deflink.vht_cap.vht_supported) {
2708e93258fSBjoern A. Zeeb 		u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);
2718e93258fSBjoern A. Zeeb 
2728e93258fSBjoern A. Zeeb 		mode |= RTW89_RA_MODE_VHT;
2738e93258fSBjoern A. Zeeb 		csi_mode = RTW89_RA_RPT_MODE_VHT;
2748e93258fSBjoern A. Zeeb 		/* MCS9, MCS8, MCS7 */
2758e93258fSBjoern A. Zeeb 		ra_mask |= get_mcs_ra_mask(mcs_map, 9, 1);
2768e93258fSBjoern A. Zeeb 		high_rate_masks = rtw89_ra_mask_vht_rates;
2778e93258fSBjoern A. Zeeb 		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
2788e93258fSBjoern A. Zeeb 			stbc_en = 1;
2798e93258fSBjoern A. Zeeb 		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
2808e93258fSBjoern A. Zeeb 			ldpc_en = 1;
2818e93258fSBjoern A. Zeeb 	} else if (sta->deflink.ht_cap.ht_supported) {
2828e93258fSBjoern A. Zeeb 		mode |= RTW89_RA_MODE_HT;
2838e93258fSBjoern A. Zeeb 		csi_mode = RTW89_RA_RPT_MODE_HT;
2848e93258fSBjoern A. Zeeb 		ra_mask |= ((u64)sta->deflink.ht_cap.mcs.rx_mask[3] << 48) |
2858e93258fSBjoern A. Zeeb 			   ((u64)sta->deflink.ht_cap.mcs.rx_mask[2] << 36) |
2868e93258fSBjoern A. Zeeb 			   (sta->deflink.ht_cap.mcs.rx_mask[1] << 24) |
2878e93258fSBjoern A. Zeeb 			   (sta->deflink.ht_cap.mcs.rx_mask[0] << 12);
2888e93258fSBjoern A. Zeeb 		high_rate_masks = rtw89_ra_mask_ht_rates;
2898e93258fSBjoern A. Zeeb 		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
2908e93258fSBjoern A. Zeeb 			stbc_en = 1;
2918e93258fSBjoern A. Zeeb 		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)
2928e93258fSBjoern A. Zeeb 			ldpc_en = 1;
2938e93258fSBjoern A. Zeeb 	}
2948e93258fSBjoern A. Zeeb 
2958e93258fSBjoern A. Zeeb 	switch (chan->band_type) {
2968e93258fSBjoern A. Zeeb 	case RTW89_BAND_2G:
2978e93258fSBjoern A. Zeeb 		ra_mask |= sta->deflink.supp_rates[NL80211_BAND_2GHZ];
298e2340276SBjoern A. Zeeb 		if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xf)
2998e93258fSBjoern A. Zeeb 			mode |= RTW89_RA_MODE_CCK;
300e2340276SBjoern A. Zeeb 		if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xff0)
301e2340276SBjoern A. Zeeb 			mode |= RTW89_RA_MODE_OFDM;
3028e93258fSBjoern A. Zeeb 		break;
3038e93258fSBjoern A. Zeeb 	case RTW89_BAND_5G:
3048e93258fSBjoern A. Zeeb 		ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_5GHZ] << 4;
3058e93258fSBjoern A. Zeeb 		mode |= RTW89_RA_MODE_OFDM;
3068e93258fSBjoern A. Zeeb 		break;
3078e93258fSBjoern A. Zeeb 	case RTW89_BAND_6G:
3088e93258fSBjoern A. Zeeb 		ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_6GHZ] << 4;
3098e93258fSBjoern A. Zeeb 		mode |= RTW89_RA_MODE_OFDM;
3108e93258fSBjoern A. Zeeb 		break;
3118e93258fSBjoern A. Zeeb 	default:
3128e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "Unknown band type\n");
3138e93258fSBjoern A. Zeeb 		break;
3148e93258fSBjoern A. Zeeb 	}
3158e93258fSBjoern A. Zeeb 
3168e93258fSBjoern A. Zeeb 	ra_mask_bak = ra_mask;
3178e93258fSBjoern A. Zeeb 
3188e93258fSBjoern A. Zeeb 	if (mode >= RTW89_RA_MODE_HT) {
3198e93258fSBjoern A. Zeeb 		u64 mask = 0;
3208e93258fSBjoern A. Zeeb 		for (i = 0; i < rtwdev->hal.tx_nss; i++)
3218e93258fSBjoern A. Zeeb 			mask |= high_rate_masks[i];
3228e93258fSBjoern A. Zeeb 		if (mode & RTW89_RA_MODE_OFDM)
3238e93258fSBjoern A. Zeeb 			mask |= RA_MASK_SUBOFDM_RATES;
3248e93258fSBjoern A. Zeeb 		if (mode & RTW89_RA_MODE_CCK)
3258e93258fSBjoern A. Zeeb 			mask |= RA_MASK_SUBCCK_RATES;
3268e93258fSBjoern A. Zeeb 		ra_mask &= mask;
3278e93258fSBjoern A. Zeeb 	} else if (mode & RTW89_RA_MODE_OFDM) {
3288e93258fSBjoern A. Zeeb 		ra_mask &= (RA_MASK_OFDM_RATES | RA_MASK_SUBCCK_RATES);
3298e93258fSBjoern A. Zeeb 	}
3308e93258fSBjoern A. Zeeb 
3318e93258fSBjoern A. Zeeb 	if (mode != RTW89_RA_MODE_CCK)
3328e93258fSBjoern A. Zeeb 		ra_mask &= rtw89_phy_ra_mask_rssi(rtwdev, rssi, 0);
3338e93258fSBjoern A. Zeeb 
3348e93258fSBjoern A. Zeeb 	ra_mask = rtw89_phy_ra_mask_recover(ra_mask, ra_mask_bak);
3358e93258fSBjoern A. Zeeb 	ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta);
3368e93258fSBjoern A. Zeeb 
3378e93258fSBjoern A. Zeeb 	switch (sta->deflink.bandwidth) {
3388e93258fSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_160:
3398e93258fSBjoern A. Zeeb 		bw_mode = RTW89_CHANNEL_WIDTH_160;
3408e93258fSBjoern A. Zeeb 		sgi = sta->deflink.vht_cap.vht_supported &&
3418e93258fSBjoern A. Zeeb 		      (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
3428e93258fSBjoern A. Zeeb 		break;
3438e93258fSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_80:
3448e93258fSBjoern A. Zeeb 		bw_mode = RTW89_CHANNEL_WIDTH_80;
3458e93258fSBjoern A. Zeeb 		sgi = sta->deflink.vht_cap.vht_supported &&
3468e93258fSBjoern A. Zeeb 		      (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
3478e93258fSBjoern A. Zeeb 		break;
3488e93258fSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_40:
3498e93258fSBjoern A. Zeeb 		bw_mode = RTW89_CHANNEL_WIDTH_40;
3508e93258fSBjoern A. Zeeb 		sgi = sta->deflink.ht_cap.ht_supported &&
3518e93258fSBjoern A. Zeeb 		      (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
3528e93258fSBjoern A. Zeeb 		break;
3538e93258fSBjoern A. Zeeb 	default:
3548e93258fSBjoern A. Zeeb 		bw_mode = RTW89_CHANNEL_WIDTH_20;
3558e93258fSBjoern A. Zeeb 		sgi = sta->deflink.ht_cap.ht_supported &&
3568e93258fSBjoern A. Zeeb 		      (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
3578e93258fSBjoern A. Zeeb 		break;
3588e93258fSBjoern A. Zeeb 	}
3598e93258fSBjoern A. Zeeb 
3608e93258fSBjoern A. Zeeb 	if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[3] &
3618e93258fSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM)
3628e93258fSBjoern A. Zeeb 		ra->dcm_cap = 1;
3638e93258fSBjoern A. Zeeb 
364e2340276SBjoern A. Zeeb 	if (rate_pattern->enable && !vif->p2p) {
3658e93258fSBjoern A. Zeeb 		ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta);
3668e93258fSBjoern A. Zeeb 		ra_mask &= rate_pattern->ra_mask;
3678e93258fSBjoern A. Zeeb 		mode = rate_pattern->ra_mode;
3688e93258fSBjoern A. Zeeb 	}
3698e93258fSBjoern A. Zeeb 
3708e93258fSBjoern A. Zeeb 	ra->bw_cap = bw_mode;
371e2340276SBjoern A. Zeeb 	ra->er_cap = rtwsta->er_cap;
3728e93258fSBjoern A. Zeeb 	ra->mode_ctrl = mode;
3738e93258fSBjoern A. Zeeb 	ra->macid = rtwsta->mac_id;
3748e93258fSBjoern A. Zeeb 	ra->stbc_cap = stbc_en;
3758e93258fSBjoern A. Zeeb 	ra->ldpc_cap = ldpc_en;
3768e93258fSBjoern A. Zeeb 	ra->ss_num = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1;
3778e93258fSBjoern A. Zeeb 	ra->en_sgi = sgi;
3788e93258fSBjoern A. Zeeb 	ra->ra_mask = ra_mask;
379e2340276SBjoern A. Zeeb 	ra->fix_giltf_en = fix_giltf_en;
380e2340276SBjoern A. Zeeb 	ra->fix_giltf = fix_giltf;
3818e93258fSBjoern A. Zeeb 
3828e93258fSBjoern A. Zeeb 	if (!csi)
3838e93258fSBjoern A. Zeeb 		return;
3848e93258fSBjoern A. Zeeb 
3858e93258fSBjoern A. Zeeb 	ra->fixed_csi_rate_en = false;
3868e93258fSBjoern A. Zeeb 	ra->ra_csi_rate_en = true;
3878e93258fSBjoern A. Zeeb 	ra->cr_tbl_sel = false;
3888e93258fSBjoern A. Zeeb 	ra->band_num = rtwvif->phy_idx;
3898e93258fSBjoern A. Zeeb 	ra->csi_bw = bw_mode;
3908e93258fSBjoern A. Zeeb 	ra->csi_gi_ltf = RTW89_GILTF_LGI_4XHE32;
3918e93258fSBjoern A. Zeeb 	ra->csi_mcs_ss_idx = 5;
3928e93258fSBjoern A. Zeeb 	ra->csi_mode = csi_mode;
3938e93258fSBjoern A. Zeeb }
3948e93258fSBjoern A. Zeeb 
3958e93258fSBjoern A. Zeeb void rtw89_phy_ra_updata_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta,
3968e93258fSBjoern A. Zeeb 			     u32 changed)
3978e93258fSBjoern A. Zeeb {
3988e93258fSBjoern A. Zeeb 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
3998e93258fSBjoern A. Zeeb 	struct rtw89_ra_info *ra = &rtwsta->ra;
4008e93258fSBjoern A. Zeeb 
4018e93258fSBjoern A. Zeeb 	rtw89_phy_ra_sta_update(rtwdev, sta, false);
4028e93258fSBjoern A. Zeeb 
4038e93258fSBjoern A. Zeeb 	if (changed & IEEE80211_RC_SUPP_RATES_CHANGED)
4048e93258fSBjoern A. Zeeb 		ra->upd_mask = 1;
4058e93258fSBjoern A. Zeeb 	if (changed & (IEEE80211_RC_BW_CHANGED | IEEE80211_RC_NSS_CHANGED))
4068e93258fSBjoern A. Zeeb 		ra->upd_bw_nss_mask = 1;
4078e93258fSBjoern A. Zeeb 
4088e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_RA,
4098e93258fSBjoern A. Zeeb 		    "ra updat: macid = %d, bw = %d, nss = %d, gi = %d %d",
4108e93258fSBjoern A. Zeeb 		    ra->macid,
4118e93258fSBjoern A. Zeeb 		    ra->bw_cap,
4128e93258fSBjoern A. Zeeb 		    ra->ss_num,
4138e93258fSBjoern A. Zeeb 		    ra->en_sgi,
4148e93258fSBjoern A. Zeeb 		    ra->giltf);
4158e93258fSBjoern A. Zeeb 
4168e93258fSBjoern A. Zeeb 	rtw89_fw_h2c_ra(rtwdev, ra, false);
4178e93258fSBjoern A. Zeeb }
4188e93258fSBjoern A. Zeeb 
4198e93258fSBjoern A. Zeeb static bool __check_rate_pattern(struct rtw89_phy_rate_pattern *next,
4208e93258fSBjoern A. Zeeb 				 u16 rate_base, u64 ra_mask, u8 ra_mode,
4218e93258fSBjoern A. Zeeb 				 u32 rate_ctrl, u32 ctrl_skip, bool force)
4228e93258fSBjoern A. Zeeb {
4238e93258fSBjoern A. Zeeb 	u8 n, c;
4248e93258fSBjoern A. Zeeb 
4258e93258fSBjoern A. Zeeb 	if (rate_ctrl == ctrl_skip)
4268e93258fSBjoern A. Zeeb 		return true;
4278e93258fSBjoern A. Zeeb 
4288e93258fSBjoern A. Zeeb 	n = hweight32(rate_ctrl);
4298e93258fSBjoern A. Zeeb 	if (n == 0)
4308e93258fSBjoern A. Zeeb 		return true;
4318e93258fSBjoern A. Zeeb 
4328e93258fSBjoern A. Zeeb 	if (force && n != 1)
4338e93258fSBjoern A. Zeeb 		return false;
4348e93258fSBjoern A. Zeeb 
4358e93258fSBjoern A. Zeeb 	if (next->enable)
4368e93258fSBjoern A. Zeeb 		return false;
4378e93258fSBjoern A. Zeeb 
4388e93258fSBjoern A. Zeeb 	c = __fls(rate_ctrl);
4398e93258fSBjoern A. Zeeb 	next->rate = rate_base + c;
4408e93258fSBjoern A. Zeeb 	next->ra_mode = ra_mode;
4418e93258fSBjoern A. Zeeb 	next->ra_mask = ra_mask;
4428e93258fSBjoern A. Zeeb 	next->enable = true;
4438e93258fSBjoern A. Zeeb 
4448e93258fSBjoern A. Zeeb 	return true;
4458e93258fSBjoern A. Zeeb }
4468e93258fSBjoern A. Zeeb 
447e2340276SBjoern A. Zeeb #define RTW89_HW_RATE_BY_CHIP_GEN(rate) \
448e2340276SBjoern A. Zeeb 	{ \
449e2340276SBjoern A. Zeeb 		[RTW89_CHIP_AX] = RTW89_HW_RATE_ ## rate, \
450e2340276SBjoern A. Zeeb 		[RTW89_CHIP_BE] = RTW89_HW_RATE_V1_ ## rate, \
451e2340276SBjoern A. Zeeb 	}
452e2340276SBjoern A. Zeeb 
4538e93258fSBjoern A. Zeeb void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
4548e93258fSBjoern A. Zeeb 				struct ieee80211_vif *vif,
4558e93258fSBjoern A. Zeeb 				const struct cfg80211_bitrate_mask *mask)
4568e93258fSBjoern A. Zeeb {
4578e93258fSBjoern A. Zeeb 	struct ieee80211_supported_band *sband;
4588e93258fSBjoern A. Zeeb 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
4598e93258fSBjoern A. Zeeb 	struct rtw89_phy_rate_pattern next_pattern = {0};
4608e93258fSBjoern A. Zeeb 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
461e2340276SBjoern A. Zeeb 	static const u16 hw_rate_he[][RTW89_CHIP_GEN_NUM] = {
462e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS1_MCS0),
463e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS2_MCS0),
464e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS3_MCS0),
465e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS4_MCS0),
466e2340276SBjoern A. Zeeb 	};
467e2340276SBjoern A. Zeeb 	static const u16 hw_rate_vht[][RTW89_CHIP_GEN_NUM] = {
468e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS1_MCS0),
469e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS2_MCS0),
470e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS3_MCS0),
471e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS4_MCS0),
472e2340276SBjoern A. Zeeb 	};
473e2340276SBjoern A. Zeeb 	static const u16 hw_rate_ht[][RTW89_CHIP_GEN_NUM] = {
474e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(MCS0),
475e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(MCS8),
476e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(MCS16),
477e2340276SBjoern A. Zeeb 		RTW89_HW_RATE_BY_CHIP_GEN(MCS24),
478e2340276SBjoern A. Zeeb 	};
4798e93258fSBjoern A. Zeeb 	u8 band = chan->band_type;
4808e93258fSBjoern A. Zeeb 	enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
481e2340276SBjoern A. Zeeb 	enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
4828e93258fSBjoern A. Zeeb 	u8 tx_nss = rtwdev->hal.tx_nss;
4838e93258fSBjoern A. Zeeb 	u8 i;
4848e93258fSBjoern A. Zeeb 
4858e93258fSBjoern A. Zeeb 	for (i = 0; i < tx_nss; i++)
486e2340276SBjoern A. Zeeb 		if (!__check_rate_pattern(&next_pattern, hw_rate_he[i][chip_gen],
4878e93258fSBjoern A. Zeeb 					  RA_MASK_HE_RATES, RTW89_RA_MODE_HE,
4888e93258fSBjoern A. Zeeb 					  mask->control[nl_band].he_mcs[i],
4898e93258fSBjoern A. Zeeb 					  0, true))
4908e93258fSBjoern A. Zeeb 			goto out;
4918e93258fSBjoern A. Zeeb 
4928e93258fSBjoern A. Zeeb 	for (i = 0; i < tx_nss; i++)
493e2340276SBjoern A. Zeeb 		if (!__check_rate_pattern(&next_pattern, hw_rate_vht[i][chip_gen],
4948e93258fSBjoern A. Zeeb 					  RA_MASK_VHT_RATES, RTW89_RA_MODE_VHT,
4958e93258fSBjoern A. Zeeb 					  mask->control[nl_band].vht_mcs[i],
4968e93258fSBjoern A. Zeeb 					  0, true))
4978e93258fSBjoern A. Zeeb 			goto out;
4988e93258fSBjoern A. Zeeb 
4998e93258fSBjoern A. Zeeb 	for (i = 0; i < tx_nss; i++)
500e2340276SBjoern A. Zeeb 		if (!__check_rate_pattern(&next_pattern, hw_rate_ht[i][chip_gen],
5018e93258fSBjoern A. Zeeb 					  RA_MASK_HT_RATES, RTW89_RA_MODE_HT,
5028e93258fSBjoern A. Zeeb 					  mask->control[nl_band].ht_mcs[i],
5038e93258fSBjoern A. Zeeb 					  0, true))
5048e93258fSBjoern A. Zeeb 			goto out;
5058e93258fSBjoern A. Zeeb 
5068e93258fSBjoern A. Zeeb 	/* lagacy cannot be empty for nl80211_parse_tx_bitrate_mask, and
5078e93258fSBjoern A. Zeeb 	 * require at least one basic rate for ieee80211_set_bitrate_mask,
5088e93258fSBjoern A. Zeeb 	 * so the decision just depends on if all bitrates are set or not.
5098e93258fSBjoern A. Zeeb 	 */
5108e93258fSBjoern A. Zeeb 	sband = rtwdev->hw->wiphy->bands[nl_band];
5118e93258fSBjoern A. Zeeb 	if (band == RTW89_BAND_2G) {
5128e93258fSBjoern A. Zeeb 		if (!__check_rate_pattern(&next_pattern, RTW89_HW_RATE_CCK1,
5138e93258fSBjoern A. Zeeb 					  RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES,
5148e93258fSBjoern A. Zeeb 					  RTW89_RA_MODE_CCK | RTW89_RA_MODE_OFDM,
5158e93258fSBjoern A. Zeeb 					  mask->control[nl_band].legacy,
5168e93258fSBjoern A. Zeeb 					  BIT(sband->n_bitrates) - 1, false))
5178e93258fSBjoern A. Zeeb 			goto out;
5188e93258fSBjoern A. Zeeb 	} else {
5198e93258fSBjoern A. Zeeb 		if (!__check_rate_pattern(&next_pattern, RTW89_HW_RATE_OFDM6,
5208e93258fSBjoern A. Zeeb 					  RA_MASK_OFDM_RATES, RTW89_RA_MODE_OFDM,
5218e93258fSBjoern A. Zeeb 					  mask->control[nl_band].legacy,
5228e93258fSBjoern A. Zeeb 					  BIT(sband->n_bitrates) - 1, false))
5238e93258fSBjoern A. Zeeb 			goto out;
5248e93258fSBjoern A. Zeeb 	}
5258e93258fSBjoern A. Zeeb 
5268e93258fSBjoern A. Zeeb 	if (!next_pattern.enable)
5278e93258fSBjoern A. Zeeb 		goto out;
5288e93258fSBjoern A. Zeeb 
5298e93258fSBjoern A. Zeeb 	rtwvif->rate_pattern = next_pattern;
5308e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_RA,
5318e93258fSBjoern A. Zeeb #if defined(__linux__)
5328e93258fSBjoern A. Zeeb 		    "configure pattern: rate 0x%x, mask 0x%llx, mode 0x%x\n",
5338e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
5348e93258fSBjoern A. Zeeb 		    "configure pattern: rate 0x%x, mask 0x%jx, mode 0x%x\n",
5358e93258fSBjoern A. Zeeb #endif
5368e93258fSBjoern A. Zeeb 		    next_pattern.rate,
5378e93258fSBjoern A. Zeeb #if defined(__FreeBSD__)
5388e93258fSBjoern A. Zeeb 		    (uintmax_t)
5398e93258fSBjoern A. Zeeb #endif
5408e93258fSBjoern A. Zeeb 		    next_pattern.ra_mask,
5418e93258fSBjoern A. Zeeb 		    next_pattern.ra_mode);
5428e93258fSBjoern A. Zeeb 	return;
5438e93258fSBjoern A. Zeeb 
5448e93258fSBjoern A. Zeeb out:
5458e93258fSBjoern A. Zeeb 	rtwvif->rate_pattern.enable = false;
5468e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_RA, "unset rate pattern\n");
5478e93258fSBjoern A. Zeeb }
5488e93258fSBjoern A. Zeeb 
5498e93258fSBjoern A. Zeeb static void rtw89_phy_ra_updata_sta_iter(void *data, struct ieee80211_sta *sta)
5508e93258fSBjoern A. Zeeb {
5518e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev = (struct rtw89_dev *)data;
5528e93258fSBjoern A. Zeeb 
5538e93258fSBjoern A. Zeeb 	rtw89_phy_ra_updata_sta(rtwdev, sta, IEEE80211_RC_SUPP_RATES_CHANGED);
5548e93258fSBjoern A. Zeeb }
5558e93258fSBjoern A. Zeeb 
5568e93258fSBjoern A. Zeeb void rtw89_phy_ra_update(struct rtw89_dev *rtwdev)
5578e93258fSBjoern A. Zeeb {
5588e93258fSBjoern A. Zeeb 	ieee80211_iterate_stations_atomic(rtwdev->hw,
5598e93258fSBjoern A. Zeeb 					  rtw89_phy_ra_updata_sta_iter,
5608e93258fSBjoern A. Zeeb 					  rtwdev);
5618e93258fSBjoern A. Zeeb }
5628e93258fSBjoern A. Zeeb 
5638e93258fSBjoern A. Zeeb void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta)
5648e93258fSBjoern A. Zeeb {
5658e93258fSBjoern A. Zeeb 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
5668e93258fSBjoern A. Zeeb 	struct rtw89_ra_info *ra = &rtwsta->ra;
5678e93258fSBjoern A. Zeeb 	u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR;
5688e93258fSBjoern A. Zeeb 	bool csi = rtw89_sta_has_beamformer_cap(sta);
5698e93258fSBjoern A. Zeeb 
5708e93258fSBjoern A. Zeeb 	rtw89_phy_ra_sta_update(rtwdev, sta, csi);
5718e93258fSBjoern A. Zeeb 
5728e93258fSBjoern A. Zeeb 	if (rssi > 40)
5738e93258fSBjoern A. Zeeb 		ra->init_rate_lv = 1;
5748e93258fSBjoern A. Zeeb 	else if (rssi > 20)
5758e93258fSBjoern A. Zeeb 		ra->init_rate_lv = 2;
5768e93258fSBjoern A. Zeeb 	else if (rssi > 1)
5778e93258fSBjoern A. Zeeb 		ra->init_rate_lv = 3;
5788e93258fSBjoern A. Zeeb 	else
5798e93258fSBjoern A. Zeeb 		ra->init_rate_lv = 0;
5808e93258fSBjoern A. Zeeb 	ra->upd_all = 1;
5818e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_RA,
5828e93258fSBjoern A. Zeeb 		    "ra assoc: macid = %d, mode = %d, bw = %d, nss = %d, lv = %d",
5838e93258fSBjoern A. Zeeb 		    ra->macid,
5848e93258fSBjoern A. Zeeb 		    ra->mode_ctrl,
5858e93258fSBjoern A. Zeeb 		    ra->bw_cap,
5868e93258fSBjoern A. Zeeb 		    ra->ss_num,
5878e93258fSBjoern A. Zeeb 		    ra->init_rate_lv);
5888e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_RA,
5898e93258fSBjoern A. Zeeb 		    "ra assoc: dcm = %d, er = %d, ldpc = %d, stbc = %d, gi = %d %d",
5908e93258fSBjoern A. Zeeb 		    ra->dcm_cap,
5918e93258fSBjoern A. Zeeb 		    ra->er_cap,
5928e93258fSBjoern A. Zeeb 		    ra->ldpc_cap,
5938e93258fSBjoern A. Zeeb 		    ra->stbc_cap,
5948e93258fSBjoern A. Zeeb 		    ra->en_sgi,
5958e93258fSBjoern A. Zeeb 		    ra->giltf);
5968e93258fSBjoern A. Zeeb 
5978e93258fSBjoern A. Zeeb 	rtw89_fw_h2c_ra(rtwdev, ra, csi);
5988e93258fSBjoern A. Zeeb }
5998e93258fSBjoern A. Zeeb 
6008e93258fSBjoern A. Zeeb u8 rtw89_phy_get_txsc(struct rtw89_dev *rtwdev,
6018e93258fSBjoern A. Zeeb 		      const struct rtw89_chan *chan,
6028e93258fSBjoern A. Zeeb 		      enum rtw89_bandwidth dbw)
6038e93258fSBjoern A. Zeeb {
6048e93258fSBjoern A. Zeeb 	enum rtw89_bandwidth cbw = chan->band_width;
6058e93258fSBjoern A. Zeeb 	u8 pri_ch = chan->primary_channel;
6068e93258fSBjoern A. Zeeb 	u8 central_ch = chan->channel;
6078e93258fSBjoern A. Zeeb 	u8 txsc_idx = 0;
6088e93258fSBjoern A. Zeeb 	u8 tmp = 0;
6098e93258fSBjoern A. Zeeb 
6108e93258fSBjoern A. Zeeb 	if (cbw == dbw || cbw == RTW89_CHANNEL_WIDTH_20)
6118e93258fSBjoern A. Zeeb 		return txsc_idx;
6128e93258fSBjoern A. Zeeb 
6138e93258fSBjoern A. Zeeb 	switch (cbw) {
6148e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_40:
6158e93258fSBjoern A. Zeeb 		txsc_idx = pri_ch > central_ch ? 1 : 2;
6168e93258fSBjoern A. Zeeb 		break;
6178e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_80:
6188e93258fSBjoern A. Zeeb 		if (dbw == RTW89_CHANNEL_WIDTH_20) {
6198e93258fSBjoern A. Zeeb 			if (pri_ch > central_ch)
6208e93258fSBjoern A. Zeeb 				txsc_idx = (pri_ch - central_ch) >> 1;
6218e93258fSBjoern A. Zeeb 			else
6228e93258fSBjoern A. Zeeb 				txsc_idx = ((central_ch - pri_ch) >> 1) + 1;
6238e93258fSBjoern A. Zeeb 		} else {
6248e93258fSBjoern A. Zeeb 			txsc_idx = pri_ch > central_ch ? 9 : 10;
6258e93258fSBjoern A. Zeeb 		}
6268e93258fSBjoern A. Zeeb 		break;
6278e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_160:
6288e93258fSBjoern A. Zeeb 		if (pri_ch > central_ch)
6298e93258fSBjoern A. Zeeb 			tmp = (pri_ch - central_ch) >> 1;
6308e93258fSBjoern A. Zeeb 		else
6318e93258fSBjoern A. Zeeb 			tmp = ((central_ch - pri_ch) >> 1) + 1;
6328e93258fSBjoern A. Zeeb 
6338e93258fSBjoern A. Zeeb 		if (dbw == RTW89_CHANNEL_WIDTH_20) {
6348e93258fSBjoern A. Zeeb 			txsc_idx = tmp;
6358e93258fSBjoern A. Zeeb 		} else if (dbw == RTW89_CHANNEL_WIDTH_40) {
6368e93258fSBjoern A. Zeeb 			if (tmp == 1 || tmp == 3)
6378e93258fSBjoern A. Zeeb 				txsc_idx = 9;
6388e93258fSBjoern A. Zeeb 			else if (tmp == 5 || tmp == 7)
6398e93258fSBjoern A. Zeeb 				txsc_idx = 11;
6408e93258fSBjoern A. Zeeb 			else if (tmp == 2 || tmp == 4)
6418e93258fSBjoern A. Zeeb 				txsc_idx = 10;
6428e93258fSBjoern A. Zeeb 			else if (tmp == 6 || tmp == 8)
6438e93258fSBjoern A. Zeeb 				txsc_idx = 12;
6448e93258fSBjoern A. Zeeb 			else
6458e93258fSBjoern A. Zeeb 				return 0xff;
6468e93258fSBjoern A. Zeeb 		} else {
6478e93258fSBjoern A. Zeeb 			txsc_idx = pri_ch > central_ch ? 13 : 14;
6488e93258fSBjoern A. Zeeb 		}
6498e93258fSBjoern A. Zeeb 		break;
6508e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_80_80:
6518e93258fSBjoern A. Zeeb 		if (dbw == RTW89_CHANNEL_WIDTH_20) {
6528e93258fSBjoern A. Zeeb 			if (pri_ch > central_ch)
6538e93258fSBjoern A. Zeeb 				txsc_idx = (10 - (pri_ch - central_ch)) >> 1;
6548e93258fSBjoern A. Zeeb 			else
6558e93258fSBjoern A. Zeeb 				txsc_idx = ((central_ch - pri_ch) >> 1) + 5;
6568e93258fSBjoern A. Zeeb 		} else if (dbw == RTW89_CHANNEL_WIDTH_40) {
6578e93258fSBjoern A. Zeeb 			txsc_idx = pri_ch > central_ch ? 10 : 12;
6588e93258fSBjoern A. Zeeb 		} else {
6598e93258fSBjoern A. Zeeb 			txsc_idx = 14;
6608e93258fSBjoern A. Zeeb 		}
6618e93258fSBjoern A. Zeeb 		break;
6628e93258fSBjoern A. Zeeb 	default:
6638e93258fSBjoern A. Zeeb 		break;
6648e93258fSBjoern A. Zeeb 	}
6658e93258fSBjoern A. Zeeb 
6668e93258fSBjoern A. Zeeb 	return txsc_idx;
6678e93258fSBjoern A. Zeeb }
6688e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_get_txsc);
6698e93258fSBjoern A. Zeeb 
6708e93258fSBjoern A. Zeeb static bool rtw89_phy_check_swsi_busy(struct rtw89_dev *rtwdev)
6718e93258fSBjoern A. Zeeb {
6728e93258fSBjoern A. Zeeb 	return !!rtw89_phy_read32_mask(rtwdev, R_SWSI_V1, B_SWSI_W_BUSY_V1) ||
6738e93258fSBjoern A. Zeeb 	       !!rtw89_phy_read32_mask(rtwdev, R_SWSI_V1, B_SWSI_R_BUSY_V1);
6748e93258fSBjoern A. Zeeb }
6758e93258fSBjoern A. Zeeb 
6768e93258fSBjoern A. Zeeb u32 rtw89_phy_read_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
6778e93258fSBjoern A. Zeeb 		      u32 addr, u32 mask)
6788e93258fSBjoern A. Zeeb {
6798e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
6808e93258fSBjoern A. Zeeb 	const u32 *base_addr = chip->rf_base_addr;
6818e93258fSBjoern A. Zeeb 	u32 val, direct_addr;
6828e93258fSBjoern A. Zeeb 
6838e93258fSBjoern A. Zeeb 	if (rf_path >= rtwdev->chip->rf_path_num) {
6848e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
6858e93258fSBjoern A. Zeeb 		return INV_RF_DATA;
6868e93258fSBjoern A. Zeeb 	}
6878e93258fSBjoern A. Zeeb 
6888e93258fSBjoern A. Zeeb 	addr &= 0xff;
6898e93258fSBjoern A. Zeeb 	direct_addr = base_addr[rf_path] + (addr << 2);
6908e93258fSBjoern A. Zeeb 	mask &= RFREG_MASK;
6918e93258fSBjoern A. Zeeb 
6928e93258fSBjoern A. Zeeb 	val = rtw89_phy_read32_mask(rtwdev, direct_addr, mask);
6938e93258fSBjoern A. Zeeb 
6948e93258fSBjoern A. Zeeb 	return val;
6958e93258fSBjoern A. Zeeb }
6968e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_read_rf);
6978e93258fSBjoern A. Zeeb 
6988e93258fSBjoern A. Zeeb static u32 rtw89_phy_read_rf_a(struct rtw89_dev *rtwdev,
6998e93258fSBjoern A. Zeeb 			       enum rtw89_rf_path rf_path, u32 addr, u32 mask)
7008e93258fSBjoern A. Zeeb {
7018e93258fSBjoern A. Zeeb 	bool busy;
7028e93258fSBjoern A. Zeeb 	bool done;
7038e93258fSBjoern A. Zeeb 	u32 val;
7048e93258fSBjoern A. Zeeb 	int ret;
7058e93258fSBjoern A. Zeeb 
7068e93258fSBjoern A. Zeeb 	ret = read_poll_timeout_atomic(rtw89_phy_check_swsi_busy, busy, !busy,
7078e93258fSBjoern A. Zeeb 				       1, 30, false, rtwdev);
7088e93258fSBjoern A. Zeeb 	if (ret) {
7098e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "read rf busy swsi\n");
7108e93258fSBjoern A. Zeeb 		return INV_RF_DATA;
7118e93258fSBjoern A. Zeeb 	}
7128e93258fSBjoern A. Zeeb 
7138e93258fSBjoern A. Zeeb 	mask &= RFREG_MASK;
7148e93258fSBjoern A. Zeeb 
7158e93258fSBjoern A. Zeeb 	val = FIELD_PREP(B_SWSI_READ_ADDR_PATH_V1, rf_path) |
7168e93258fSBjoern A. Zeeb 	      FIELD_PREP(B_SWSI_READ_ADDR_ADDR_V1, addr);
7178e93258fSBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, R_SWSI_READ_ADDR_V1, B_SWSI_READ_ADDR_V1, val);
7188e93258fSBjoern A. Zeeb 	udelay(2);
7198e93258fSBjoern A. Zeeb 
7208e93258fSBjoern A. Zeeb 	ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, done, done, 1,
7218e93258fSBjoern A. Zeeb 				       30, false, rtwdev, R_SWSI_V1,
7228e93258fSBjoern A. Zeeb 				       B_SWSI_R_DATA_DONE_V1);
7238e93258fSBjoern A. Zeeb 	if (ret) {
7248e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "read swsi busy\n");
7258e93258fSBjoern A. Zeeb 		return INV_RF_DATA;
7268e93258fSBjoern A. Zeeb 	}
7278e93258fSBjoern A. Zeeb 
7288e93258fSBjoern A. Zeeb 	return rtw89_phy_read32_mask(rtwdev, R_SWSI_V1, mask);
7298e93258fSBjoern A. Zeeb }
7308e93258fSBjoern A. Zeeb 
7318e93258fSBjoern A. Zeeb u32 rtw89_phy_read_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
7328e93258fSBjoern A. Zeeb 			 u32 addr, u32 mask)
7338e93258fSBjoern A. Zeeb {
7348e93258fSBjoern A. Zeeb 	bool ad_sel = FIELD_GET(RTW89_RF_ADDR_ADSEL_MASK, addr);
7358e93258fSBjoern A. Zeeb 
7368e93258fSBjoern A. Zeeb 	if (rf_path >= rtwdev->chip->rf_path_num) {
7378e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
7388e93258fSBjoern A. Zeeb 		return INV_RF_DATA;
7398e93258fSBjoern A. Zeeb 	}
7408e93258fSBjoern A. Zeeb 
7418e93258fSBjoern A. Zeeb 	if (ad_sel)
7428e93258fSBjoern A. Zeeb 		return rtw89_phy_read_rf(rtwdev, rf_path, addr, mask);
7438e93258fSBjoern A. Zeeb 	else
7448e93258fSBjoern A. Zeeb 		return rtw89_phy_read_rf_a(rtwdev, rf_path, addr, mask);
7458e93258fSBjoern A. Zeeb }
7468e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_read_rf_v1);
7478e93258fSBjoern A. Zeeb 
7488e93258fSBjoern A. Zeeb bool rtw89_phy_write_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
7498e93258fSBjoern A. Zeeb 			u32 addr, u32 mask, u32 data)
7508e93258fSBjoern A. Zeeb {
7518e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
7528e93258fSBjoern A. Zeeb 	const u32 *base_addr = chip->rf_base_addr;
7538e93258fSBjoern A. Zeeb 	u32 direct_addr;
7548e93258fSBjoern A. Zeeb 
7558e93258fSBjoern A. Zeeb 	if (rf_path >= rtwdev->chip->rf_path_num) {
7568e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
7578e93258fSBjoern A. Zeeb 		return false;
7588e93258fSBjoern A. Zeeb 	}
7598e93258fSBjoern A. Zeeb 
7608e93258fSBjoern A. Zeeb 	addr &= 0xff;
7618e93258fSBjoern A. Zeeb 	direct_addr = base_addr[rf_path] + (addr << 2);
7628e93258fSBjoern A. Zeeb 	mask &= RFREG_MASK;
7638e93258fSBjoern A. Zeeb 
7648e93258fSBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, direct_addr, mask, data);
7658e93258fSBjoern A. Zeeb 
7668e93258fSBjoern A. Zeeb 	/* delay to ensure writing properly */
7678e93258fSBjoern A. Zeeb 	udelay(1);
7688e93258fSBjoern A. Zeeb 
7698e93258fSBjoern A. Zeeb 	return true;
7708e93258fSBjoern A. Zeeb }
7718e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_write_rf);
7728e93258fSBjoern A. Zeeb 
7738e93258fSBjoern A. Zeeb static bool rtw89_phy_write_rf_a(struct rtw89_dev *rtwdev,
7748e93258fSBjoern A. Zeeb 				 enum rtw89_rf_path rf_path, u32 addr, u32 mask,
7758e93258fSBjoern A. Zeeb 				 u32 data)
7768e93258fSBjoern A. Zeeb {
7778e93258fSBjoern A. Zeeb 	u8 bit_shift;
7788e93258fSBjoern A. Zeeb 	u32 val;
7798e93258fSBjoern A. Zeeb 	bool busy, b_msk_en = false;
7808e93258fSBjoern A. Zeeb 	int ret;
7818e93258fSBjoern A. Zeeb 
7828e93258fSBjoern A. Zeeb 	ret = read_poll_timeout_atomic(rtw89_phy_check_swsi_busy, busy, !busy,
7838e93258fSBjoern A. Zeeb 				       1, 30, false, rtwdev);
7848e93258fSBjoern A. Zeeb 	if (ret) {
7858e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "write rf busy swsi\n");
7868e93258fSBjoern A. Zeeb 		return false;
7878e93258fSBjoern A. Zeeb 	}
7888e93258fSBjoern A. Zeeb 
7898e93258fSBjoern A. Zeeb 	data &= RFREG_MASK;
7908e93258fSBjoern A. Zeeb 	mask &= RFREG_MASK;
7918e93258fSBjoern A. Zeeb 
7928e93258fSBjoern A. Zeeb 	if (mask != RFREG_MASK) {
7938e93258fSBjoern A. Zeeb 		b_msk_en = true;
7948e93258fSBjoern A. Zeeb 		rtw89_phy_write32_mask(rtwdev, R_SWSI_BIT_MASK_V1, RFREG_MASK,
7958e93258fSBjoern A. Zeeb 				       mask);
7968e93258fSBjoern A. Zeeb 		bit_shift = __ffs(mask);
7978e93258fSBjoern A. Zeeb 		data = (data << bit_shift) & RFREG_MASK;
7988e93258fSBjoern A. Zeeb 	}
7998e93258fSBjoern A. Zeeb 
8008e93258fSBjoern A. Zeeb 	val = FIELD_PREP(B_SWSI_DATA_BIT_MASK_EN_V1, b_msk_en) |
8018e93258fSBjoern A. Zeeb 	      FIELD_PREP(B_SWSI_DATA_PATH_V1, rf_path) |
8028e93258fSBjoern A. Zeeb 	      FIELD_PREP(B_SWSI_DATA_ADDR_V1, addr) |
8038e93258fSBjoern A. Zeeb 	      FIELD_PREP(B_SWSI_DATA_VAL_V1, data);
8048e93258fSBjoern A. Zeeb 
8058e93258fSBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, R_SWSI_DATA_V1, MASKDWORD, val);
8068e93258fSBjoern A. Zeeb 
8078e93258fSBjoern A. Zeeb 	return true;
8088e93258fSBjoern A. Zeeb }
8098e93258fSBjoern A. Zeeb 
8108e93258fSBjoern A. Zeeb bool rtw89_phy_write_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
8118e93258fSBjoern A. Zeeb 			   u32 addr, u32 mask, u32 data)
8128e93258fSBjoern A. Zeeb {
8138e93258fSBjoern A. Zeeb 	bool ad_sel = FIELD_GET(RTW89_RF_ADDR_ADSEL_MASK, addr);
8148e93258fSBjoern A. Zeeb 
8158e93258fSBjoern A. Zeeb 	if (rf_path >= rtwdev->chip->rf_path_num) {
8168e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
8178e93258fSBjoern A. Zeeb 		return false;
8188e93258fSBjoern A. Zeeb 	}
8198e93258fSBjoern A. Zeeb 
8208e93258fSBjoern A. Zeeb 	if (ad_sel)
8218e93258fSBjoern A. Zeeb 		return rtw89_phy_write_rf(rtwdev, rf_path, addr, mask, data);
8228e93258fSBjoern A. Zeeb 	else
8238e93258fSBjoern A. Zeeb 		return rtw89_phy_write_rf_a(rtwdev, rf_path, addr, mask, data);
8248e93258fSBjoern A. Zeeb }
8258e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_write_rf_v1);
8268e93258fSBjoern A. Zeeb 
827e2340276SBjoern A. Zeeb static bool rtw89_chip_rf_v1(struct rtw89_dev *rtwdev)
828e2340276SBjoern A. Zeeb {
829e2340276SBjoern A. Zeeb 	return rtwdev->chip->ops->write_rf == rtw89_phy_write_rf_v1;
830e2340276SBjoern A. Zeeb }
831e2340276SBjoern A. Zeeb 
8328e93258fSBjoern A. Zeeb static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev,
8338e93258fSBjoern A. Zeeb 			       enum rtw89_phy_idx phy_idx)
8348e93258fSBjoern A. Zeeb {
8358e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
8368e93258fSBjoern A. Zeeb 
8378e93258fSBjoern A. Zeeb 	chip->ops->bb_reset(rtwdev, phy_idx);
8388e93258fSBjoern A. Zeeb }
8398e93258fSBjoern A. Zeeb 
8408e93258fSBjoern A. Zeeb static void rtw89_phy_config_bb_reg(struct rtw89_dev *rtwdev,
8418e93258fSBjoern A. Zeeb 				    const struct rtw89_reg2_def *reg,
8428e93258fSBjoern A. Zeeb 				    enum rtw89_rf_path rf_path,
8438e93258fSBjoern A. Zeeb 				    void *extra_data)
8448e93258fSBjoern A. Zeeb {
8458e93258fSBjoern A. Zeeb 	if (reg->addr == 0xfe)
8468e93258fSBjoern A. Zeeb 		mdelay(50);
8478e93258fSBjoern A. Zeeb 	else if (reg->addr == 0xfd)
8488e93258fSBjoern A. Zeeb 		mdelay(5);
8498e93258fSBjoern A. Zeeb 	else if (reg->addr == 0xfc)
8508e93258fSBjoern A. Zeeb 		mdelay(1);
8518e93258fSBjoern A. Zeeb 	else if (reg->addr == 0xfb)
8528e93258fSBjoern A. Zeeb 		udelay(50);
8538e93258fSBjoern A. Zeeb 	else if (reg->addr == 0xfa)
8548e93258fSBjoern A. Zeeb 		udelay(5);
8558e93258fSBjoern A. Zeeb 	else if (reg->addr == 0xf9)
8568e93258fSBjoern A. Zeeb 		udelay(1);
8578e93258fSBjoern A. Zeeb 	else
8588e93258fSBjoern A. Zeeb 		rtw89_phy_write32(rtwdev, reg->addr, reg->data);
8598e93258fSBjoern A. Zeeb }
8608e93258fSBjoern A. Zeeb 
8618e93258fSBjoern A. Zeeb union rtw89_phy_bb_gain_arg {
8628e93258fSBjoern A. Zeeb 	u32 addr;
8638e93258fSBjoern A. Zeeb 	struct {
8648e93258fSBjoern A. Zeeb 		union {
8658e93258fSBjoern A. Zeeb 			u8 type;
8668e93258fSBjoern A. Zeeb 			struct {
8678e93258fSBjoern A. Zeeb 				u8 rxsc_start:4;
8688e93258fSBjoern A. Zeeb 				u8 bw:4;
8698e93258fSBjoern A. Zeeb 			};
8708e93258fSBjoern A. Zeeb 		};
8718e93258fSBjoern A. Zeeb 		u8 path;
8728e93258fSBjoern A. Zeeb 		u8 gain_band;
8738e93258fSBjoern A. Zeeb 		u8 cfg_type;
8748e93258fSBjoern A. Zeeb 	};
8758e93258fSBjoern A. Zeeb } __packed;
8768e93258fSBjoern A. Zeeb 
8778e93258fSBjoern A. Zeeb static void
8788e93258fSBjoern A. Zeeb rtw89_phy_cfg_bb_gain_error(struct rtw89_dev *rtwdev,
8798e93258fSBjoern A. Zeeb 			    union rtw89_phy_bb_gain_arg arg, u32 data)
8808e93258fSBjoern A. Zeeb {
8818e93258fSBjoern A. Zeeb 	struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
8828e93258fSBjoern A. Zeeb 	u8 type = arg.type;
8838e93258fSBjoern A. Zeeb 	u8 path = arg.path;
8848e93258fSBjoern A. Zeeb 	u8 gband = arg.gain_band;
8858e93258fSBjoern A. Zeeb 	int i;
8868e93258fSBjoern A. Zeeb 
8878e93258fSBjoern A. Zeeb 	switch (type) {
8888e93258fSBjoern A. Zeeb 	case 0:
8898e93258fSBjoern A. Zeeb 		for (i = 0; i < 4; i++, data >>= 8)
8908e93258fSBjoern A. Zeeb 			gain->lna_gain[gband][path][i] = data & 0xff;
8918e93258fSBjoern A. Zeeb 		break;
8928e93258fSBjoern A. Zeeb 	case 1:
8938e93258fSBjoern A. Zeeb 		for (i = 4; i < 7; i++, data >>= 8)
8948e93258fSBjoern A. Zeeb 			gain->lna_gain[gband][path][i] = data & 0xff;
8958e93258fSBjoern A. Zeeb 		break;
8968e93258fSBjoern A. Zeeb 	case 2:
8978e93258fSBjoern A. Zeeb 		for (i = 0; i < 2; i++, data >>= 8)
8988e93258fSBjoern A. Zeeb 			gain->tia_gain[gband][path][i] = data & 0xff;
8998e93258fSBjoern A. Zeeb 		break;
9008e93258fSBjoern A. Zeeb 	default:
9018e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev,
9028e93258fSBjoern A. Zeeb 			   "bb gain error {0x%x:0x%x} with unknown type: %d\n",
9038e93258fSBjoern A. Zeeb 			   arg.addr, data, type);
9048e93258fSBjoern A. Zeeb 		break;
9058e93258fSBjoern A. Zeeb 	}
9068e93258fSBjoern A. Zeeb }
9078e93258fSBjoern A. Zeeb 
9088e93258fSBjoern A. Zeeb enum rtw89_phy_bb_rxsc_start_idx {
9098e93258fSBjoern A. Zeeb 	RTW89_BB_RXSC_START_IDX_FULL = 0,
9108e93258fSBjoern A. Zeeb 	RTW89_BB_RXSC_START_IDX_20 = 1,
9118e93258fSBjoern A. Zeeb 	RTW89_BB_RXSC_START_IDX_20_1 = 5,
9128e93258fSBjoern A. Zeeb 	RTW89_BB_RXSC_START_IDX_40 = 9,
9138e93258fSBjoern A. Zeeb 	RTW89_BB_RXSC_START_IDX_80 = 13,
9148e93258fSBjoern A. Zeeb };
9158e93258fSBjoern A. Zeeb 
9168e93258fSBjoern A. Zeeb static void
9178e93258fSBjoern A. Zeeb rtw89_phy_cfg_bb_rpl_ofst(struct rtw89_dev *rtwdev,
9188e93258fSBjoern A. Zeeb 			  union rtw89_phy_bb_gain_arg arg, u32 data)
9198e93258fSBjoern A. Zeeb {
9208e93258fSBjoern A. Zeeb 	struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
9218e93258fSBjoern A. Zeeb 	u8 rxsc_start = arg.rxsc_start;
9228e93258fSBjoern A. Zeeb 	u8 bw = arg.bw;
9238e93258fSBjoern A. Zeeb 	u8 path = arg.path;
9248e93258fSBjoern A. Zeeb 	u8 gband = arg.gain_band;
9258e93258fSBjoern A. Zeeb 	u8 rxsc;
9268e93258fSBjoern A. Zeeb 	s8 ofst;
9278e93258fSBjoern A. Zeeb 	int i;
9288e93258fSBjoern A. Zeeb 
9298e93258fSBjoern A. Zeeb 	switch (bw) {
9308e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_20:
9318e93258fSBjoern A. Zeeb 		gain->rpl_ofst_20[gband][path] = (s8)data;
9328e93258fSBjoern A. Zeeb 		break;
9338e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_40:
9348e93258fSBjoern A. Zeeb 		if (rxsc_start == RTW89_BB_RXSC_START_IDX_FULL) {
9358e93258fSBjoern A. Zeeb 			gain->rpl_ofst_40[gband][path][0] = (s8)data;
9368e93258fSBjoern A. Zeeb 		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_20) {
9378e93258fSBjoern A. Zeeb 			for (i = 0; i < 2; i++, data >>= 8) {
9388e93258fSBjoern A. Zeeb 				rxsc = RTW89_BB_RXSC_START_IDX_20 + i;
9398e93258fSBjoern A. Zeeb 				ofst = (s8)(data & 0xff);
9408e93258fSBjoern A. Zeeb 				gain->rpl_ofst_40[gband][path][rxsc] = ofst;
9418e93258fSBjoern A. Zeeb 			}
9428e93258fSBjoern A. Zeeb 		}
9438e93258fSBjoern A. Zeeb 		break;
9448e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_80:
9458e93258fSBjoern A. Zeeb 		if (rxsc_start == RTW89_BB_RXSC_START_IDX_FULL) {
9468e93258fSBjoern A. Zeeb 			gain->rpl_ofst_80[gband][path][0] = (s8)data;
9478e93258fSBjoern A. Zeeb 		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_20) {
9488e93258fSBjoern A. Zeeb 			for (i = 0; i < 4; i++, data >>= 8) {
9498e93258fSBjoern A. Zeeb 				rxsc = RTW89_BB_RXSC_START_IDX_20 + i;
9508e93258fSBjoern A. Zeeb 				ofst = (s8)(data & 0xff);
9518e93258fSBjoern A. Zeeb 				gain->rpl_ofst_80[gband][path][rxsc] = ofst;
9528e93258fSBjoern A. Zeeb 			}
9538e93258fSBjoern A. Zeeb 		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_40) {
9548e93258fSBjoern A. Zeeb 			for (i = 0; i < 2; i++, data >>= 8) {
9558e93258fSBjoern A. Zeeb 				rxsc = RTW89_BB_RXSC_START_IDX_40 + i;
9568e93258fSBjoern A. Zeeb 				ofst = (s8)(data & 0xff);
9578e93258fSBjoern A. Zeeb 				gain->rpl_ofst_80[gband][path][rxsc] = ofst;
9588e93258fSBjoern A. Zeeb 			}
9598e93258fSBjoern A. Zeeb 		}
9608e93258fSBjoern A. Zeeb 		break;
9618e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_160:
9628e93258fSBjoern A. Zeeb 		if (rxsc_start == RTW89_BB_RXSC_START_IDX_FULL) {
9638e93258fSBjoern A. Zeeb 			gain->rpl_ofst_160[gband][path][0] = (s8)data;
9648e93258fSBjoern A. Zeeb 		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_20) {
9658e93258fSBjoern A. Zeeb 			for (i = 0; i < 4; i++, data >>= 8) {
9668e93258fSBjoern A. Zeeb 				rxsc = RTW89_BB_RXSC_START_IDX_20 + i;
9678e93258fSBjoern A. Zeeb 				ofst = (s8)(data & 0xff);
9688e93258fSBjoern A. Zeeb 				gain->rpl_ofst_160[gband][path][rxsc] = ofst;
9698e93258fSBjoern A. Zeeb 			}
9708e93258fSBjoern A. Zeeb 		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_20_1) {
9718e93258fSBjoern A. Zeeb 			for (i = 0; i < 4; i++, data >>= 8) {
9728e93258fSBjoern A. Zeeb 				rxsc = RTW89_BB_RXSC_START_IDX_20_1 + i;
9738e93258fSBjoern A. Zeeb 				ofst = (s8)(data & 0xff);
9748e93258fSBjoern A. Zeeb 				gain->rpl_ofst_160[gband][path][rxsc] = ofst;
9758e93258fSBjoern A. Zeeb 			}
9768e93258fSBjoern A. Zeeb 		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_40) {
9778e93258fSBjoern A. Zeeb 			for (i = 0; i < 4; i++, data >>= 8) {
9788e93258fSBjoern A. Zeeb 				rxsc = RTW89_BB_RXSC_START_IDX_40 + i;
9798e93258fSBjoern A. Zeeb 				ofst = (s8)(data & 0xff);
9808e93258fSBjoern A. Zeeb 				gain->rpl_ofst_160[gband][path][rxsc] = ofst;
9818e93258fSBjoern A. Zeeb 			}
9828e93258fSBjoern A. Zeeb 		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_80) {
9838e93258fSBjoern A. Zeeb 			for (i = 0; i < 2; i++, data >>= 8) {
9848e93258fSBjoern A. Zeeb 				rxsc = RTW89_BB_RXSC_START_IDX_80 + i;
9858e93258fSBjoern A. Zeeb 				ofst = (s8)(data & 0xff);
9868e93258fSBjoern A. Zeeb 				gain->rpl_ofst_160[gband][path][rxsc] = ofst;
9878e93258fSBjoern A. Zeeb 			}
9888e93258fSBjoern A. Zeeb 		}
9898e93258fSBjoern A. Zeeb 		break;
9908e93258fSBjoern A. Zeeb 	default:
9918e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev,
9928e93258fSBjoern A. Zeeb 			   "bb rpl ofst {0x%x:0x%x} with unknown bw: %d\n",
9938e93258fSBjoern A. Zeeb 			   arg.addr, data, bw);
9948e93258fSBjoern A. Zeeb 		break;
9958e93258fSBjoern A. Zeeb 	}
9968e93258fSBjoern A. Zeeb }
9978e93258fSBjoern A. Zeeb 
9988e93258fSBjoern A. Zeeb static void
9998e93258fSBjoern A. Zeeb rtw89_phy_cfg_bb_gain_bypass(struct rtw89_dev *rtwdev,
10008e93258fSBjoern A. Zeeb 			     union rtw89_phy_bb_gain_arg arg, u32 data)
10018e93258fSBjoern A. Zeeb {
10028e93258fSBjoern A. Zeeb 	struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
10038e93258fSBjoern A. Zeeb 	u8 type = arg.type;
10048e93258fSBjoern A. Zeeb 	u8 path = arg.path;
10058e93258fSBjoern A. Zeeb 	u8 gband = arg.gain_band;
10068e93258fSBjoern A. Zeeb 	int i;
10078e93258fSBjoern A. Zeeb 
10088e93258fSBjoern A. Zeeb 	switch (type) {
10098e93258fSBjoern A. Zeeb 	case 0:
10108e93258fSBjoern A. Zeeb 		for (i = 0; i < 4; i++, data >>= 8)
10118e93258fSBjoern A. Zeeb 			gain->lna_gain_bypass[gband][path][i] = data & 0xff;
10128e93258fSBjoern A. Zeeb 		break;
10138e93258fSBjoern A. Zeeb 	case 1:
10148e93258fSBjoern A. Zeeb 		for (i = 4; i < 7; i++, data >>= 8)
10158e93258fSBjoern A. Zeeb 			gain->lna_gain_bypass[gband][path][i] = data & 0xff;
10168e93258fSBjoern A. Zeeb 		break;
10178e93258fSBjoern A. Zeeb 	default:
10188e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev,
10198e93258fSBjoern A. Zeeb 			   "bb gain bypass {0x%x:0x%x} with unknown type: %d\n",
10208e93258fSBjoern A. Zeeb 			   arg.addr, data, type);
10218e93258fSBjoern A. Zeeb 		break;
10228e93258fSBjoern A. Zeeb 	}
10238e93258fSBjoern A. Zeeb }
10248e93258fSBjoern A. Zeeb 
10258e93258fSBjoern A. Zeeb static void
10268e93258fSBjoern A. Zeeb rtw89_phy_cfg_bb_gain_op1db(struct rtw89_dev *rtwdev,
10278e93258fSBjoern A. Zeeb 			    union rtw89_phy_bb_gain_arg arg, u32 data)
10288e93258fSBjoern A. Zeeb {
10298e93258fSBjoern A. Zeeb 	struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
10308e93258fSBjoern A. Zeeb 	u8 type = arg.type;
10318e93258fSBjoern A. Zeeb 	u8 path = arg.path;
10328e93258fSBjoern A. Zeeb 	u8 gband = arg.gain_band;
10338e93258fSBjoern A. Zeeb 	int i;
10348e93258fSBjoern A. Zeeb 
10358e93258fSBjoern A. Zeeb 	switch (type) {
10368e93258fSBjoern A. Zeeb 	case 0:
10378e93258fSBjoern A. Zeeb 		for (i = 0; i < 4; i++, data >>= 8)
10388e93258fSBjoern A. Zeeb 			gain->lna_op1db[gband][path][i] = data & 0xff;
10398e93258fSBjoern A. Zeeb 		break;
10408e93258fSBjoern A. Zeeb 	case 1:
10418e93258fSBjoern A. Zeeb 		for (i = 4; i < 7; i++, data >>= 8)
10428e93258fSBjoern A. Zeeb 			gain->lna_op1db[gband][path][i] = data & 0xff;
10438e93258fSBjoern A. Zeeb 		break;
10448e93258fSBjoern A. Zeeb 	case 2:
10458e93258fSBjoern A. Zeeb 		for (i = 0; i < 4; i++, data >>= 8)
10468e93258fSBjoern A. Zeeb 			gain->tia_lna_op1db[gband][path][i] = data & 0xff;
10478e93258fSBjoern A. Zeeb 		break;
10488e93258fSBjoern A. Zeeb 	case 3:
10498e93258fSBjoern A. Zeeb 		for (i = 4; i < 8; i++, data >>= 8)
10508e93258fSBjoern A. Zeeb 			gain->tia_lna_op1db[gband][path][i] = data & 0xff;
10518e93258fSBjoern A. Zeeb 		break;
10528e93258fSBjoern A. Zeeb 	default:
10538e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev,
10548e93258fSBjoern A. Zeeb 			   "bb gain op1db {0x%x:0x%x} with unknown type: %d\n",
10558e93258fSBjoern A. Zeeb 			   arg.addr, data, type);
10568e93258fSBjoern A. Zeeb 		break;
10578e93258fSBjoern A. Zeeb 	}
10588e93258fSBjoern A. Zeeb }
10598e93258fSBjoern A. Zeeb 
10608e93258fSBjoern A. Zeeb static void rtw89_phy_config_bb_gain(struct rtw89_dev *rtwdev,
10618e93258fSBjoern A. Zeeb 				     const struct rtw89_reg2_def *reg,
10628e93258fSBjoern A. Zeeb 				     enum rtw89_rf_path rf_path,
10638e93258fSBjoern A. Zeeb 				     void *extra_data)
10648e93258fSBjoern A. Zeeb {
10658e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
10668e93258fSBjoern A. Zeeb 	union rtw89_phy_bb_gain_arg arg = { .addr = reg->addr };
1067e2340276SBjoern A. Zeeb 	struct rtw89_efuse *efuse = &rtwdev->efuse;
10688e93258fSBjoern A. Zeeb 
10698e93258fSBjoern A. Zeeb 	if (arg.gain_band >= RTW89_BB_GAIN_BAND_NR)
10708e93258fSBjoern A. Zeeb 		return;
10718e93258fSBjoern A. Zeeb 
10728e93258fSBjoern A. Zeeb 	if (arg.path >= chip->rf_path_num)
10738e93258fSBjoern A. Zeeb 		return;
10748e93258fSBjoern A. Zeeb 
10758e93258fSBjoern A. Zeeb 	if (arg.addr >= 0xf9 && arg.addr <= 0xfe) {
10768e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "bb gain table with flow ctrl\n");
10778e93258fSBjoern A. Zeeb 		return;
10788e93258fSBjoern A. Zeeb 	}
10798e93258fSBjoern A. Zeeb 
10808e93258fSBjoern A. Zeeb 	switch (arg.cfg_type) {
10818e93258fSBjoern A. Zeeb 	case 0:
10828e93258fSBjoern A. Zeeb 		rtw89_phy_cfg_bb_gain_error(rtwdev, arg, reg->data);
10838e93258fSBjoern A. Zeeb 		break;
10848e93258fSBjoern A. Zeeb 	case 1:
10858e93258fSBjoern A. Zeeb 		rtw89_phy_cfg_bb_rpl_ofst(rtwdev, arg, reg->data);
10868e93258fSBjoern A. Zeeb 		break;
10878e93258fSBjoern A. Zeeb 	case 2:
10888e93258fSBjoern A. Zeeb 		rtw89_phy_cfg_bb_gain_bypass(rtwdev, arg, reg->data);
10898e93258fSBjoern A. Zeeb 		break;
10908e93258fSBjoern A. Zeeb 	case 3:
10918e93258fSBjoern A. Zeeb 		rtw89_phy_cfg_bb_gain_op1db(rtwdev, arg, reg->data);
10928e93258fSBjoern A. Zeeb 		break;
1093e2340276SBjoern A. Zeeb 	case 4:
1094e2340276SBjoern A. Zeeb 		/* This cfg_type is only used by rfe_type >= 50 with eFEM */
1095e2340276SBjoern A. Zeeb 		if (efuse->rfe_type < 50)
1096e2340276SBjoern A. Zeeb 			break;
1097e2340276SBjoern A. Zeeb 		fallthrough;
10988e93258fSBjoern A. Zeeb 	default:
10998e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev,
11008e93258fSBjoern A. Zeeb 			   "bb gain {0x%x:0x%x} with unknown cfg type: %d\n",
11018e93258fSBjoern A. Zeeb 			   arg.addr, reg->data, arg.cfg_type);
11028e93258fSBjoern A. Zeeb 		break;
11038e93258fSBjoern A. Zeeb 	}
11048e93258fSBjoern A. Zeeb }
11058e93258fSBjoern A. Zeeb 
11068e93258fSBjoern A. Zeeb static void
11078e93258fSBjoern A. Zeeb rtw89_phy_cofig_rf_reg_store(struct rtw89_dev *rtwdev,
11088e93258fSBjoern A. Zeeb 			     const struct rtw89_reg2_def *reg,
11098e93258fSBjoern A. Zeeb 			     enum rtw89_rf_path rf_path,
11108e93258fSBjoern A. Zeeb 			     struct rtw89_fw_h2c_rf_reg_info *info)
11118e93258fSBjoern A. Zeeb {
11128e93258fSBjoern A. Zeeb 	u16 idx = info->curr_idx % RTW89_H2C_RF_PAGE_SIZE;
11138e93258fSBjoern A. Zeeb 	u8 page = info->curr_idx / RTW89_H2C_RF_PAGE_SIZE;
11148e93258fSBjoern A. Zeeb 
11158e93258fSBjoern A. Zeeb 	if (page >= RTW89_H2C_RF_PAGE_NUM) {
11168e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "RF parameters exceed size. path=%d, idx=%d",
11178e93258fSBjoern A. Zeeb 			   rf_path, info->curr_idx);
11188e93258fSBjoern A. Zeeb 		return;
11198e93258fSBjoern A. Zeeb 	}
11208e93258fSBjoern A. Zeeb 
11218e93258fSBjoern A. Zeeb 	info->rtw89_phy_config_rf_h2c[page][idx] =
11228e93258fSBjoern A. Zeeb 		cpu_to_le32((reg->addr << 20) | reg->data);
11238e93258fSBjoern A. Zeeb 	info->curr_idx++;
11248e93258fSBjoern A. Zeeb }
11258e93258fSBjoern A. Zeeb 
11268e93258fSBjoern A. Zeeb static int rtw89_phy_config_rf_reg_fw(struct rtw89_dev *rtwdev,
11278e93258fSBjoern A. Zeeb 				      struct rtw89_fw_h2c_rf_reg_info *info)
11288e93258fSBjoern A. Zeeb {
11298e93258fSBjoern A. Zeeb 	u16 remain = info->curr_idx;
11308e93258fSBjoern A. Zeeb 	u16 len = 0;
11318e93258fSBjoern A. Zeeb 	u8 i;
11328e93258fSBjoern A. Zeeb 	int ret = 0;
11338e93258fSBjoern A. Zeeb 
11348e93258fSBjoern A. Zeeb 	if (remain > RTW89_H2C_RF_PAGE_NUM * RTW89_H2C_RF_PAGE_SIZE) {
11358e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev,
11368e93258fSBjoern A. Zeeb 			   "rf reg h2c total len %d larger than %d\n",
11378e93258fSBjoern A. Zeeb 			   remain, RTW89_H2C_RF_PAGE_NUM * RTW89_H2C_RF_PAGE_SIZE);
11388e93258fSBjoern A. Zeeb 		ret = -EINVAL;
11398e93258fSBjoern A. Zeeb 		goto out;
11408e93258fSBjoern A. Zeeb 	}
11418e93258fSBjoern A. Zeeb 
11428e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_H2C_RF_PAGE_NUM && remain; i++, remain -= len) {
11438e93258fSBjoern A. Zeeb 		len = remain > RTW89_H2C_RF_PAGE_SIZE ? RTW89_H2C_RF_PAGE_SIZE : remain;
11448e93258fSBjoern A. Zeeb 		ret = rtw89_fw_h2c_rf_reg(rtwdev, info, len * 4, i);
11458e93258fSBjoern A. Zeeb 		if (ret)
11468e93258fSBjoern A. Zeeb 			goto out;
11478e93258fSBjoern A. Zeeb 	}
11488e93258fSBjoern A. Zeeb out:
11498e93258fSBjoern A. Zeeb 	info->curr_idx = 0;
11508e93258fSBjoern A. Zeeb 
11518e93258fSBjoern A. Zeeb 	return ret;
11528e93258fSBjoern A. Zeeb }
11538e93258fSBjoern A. Zeeb 
1154e2340276SBjoern A. Zeeb static void rtw89_phy_config_rf_reg_noio(struct rtw89_dev *rtwdev,
1155e2340276SBjoern A. Zeeb 					 const struct rtw89_reg2_def *reg,
1156e2340276SBjoern A. Zeeb 					 enum rtw89_rf_path rf_path,
1157e2340276SBjoern A. Zeeb 					 void *extra_data)
1158e2340276SBjoern A. Zeeb {
1159e2340276SBjoern A. Zeeb 	u32 addr = reg->addr;
1160e2340276SBjoern A. Zeeb 
1161e2340276SBjoern A. Zeeb 	if (addr == 0xfe || addr == 0xfd || addr == 0xfc || addr == 0xfb ||
1162e2340276SBjoern A. Zeeb 	    addr == 0xfa || addr == 0xf9)
1163e2340276SBjoern A. Zeeb 		return;
1164e2340276SBjoern A. Zeeb 
1165e2340276SBjoern A. Zeeb 	if (rtw89_chip_rf_v1(rtwdev) && addr < 0x100)
1166e2340276SBjoern A. Zeeb 		return;
1167e2340276SBjoern A. Zeeb 
1168e2340276SBjoern A. Zeeb 	rtw89_phy_cofig_rf_reg_store(rtwdev, reg, rf_path,
1169e2340276SBjoern A. Zeeb 				     (struct rtw89_fw_h2c_rf_reg_info *)extra_data);
1170e2340276SBjoern A. Zeeb }
1171e2340276SBjoern A. Zeeb 
11728e93258fSBjoern A. Zeeb static void rtw89_phy_config_rf_reg(struct rtw89_dev *rtwdev,
11738e93258fSBjoern A. Zeeb 				    const struct rtw89_reg2_def *reg,
11748e93258fSBjoern A. Zeeb 				    enum rtw89_rf_path rf_path,
11758e93258fSBjoern A. Zeeb 				    void *extra_data)
11768e93258fSBjoern A. Zeeb {
11778e93258fSBjoern A. Zeeb 	if (reg->addr == 0xfe) {
11788e93258fSBjoern A. Zeeb 		mdelay(50);
11798e93258fSBjoern A. Zeeb 	} else if (reg->addr == 0xfd) {
11808e93258fSBjoern A. Zeeb 		mdelay(5);
11818e93258fSBjoern A. Zeeb 	} else if (reg->addr == 0xfc) {
11828e93258fSBjoern A. Zeeb 		mdelay(1);
11838e93258fSBjoern A. Zeeb 	} else if (reg->addr == 0xfb) {
11848e93258fSBjoern A. Zeeb 		udelay(50);
11858e93258fSBjoern A. Zeeb 	} else if (reg->addr == 0xfa) {
11868e93258fSBjoern A. Zeeb 		udelay(5);
11878e93258fSBjoern A. Zeeb 	} else if (reg->addr == 0xf9) {
11888e93258fSBjoern A. Zeeb 		udelay(1);
11898e93258fSBjoern A. Zeeb 	} else {
11908e93258fSBjoern A. Zeeb 		rtw89_write_rf(rtwdev, rf_path, reg->addr, 0xfffff, reg->data);
11918e93258fSBjoern A. Zeeb 		rtw89_phy_cofig_rf_reg_store(rtwdev, reg, rf_path,
11928e93258fSBjoern A. Zeeb 					     (struct rtw89_fw_h2c_rf_reg_info *)extra_data);
11938e93258fSBjoern A. Zeeb 	}
11948e93258fSBjoern A. Zeeb }
11958e93258fSBjoern A. Zeeb 
11968e93258fSBjoern A. Zeeb void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev,
11978e93258fSBjoern A. Zeeb 				const struct rtw89_reg2_def *reg,
11988e93258fSBjoern A. Zeeb 				enum rtw89_rf_path rf_path,
11998e93258fSBjoern A. Zeeb 				void *extra_data)
12008e93258fSBjoern A. Zeeb {
12018e93258fSBjoern A. Zeeb 	rtw89_write_rf(rtwdev, rf_path, reg->addr, RFREG_MASK, reg->data);
12028e93258fSBjoern A. Zeeb 
12038e93258fSBjoern A. Zeeb 	if (reg->addr < 0x100)
12048e93258fSBjoern A. Zeeb 		return;
12058e93258fSBjoern A. Zeeb 
12068e93258fSBjoern A. Zeeb 	rtw89_phy_cofig_rf_reg_store(rtwdev, reg, rf_path,
12078e93258fSBjoern A. Zeeb 				     (struct rtw89_fw_h2c_rf_reg_info *)extra_data);
12088e93258fSBjoern A. Zeeb }
12098e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_config_rf_reg_v1);
12108e93258fSBjoern A. Zeeb 
12118e93258fSBjoern A. Zeeb static int rtw89_phy_sel_headline(struct rtw89_dev *rtwdev,
12128e93258fSBjoern A. Zeeb 				  const struct rtw89_phy_table *table,
12138e93258fSBjoern A. Zeeb 				  u32 *headline_size, u32 *headline_idx,
12148e93258fSBjoern A. Zeeb 				  u8 rfe, u8 cv)
12158e93258fSBjoern A. Zeeb {
12168e93258fSBjoern A. Zeeb 	const struct rtw89_reg2_def *reg;
12178e93258fSBjoern A. Zeeb 	u32 headline;
12188e93258fSBjoern A. Zeeb 	u32 compare, target;
12198e93258fSBjoern A. Zeeb 	u8 rfe_para, cv_para;
12208e93258fSBjoern A. Zeeb 	u8 cv_max = 0;
12218e93258fSBjoern A. Zeeb 	bool case_matched = false;
12228e93258fSBjoern A. Zeeb 	u32 i;
12238e93258fSBjoern A. Zeeb 
12248e93258fSBjoern A. Zeeb 	for (i = 0; i < table->n_regs; i++) {
12258e93258fSBjoern A. Zeeb 		reg = &table->regs[i];
12268e93258fSBjoern A. Zeeb 		headline = get_phy_headline(reg->addr);
12278e93258fSBjoern A. Zeeb 		if (headline != PHY_HEADLINE_VALID)
12288e93258fSBjoern A. Zeeb 			break;
12298e93258fSBjoern A. Zeeb 	}
12308e93258fSBjoern A. Zeeb 	*headline_size = i;
12318e93258fSBjoern A. Zeeb 	if (*headline_size == 0)
12328e93258fSBjoern A. Zeeb 		return 0;
12338e93258fSBjoern A. Zeeb 
12348e93258fSBjoern A. Zeeb 	/* case 1: RFE match, CV match */
12358e93258fSBjoern A. Zeeb 	compare = get_phy_compare(rfe, cv);
12368e93258fSBjoern A. Zeeb 	for (i = 0; i < *headline_size; i++) {
12378e93258fSBjoern A. Zeeb 		reg = &table->regs[i];
12388e93258fSBjoern A. Zeeb 		target = get_phy_target(reg->addr);
12398e93258fSBjoern A. Zeeb 		if (target == compare) {
12408e93258fSBjoern A. Zeeb 			*headline_idx = i;
12418e93258fSBjoern A. Zeeb 			return 0;
12428e93258fSBjoern A. Zeeb 		}
12438e93258fSBjoern A. Zeeb 	}
12448e93258fSBjoern A. Zeeb 
12458e93258fSBjoern A. Zeeb 	/* case 2: RFE match, CV don't care */
12468e93258fSBjoern A. Zeeb 	compare = get_phy_compare(rfe, PHY_COND_DONT_CARE);
12478e93258fSBjoern A. Zeeb 	for (i = 0; i < *headline_size; i++) {
12488e93258fSBjoern A. Zeeb 		reg = &table->regs[i];
12498e93258fSBjoern A. Zeeb 		target = get_phy_target(reg->addr);
12508e93258fSBjoern A. Zeeb 		if (target == compare) {
12518e93258fSBjoern A. Zeeb 			*headline_idx = i;
12528e93258fSBjoern A. Zeeb 			return 0;
12538e93258fSBjoern A. Zeeb 		}
12548e93258fSBjoern A. Zeeb 	}
12558e93258fSBjoern A. Zeeb 
12568e93258fSBjoern A. Zeeb 	/* case 3: RFE match, CV max in table */
12578e93258fSBjoern A. Zeeb 	for (i = 0; i < *headline_size; i++) {
12588e93258fSBjoern A. Zeeb 		reg = &table->regs[i];
12598e93258fSBjoern A. Zeeb 		rfe_para = get_phy_cond_rfe(reg->addr);
12608e93258fSBjoern A. Zeeb 		cv_para = get_phy_cond_cv(reg->addr);
12618e93258fSBjoern A. Zeeb 		if (rfe_para == rfe) {
12628e93258fSBjoern A. Zeeb 			if (cv_para >= cv_max) {
12638e93258fSBjoern A. Zeeb 				cv_max = cv_para;
12648e93258fSBjoern A. Zeeb 				*headline_idx = i;
12658e93258fSBjoern A. Zeeb 				case_matched = true;
12668e93258fSBjoern A. Zeeb 			}
12678e93258fSBjoern A. Zeeb 		}
12688e93258fSBjoern A. Zeeb 	}
12698e93258fSBjoern A. Zeeb 
12708e93258fSBjoern A. Zeeb 	if (case_matched)
12718e93258fSBjoern A. Zeeb 		return 0;
12728e93258fSBjoern A. Zeeb 
12738e93258fSBjoern A. Zeeb 	/* case 4: RFE don't care, CV max in table */
12748e93258fSBjoern A. Zeeb 	for (i = 0; i < *headline_size; i++) {
12758e93258fSBjoern A. Zeeb 		reg = &table->regs[i];
12768e93258fSBjoern A. Zeeb 		rfe_para = get_phy_cond_rfe(reg->addr);
12778e93258fSBjoern A. Zeeb 		cv_para = get_phy_cond_cv(reg->addr);
12788e93258fSBjoern A. Zeeb 		if (rfe_para == PHY_COND_DONT_CARE) {
12798e93258fSBjoern A. Zeeb 			if (cv_para >= cv_max) {
12808e93258fSBjoern A. Zeeb 				cv_max = cv_para;
12818e93258fSBjoern A. Zeeb 				*headline_idx = i;
12828e93258fSBjoern A. Zeeb 				case_matched = true;
12838e93258fSBjoern A. Zeeb 			}
12848e93258fSBjoern A. Zeeb 		}
12858e93258fSBjoern A. Zeeb 	}
12868e93258fSBjoern A. Zeeb 
12878e93258fSBjoern A. Zeeb 	if (case_matched)
12888e93258fSBjoern A. Zeeb 		return 0;
12898e93258fSBjoern A. Zeeb 
12908e93258fSBjoern A. Zeeb 	return -EINVAL;
12918e93258fSBjoern A. Zeeb }
12928e93258fSBjoern A. Zeeb 
12938e93258fSBjoern A. Zeeb static void rtw89_phy_init_reg(struct rtw89_dev *rtwdev,
12948e93258fSBjoern A. Zeeb 			       const struct rtw89_phy_table *table,
12958e93258fSBjoern A. Zeeb 			       void (*config)(struct rtw89_dev *rtwdev,
12968e93258fSBjoern A. Zeeb 					      const struct rtw89_reg2_def *reg,
12978e93258fSBjoern A. Zeeb 					      enum rtw89_rf_path rf_path,
12988e93258fSBjoern A. Zeeb 					      void *data),
12998e93258fSBjoern A. Zeeb 			       void *extra_data)
13008e93258fSBjoern A. Zeeb {
13018e93258fSBjoern A. Zeeb 	const struct rtw89_reg2_def *reg;
13028e93258fSBjoern A. Zeeb 	enum rtw89_rf_path rf_path = table->rf_path;
13038e93258fSBjoern A. Zeeb 	u8 rfe = rtwdev->efuse.rfe_type;
13048e93258fSBjoern A. Zeeb 	u8 cv = rtwdev->hal.cv;
13058e93258fSBjoern A. Zeeb 	u32 i;
13068e93258fSBjoern A. Zeeb 	u32 headline_size = 0, headline_idx = 0;
13078e93258fSBjoern A. Zeeb 	u32 target = 0, cfg_target;
13088e93258fSBjoern A. Zeeb 	u8 cond;
13098e93258fSBjoern A. Zeeb 	bool is_matched = true;
13108e93258fSBjoern A. Zeeb 	bool target_found = false;
13118e93258fSBjoern A. Zeeb 	int ret;
13128e93258fSBjoern A. Zeeb 
13138e93258fSBjoern A. Zeeb 	ret = rtw89_phy_sel_headline(rtwdev, table, &headline_size,
13148e93258fSBjoern A. Zeeb 				     &headline_idx, rfe, cv);
13158e93258fSBjoern A. Zeeb 	if (ret) {
13168e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "invalid PHY package: %d/%d\n", rfe, cv);
13178e93258fSBjoern A. Zeeb 		return;
13188e93258fSBjoern A. Zeeb 	}
13198e93258fSBjoern A. Zeeb 
13208e93258fSBjoern A. Zeeb 	cfg_target = get_phy_target(table->regs[headline_idx].addr);
13218e93258fSBjoern A. Zeeb 	for (i = headline_size; i < table->n_regs; i++) {
13228e93258fSBjoern A. Zeeb 		reg = &table->regs[i];
13238e93258fSBjoern A. Zeeb 		cond = get_phy_cond(reg->addr);
13248e93258fSBjoern A. Zeeb 		switch (cond) {
13258e93258fSBjoern A. Zeeb 		case PHY_COND_BRANCH_IF:
13268e93258fSBjoern A. Zeeb 		case PHY_COND_BRANCH_ELIF:
13278e93258fSBjoern A. Zeeb 			target = get_phy_target(reg->addr);
13288e93258fSBjoern A. Zeeb 			break;
13298e93258fSBjoern A. Zeeb 		case PHY_COND_BRANCH_ELSE:
13308e93258fSBjoern A. Zeeb 			is_matched = false;
13318e93258fSBjoern A. Zeeb 			if (!target_found) {
13328e93258fSBjoern A. Zeeb 				rtw89_warn(rtwdev, "failed to load CR %x/%x\n",
13338e93258fSBjoern A. Zeeb 					   reg->addr, reg->data);
13348e93258fSBjoern A. Zeeb 				return;
13358e93258fSBjoern A. Zeeb 			}
13368e93258fSBjoern A. Zeeb 			break;
13378e93258fSBjoern A. Zeeb 		case PHY_COND_BRANCH_END:
13388e93258fSBjoern A. Zeeb 			is_matched = true;
13398e93258fSBjoern A. Zeeb 			target_found = false;
13408e93258fSBjoern A. Zeeb 			break;
13418e93258fSBjoern A. Zeeb 		case PHY_COND_CHECK:
13428e93258fSBjoern A. Zeeb 			if (target_found) {
13438e93258fSBjoern A. Zeeb 				is_matched = false;
13448e93258fSBjoern A. Zeeb 				break;
13458e93258fSBjoern A. Zeeb 			}
13468e93258fSBjoern A. Zeeb 
13478e93258fSBjoern A. Zeeb 			if (target == cfg_target) {
13488e93258fSBjoern A. Zeeb 				is_matched = true;
13498e93258fSBjoern A. Zeeb 				target_found = true;
13508e93258fSBjoern A. Zeeb 			} else {
13518e93258fSBjoern A. Zeeb 				is_matched = false;
13528e93258fSBjoern A. Zeeb 				target_found = false;
13538e93258fSBjoern A. Zeeb 			}
13548e93258fSBjoern A. Zeeb 			break;
13558e93258fSBjoern A. Zeeb 		default:
13568e93258fSBjoern A. Zeeb 			if (is_matched)
13578e93258fSBjoern A. Zeeb 				config(rtwdev, reg, rf_path, extra_data);
13588e93258fSBjoern A. Zeeb 			break;
13598e93258fSBjoern A. Zeeb 		}
13608e93258fSBjoern A. Zeeb 	}
13618e93258fSBjoern A. Zeeb }
13628e93258fSBjoern A. Zeeb 
13638e93258fSBjoern A. Zeeb void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev)
13648e93258fSBjoern A. Zeeb {
1365e2340276SBjoern A. Zeeb 	struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
13668e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
1367e2340276SBjoern A. Zeeb 	const struct rtw89_phy_table *bb_table;
1368e2340276SBjoern A. Zeeb 	const struct rtw89_phy_table *bb_gain_table;
13698e93258fSBjoern A. Zeeb 
1370e2340276SBjoern A. Zeeb 	bb_table = elm_info->bb_tbl ? elm_info->bb_tbl : chip->bb_table;
13718e93258fSBjoern A. Zeeb 	rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg, NULL);
13728e93258fSBjoern A. Zeeb 	rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0);
1373e2340276SBjoern A. Zeeb 
1374e2340276SBjoern A. Zeeb 	bb_gain_table = elm_info->bb_gain ? elm_info->bb_gain : chip->bb_gain_table;
13758e93258fSBjoern A. Zeeb 	if (bb_gain_table)
13768e93258fSBjoern A. Zeeb 		rtw89_phy_init_reg(rtwdev, bb_gain_table,
13778e93258fSBjoern A. Zeeb 				   rtw89_phy_config_bb_gain, NULL);
13788e93258fSBjoern A. Zeeb 	rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0);
13798e93258fSBjoern A. Zeeb }
13808e93258fSBjoern A. Zeeb 
13818e93258fSBjoern A. Zeeb static u32 rtw89_phy_nctl_poll(struct rtw89_dev *rtwdev)
13828e93258fSBjoern A. Zeeb {
13838e93258fSBjoern A. Zeeb 	rtw89_phy_write32(rtwdev, 0x8080, 0x4);
13848e93258fSBjoern A. Zeeb 	udelay(1);
13858e93258fSBjoern A. Zeeb 	return rtw89_phy_read32(rtwdev, 0x8080);
13868e93258fSBjoern A. Zeeb }
13878e93258fSBjoern A. Zeeb 
1388e2340276SBjoern A. Zeeb void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio)
13898e93258fSBjoern A. Zeeb {
13908e93258fSBjoern A. Zeeb 	void (*config)(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg,
13918e93258fSBjoern A. Zeeb 		       enum rtw89_rf_path rf_path, void *data);
1392e2340276SBjoern A. Zeeb 	struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
13938e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
13948e93258fSBjoern A. Zeeb 	const struct rtw89_phy_table *rf_table;
13958e93258fSBjoern A. Zeeb 	struct rtw89_fw_h2c_rf_reg_info *rf_reg_info;
13968e93258fSBjoern A. Zeeb 	u8 path;
13978e93258fSBjoern A. Zeeb 
13988e93258fSBjoern A. Zeeb 	rf_reg_info = kzalloc(sizeof(*rf_reg_info), GFP_KERNEL);
13998e93258fSBjoern A. Zeeb 	if (!rf_reg_info)
14008e93258fSBjoern A. Zeeb 		return;
14018e93258fSBjoern A. Zeeb 
14028e93258fSBjoern A. Zeeb 	for (path = RF_PATH_A; path < chip->rf_path_num; path++) {
1403e2340276SBjoern A. Zeeb 		rf_table = elm_info->rf_radio[path] ?
1404e2340276SBjoern A. Zeeb 			   elm_info->rf_radio[path] : chip->rf_table[path];
14058e93258fSBjoern A. Zeeb 		rf_reg_info->rf_path = rf_table->rf_path;
1406e2340276SBjoern A. Zeeb 		if (noio)
1407e2340276SBjoern A. Zeeb 			config = rtw89_phy_config_rf_reg_noio;
1408e2340276SBjoern A. Zeeb 		else
1409e2340276SBjoern A. Zeeb 			config = rf_table->config ? rf_table->config :
1410e2340276SBjoern A. Zeeb 				 rtw89_phy_config_rf_reg;
14118e93258fSBjoern A. Zeeb 		rtw89_phy_init_reg(rtwdev, rf_table, config, (void *)rf_reg_info);
14128e93258fSBjoern A. Zeeb 		if (rtw89_phy_config_rf_reg_fw(rtwdev, rf_reg_info))
14138e93258fSBjoern A. Zeeb 			rtw89_warn(rtwdev, "rf path %d reg h2c config failed\n",
14148e93258fSBjoern A. Zeeb 				   rf_reg_info->rf_path);
14158e93258fSBjoern A. Zeeb 	}
14168e93258fSBjoern A. Zeeb 	kfree(rf_reg_info);
14178e93258fSBjoern A. Zeeb }
14188e93258fSBjoern A. Zeeb 
14198e93258fSBjoern A. Zeeb static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev)
14208e93258fSBjoern A. Zeeb {
1421e2340276SBjoern A. Zeeb 	struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
14228e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
14238e93258fSBjoern A. Zeeb 	const struct rtw89_phy_table *nctl_table;
14248e93258fSBjoern A. Zeeb 	u32 val;
14258e93258fSBjoern A. Zeeb 	int ret;
14268e93258fSBjoern A. Zeeb 
14278e93258fSBjoern A. Zeeb 	/* IQK/DPK clock & reset */
1428e2340276SBjoern A. Zeeb 	rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x3);
1429e2340276SBjoern A. Zeeb 	rtw89_phy_write32_set(rtwdev, R_GNT_BT_WGT_EN, 0x1);
1430e2340276SBjoern A. Zeeb 	rtw89_phy_write32_set(rtwdev, R_P0_PATH_RST, 0x8000000);
1431e2340276SBjoern A. Zeeb 	if (chip->chip_id != RTL8851B)
1432e2340276SBjoern A. Zeeb 		rtw89_phy_write32_set(rtwdev, R_P1_PATH_RST, 0x8000000);
1433e2340276SBjoern A. Zeeb 	if (chip->chip_id == RTL8852B)
1434e2340276SBjoern A. Zeeb 		rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x2);
14358e93258fSBjoern A. Zeeb 
14368e93258fSBjoern A. Zeeb 	/* check 0x8080 */
1437e2340276SBjoern A. Zeeb 	rtw89_phy_write32(rtwdev, R_NCTL_CFG, 0x8);
14388e93258fSBjoern A. Zeeb 
14398e93258fSBjoern A. Zeeb 	ret = read_poll_timeout(rtw89_phy_nctl_poll, val, val == 0x4, 10,
14408e93258fSBjoern A. Zeeb 				1000, false, rtwdev);
14418e93258fSBjoern A. Zeeb 	if (ret)
1442*118d0ff5SBjoern A. Zeeb #if defined(__linux__)
14438e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to poll nctl block\n");
1444*118d0ff5SBjoern A. Zeeb #elif defined(__FreeBSD__)
1445*118d0ff5SBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to poll nctl block: ret %d val %#06x\n", ret, val);
1446*118d0ff5SBjoern A. Zeeb #endif
14478e93258fSBjoern A. Zeeb 
1448e2340276SBjoern A. Zeeb 	nctl_table = elm_info->rf_nctl ? elm_info->rf_nctl : chip->nctl_table;
14498e93258fSBjoern A. Zeeb 	rtw89_phy_init_reg(rtwdev, nctl_table, rtw89_phy_config_bb_reg, NULL);
1450e2340276SBjoern A. Zeeb 
1451e2340276SBjoern A. Zeeb 	if (chip->nctl_post_table)
1452e2340276SBjoern A. Zeeb 		rtw89_rfk_parser(rtwdev, chip->nctl_post_table);
14538e93258fSBjoern A. Zeeb }
14548e93258fSBjoern A. Zeeb 
14558e93258fSBjoern A. Zeeb static u32 rtw89_phy0_phy1_offset(struct rtw89_dev *rtwdev, u32 addr)
14568e93258fSBjoern A. Zeeb {
14578e93258fSBjoern A. Zeeb 	u32 phy_page = addr >> 8;
14588e93258fSBjoern A. Zeeb 	u32 ofst = 0;
14598e93258fSBjoern A. Zeeb 
14608e93258fSBjoern A. Zeeb 	switch (phy_page) {
14618e93258fSBjoern A. Zeeb 	case 0x6:
14628e93258fSBjoern A. Zeeb 	case 0x7:
14638e93258fSBjoern A. Zeeb 	case 0x8:
14648e93258fSBjoern A. Zeeb 	case 0x9:
14658e93258fSBjoern A. Zeeb 	case 0xa:
14668e93258fSBjoern A. Zeeb 	case 0xb:
14678e93258fSBjoern A. Zeeb 	case 0xc:
14688e93258fSBjoern A. Zeeb 	case 0xd:
14698e93258fSBjoern A. Zeeb 	case 0x19:
14708e93258fSBjoern A. Zeeb 	case 0x1a:
14718e93258fSBjoern A. Zeeb 	case 0x1b:
14728e93258fSBjoern A. Zeeb 		ofst = 0x2000;
14738e93258fSBjoern A. Zeeb 		break;
14748e93258fSBjoern A. Zeeb 	default:
14758e93258fSBjoern A. Zeeb 		/* warning case */
14768e93258fSBjoern A. Zeeb 		ofst = 0;
14778e93258fSBjoern A. Zeeb 		break;
14788e93258fSBjoern A. Zeeb 	}
14798e93258fSBjoern A. Zeeb 
14808e93258fSBjoern A. Zeeb 	if (phy_page >= 0x40 && phy_page <= 0x4f)
14818e93258fSBjoern A. Zeeb 		ofst = 0x2000;
14828e93258fSBjoern A. Zeeb 
14838e93258fSBjoern A. Zeeb 	return ofst;
14848e93258fSBjoern A. Zeeb }
14858e93258fSBjoern A. Zeeb 
14868e93258fSBjoern A. Zeeb void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
14878e93258fSBjoern A. Zeeb 			   u32 data, enum rtw89_phy_idx phy_idx)
14888e93258fSBjoern A. Zeeb {
14898e93258fSBjoern A. Zeeb 	if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1)
14908e93258fSBjoern A. Zeeb 		addr += rtw89_phy0_phy1_offset(rtwdev, addr);
14918e93258fSBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, addr, mask, data);
14928e93258fSBjoern A. Zeeb }
14938e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_write32_idx);
14948e93258fSBjoern A. Zeeb 
1495e2340276SBjoern A. Zeeb u32 rtw89_phy_read32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
1496e2340276SBjoern A. Zeeb 			 enum rtw89_phy_idx phy_idx)
1497e2340276SBjoern A. Zeeb {
1498e2340276SBjoern A. Zeeb 	if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1)
1499e2340276SBjoern A. Zeeb 		addr += rtw89_phy0_phy1_offset(rtwdev, addr);
1500e2340276SBjoern A. Zeeb 	return rtw89_phy_read32_mask(rtwdev, addr, mask);
1501e2340276SBjoern A. Zeeb }
1502e2340276SBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_read32_idx);
1503e2340276SBjoern A. Zeeb 
15048e93258fSBjoern A. Zeeb void rtw89_phy_set_phy_regs(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
15058e93258fSBjoern A. Zeeb 			    u32 val)
15068e93258fSBjoern A. Zeeb {
15078e93258fSBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_0);
15088e93258fSBjoern A. Zeeb 
15098e93258fSBjoern A. Zeeb 	if (!rtwdev->dbcc_en)
15108e93258fSBjoern A. Zeeb 		return;
15118e93258fSBjoern A. Zeeb 
15128e93258fSBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_1);
15138e93258fSBjoern A. Zeeb }
15148e93258fSBjoern A. Zeeb 
15158e93258fSBjoern A. Zeeb void rtw89_phy_write_reg3_tbl(struct rtw89_dev *rtwdev,
15168e93258fSBjoern A. Zeeb 			      const struct rtw89_phy_reg3_tbl *tbl)
15178e93258fSBjoern A. Zeeb {
15188e93258fSBjoern A. Zeeb 	const struct rtw89_reg3_def *reg3;
15198e93258fSBjoern A. Zeeb 	int i;
15208e93258fSBjoern A. Zeeb 
15218e93258fSBjoern A. Zeeb 	for (i = 0; i < tbl->size; i++) {
15228e93258fSBjoern A. Zeeb 		reg3 = &tbl->reg3[i];
15238e93258fSBjoern A. Zeeb 		rtw89_phy_write32_mask(rtwdev, reg3->addr, reg3->mask, reg3->data);
15248e93258fSBjoern A. Zeeb 	}
15258e93258fSBjoern A. Zeeb }
15268e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_write_reg3_tbl);
15278e93258fSBjoern A. Zeeb 
1528e2340276SBjoern A. Zeeb static const u8 rtw89_rs_idx_num[] = {
1529e2340276SBjoern A. Zeeb 	[RTW89_RS_CCK] = RTW89_RATE_CCK_NUM,
1530e2340276SBjoern A. Zeeb 	[RTW89_RS_OFDM] = RTW89_RATE_OFDM_NUM,
1531e2340276SBjoern A. Zeeb 	[RTW89_RS_MCS] = RTW89_RATE_MCS_NUM,
1532e2340276SBjoern A. Zeeb 	[RTW89_RS_HEDCM] = RTW89_RATE_HEDCM_NUM,
1533e2340276SBjoern A. Zeeb 	[RTW89_RS_OFFSET] = RTW89_RATE_OFFSET_NUM,
15348e93258fSBjoern A. Zeeb };
15358e93258fSBjoern A. Zeeb 
1536e2340276SBjoern A. Zeeb static const u8 rtw89_rs_nss_num[] = {
15378e93258fSBjoern A. Zeeb 	[RTW89_RS_CCK] = 1,
15388e93258fSBjoern A. Zeeb 	[RTW89_RS_OFDM] = 1,
1539e2340276SBjoern A. Zeeb 	[RTW89_RS_MCS] = RTW89_NSS_NUM,
1540e2340276SBjoern A. Zeeb 	[RTW89_RS_HEDCM] = RTW89_NSS_HEDCM_NUM,
15418e93258fSBjoern A. Zeeb 	[RTW89_RS_OFFSET] = 1,
15428e93258fSBjoern A. Zeeb };
15438e93258fSBjoern A. Zeeb 
15448e93258fSBjoern A. Zeeb static const u8 _byr_of_rs[] = {
15458e93258fSBjoern A. Zeeb 	[RTW89_RS_CCK] = offsetof(struct rtw89_txpwr_byrate, cck),
15468e93258fSBjoern A. Zeeb 	[RTW89_RS_OFDM] = offsetof(struct rtw89_txpwr_byrate, ofdm),
15478e93258fSBjoern A. Zeeb 	[RTW89_RS_MCS] = offsetof(struct rtw89_txpwr_byrate, mcs),
15488e93258fSBjoern A. Zeeb 	[RTW89_RS_HEDCM] = offsetof(struct rtw89_txpwr_byrate, hedcm),
15498e93258fSBjoern A. Zeeb 	[RTW89_RS_OFFSET] = offsetof(struct rtw89_txpwr_byrate, offset),
15508e93258fSBjoern A. Zeeb };
15518e93258fSBjoern A. Zeeb 
15528e93258fSBjoern A. Zeeb #define _byr_seek(rs, raw) ((s8 *)(raw) + _byr_of_rs[rs])
1553e2340276SBjoern A. Zeeb #define _byr_idx(rs, nss, idx) ((nss) * rtw89_rs_idx_num[rs] + (idx))
15548e93258fSBjoern A. Zeeb #define _byr_chk(rs, nss, idx) \
1555e2340276SBjoern A. Zeeb 	((nss) < rtw89_rs_nss_num[rs] && (idx) < rtw89_rs_idx_num[rs])
15568e93258fSBjoern A. Zeeb 
15578e93258fSBjoern A. Zeeb void rtw89_phy_load_txpwr_byrate(struct rtw89_dev *rtwdev,
15588e93258fSBjoern A. Zeeb 				 const struct rtw89_txpwr_table *tbl)
15598e93258fSBjoern A. Zeeb {
15608e93258fSBjoern A. Zeeb 	const struct rtw89_txpwr_byrate_cfg *cfg = tbl->data;
15618e93258fSBjoern A. Zeeb 	const struct rtw89_txpwr_byrate_cfg *end = cfg + tbl->size;
15628e93258fSBjoern A. Zeeb 	s8 *byr;
15638e93258fSBjoern A. Zeeb 	u32 data;
15648e93258fSBjoern A. Zeeb 	u8 i, idx;
15658e93258fSBjoern A. Zeeb 
15668e93258fSBjoern A. Zeeb 	for (; cfg < end; cfg++) {
15678e93258fSBjoern A. Zeeb 		byr = _byr_seek(cfg->rs, &rtwdev->byr[cfg->band]);
15688e93258fSBjoern A. Zeeb 		data = cfg->data;
15698e93258fSBjoern A. Zeeb 
15708e93258fSBjoern A. Zeeb 		for (i = 0; i < cfg->len; i++, data >>= 8) {
15718e93258fSBjoern A. Zeeb 			idx = _byr_idx(cfg->rs, cfg->nss, (cfg->shf + i));
15728e93258fSBjoern A. Zeeb 			byr[idx] = (s8)(data & 0xff);
15738e93258fSBjoern A. Zeeb 		}
15748e93258fSBjoern A. Zeeb 	}
15758e93258fSBjoern A. Zeeb }
15768e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_load_txpwr_byrate);
15778e93258fSBjoern A. Zeeb 
15788e93258fSBjoern A. Zeeb #define _phy_txpwr_rf_to_mac(rtwdev, txpwr_rf)				\
15798e93258fSBjoern A. Zeeb ({									\
15808e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *__c = (rtwdev)->chip;		\
15818e93258fSBjoern A. Zeeb 	(txpwr_rf) >> (__c->txpwr_factor_rf - __c->txpwr_factor_mac);	\
15828e93258fSBjoern A. Zeeb })
15838e93258fSBjoern A. Zeeb 
1584e2340276SBjoern A. Zeeb static
15858e93258fSBjoern A. Zeeb s8 rtw89_phy_read_txpwr_byrate(struct rtw89_dev *rtwdev, u8 band,
15868e93258fSBjoern A. Zeeb 			       const struct rtw89_rate_desc *rate_desc)
15878e93258fSBjoern A. Zeeb {
15888e93258fSBjoern A. Zeeb 	s8 *byr;
15898e93258fSBjoern A. Zeeb 	u8 idx;
15908e93258fSBjoern A. Zeeb 
15918e93258fSBjoern A. Zeeb 	if (rate_desc->rs == RTW89_RS_CCK)
15928e93258fSBjoern A. Zeeb 		band = RTW89_BAND_2G;
15938e93258fSBjoern A. Zeeb 
15948e93258fSBjoern A. Zeeb 	if (!_byr_chk(rate_desc->rs, rate_desc->nss, rate_desc->idx)) {
15958e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
15968e93258fSBjoern A. Zeeb 			    "[TXPWR] unknown byrate desc rs=%d nss=%d idx=%d\n",
15978e93258fSBjoern A. Zeeb 			    rate_desc->rs, rate_desc->nss, rate_desc->idx);
15988e93258fSBjoern A. Zeeb 
15998e93258fSBjoern A. Zeeb 		return 0;
16008e93258fSBjoern A. Zeeb 	}
16018e93258fSBjoern A. Zeeb 
16028e93258fSBjoern A. Zeeb 	byr = _byr_seek(rate_desc->rs, &rtwdev->byr[band]);
16038e93258fSBjoern A. Zeeb 	idx = _byr_idx(rate_desc->rs, rate_desc->nss, rate_desc->idx);
16048e93258fSBjoern A. Zeeb 
16058e93258fSBjoern A. Zeeb 	return _phy_txpwr_rf_to_mac(rtwdev, byr[idx]);
16068e93258fSBjoern A. Zeeb }
16078e93258fSBjoern A. Zeeb 
16088e93258fSBjoern A. Zeeb static u8 rtw89_channel_6g_to_idx(struct rtw89_dev *rtwdev, u8 channel_6g)
16098e93258fSBjoern A. Zeeb {
16108e93258fSBjoern A. Zeeb 	switch (channel_6g) {
16118e93258fSBjoern A. Zeeb 	case 1 ... 29:
16128e93258fSBjoern A. Zeeb 		return (channel_6g - 1) / 2;
16138e93258fSBjoern A. Zeeb 	case 33 ... 61:
16148e93258fSBjoern A. Zeeb 		return (channel_6g - 3) / 2;
16158e93258fSBjoern A. Zeeb 	case 65 ... 93:
16168e93258fSBjoern A. Zeeb 		return (channel_6g - 5) / 2;
16178e93258fSBjoern A. Zeeb 	case 97 ... 125:
16188e93258fSBjoern A. Zeeb 		return (channel_6g - 7) / 2;
16198e93258fSBjoern A. Zeeb 	case 129 ... 157:
16208e93258fSBjoern A. Zeeb 		return (channel_6g - 9) / 2;
16218e93258fSBjoern A. Zeeb 	case 161 ... 189:
16228e93258fSBjoern A. Zeeb 		return (channel_6g - 11) / 2;
16238e93258fSBjoern A. Zeeb 	case 193 ... 221:
16248e93258fSBjoern A. Zeeb 		return (channel_6g - 13) / 2;
16258e93258fSBjoern A. Zeeb 	case 225 ... 253:
16268e93258fSBjoern A. Zeeb 		return (channel_6g - 15) / 2;
16278e93258fSBjoern A. Zeeb 	default:
16288e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "unknown 6g channel: %d\n", channel_6g);
16298e93258fSBjoern A. Zeeb 		return 0;
16308e93258fSBjoern A. Zeeb 	}
16318e93258fSBjoern A. Zeeb }
16328e93258fSBjoern A. Zeeb 
16338e93258fSBjoern A. Zeeb static u8 rtw89_channel_to_idx(struct rtw89_dev *rtwdev, u8 band, u8 channel)
16348e93258fSBjoern A. Zeeb {
16358e93258fSBjoern A. Zeeb 	if (band == RTW89_BAND_6G)
16368e93258fSBjoern A. Zeeb 		return rtw89_channel_6g_to_idx(rtwdev, channel);
16378e93258fSBjoern A. Zeeb 
16388e93258fSBjoern A. Zeeb 	switch (channel) {
16398e93258fSBjoern A. Zeeb 	case 1 ... 14:
16408e93258fSBjoern A. Zeeb 		return channel - 1;
16418e93258fSBjoern A. Zeeb 	case 36 ... 64:
16428e93258fSBjoern A. Zeeb 		return (channel - 36) / 2;
16438e93258fSBjoern A. Zeeb 	case 100 ... 144:
16448e93258fSBjoern A. Zeeb 		return ((channel - 100) / 2) + 15;
16458e93258fSBjoern A. Zeeb 	case 149 ... 177:
16468e93258fSBjoern A. Zeeb 		return ((channel - 149) / 2) + 38;
16478e93258fSBjoern A. Zeeb 	default:
16488e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "unknown channel: %d\n", channel);
16498e93258fSBjoern A. Zeeb 		return 0;
16508e93258fSBjoern A. Zeeb 	}
16518e93258fSBjoern A. Zeeb }
16528e93258fSBjoern A. Zeeb 
16538e93258fSBjoern A. Zeeb s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
16548e93258fSBjoern A. Zeeb 			      u8 bw, u8 ntx, u8 rs, u8 bf, u8 ch)
16558e93258fSBjoern A. Zeeb {
1656e2340276SBjoern A. Zeeb 	const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms;
1657e2340276SBjoern A. Zeeb 	const struct rtw89_txpwr_rule_2ghz *rule_2ghz = &rfe_parms->rule_2ghz;
1658e2340276SBjoern A. Zeeb 	const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz;
1659e2340276SBjoern A. Zeeb 	const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz;
1660e2340276SBjoern A. Zeeb 	struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
16618e93258fSBjoern A. Zeeb 	u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch);
16628e93258fSBjoern A. Zeeb 	u8 regd = rtw89_regd_get(rtwdev, band);
1663e2340276SBjoern A. Zeeb 	u8 reg6 = regulatory->reg_6ghz_power;
16648e93258fSBjoern A. Zeeb 	s8 lmt = 0, sar;
16658e93258fSBjoern A. Zeeb 
16668e93258fSBjoern A. Zeeb 	switch (band) {
16678e93258fSBjoern A. Zeeb 	case RTW89_BAND_2G:
1668e2340276SBjoern A. Zeeb 		lmt = (*rule_2ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
1669e2340276SBjoern A. Zeeb 		if (lmt)
1670e2340276SBjoern A. Zeeb 			break;
1671e2340276SBjoern A. Zeeb 
1672e2340276SBjoern A. Zeeb 		lmt = (*rule_2ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx];
16738e93258fSBjoern A. Zeeb 		break;
16748e93258fSBjoern A. Zeeb 	case RTW89_BAND_5G:
1675e2340276SBjoern A. Zeeb 		lmt = (*rule_5ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
1676e2340276SBjoern A. Zeeb 		if (lmt)
1677e2340276SBjoern A. Zeeb 			break;
1678e2340276SBjoern A. Zeeb 
1679e2340276SBjoern A. Zeeb 		lmt = (*rule_5ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx];
16808e93258fSBjoern A. Zeeb 		break;
16818e93258fSBjoern A. Zeeb 	case RTW89_BAND_6G:
1682e2340276SBjoern A. Zeeb 		lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][regd][reg6][ch_idx];
1683e2340276SBjoern A. Zeeb 		if (lmt)
1684e2340276SBjoern A. Zeeb 			break;
1685e2340276SBjoern A. Zeeb 
1686e2340276SBjoern A. Zeeb 		lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][RTW89_WW]
1687e2340276SBjoern A. Zeeb 				       [RTW89_REG_6GHZ_POWER_DFLT]
1688e2340276SBjoern A. Zeeb 				       [ch_idx];
16898e93258fSBjoern A. Zeeb 		break;
16908e93258fSBjoern A. Zeeb 	default:
16918e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "unknown band type: %d\n", band);
16928e93258fSBjoern A. Zeeb 		return 0;
16938e93258fSBjoern A. Zeeb 	}
16948e93258fSBjoern A. Zeeb 
16958e93258fSBjoern A. Zeeb 	lmt = _phy_txpwr_rf_to_mac(rtwdev, lmt);
16968e93258fSBjoern A. Zeeb 	sar = rtw89_query_sar(rtwdev);
16978e93258fSBjoern A. Zeeb 
16988e93258fSBjoern A. Zeeb 	return min(lmt, sar);
16998e93258fSBjoern A. Zeeb }
17008e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_read_txpwr_limit);
17018e93258fSBjoern A. Zeeb 
17028e93258fSBjoern A. Zeeb #define __fill_txpwr_limit_nonbf_bf(ptr, band, bw, ntx, rs, ch)		\
17038e93258fSBjoern A. Zeeb 	do {								\
17048e93258fSBjoern A. Zeeb 		u8 __i;							\
17058e93258fSBjoern A. Zeeb 		for (__i = 0; __i < RTW89_BF_NUM; __i++)		\
17068e93258fSBjoern A. Zeeb 			ptr[__i] = rtw89_phy_read_txpwr_limit(rtwdev,	\
17078e93258fSBjoern A. Zeeb 							      band,	\
17088e93258fSBjoern A. Zeeb 							      bw, ntx,	\
17098e93258fSBjoern A. Zeeb 							      rs, __i,	\
17108e93258fSBjoern A. Zeeb 							      (ch));	\
17118e93258fSBjoern A. Zeeb 	} while (0)
17128e93258fSBjoern A. Zeeb 
17138e93258fSBjoern A. Zeeb static void rtw89_phy_fill_txpwr_limit_20m(struct rtw89_dev *rtwdev,
17148e93258fSBjoern A. Zeeb 					   struct rtw89_txpwr_limit *lmt,
17158e93258fSBjoern A. Zeeb 					   u8 band, u8 ntx, u8 ch)
17168e93258fSBjoern A. Zeeb {
17178e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->cck_20m, band, RTW89_CHANNEL_WIDTH_20,
17188e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_CCK, ch);
17198e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->cck_40m, band, RTW89_CHANNEL_WIDTH_40,
17208e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_CCK, ch);
17218e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->ofdm, band, RTW89_CHANNEL_WIDTH_20,
17228e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_OFDM, ch);
17238e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[0], band,
17248e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
17258e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch);
17268e93258fSBjoern A. Zeeb }
17278e93258fSBjoern A. Zeeb 
17288e93258fSBjoern A. Zeeb static void rtw89_phy_fill_txpwr_limit_40m(struct rtw89_dev *rtwdev,
17298e93258fSBjoern A. Zeeb 					   struct rtw89_txpwr_limit *lmt,
17308e93258fSBjoern A. Zeeb 					   u8 band, u8 ntx, u8 ch, u8 pri_ch)
17318e93258fSBjoern A. Zeeb {
17328e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->cck_20m, band, RTW89_CHANNEL_WIDTH_20,
17338e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_CCK, ch - 2);
17348e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->cck_40m, band, RTW89_CHANNEL_WIDTH_40,
17358e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_CCK, ch);
17368e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->ofdm, band, RTW89_CHANNEL_WIDTH_20,
17378e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_OFDM, pri_ch);
17388e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[0], band,
17398e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
17408e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 2);
17418e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[1], band,
17428e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
17438e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 2);
17448e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_40m[0], band,
17458e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_40,
17468e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch);
17478e93258fSBjoern A. Zeeb }
17488e93258fSBjoern A. Zeeb 
17498e93258fSBjoern A. Zeeb static void rtw89_phy_fill_txpwr_limit_80m(struct rtw89_dev *rtwdev,
17508e93258fSBjoern A. Zeeb 					   struct rtw89_txpwr_limit *lmt,
17518e93258fSBjoern A. Zeeb 					   u8 band, u8 ntx, u8 ch, u8 pri_ch)
17528e93258fSBjoern A. Zeeb {
17538e93258fSBjoern A. Zeeb 	s8 val_0p5_n[RTW89_BF_NUM];
17548e93258fSBjoern A. Zeeb 	s8 val_0p5_p[RTW89_BF_NUM];
17558e93258fSBjoern A. Zeeb 	u8 i;
17568e93258fSBjoern A. Zeeb 
17578e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->ofdm, band, RTW89_CHANNEL_WIDTH_20,
17588e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_OFDM, pri_ch);
17598e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[0], band,
17608e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
17618e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 6);
17628e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[1], band,
17638e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
17648e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 2);
17658e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[2], band,
17668e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
17678e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 2);
17688e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[3], band,
17698e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
17708e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 6);
17718e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_40m[0], band,
17728e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_40,
17738e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 4);
17748e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_40m[1], band,
17758e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_40,
17768e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 4);
17778e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_80m[0], band,
17788e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_80,
17798e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch);
17808e93258fSBjoern A. Zeeb 
17818e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(val_0p5_n, band, RTW89_CHANNEL_WIDTH_40,
17828e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 4);
17838e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(val_0p5_p, band, RTW89_CHANNEL_WIDTH_40,
17848e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 4);
17858e93258fSBjoern A. Zeeb 
17868e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_BF_NUM; i++)
17878e93258fSBjoern A. Zeeb 		lmt->mcs_40m_0p5[i] = min_t(s8, val_0p5_n[i], val_0p5_p[i]);
17888e93258fSBjoern A. Zeeb }
17898e93258fSBjoern A. Zeeb 
17908e93258fSBjoern A. Zeeb static void rtw89_phy_fill_txpwr_limit_160m(struct rtw89_dev *rtwdev,
17918e93258fSBjoern A. Zeeb 					    struct rtw89_txpwr_limit *lmt,
17928e93258fSBjoern A. Zeeb 					    u8 band, u8 ntx, u8 ch, u8 pri_ch)
17938e93258fSBjoern A. Zeeb {
17948e93258fSBjoern A. Zeeb 	s8 val_0p5_n[RTW89_BF_NUM];
17958e93258fSBjoern A. Zeeb 	s8 val_0p5_p[RTW89_BF_NUM];
17968e93258fSBjoern A. Zeeb 	s8 val_2p5_n[RTW89_BF_NUM];
17978e93258fSBjoern A. Zeeb 	s8 val_2p5_p[RTW89_BF_NUM];
17988e93258fSBjoern A. Zeeb 	u8 i;
17998e93258fSBjoern A. Zeeb 
18008e93258fSBjoern A. Zeeb 	/* fill ofdm section */
18018e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->ofdm, band, RTW89_CHANNEL_WIDTH_20,
18028e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_OFDM, pri_ch);
18038e93258fSBjoern A. Zeeb 
18048e93258fSBjoern A. Zeeb 	/* fill mcs 20m section */
18058e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[0], band,
18068e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
18078e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 14);
18088e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[1], band,
18098e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
18108e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 10);
18118e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[2], band,
18128e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
18138e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 6);
18148e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[3], band,
18158e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
18168e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 2);
18178e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[4], band,
18188e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
18198e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 2);
18208e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[5], band,
18218e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
18228e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 6);
18238e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[6], band,
18248e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
18258e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 10);
18268e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_20m[7], band,
18278e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_20,
18288e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 14);
18298e93258fSBjoern A. Zeeb 
18308e93258fSBjoern A. Zeeb 	/* fill mcs 40m section */
18318e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_40m[0], band,
18328e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_40,
18338e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 12);
18348e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_40m[1], band,
18358e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_40,
18368e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 4);
18378e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_40m[2], band,
18388e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_40,
18398e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 4);
18408e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_40m[3], band,
18418e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_40,
18428e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 12);
18438e93258fSBjoern A. Zeeb 
18448e93258fSBjoern A. Zeeb 	/* fill mcs 80m section */
18458e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_80m[0], band,
18468e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_80,
18478e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 8);
18488e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_80m[1], band,
18498e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_80,
18508e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 8);
18518e93258fSBjoern A. Zeeb 
18528e93258fSBjoern A. Zeeb 	/* fill mcs 160m section */
18538e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(lmt->mcs_160m, band,
18548e93258fSBjoern A. Zeeb 				    RTW89_CHANNEL_WIDTH_160,
18558e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch);
18568e93258fSBjoern A. Zeeb 
18578e93258fSBjoern A. Zeeb 	/* fill mcs 40m 0p5 section */
18588e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(val_0p5_n, band, RTW89_CHANNEL_WIDTH_40,
18598e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 4);
18608e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(val_0p5_p, band, RTW89_CHANNEL_WIDTH_40,
18618e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 4);
18628e93258fSBjoern A. Zeeb 
18638e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_BF_NUM; i++)
18648e93258fSBjoern A. Zeeb 		lmt->mcs_40m_0p5[i] = min_t(s8, val_0p5_n[i], val_0p5_p[i]);
18658e93258fSBjoern A. Zeeb 
18668e93258fSBjoern A. Zeeb 	/* fill mcs 40m 2p5 section */
18678e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(val_2p5_n, band, RTW89_CHANNEL_WIDTH_40,
18688e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch - 8);
18698e93258fSBjoern A. Zeeb 	__fill_txpwr_limit_nonbf_bf(val_2p5_p, band, RTW89_CHANNEL_WIDTH_40,
18708e93258fSBjoern A. Zeeb 				    ntx, RTW89_RS_MCS, ch + 8);
18718e93258fSBjoern A. Zeeb 
18728e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_BF_NUM; i++)
18738e93258fSBjoern A. Zeeb 		lmt->mcs_40m_2p5[i] = min_t(s8, val_2p5_n[i], val_2p5_p[i]);
18748e93258fSBjoern A. Zeeb }
18758e93258fSBjoern A. Zeeb 
1876e2340276SBjoern A. Zeeb static
18778e93258fSBjoern A. Zeeb void rtw89_phy_fill_txpwr_limit(struct rtw89_dev *rtwdev,
18788e93258fSBjoern A. Zeeb 				const struct rtw89_chan *chan,
18798e93258fSBjoern A. Zeeb 				struct rtw89_txpwr_limit *lmt,
18808e93258fSBjoern A. Zeeb 				u8 ntx)
18818e93258fSBjoern A. Zeeb {
18828e93258fSBjoern A. Zeeb 	u8 band = chan->band_type;
18838e93258fSBjoern A. Zeeb 	u8 pri_ch = chan->primary_channel;
18848e93258fSBjoern A. Zeeb 	u8 ch = chan->channel;
18858e93258fSBjoern A. Zeeb 	u8 bw = chan->band_width;
18868e93258fSBjoern A. Zeeb 
18878e93258fSBjoern A. Zeeb 	memset(lmt, 0, sizeof(*lmt));
18888e93258fSBjoern A. Zeeb 
18898e93258fSBjoern A. Zeeb 	switch (bw) {
18908e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_20:
18918e93258fSBjoern A. Zeeb 		rtw89_phy_fill_txpwr_limit_20m(rtwdev, lmt, band, ntx, ch);
18928e93258fSBjoern A. Zeeb 		break;
18938e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_40:
18948e93258fSBjoern A. Zeeb 		rtw89_phy_fill_txpwr_limit_40m(rtwdev, lmt, band, ntx, ch,
18958e93258fSBjoern A. Zeeb 					       pri_ch);
18968e93258fSBjoern A. Zeeb 		break;
18978e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_80:
18988e93258fSBjoern A. Zeeb 		rtw89_phy_fill_txpwr_limit_80m(rtwdev, lmt, band, ntx, ch,
18998e93258fSBjoern A. Zeeb 					       pri_ch);
19008e93258fSBjoern A. Zeeb 		break;
19018e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_160:
19028e93258fSBjoern A. Zeeb 		rtw89_phy_fill_txpwr_limit_160m(rtwdev, lmt, band, ntx, ch,
19038e93258fSBjoern A. Zeeb 						pri_ch);
19048e93258fSBjoern A. Zeeb 		break;
19058e93258fSBjoern A. Zeeb 	}
19068e93258fSBjoern A. Zeeb }
19078e93258fSBjoern A. Zeeb 
19088e93258fSBjoern A. Zeeb static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
19098e93258fSBjoern A. Zeeb 					u8 ru, u8 ntx, u8 ch)
19108e93258fSBjoern A. Zeeb {
1911e2340276SBjoern A. Zeeb 	const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms;
1912e2340276SBjoern A. Zeeb 	const struct rtw89_txpwr_rule_2ghz *rule_2ghz = &rfe_parms->rule_2ghz;
1913e2340276SBjoern A. Zeeb 	const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz;
1914e2340276SBjoern A. Zeeb 	const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz;
1915e2340276SBjoern A. Zeeb 	struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
19168e93258fSBjoern A. Zeeb 	u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch);
19178e93258fSBjoern A. Zeeb 	u8 regd = rtw89_regd_get(rtwdev, band);
1918e2340276SBjoern A. Zeeb 	u8 reg6 = regulatory->reg_6ghz_power;
19198e93258fSBjoern A. Zeeb 	s8 lmt_ru = 0, sar;
19208e93258fSBjoern A. Zeeb 
19218e93258fSBjoern A. Zeeb 	switch (band) {
19228e93258fSBjoern A. Zeeb 	case RTW89_BAND_2G:
1923e2340276SBjoern A. Zeeb 		lmt_ru = (*rule_2ghz->lmt_ru)[ru][ntx][regd][ch_idx];
1924e2340276SBjoern A. Zeeb 		if (lmt_ru)
1925e2340276SBjoern A. Zeeb 			break;
1926e2340276SBjoern A. Zeeb 
1927e2340276SBjoern A. Zeeb 		lmt_ru = (*rule_2ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx];
19288e93258fSBjoern A. Zeeb 		break;
19298e93258fSBjoern A. Zeeb 	case RTW89_BAND_5G:
1930e2340276SBjoern A. Zeeb 		lmt_ru = (*rule_5ghz->lmt_ru)[ru][ntx][regd][ch_idx];
1931e2340276SBjoern A. Zeeb 		if (lmt_ru)
1932e2340276SBjoern A. Zeeb 			break;
1933e2340276SBjoern A. Zeeb 
1934e2340276SBjoern A. Zeeb 		lmt_ru = (*rule_5ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx];
19358e93258fSBjoern A. Zeeb 		break;
19368e93258fSBjoern A. Zeeb 	case RTW89_BAND_6G:
1937e2340276SBjoern A. Zeeb 		lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][regd][reg6][ch_idx];
1938e2340276SBjoern A. Zeeb 		if (lmt_ru)
1939e2340276SBjoern A. Zeeb 			break;
1940e2340276SBjoern A. Zeeb 
1941e2340276SBjoern A. Zeeb 		lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][RTW89_WW]
1942e2340276SBjoern A. Zeeb 					     [RTW89_REG_6GHZ_POWER_DFLT]
1943e2340276SBjoern A. Zeeb 					     [ch_idx];
19448e93258fSBjoern A. Zeeb 		break;
19458e93258fSBjoern A. Zeeb 	default:
19468e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "unknown band type: %d\n", band);
19478e93258fSBjoern A. Zeeb 		return 0;
19488e93258fSBjoern A. Zeeb 	}
19498e93258fSBjoern A. Zeeb 
19508e93258fSBjoern A. Zeeb 	lmt_ru = _phy_txpwr_rf_to_mac(rtwdev, lmt_ru);
19518e93258fSBjoern A. Zeeb 	sar = rtw89_query_sar(rtwdev);
19528e93258fSBjoern A. Zeeb 
19538e93258fSBjoern A. Zeeb 	return min(lmt_ru, sar);
19548e93258fSBjoern A. Zeeb }
19558e93258fSBjoern A. Zeeb 
19568e93258fSBjoern A. Zeeb static void
19578e93258fSBjoern A. Zeeb rtw89_phy_fill_txpwr_limit_ru_20m(struct rtw89_dev *rtwdev,
19588e93258fSBjoern A. Zeeb 				  struct rtw89_txpwr_limit_ru *lmt_ru,
19598e93258fSBjoern A. Zeeb 				  u8 band, u8 ntx, u8 ch)
19608e93258fSBjoern A. Zeeb {
19618e93258fSBjoern A. Zeeb 	lmt_ru->ru26[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
19628e93258fSBjoern A. Zeeb 							RTW89_RU26,
19638e93258fSBjoern A. Zeeb 							ntx, ch);
19648e93258fSBjoern A. Zeeb 	lmt_ru->ru52[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
19658e93258fSBjoern A. Zeeb 							RTW89_RU52,
19668e93258fSBjoern A. Zeeb 							ntx, ch);
19678e93258fSBjoern A. Zeeb 	lmt_ru->ru106[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
19688e93258fSBjoern A. Zeeb 							 RTW89_RU106,
19698e93258fSBjoern A. Zeeb 							 ntx, ch);
19708e93258fSBjoern A. Zeeb }
19718e93258fSBjoern A. Zeeb 
19728e93258fSBjoern A. Zeeb static void
19738e93258fSBjoern A. Zeeb rtw89_phy_fill_txpwr_limit_ru_40m(struct rtw89_dev *rtwdev,
19748e93258fSBjoern A. Zeeb 				  struct rtw89_txpwr_limit_ru *lmt_ru,
19758e93258fSBjoern A. Zeeb 				  u8 band, u8 ntx, u8 ch)
19768e93258fSBjoern A. Zeeb {
19778e93258fSBjoern A. Zeeb 	lmt_ru->ru26[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
19788e93258fSBjoern A. Zeeb 							RTW89_RU26,
19798e93258fSBjoern A. Zeeb 							ntx, ch - 2);
19808e93258fSBjoern A. Zeeb 	lmt_ru->ru26[1] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
19818e93258fSBjoern A. Zeeb 							RTW89_RU26,
19828e93258fSBjoern A. Zeeb 							ntx, ch + 2);
19838e93258fSBjoern A. Zeeb 	lmt_ru->ru52[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
19848e93258fSBjoern A. Zeeb 							RTW89_RU52,
19858e93258fSBjoern A. Zeeb 							ntx, ch - 2);
19868e93258fSBjoern A. Zeeb 	lmt_ru->ru52[1] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
19878e93258fSBjoern A. Zeeb 							RTW89_RU52,
19888e93258fSBjoern A. Zeeb 							ntx, ch + 2);
19898e93258fSBjoern A. Zeeb 	lmt_ru->ru106[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
19908e93258fSBjoern A. Zeeb 							 RTW89_RU106,
19918e93258fSBjoern A. Zeeb 							 ntx, ch - 2);
19928e93258fSBjoern A. Zeeb 	lmt_ru->ru106[1] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
19938e93258fSBjoern A. Zeeb 							 RTW89_RU106,
19948e93258fSBjoern A. Zeeb 							 ntx, ch + 2);
19958e93258fSBjoern A. Zeeb }
19968e93258fSBjoern A. Zeeb 
19978e93258fSBjoern A. Zeeb static void
19988e93258fSBjoern A. Zeeb rtw89_phy_fill_txpwr_limit_ru_80m(struct rtw89_dev *rtwdev,
19998e93258fSBjoern A. Zeeb 				  struct rtw89_txpwr_limit_ru *lmt_ru,
20008e93258fSBjoern A. Zeeb 				  u8 band, u8 ntx, u8 ch)
20018e93258fSBjoern A. Zeeb {
20028e93258fSBjoern A. Zeeb 	lmt_ru->ru26[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20038e93258fSBjoern A. Zeeb 							RTW89_RU26,
20048e93258fSBjoern A. Zeeb 							ntx, ch - 6);
20058e93258fSBjoern A. Zeeb 	lmt_ru->ru26[1] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20068e93258fSBjoern A. Zeeb 							RTW89_RU26,
20078e93258fSBjoern A. Zeeb 							ntx, ch - 2);
20088e93258fSBjoern A. Zeeb 	lmt_ru->ru26[2] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20098e93258fSBjoern A. Zeeb 							RTW89_RU26,
20108e93258fSBjoern A. Zeeb 							ntx, ch + 2);
20118e93258fSBjoern A. Zeeb 	lmt_ru->ru26[3] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20128e93258fSBjoern A. Zeeb 							RTW89_RU26,
20138e93258fSBjoern A. Zeeb 							ntx, ch + 6);
20148e93258fSBjoern A. Zeeb 	lmt_ru->ru52[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20158e93258fSBjoern A. Zeeb 							RTW89_RU52,
20168e93258fSBjoern A. Zeeb 							ntx, ch - 6);
20178e93258fSBjoern A. Zeeb 	lmt_ru->ru52[1] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20188e93258fSBjoern A. Zeeb 							RTW89_RU52,
20198e93258fSBjoern A. Zeeb 							ntx, ch - 2);
20208e93258fSBjoern A. Zeeb 	lmt_ru->ru52[2] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20218e93258fSBjoern A. Zeeb 							RTW89_RU52,
20228e93258fSBjoern A. Zeeb 							ntx, ch + 2);
20238e93258fSBjoern A. Zeeb 	lmt_ru->ru52[3] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20248e93258fSBjoern A. Zeeb 							RTW89_RU52,
20258e93258fSBjoern A. Zeeb 							ntx, ch + 6);
20268e93258fSBjoern A. Zeeb 	lmt_ru->ru106[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20278e93258fSBjoern A. Zeeb 							 RTW89_RU106,
20288e93258fSBjoern A. Zeeb 							 ntx, ch - 6);
20298e93258fSBjoern A. Zeeb 	lmt_ru->ru106[1] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20308e93258fSBjoern A. Zeeb 							 RTW89_RU106,
20318e93258fSBjoern A. Zeeb 							 ntx, ch - 2);
20328e93258fSBjoern A. Zeeb 	lmt_ru->ru106[2] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20338e93258fSBjoern A. Zeeb 							 RTW89_RU106,
20348e93258fSBjoern A. Zeeb 							 ntx, ch + 2);
20358e93258fSBjoern A. Zeeb 	lmt_ru->ru106[3] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20368e93258fSBjoern A. Zeeb 							 RTW89_RU106,
20378e93258fSBjoern A. Zeeb 							 ntx, ch + 6);
20388e93258fSBjoern A. Zeeb }
20398e93258fSBjoern A. Zeeb 
20408e93258fSBjoern A. Zeeb static void
20418e93258fSBjoern A. Zeeb rtw89_phy_fill_txpwr_limit_ru_160m(struct rtw89_dev *rtwdev,
20428e93258fSBjoern A. Zeeb 				   struct rtw89_txpwr_limit_ru *lmt_ru,
20438e93258fSBjoern A. Zeeb 				   u8 band, u8 ntx, u8 ch)
20448e93258fSBjoern A. Zeeb {
20458e93258fSBjoern A. Zeeb 	static const int ofst[] = { -14, -10, -6, -2, 2, 6, 10, 14 };
20468e93258fSBjoern A. Zeeb 	int i;
20478e93258fSBjoern A. Zeeb 
20488e93258fSBjoern A. Zeeb #if defined(__linux__)
20498e93258fSBjoern A. Zeeb 	static_assert(ARRAY_SIZE(ofst) == RTW89_RU_SEC_NUM);
20508e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
20518e93258fSBjoern A. Zeeb 	rtw89_static_assert(ARRAY_SIZE(ofst) == RTW89_RU_SEC_NUM);
20528e93258fSBjoern A. Zeeb #endif
20538e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_RU_SEC_NUM; i++) {
20548e93258fSBjoern A. Zeeb 		lmt_ru->ru26[i] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20558e93258fSBjoern A. Zeeb 								RTW89_RU26,
20568e93258fSBjoern A. Zeeb 								ntx,
20578e93258fSBjoern A. Zeeb 								ch + ofst[i]);
20588e93258fSBjoern A. Zeeb 		lmt_ru->ru52[i] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20598e93258fSBjoern A. Zeeb 								RTW89_RU52,
20608e93258fSBjoern A. Zeeb 								ntx,
20618e93258fSBjoern A. Zeeb 								ch + ofst[i]);
20628e93258fSBjoern A. Zeeb 		lmt_ru->ru106[i] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
20638e93258fSBjoern A. Zeeb 								 RTW89_RU106,
20648e93258fSBjoern A. Zeeb 								 ntx,
20658e93258fSBjoern A. Zeeb 								 ch + ofst[i]);
20668e93258fSBjoern A. Zeeb 	}
20678e93258fSBjoern A. Zeeb }
20688e93258fSBjoern A. Zeeb 
2069e2340276SBjoern A. Zeeb static
20708e93258fSBjoern A. Zeeb void rtw89_phy_fill_txpwr_limit_ru(struct rtw89_dev *rtwdev,
20718e93258fSBjoern A. Zeeb 				   const struct rtw89_chan *chan,
20728e93258fSBjoern A. Zeeb 				   struct rtw89_txpwr_limit_ru *lmt_ru,
20738e93258fSBjoern A. Zeeb 				   u8 ntx)
20748e93258fSBjoern A. Zeeb {
20758e93258fSBjoern A. Zeeb 	u8 band = chan->band_type;
20768e93258fSBjoern A. Zeeb 	u8 ch = chan->channel;
20778e93258fSBjoern A. Zeeb 	u8 bw = chan->band_width;
20788e93258fSBjoern A. Zeeb 
20798e93258fSBjoern A. Zeeb 	memset(lmt_ru, 0, sizeof(*lmt_ru));
20808e93258fSBjoern A. Zeeb 
20818e93258fSBjoern A. Zeeb 	switch (bw) {
20828e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_20:
20838e93258fSBjoern A. Zeeb 		rtw89_phy_fill_txpwr_limit_ru_20m(rtwdev, lmt_ru, band, ntx,
20848e93258fSBjoern A. Zeeb 						  ch);
20858e93258fSBjoern A. Zeeb 		break;
20868e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_40:
20878e93258fSBjoern A. Zeeb 		rtw89_phy_fill_txpwr_limit_ru_40m(rtwdev, lmt_ru, band, ntx,
20888e93258fSBjoern A. Zeeb 						  ch);
20898e93258fSBjoern A. Zeeb 		break;
20908e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_80:
20918e93258fSBjoern A. Zeeb 		rtw89_phy_fill_txpwr_limit_ru_80m(rtwdev, lmt_ru, band, ntx,
20928e93258fSBjoern A. Zeeb 						  ch);
20938e93258fSBjoern A. Zeeb 		break;
20948e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_160:
20958e93258fSBjoern A. Zeeb 		rtw89_phy_fill_txpwr_limit_ru_160m(rtwdev, lmt_ru, band, ntx,
20968e93258fSBjoern A. Zeeb 						   ch);
20978e93258fSBjoern A. Zeeb 		break;
20988e93258fSBjoern A. Zeeb 	}
20998e93258fSBjoern A. Zeeb }
2100e2340276SBjoern A. Zeeb 
2101e2340276SBjoern A. Zeeb void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev,
2102e2340276SBjoern A. Zeeb 				const struct rtw89_chan *chan,
2103e2340276SBjoern A. Zeeb 				enum rtw89_phy_idx phy_idx)
2104e2340276SBjoern A. Zeeb {
2105e2340276SBjoern A. Zeeb 	u8 max_nss_num = rtwdev->chip->rf_path_num;
2106e2340276SBjoern A. Zeeb 	static const u8 rs[] = {
2107e2340276SBjoern A. Zeeb 		RTW89_RS_CCK,
2108e2340276SBjoern A. Zeeb 		RTW89_RS_OFDM,
2109e2340276SBjoern A. Zeeb 		RTW89_RS_MCS,
2110e2340276SBjoern A. Zeeb 		RTW89_RS_HEDCM,
2111e2340276SBjoern A. Zeeb 	};
2112e2340276SBjoern A. Zeeb 	struct rtw89_rate_desc cur;
2113e2340276SBjoern A. Zeeb 	u8 band = chan->band_type;
2114e2340276SBjoern A. Zeeb 	u8 ch = chan->channel;
2115e2340276SBjoern A. Zeeb 	u32 addr, val;
2116e2340276SBjoern A. Zeeb 	s8 v[4] = {};
2117e2340276SBjoern A. Zeeb 	u8 i;
2118e2340276SBjoern A. Zeeb 
2119e2340276SBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
2120e2340276SBjoern A. Zeeb 		    "[TXPWR] set txpwr byrate with ch=%d\n", ch);
2121e2340276SBjoern A. Zeeb 
2122e2340276SBjoern A. Zeeb 	BUILD_BUG_ON(rtw89_rs_idx_num[RTW89_RS_CCK] % 4);
2123e2340276SBjoern A. Zeeb 	BUILD_BUG_ON(rtw89_rs_idx_num[RTW89_RS_OFDM] % 4);
2124e2340276SBjoern A. Zeeb 	BUILD_BUG_ON(rtw89_rs_idx_num[RTW89_RS_MCS] % 4);
2125e2340276SBjoern A. Zeeb 	BUILD_BUG_ON(rtw89_rs_idx_num[RTW89_RS_HEDCM] % 4);
2126e2340276SBjoern A. Zeeb 
2127e2340276SBjoern A. Zeeb 	addr = R_AX_PWR_BY_RATE;
2128e2340276SBjoern A. Zeeb 	for (cur.nss = 0; cur.nss < max_nss_num; cur.nss++) {
2129e2340276SBjoern A. Zeeb 		for (i = 0; i < ARRAY_SIZE(rs); i++) {
2130e2340276SBjoern A. Zeeb 			if (cur.nss >= rtw89_rs_nss_num[rs[i]])
2131e2340276SBjoern A. Zeeb 				continue;
2132e2340276SBjoern A. Zeeb 
2133e2340276SBjoern A. Zeeb 			cur.rs = rs[i];
2134e2340276SBjoern A. Zeeb 			for (cur.idx = 0; cur.idx < rtw89_rs_idx_num[rs[i]];
2135e2340276SBjoern A. Zeeb 			     cur.idx++) {
2136e2340276SBjoern A. Zeeb 				v[cur.idx % 4] =
2137e2340276SBjoern A. Zeeb 					rtw89_phy_read_txpwr_byrate(rtwdev,
2138e2340276SBjoern A. Zeeb 								    band,
2139e2340276SBjoern A. Zeeb 								    &cur);
2140e2340276SBjoern A. Zeeb 
2141e2340276SBjoern A. Zeeb 				if ((cur.idx + 1) % 4)
2142e2340276SBjoern A. Zeeb 					continue;
2143e2340276SBjoern A. Zeeb 
2144e2340276SBjoern A. Zeeb 				val = FIELD_PREP(GENMASK(7, 0), v[0]) |
2145e2340276SBjoern A. Zeeb 				      FIELD_PREP(GENMASK(15, 8), v[1]) |
2146e2340276SBjoern A. Zeeb 				      FIELD_PREP(GENMASK(23, 16), v[2]) |
2147e2340276SBjoern A. Zeeb 				      FIELD_PREP(GENMASK(31, 24), v[3]);
2148e2340276SBjoern A. Zeeb 
2149e2340276SBjoern A. Zeeb 				rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr,
2150e2340276SBjoern A. Zeeb 							val);
2151e2340276SBjoern A. Zeeb 				addr += 4;
2152e2340276SBjoern A. Zeeb 			}
2153e2340276SBjoern A. Zeeb 		}
2154e2340276SBjoern A. Zeeb 	}
2155e2340276SBjoern A. Zeeb }
2156e2340276SBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_set_txpwr_byrate);
2157e2340276SBjoern A. Zeeb 
2158e2340276SBjoern A. Zeeb void rtw89_phy_set_txpwr_offset(struct rtw89_dev *rtwdev,
2159e2340276SBjoern A. Zeeb 				const struct rtw89_chan *chan,
2160e2340276SBjoern A. Zeeb 				enum rtw89_phy_idx phy_idx)
2161e2340276SBjoern A. Zeeb {
2162e2340276SBjoern A. Zeeb 	struct rtw89_rate_desc desc = {
2163e2340276SBjoern A. Zeeb 		.nss = RTW89_NSS_1,
2164e2340276SBjoern A. Zeeb 		.rs = RTW89_RS_OFFSET,
2165e2340276SBjoern A. Zeeb 	};
2166e2340276SBjoern A. Zeeb 	u8 band = chan->band_type;
2167e2340276SBjoern A. Zeeb 	s8 v[RTW89_RATE_OFFSET_NUM] = {};
2168e2340276SBjoern A. Zeeb 	u32 val;
2169e2340276SBjoern A. Zeeb 
2170e2340276SBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr offset\n");
2171e2340276SBjoern A. Zeeb 
2172e2340276SBjoern A. Zeeb 	for (desc.idx = 0; desc.idx < RTW89_RATE_OFFSET_NUM; desc.idx++)
2173e2340276SBjoern A. Zeeb 		v[desc.idx] = rtw89_phy_read_txpwr_byrate(rtwdev, band, &desc);
2174e2340276SBjoern A. Zeeb 
2175e2340276SBjoern A. Zeeb 	BUILD_BUG_ON(RTW89_RATE_OFFSET_NUM != 5);
2176e2340276SBjoern A. Zeeb 	val = FIELD_PREP(GENMASK(3, 0), v[0]) |
2177e2340276SBjoern A. Zeeb 	      FIELD_PREP(GENMASK(7, 4), v[1]) |
2178e2340276SBjoern A. Zeeb 	      FIELD_PREP(GENMASK(11, 8), v[2]) |
2179e2340276SBjoern A. Zeeb 	      FIELD_PREP(GENMASK(15, 12), v[3]) |
2180e2340276SBjoern A. Zeeb 	      FIELD_PREP(GENMASK(19, 16), v[4]);
2181e2340276SBjoern A. Zeeb 
2182e2340276SBjoern A. Zeeb 	rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_OFST_CTRL,
2183e2340276SBjoern A. Zeeb 				     GENMASK(19, 0), val);
2184e2340276SBjoern A. Zeeb }
2185e2340276SBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_set_txpwr_offset);
2186e2340276SBjoern A. Zeeb 
2187e2340276SBjoern A. Zeeb void rtw89_phy_set_txpwr_limit(struct rtw89_dev *rtwdev,
2188e2340276SBjoern A. Zeeb 			       const struct rtw89_chan *chan,
2189e2340276SBjoern A. Zeeb 			       enum rtw89_phy_idx phy_idx)
2190e2340276SBjoern A. Zeeb {
2191e2340276SBjoern A. Zeeb 	u8 max_ntx_num = rtwdev->chip->rf_path_num;
2192e2340276SBjoern A. Zeeb 	struct rtw89_txpwr_limit lmt;
2193e2340276SBjoern A. Zeeb 	u8 ch = chan->channel;
2194e2340276SBjoern A. Zeeb 	u8 bw = chan->band_width;
2195e2340276SBjoern A. Zeeb 	const s8 *ptr;
2196e2340276SBjoern A. Zeeb 	u32 addr, val;
2197e2340276SBjoern A. Zeeb 	u8 i, j;
2198e2340276SBjoern A. Zeeb 
2199e2340276SBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
2200e2340276SBjoern A. Zeeb 		    "[TXPWR] set txpwr limit with ch=%d bw=%d\n", ch, bw);
2201e2340276SBjoern A. Zeeb 
2202e2340276SBjoern A. Zeeb 	BUILD_BUG_ON(sizeof(struct rtw89_txpwr_limit) !=
2203e2340276SBjoern A. Zeeb 		     RTW89_TXPWR_LMT_PAGE_SIZE);
2204e2340276SBjoern A. Zeeb 
2205e2340276SBjoern A. Zeeb 	addr = R_AX_PWR_LMT;
2206e2340276SBjoern A. Zeeb 	for (i = 0; i < max_ntx_num; i++) {
2207e2340276SBjoern A. Zeeb 		rtw89_phy_fill_txpwr_limit(rtwdev, chan, &lmt, i);
2208e2340276SBjoern A. Zeeb 
2209e2340276SBjoern A. Zeeb 		ptr = (s8 *)&lmt;
2210e2340276SBjoern A. Zeeb 		for (j = 0; j < RTW89_TXPWR_LMT_PAGE_SIZE;
2211e2340276SBjoern A. Zeeb 		     j += 4, addr += 4, ptr += 4) {
2212e2340276SBjoern A. Zeeb 			val = FIELD_PREP(GENMASK(7, 0), ptr[0]) |
2213e2340276SBjoern A. Zeeb 			      FIELD_PREP(GENMASK(15, 8), ptr[1]) |
2214e2340276SBjoern A. Zeeb 			      FIELD_PREP(GENMASK(23, 16), ptr[2]) |
2215e2340276SBjoern A. Zeeb 			      FIELD_PREP(GENMASK(31, 24), ptr[3]);
2216e2340276SBjoern A. Zeeb 
2217e2340276SBjoern A. Zeeb 			rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val);
2218e2340276SBjoern A. Zeeb 		}
2219e2340276SBjoern A. Zeeb 	}
2220e2340276SBjoern A. Zeeb }
2221e2340276SBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_set_txpwr_limit);
2222e2340276SBjoern A. Zeeb 
2223e2340276SBjoern A. Zeeb void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev,
2224e2340276SBjoern A. Zeeb 				  const struct rtw89_chan *chan,
2225e2340276SBjoern A. Zeeb 				  enum rtw89_phy_idx phy_idx)
2226e2340276SBjoern A. Zeeb {
2227e2340276SBjoern A. Zeeb 	u8 max_ntx_num = rtwdev->chip->rf_path_num;
2228e2340276SBjoern A. Zeeb 	struct rtw89_txpwr_limit_ru lmt_ru;
2229e2340276SBjoern A. Zeeb 	u8 ch = chan->channel;
2230e2340276SBjoern A. Zeeb 	u8 bw = chan->band_width;
2231e2340276SBjoern A. Zeeb 	const s8 *ptr;
2232e2340276SBjoern A. Zeeb 	u32 addr, val;
2233e2340276SBjoern A. Zeeb 	u8 i, j;
2234e2340276SBjoern A. Zeeb 
2235e2340276SBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
2236e2340276SBjoern A. Zeeb 		    "[TXPWR] set txpwr limit ru with ch=%d bw=%d\n", ch, bw);
2237e2340276SBjoern A. Zeeb 
2238e2340276SBjoern A. Zeeb 	BUILD_BUG_ON(sizeof(struct rtw89_txpwr_limit_ru) !=
2239e2340276SBjoern A. Zeeb 		     RTW89_TXPWR_LMT_RU_PAGE_SIZE);
2240e2340276SBjoern A. Zeeb 
2241e2340276SBjoern A. Zeeb 	addr = R_AX_PWR_RU_LMT;
2242e2340276SBjoern A. Zeeb 	for (i = 0; i < max_ntx_num; i++) {
2243e2340276SBjoern A. Zeeb 		rtw89_phy_fill_txpwr_limit_ru(rtwdev, chan, &lmt_ru, i);
2244e2340276SBjoern A. Zeeb 
2245e2340276SBjoern A. Zeeb 		ptr = (s8 *)&lmt_ru;
2246e2340276SBjoern A. Zeeb 		for (j = 0; j < RTW89_TXPWR_LMT_RU_PAGE_SIZE;
2247e2340276SBjoern A. Zeeb 		     j += 4, addr += 4, ptr += 4) {
2248e2340276SBjoern A. Zeeb 			val = FIELD_PREP(GENMASK(7, 0), ptr[0]) |
2249e2340276SBjoern A. Zeeb 			      FIELD_PREP(GENMASK(15, 8), ptr[1]) |
2250e2340276SBjoern A. Zeeb 			      FIELD_PREP(GENMASK(23, 16), ptr[2]) |
2251e2340276SBjoern A. Zeeb 			      FIELD_PREP(GENMASK(31, 24), ptr[3]);
2252e2340276SBjoern A. Zeeb 
2253e2340276SBjoern A. Zeeb 			rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val);
2254e2340276SBjoern A. Zeeb 		}
2255e2340276SBjoern A. Zeeb 	}
2256e2340276SBjoern A. Zeeb }
2257e2340276SBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_set_txpwr_limit_ru);
22588e93258fSBjoern A. Zeeb 
22598e93258fSBjoern A. Zeeb struct rtw89_phy_iter_ra_data {
22608e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev;
22618e93258fSBjoern A. Zeeb 	struct sk_buff *c2h;
22628e93258fSBjoern A. Zeeb };
22638e93258fSBjoern A. Zeeb 
22648e93258fSBjoern A. Zeeb static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
22658e93258fSBjoern A. Zeeb {
22668e93258fSBjoern A. Zeeb 	struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data;
22678e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev = ra_data->rtwdev;
22688e93258fSBjoern A. Zeeb 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
2269e2340276SBjoern A. Zeeb 	const struct rtw89_c2h_ra_rpt *c2h =
2270e2340276SBjoern A. Zeeb 		(const struct rtw89_c2h_ra_rpt *)ra_data->c2h->data;
22718e93258fSBjoern A. Zeeb 	struct rtw89_ra_report *ra_report = &rtwsta->ra_report;
2272e2340276SBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
2273e2340276SBjoern A. Zeeb 	bool format_v1 = chip->chip_gen == RTW89_CHIP_BE;
22748e93258fSBjoern A. Zeeb 	u8 mode, rate, bw, giltf, mac_id;
22758e93258fSBjoern A. Zeeb 	u16 legacy_bitrate;
22768e93258fSBjoern A. Zeeb 	bool valid;
22778e93258fSBjoern A. Zeeb 	u8 mcs = 0;
2278e2340276SBjoern A. Zeeb 	u8 t;
22798e93258fSBjoern A. Zeeb 
2280e2340276SBjoern A. Zeeb 	mac_id = le32_get_bits(c2h->w2, RTW89_C2H_RA_RPT_W2_MACID);
22818e93258fSBjoern A. Zeeb 	if (mac_id != rtwsta->mac_id)
22828e93258fSBjoern A. Zeeb 		return;
22838e93258fSBjoern A. Zeeb 
2284e2340276SBjoern A. Zeeb 	rate = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MCSNSS);
2285e2340276SBjoern A. Zeeb 	bw = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_BW);
2286e2340276SBjoern A. Zeeb 	giltf = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_GILTF);
2287e2340276SBjoern A. Zeeb 	mode = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MD_SEL);
2288e2340276SBjoern A. Zeeb 
2289e2340276SBjoern A. Zeeb 	if (format_v1) {
2290e2340276SBjoern A. Zeeb 		t = le32_get_bits(c2h->w2, RTW89_C2H_RA_RPT_W2_MCSNSS_B7);
2291e2340276SBjoern A. Zeeb 		rate |= u8_encode_bits(t, BIT(7));
2292e2340276SBjoern A. Zeeb 		t = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_BW_B2);
2293e2340276SBjoern A. Zeeb 		bw |= u8_encode_bits(t, BIT(2));
2294e2340276SBjoern A. Zeeb 		t = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MD_SEL_B2);
2295e2340276SBjoern A. Zeeb 		mode |= u8_encode_bits(t, BIT(2));
2296e2340276SBjoern A. Zeeb 	}
22978e93258fSBjoern A. Zeeb 
22988e93258fSBjoern A. Zeeb 	if (mode == RTW89_RA_RPT_MODE_LEGACY) {
22998e93258fSBjoern A. Zeeb 		valid = rtw89_ra_report_to_bitrate(rtwdev, rate, &legacy_bitrate);
23008e93258fSBjoern A. Zeeb 		if (!valid)
23018e93258fSBjoern A. Zeeb 			return;
23028e93258fSBjoern A. Zeeb 	}
23038e93258fSBjoern A. Zeeb 
23048e93258fSBjoern A. Zeeb 	memset(&ra_report->txrate, 0, sizeof(ra_report->txrate));
23058e93258fSBjoern A. Zeeb 
23068e93258fSBjoern A. Zeeb 	switch (mode) {
23078e93258fSBjoern A. Zeeb 	case RTW89_RA_RPT_MODE_LEGACY:
23088e93258fSBjoern A. Zeeb 		ra_report->txrate.legacy = legacy_bitrate;
23098e93258fSBjoern A. Zeeb 		break;
23108e93258fSBjoern A. Zeeb 	case RTW89_RA_RPT_MODE_HT:
23118e93258fSBjoern A. Zeeb 		ra_report->txrate.flags |= RATE_INFO_FLAGS_MCS;
23128e93258fSBjoern A. Zeeb 		if (RTW89_CHK_FW_FEATURE(OLD_HT_RA_FORMAT, &rtwdev->fw))
23138e93258fSBjoern A. Zeeb 			rate = RTW89_MK_HT_RATE(FIELD_GET(RTW89_RA_RATE_MASK_NSS, rate),
23148e93258fSBjoern A. Zeeb 						FIELD_GET(RTW89_RA_RATE_MASK_MCS, rate));
23158e93258fSBjoern A. Zeeb 		else
23168e93258fSBjoern A. Zeeb 			rate = FIELD_GET(RTW89_RA_RATE_MASK_HT_MCS, rate);
23178e93258fSBjoern A. Zeeb 		ra_report->txrate.mcs = rate;
23188e93258fSBjoern A. Zeeb 		if (giltf)
23198e93258fSBjoern A. Zeeb 			ra_report->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
23208e93258fSBjoern A. Zeeb 		mcs = ra_report->txrate.mcs & 0x07;
23218e93258fSBjoern A. Zeeb 		break;
23228e93258fSBjoern A. Zeeb 	case RTW89_RA_RPT_MODE_VHT:
23238e93258fSBjoern A. Zeeb 		ra_report->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2324e2340276SBjoern A. Zeeb 		ra_report->txrate.mcs = format_v1 ?
2325e2340276SBjoern A. Zeeb 			u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS_V1) :
2326e2340276SBjoern A. Zeeb 			u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS);
2327e2340276SBjoern A. Zeeb 		ra_report->txrate.nss = format_v1 ?
2328e2340276SBjoern A. Zeeb 			u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS_V1) + 1 :
2329e2340276SBjoern A. Zeeb 			u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS) + 1;
23308e93258fSBjoern A. Zeeb 		if (giltf)
23318e93258fSBjoern A. Zeeb 			ra_report->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
23328e93258fSBjoern A. Zeeb 		mcs = ra_report->txrate.mcs;
23338e93258fSBjoern A. Zeeb 		break;
23348e93258fSBjoern A. Zeeb 	case RTW89_RA_RPT_MODE_HE:
23358e93258fSBjoern A. Zeeb 		ra_report->txrate.flags |= RATE_INFO_FLAGS_HE_MCS;
2336e2340276SBjoern A. Zeeb 		ra_report->txrate.mcs = format_v1 ?
2337e2340276SBjoern A. Zeeb 			u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS_V1) :
2338e2340276SBjoern A. Zeeb 			u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS);
2339e2340276SBjoern A. Zeeb 		ra_report->txrate.nss  = format_v1 ?
2340e2340276SBjoern A. Zeeb 			u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS_V1) + 1 :
2341e2340276SBjoern A. Zeeb 			u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS) + 1;
23428e93258fSBjoern A. Zeeb 		if (giltf == RTW89_GILTF_2XHE08 || giltf == RTW89_GILTF_1XHE08)
23438e93258fSBjoern A. Zeeb 			ra_report->txrate.he_gi = NL80211_RATE_INFO_HE_GI_0_8;
23448e93258fSBjoern A. Zeeb 		else if (giltf == RTW89_GILTF_2XHE16 || giltf == RTW89_GILTF_1XHE16)
23458e93258fSBjoern A. Zeeb 			ra_report->txrate.he_gi = NL80211_RATE_INFO_HE_GI_1_6;
23468e93258fSBjoern A. Zeeb 		else
23478e93258fSBjoern A. Zeeb 			ra_report->txrate.he_gi = NL80211_RATE_INFO_HE_GI_3_2;
23488e93258fSBjoern A. Zeeb 		mcs = ra_report->txrate.mcs;
23498e93258fSBjoern A. Zeeb 		break;
23508e93258fSBjoern A. Zeeb 	}
23518e93258fSBjoern A. Zeeb 
23528e93258fSBjoern A. Zeeb 	ra_report->txrate.bw = rtw89_hw_to_rate_info_bw(bw);
23538e93258fSBjoern A. Zeeb 	ra_report->bit_rate = cfg80211_calculate_bitrate(&ra_report->txrate);
2354e2340276SBjoern A. Zeeb 	ra_report->hw_rate = format_v1 ?
2355e2340276SBjoern A. Zeeb 			     u16_encode_bits(mode, RTW89_HW_RATE_V1_MASK_MOD) |
2356e2340276SBjoern A. Zeeb 			     u16_encode_bits(rate, RTW89_HW_RATE_V1_MASK_VAL) :
2357e2340276SBjoern A. Zeeb 			     u16_encode_bits(mode, RTW89_HW_RATE_MASK_MOD) |
2358e2340276SBjoern A. Zeeb 			     u16_encode_bits(rate, RTW89_HW_RATE_MASK_VAL);
23598e93258fSBjoern A. Zeeb 	ra_report->might_fallback_legacy = mcs <= 2;
2360e2340276SBjoern A. Zeeb 	sta->deflink.agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report);
2361e2340276SBjoern A. Zeeb 	rtwsta->max_agg_wait = sta->deflink.agg.max_rc_amsdu_len / 1500 - 1;
23628e93258fSBjoern A. Zeeb }
23638e93258fSBjoern A. Zeeb 
23648e93258fSBjoern A. Zeeb static void
23658e93258fSBjoern A. Zeeb rtw89_phy_c2h_ra_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
23668e93258fSBjoern A. Zeeb {
23678e93258fSBjoern A. Zeeb 	struct rtw89_phy_iter_ra_data ra_data;
23688e93258fSBjoern A. Zeeb 
23698e93258fSBjoern A. Zeeb 	ra_data.rtwdev = rtwdev;
23708e93258fSBjoern A. Zeeb 	ra_data.c2h = c2h;
23718e93258fSBjoern A. Zeeb 	ieee80211_iterate_stations_atomic(rtwdev->hw,
23728e93258fSBjoern A. Zeeb 					  rtw89_phy_c2h_ra_rpt_iter,
23738e93258fSBjoern A. Zeeb 					  &ra_data);
23748e93258fSBjoern A. Zeeb }
23758e93258fSBjoern A. Zeeb 
23768e93258fSBjoern A. Zeeb static
23778e93258fSBjoern A. Zeeb void (* const rtw89_phy_c2h_ra_handler[])(struct rtw89_dev *rtwdev,
23788e93258fSBjoern A. Zeeb 					  struct sk_buff *c2h, u32 len) = {
23798e93258fSBjoern A. Zeeb 	[RTW89_PHY_C2H_FUNC_STS_RPT] = rtw89_phy_c2h_ra_rpt,
23808e93258fSBjoern A. Zeeb 	[RTW89_PHY_C2H_FUNC_MU_GPTBL_RPT] = NULL,
23818e93258fSBjoern A. Zeeb 	[RTW89_PHY_C2H_FUNC_TXSTS] = NULL,
23828e93258fSBjoern A. Zeeb };
23838e93258fSBjoern A. Zeeb 
23848e93258fSBjoern A. Zeeb void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
23858e93258fSBjoern A. Zeeb 			  u32 len, u8 class, u8 func)
23868e93258fSBjoern A. Zeeb {
23878e93258fSBjoern A. Zeeb 	void (*handler)(struct rtw89_dev *rtwdev,
23888e93258fSBjoern A. Zeeb 			struct sk_buff *c2h, u32 len) = NULL;
23898e93258fSBjoern A. Zeeb 
23908e93258fSBjoern A. Zeeb 	switch (class) {
23918e93258fSBjoern A. Zeeb 	case RTW89_PHY_C2H_CLASS_RA:
23928e93258fSBjoern A. Zeeb 		if (func < RTW89_PHY_C2H_FUNC_RA_MAX)
23938e93258fSBjoern A. Zeeb 			handler = rtw89_phy_c2h_ra_handler[func];
23948e93258fSBjoern A. Zeeb 		break;
2395e2340276SBjoern A. Zeeb 	case RTW89_PHY_C2H_CLASS_DM:
2396e2340276SBjoern A. Zeeb 		if (func == RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY)
2397e2340276SBjoern A. Zeeb 			return;
2398e2340276SBjoern A. Zeeb 		fallthrough;
23998e93258fSBjoern A. Zeeb 	default:
24008e93258fSBjoern A. Zeeb 		rtw89_info(rtwdev, "c2h class %d not support\n", class);
24018e93258fSBjoern A. Zeeb 		return;
24028e93258fSBjoern A. Zeeb 	}
24038e93258fSBjoern A. Zeeb 	if (!handler) {
24048e93258fSBjoern A. Zeeb 		rtw89_info(rtwdev, "c2h class %d func %d not support\n", class,
24058e93258fSBjoern A. Zeeb 			   func);
24068e93258fSBjoern A. Zeeb 		return;
24078e93258fSBjoern A. Zeeb 	}
24088e93258fSBjoern A. Zeeb 	handler(rtwdev, skb, len);
24098e93258fSBjoern A. Zeeb }
24108e93258fSBjoern A. Zeeb 
24118e93258fSBjoern A. Zeeb static u8 rtw89_phy_cfo_get_xcap_reg(struct rtw89_dev *rtwdev, bool sc_xo)
24128e93258fSBjoern A. Zeeb {
2413e2340276SBjoern A. Zeeb 	const struct rtw89_xtal_info *xtal = rtwdev->chip->xtal_info;
24148e93258fSBjoern A. Zeeb 	u32 reg_mask;
24158e93258fSBjoern A. Zeeb 
24168e93258fSBjoern A. Zeeb 	if (sc_xo)
2417e2340276SBjoern A. Zeeb 		reg_mask = xtal->sc_xo_mask;
24188e93258fSBjoern A. Zeeb 	else
2419e2340276SBjoern A. Zeeb 		reg_mask = xtal->sc_xi_mask;
24208e93258fSBjoern A. Zeeb 
2421e2340276SBjoern A. Zeeb 	return (u8)rtw89_read32_mask(rtwdev, xtal->xcap_reg, reg_mask);
24228e93258fSBjoern A. Zeeb }
24238e93258fSBjoern A. Zeeb 
24248e93258fSBjoern A. Zeeb static void rtw89_phy_cfo_set_xcap_reg(struct rtw89_dev *rtwdev, bool sc_xo,
24258e93258fSBjoern A. Zeeb 				       u8 val)
24268e93258fSBjoern A. Zeeb {
2427e2340276SBjoern A. Zeeb 	const struct rtw89_xtal_info *xtal = rtwdev->chip->xtal_info;
24288e93258fSBjoern A. Zeeb 	u32 reg_mask;
24298e93258fSBjoern A. Zeeb 
24308e93258fSBjoern A. Zeeb 	if (sc_xo)
2431e2340276SBjoern A. Zeeb 		reg_mask = xtal->sc_xo_mask;
24328e93258fSBjoern A. Zeeb 	else
2433e2340276SBjoern A. Zeeb 		reg_mask = xtal->sc_xi_mask;
24348e93258fSBjoern A. Zeeb 
2435e2340276SBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, xtal->xcap_reg, reg_mask, val);
24368e93258fSBjoern A. Zeeb }
24378e93258fSBjoern A. Zeeb 
24388e93258fSBjoern A. Zeeb static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev,
24398e93258fSBjoern A. Zeeb 					  u8 crystal_cap, bool force)
24408e93258fSBjoern A. Zeeb {
24418e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
24428e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
24438e93258fSBjoern A. Zeeb 	u8 sc_xi_val, sc_xo_val;
24448e93258fSBjoern A. Zeeb 
24458e93258fSBjoern A. Zeeb 	if (!force && cfo->crystal_cap == crystal_cap)
24468e93258fSBjoern A. Zeeb 		return;
24478e93258fSBjoern A. Zeeb 	crystal_cap = clamp_t(u8, crystal_cap, 0, 127);
2448e2340276SBjoern A. Zeeb 	if (chip->chip_id == RTL8852A || chip->chip_id == RTL8851B) {
24498e93258fSBjoern A. Zeeb 		rtw89_phy_cfo_set_xcap_reg(rtwdev, true, crystal_cap);
24508e93258fSBjoern A. Zeeb 		rtw89_phy_cfo_set_xcap_reg(rtwdev, false, crystal_cap);
24518e93258fSBjoern A. Zeeb 		sc_xo_val = rtw89_phy_cfo_get_xcap_reg(rtwdev, true);
24528e93258fSBjoern A. Zeeb 		sc_xi_val = rtw89_phy_cfo_get_xcap_reg(rtwdev, false);
24538e93258fSBjoern A. Zeeb 	} else {
24548e93258fSBjoern A. Zeeb 		rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XTAL_SC_XO,
24558e93258fSBjoern A. Zeeb 					crystal_cap, XTAL_SC_XO_MASK);
24568e93258fSBjoern A. Zeeb 		rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XTAL_SC_XI,
24578e93258fSBjoern A. Zeeb 					crystal_cap, XTAL_SC_XI_MASK);
24588e93258fSBjoern A. Zeeb 		rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_XTAL_SC_XO, &sc_xo_val);
24598e93258fSBjoern A. Zeeb 		rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_XTAL_SC_XI, &sc_xi_val);
24608e93258fSBjoern A. Zeeb 	}
24618e93258fSBjoern A. Zeeb 	cfo->crystal_cap = sc_xi_val;
24628e93258fSBjoern A. Zeeb 	cfo->x_cap_ofst = (s8)((int)cfo->crystal_cap - cfo->def_x_cap);
24638e93258fSBjoern A. Zeeb 
24648e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "Set sc_xi=0x%x\n", sc_xi_val);
24658e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "Set sc_xo=0x%x\n", sc_xo_val);
24668e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "Get xcap_ofst=%d\n",
24678e93258fSBjoern A. Zeeb 		    cfo->x_cap_ofst);
24688e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "Set xcap OK\n");
24698e93258fSBjoern A. Zeeb }
24708e93258fSBjoern A. Zeeb 
24718e93258fSBjoern A. Zeeb static void rtw89_phy_cfo_reset(struct rtw89_dev *rtwdev)
24728e93258fSBjoern A. Zeeb {
24738e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
24748e93258fSBjoern A. Zeeb 	u8 cap;
24758e93258fSBjoern A. Zeeb 
24768e93258fSBjoern A. Zeeb 	cfo->def_x_cap = cfo->crystal_cap_default & B_AX_XTAL_SC_MASK;
24778e93258fSBjoern A. Zeeb 	cfo->is_adjust = false;
24788e93258fSBjoern A. Zeeb 	if (cfo->crystal_cap == cfo->def_x_cap)
24798e93258fSBjoern A. Zeeb 		return;
24808e93258fSBjoern A. Zeeb 	cap = cfo->crystal_cap;
24818e93258fSBjoern A. Zeeb 	cap += (cap > cfo->def_x_cap ? -1 : 1);
24828e93258fSBjoern A. Zeeb 	rtw89_phy_cfo_set_crystal_cap(rtwdev, cap, false);
24838e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO,
24848e93258fSBjoern A. Zeeb 		    "(0x%x) approach to dflt_val=(0x%x)\n", cfo->crystal_cap,
24858e93258fSBjoern A. Zeeb 		    cfo->def_x_cap);
24868e93258fSBjoern A. Zeeb }
24878e93258fSBjoern A. Zeeb 
24888e93258fSBjoern A. Zeeb static void rtw89_dcfo_comp(struct rtw89_dev *rtwdev, s32 curr_cfo)
24898e93258fSBjoern A. Zeeb {
24908e93258fSBjoern A. Zeeb 	const struct rtw89_reg_def *dcfo_comp = rtwdev->chip->dcfo_comp;
24918e93258fSBjoern A. Zeeb 	bool is_linked = rtwdev->total_sta_assoc > 0;
24928e93258fSBjoern A. Zeeb 	s32 cfo_avg_312;
24938e93258fSBjoern A. Zeeb 	s32 dcfo_comp_val;
24948e93258fSBjoern A. Zeeb 	int sign;
24958e93258fSBjoern A. Zeeb 
24968e93258fSBjoern A. Zeeb 	if (!is_linked) {
24978e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "DCFO: is_linked=%d\n",
24988e93258fSBjoern A. Zeeb 			    is_linked);
24998e93258fSBjoern A. Zeeb 		return;
25008e93258fSBjoern A. Zeeb 	}
25018e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "DCFO: curr_cfo=%d\n", curr_cfo);
25028e93258fSBjoern A. Zeeb 	if (curr_cfo == 0)
25038e93258fSBjoern A. Zeeb 		return;
25048e93258fSBjoern A. Zeeb 	dcfo_comp_val = rtw89_phy_read32_mask(rtwdev, R_DCFO, B_DCFO);
25058e93258fSBjoern A. Zeeb 	sign = curr_cfo > 0 ? 1 : -1;
2506e2340276SBjoern A. Zeeb 	cfo_avg_312 = curr_cfo / 625 + sign * dcfo_comp_val;
2507e2340276SBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "avg_cfo_312=%d step\n", cfo_avg_312);
25088e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv == CHIP_CBV)
25098e93258fSBjoern A. Zeeb 		cfo_avg_312 = -cfo_avg_312;
25108e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, dcfo_comp->addr, dcfo_comp->mask,
25118e93258fSBjoern A. Zeeb 			       cfo_avg_312);
25128e93258fSBjoern A. Zeeb }
25138e93258fSBjoern A. Zeeb 
25148e93258fSBjoern A. Zeeb static void rtw89_dcfo_comp_init(struct rtw89_dev *rtwdev)
25158e93258fSBjoern A. Zeeb {
2516e2340276SBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
2517e2340276SBjoern A. Zeeb 
25188e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_DCFO_OPT, B_DCFO_OPT_EN, 1);
25198e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_DCFO_WEIGHT, B_DCFO_WEIGHT_MSK, 8);
2520e2340276SBjoern A. Zeeb 
2521e2340276SBjoern A. Zeeb 	if (chip->cfo_hw_comp)
2522e2340276SBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, R_AX_PWR_UL_CTRL2,
2523e2340276SBjoern A. Zeeb 				   B_AX_PWR_UL_CFO_MASK, 0x6);
2524e2340276SBjoern A. Zeeb 	else
25258e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_PWR_UL_CTRL2, B_AX_PWR_UL_CFO_MASK);
25268e93258fSBjoern A. Zeeb }
25278e93258fSBjoern A. Zeeb 
25288e93258fSBjoern A. Zeeb static void rtw89_phy_cfo_init(struct rtw89_dev *rtwdev)
25298e93258fSBjoern A. Zeeb {
25308e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
25318e93258fSBjoern A. Zeeb 	struct rtw89_efuse *efuse = &rtwdev->efuse;
25328e93258fSBjoern A. Zeeb 
25338e93258fSBjoern A. Zeeb 	cfo->crystal_cap_default = efuse->xtal_cap & B_AX_XTAL_SC_MASK;
25348e93258fSBjoern A. Zeeb 	cfo->crystal_cap = cfo->crystal_cap_default;
25358e93258fSBjoern A. Zeeb 	cfo->def_x_cap = cfo->crystal_cap;
25368e93258fSBjoern A. Zeeb 	cfo->x_cap_ub = min_t(int, cfo->def_x_cap + CFO_BOUND, 0x7f);
25378e93258fSBjoern A. Zeeb 	cfo->x_cap_lb = max_t(int, cfo->def_x_cap - CFO_BOUND, 0x1);
25388e93258fSBjoern A. Zeeb 	cfo->is_adjust = false;
25398e93258fSBjoern A. Zeeb 	cfo->divergence_lock_en = false;
25408e93258fSBjoern A. Zeeb 	cfo->x_cap_ofst = 0;
25418e93258fSBjoern A. Zeeb 	cfo->lock_cnt = 0;
25428e93258fSBjoern A. Zeeb 	cfo->rtw89_multi_cfo_mode = RTW89_TP_BASED_AVG_MODE;
25438e93258fSBjoern A. Zeeb 	cfo->apply_compensation = false;
25448e93258fSBjoern A. Zeeb 	cfo->residual_cfo_acc = 0;
25458e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "Default xcap=%0x\n",
25468e93258fSBjoern A. Zeeb 		    cfo->crystal_cap_default);
25478e93258fSBjoern A. Zeeb 	rtw89_phy_cfo_set_crystal_cap(rtwdev, cfo->crystal_cap_default, true);
25488e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_DCFO, B_DCFO, 1);
25498e93258fSBjoern A. Zeeb 	rtw89_dcfo_comp_init(rtwdev);
25508e93258fSBjoern A. Zeeb 	cfo->cfo_timer_ms = 2000;
25518e93258fSBjoern A. Zeeb 	cfo->cfo_trig_by_timer_en = false;
25528e93258fSBjoern A. Zeeb 	cfo->phy_cfo_trk_cnt = 0;
25538e93258fSBjoern A. Zeeb 	cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_NORMAL;
25548e93258fSBjoern A. Zeeb 	cfo->cfo_ul_ofdma_acc_mode = RTW89_CFO_UL_OFDMA_ACC_ENABLE;
25558e93258fSBjoern A. Zeeb }
25568e93258fSBjoern A. Zeeb 
25578e93258fSBjoern A. Zeeb static void rtw89_phy_cfo_crystal_cap_adjust(struct rtw89_dev *rtwdev,
25588e93258fSBjoern A. Zeeb 					     s32 curr_cfo)
25598e93258fSBjoern A. Zeeb {
25608e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
25618e93258fSBjoern A. Zeeb 	s8 crystal_cap = cfo->crystal_cap;
25628e93258fSBjoern A. Zeeb 	s32 cfo_abs = abs(curr_cfo);
25638e93258fSBjoern A. Zeeb 	int sign;
25648e93258fSBjoern A. Zeeb 
25658e93258fSBjoern A. Zeeb 	if (!cfo->is_adjust) {
25668e93258fSBjoern A. Zeeb 		if (cfo_abs > CFO_TRK_ENABLE_TH)
25678e93258fSBjoern A. Zeeb 			cfo->is_adjust = true;
25688e93258fSBjoern A. Zeeb 	} else {
25698e93258fSBjoern A. Zeeb 		if (cfo_abs < CFO_TRK_STOP_TH)
25708e93258fSBjoern A. Zeeb 			cfo->is_adjust = false;
25718e93258fSBjoern A. Zeeb 	}
25728e93258fSBjoern A. Zeeb 	if (!cfo->is_adjust) {
25738e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "Stop CFO tracking\n");
25748e93258fSBjoern A. Zeeb 		return;
25758e93258fSBjoern A. Zeeb 	}
25768e93258fSBjoern A. Zeeb 	sign = curr_cfo > 0 ? 1 : -1;
25778e93258fSBjoern A. Zeeb 	if (cfo_abs > CFO_TRK_STOP_TH_4)
25788e93258fSBjoern A. Zeeb 		crystal_cap += 7 * sign;
25798e93258fSBjoern A. Zeeb 	else if (cfo_abs > CFO_TRK_STOP_TH_3)
25808e93258fSBjoern A. Zeeb 		crystal_cap += 5 * sign;
25818e93258fSBjoern A. Zeeb 	else if (cfo_abs > CFO_TRK_STOP_TH_2)
25828e93258fSBjoern A. Zeeb 		crystal_cap += 3 * sign;
25838e93258fSBjoern A. Zeeb 	else if (cfo_abs > CFO_TRK_STOP_TH_1)
25848e93258fSBjoern A. Zeeb 		crystal_cap += 1 * sign;
25858e93258fSBjoern A. Zeeb 	else
25868e93258fSBjoern A. Zeeb 		return;
25878e93258fSBjoern A. Zeeb 	rtw89_phy_cfo_set_crystal_cap(rtwdev, (u8)crystal_cap, false);
25888e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO,
25898e93258fSBjoern A. Zeeb 		    "X_cap{Curr,Default}={0x%x,0x%x}\n",
25908e93258fSBjoern A. Zeeb 		    cfo->crystal_cap, cfo->def_x_cap);
25918e93258fSBjoern A. Zeeb }
25928e93258fSBjoern A. Zeeb 
25938e93258fSBjoern A. Zeeb static s32 rtw89_phy_average_cfo_calc(struct rtw89_dev *rtwdev)
25948e93258fSBjoern A. Zeeb {
2595e2340276SBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
25968e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
25978e93258fSBjoern A. Zeeb 	s32 cfo_khz_all = 0;
25988e93258fSBjoern A. Zeeb 	s32 cfo_cnt_all = 0;
25998e93258fSBjoern A. Zeeb 	s32 cfo_all_avg = 0;
26008e93258fSBjoern A. Zeeb 	u8 i;
26018e93258fSBjoern A. Zeeb 
26028e93258fSBjoern A. Zeeb 	if (rtwdev->total_sta_assoc != 1)
26038e93258fSBjoern A. Zeeb 		return 0;
26048e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "one_entry_only\n");
26058e93258fSBjoern A. Zeeb 	for (i = 0; i < CFO_TRACK_MAX_USER; i++) {
26068e93258fSBjoern A. Zeeb 		if (cfo->cfo_cnt[i] == 0)
26078e93258fSBjoern A. Zeeb 			continue;
26088e93258fSBjoern A. Zeeb 		cfo_khz_all += cfo->cfo_tail[i];
26098e93258fSBjoern A. Zeeb 		cfo_cnt_all += cfo->cfo_cnt[i];
26108e93258fSBjoern A. Zeeb 		cfo_all_avg = phy_div(cfo_khz_all, cfo_cnt_all);
26118e93258fSBjoern A. Zeeb 		cfo->pre_cfo_avg[i] = cfo->cfo_avg[i];
2612e2340276SBjoern A. Zeeb 		cfo->dcfo_avg = phy_div(cfo_khz_all << chip->dcfo_comp_sft,
2613e2340276SBjoern A. Zeeb 					cfo_cnt_all);
26148e93258fSBjoern A. Zeeb 	}
26158e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO,
26168e93258fSBjoern A. Zeeb 		    "CFO track for macid = %d\n", i);
26178e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO,
26188e93258fSBjoern A. Zeeb 		    "Total cfo=%dK, pkt_cnt=%d, avg_cfo=%dK\n",
26198e93258fSBjoern A. Zeeb 		    cfo_khz_all, cfo_cnt_all, cfo_all_avg);
26208e93258fSBjoern A. Zeeb 	return cfo_all_avg;
26218e93258fSBjoern A. Zeeb }
26228e93258fSBjoern A. Zeeb 
26238e93258fSBjoern A. Zeeb static s32 rtw89_phy_multi_sta_cfo_calc(struct rtw89_dev *rtwdev)
26248e93258fSBjoern A. Zeeb {
26258e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
26268e93258fSBjoern A. Zeeb 	struct rtw89_traffic_stats *stats = &rtwdev->stats;
26278e93258fSBjoern A. Zeeb 	s32 target_cfo = 0;
26288e93258fSBjoern A. Zeeb 	s32 cfo_khz_all = 0;
26298e93258fSBjoern A. Zeeb 	s32 cfo_khz_all_tp_wgt = 0;
26308e93258fSBjoern A. Zeeb 	s32 cfo_avg = 0;
26318e93258fSBjoern A. Zeeb 	s32 max_cfo_lb = BIT(31);
26328e93258fSBjoern A. Zeeb 	s32 min_cfo_ub = GENMASK(30, 0);
26338e93258fSBjoern A. Zeeb 	u16 cfo_cnt_all = 0;
26348e93258fSBjoern A. Zeeb 	u8 active_entry_cnt = 0;
26358e93258fSBjoern A. Zeeb 	u8 sta_cnt = 0;
26368e93258fSBjoern A. Zeeb 	u32 tp_all = 0;
26378e93258fSBjoern A. Zeeb 	u8 i;
26388e93258fSBjoern A. Zeeb 	u8 cfo_tol = 0;
26398e93258fSBjoern A. Zeeb 
26408e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "Multi entry cfo_trk\n");
26418e93258fSBjoern A. Zeeb 	if (cfo->rtw89_multi_cfo_mode == RTW89_PKT_BASED_AVG_MODE) {
26428e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "Pkt based avg mode\n");
26438e93258fSBjoern A. Zeeb 		for (i = 0; i < CFO_TRACK_MAX_USER; i++) {
26448e93258fSBjoern A. Zeeb 			if (cfo->cfo_cnt[i] == 0)
26458e93258fSBjoern A. Zeeb 				continue;
26468e93258fSBjoern A. Zeeb 			cfo_khz_all += cfo->cfo_tail[i];
26478e93258fSBjoern A. Zeeb 			cfo_cnt_all += cfo->cfo_cnt[i];
26488e93258fSBjoern A. Zeeb 			cfo_avg = phy_div(cfo_khz_all, (s32)cfo_cnt_all);
26498e93258fSBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_CFO,
26508e93258fSBjoern A. Zeeb 				    "Msta cfo=%d, pkt_cnt=%d, avg_cfo=%d\n",
26518e93258fSBjoern A. Zeeb 				    cfo_khz_all, cfo_cnt_all, cfo_avg);
26528e93258fSBjoern A. Zeeb 			target_cfo = cfo_avg;
26538e93258fSBjoern A. Zeeb 		}
26548e93258fSBjoern A. Zeeb 	} else if (cfo->rtw89_multi_cfo_mode == RTW89_ENTRY_BASED_AVG_MODE) {
26558e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "Entry based avg mode\n");
26568e93258fSBjoern A. Zeeb 		for (i = 0; i < CFO_TRACK_MAX_USER; i++) {
26578e93258fSBjoern A. Zeeb 			if (cfo->cfo_cnt[i] == 0)
26588e93258fSBjoern A. Zeeb 				continue;
26598e93258fSBjoern A. Zeeb 			cfo->cfo_avg[i] = phy_div(cfo->cfo_tail[i],
26608e93258fSBjoern A. Zeeb 						  (s32)cfo->cfo_cnt[i]);
26618e93258fSBjoern A. Zeeb 			cfo_khz_all += cfo->cfo_avg[i];
26628e93258fSBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_CFO,
26638e93258fSBjoern A. Zeeb 				    "Macid=%d, cfo_avg=%d\n", i,
26648e93258fSBjoern A. Zeeb 				    cfo->cfo_avg[i]);
26658e93258fSBjoern A. Zeeb 		}
26668e93258fSBjoern A. Zeeb 		sta_cnt = rtwdev->total_sta_assoc;
26678e93258fSBjoern A. Zeeb 		cfo_avg = phy_div(cfo_khz_all, (s32)sta_cnt);
26688e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO,
26698e93258fSBjoern A. Zeeb 			    "Msta cfo_acc=%d, ent_cnt=%d, avg_cfo=%d\n",
26708e93258fSBjoern A. Zeeb 			    cfo_khz_all, sta_cnt, cfo_avg);
26718e93258fSBjoern A. Zeeb 		target_cfo = cfo_avg;
26728e93258fSBjoern A. Zeeb 	} else if (cfo->rtw89_multi_cfo_mode == RTW89_TP_BASED_AVG_MODE) {
26738e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "TP based avg mode\n");
26748e93258fSBjoern A. Zeeb 		cfo_tol = cfo->sta_cfo_tolerance;
26758e93258fSBjoern A. Zeeb 		for (i = 0; i < CFO_TRACK_MAX_USER; i++) {
26768e93258fSBjoern A. Zeeb 			sta_cnt++;
26778e93258fSBjoern A. Zeeb 			if (cfo->cfo_cnt[i] != 0) {
26788e93258fSBjoern A. Zeeb 				cfo->cfo_avg[i] = phy_div(cfo->cfo_tail[i],
26798e93258fSBjoern A. Zeeb 							  (s32)cfo->cfo_cnt[i]);
26808e93258fSBjoern A. Zeeb 				active_entry_cnt++;
26818e93258fSBjoern A. Zeeb 			} else {
26828e93258fSBjoern A. Zeeb 				cfo->cfo_avg[i] = cfo->pre_cfo_avg[i];
26838e93258fSBjoern A. Zeeb 			}
26848e93258fSBjoern A. Zeeb 			max_cfo_lb = max(cfo->cfo_avg[i] - cfo_tol, max_cfo_lb);
26858e93258fSBjoern A. Zeeb 			min_cfo_ub = min(cfo->cfo_avg[i] + cfo_tol, min_cfo_ub);
26868e93258fSBjoern A. Zeeb 			cfo_khz_all += cfo->cfo_avg[i];
26878e93258fSBjoern A. Zeeb 			/* need tp for each entry */
26888e93258fSBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_CFO,
26898e93258fSBjoern A. Zeeb 				    "[%d] cfo_avg=%d, tp=tbd\n",
26908e93258fSBjoern A. Zeeb 				    i, cfo->cfo_avg[i]);
26918e93258fSBjoern A. Zeeb 			if (sta_cnt >= rtwdev->total_sta_assoc)
26928e93258fSBjoern A. Zeeb 				break;
26938e93258fSBjoern A. Zeeb 		}
26948e93258fSBjoern A. Zeeb 		tp_all = stats->rx_throughput; /* need tp for each entry */
26958e93258fSBjoern A. Zeeb 		cfo_avg =  phy_div(cfo_khz_all_tp_wgt, (s32)tp_all);
26968e93258fSBjoern A. Zeeb 
26978e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "Assoc sta cnt=%d\n",
26988e93258fSBjoern A. Zeeb 			    sta_cnt);
26998e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "Active sta cnt=%d\n",
27008e93258fSBjoern A. Zeeb 			    active_entry_cnt);
27018e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO,
27028e93258fSBjoern A. Zeeb 			    "Msta cfo with tp_wgt=%d, avg_cfo=%d\n",
27038e93258fSBjoern A. Zeeb 			    cfo_khz_all_tp_wgt, cfo_avg);
27048e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "cfo_lb=%d,cfo_ub=%d\n",
27058e93258fSBjoern A. Zeeb 			    max_cfo_lb, min_cfo_ub);
27068e93258fSBjoern A. Zeeb 		if (max_cfo_lb <= min_cfo_ub) {
27078e93258fSBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_CFO,
27088e93258fSBjoern A. Zeeb 				    "cfo win_size=%d\n",
27098e93258fSBjoern A. Zeeb 				    min_cfo_ub - max_cfo_lb);
27108e93258fSBjoern A. Zeeb 			target_cfo = clamp(cfo_avg, max_cfo_lb, min_cfo_ub);
27118e93258fSBjoern A. Zeeb 		} else {
27128e93258fSBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_CFO,
27138e93258fSBjoern A. Zeeb 				    "No intersection of cfo tolerance windows\n");
27148e93258fSBjoern A. Zeeb 			target_cfo = phy_div(cfo_khz_all, (s32)sta_cnt);
27158e93258fSBjoern A. Zeeb 		}
27168e93258fSBjoern A. Zeeb 		for (i = 0; i < CFO_TRACK_MAX_USER; i++)
27178e93258fSBjoern A. Zeeb 			cfo->pre_cfo_avg[i] = cfo->cfo_avg[i];
27188e93258fSBjoern A. Zeeb 	}
27198e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "Target cfo=%d\n", target_cfo);
27208e93258fSBjoern A. Zeeb 	return target_cfo;
27218e93258fSBjoern A. Zeeb }
27228e93258fSBjoern A. Zeeb 
27238e93258fSBjoern A. Zeeb static void rtw89_phy_cfo_statistics_reset(struct rtw89_dev *rtwdev)
27248e93258fSBjoern A. Zeeb {
27258e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
27268e93258fSBjoern A. Zeeb 
27278e93258fSBjoern A. Zeeb 	memset(&cfo->cfo_tail, 0, sizeof(cfo->cfo_tail));
27288e93258fSBjoern A. Zeeb 	memset(&cfo->cfo_cnt, 0, sizeof(cfo->cfo_cnt));
27298e93258fSBjoern A. Zeeb 	cfo->packet_count = 0;
27308e93258fSBjoern A. Zeeb 	cfo->packet_count_pre = 0;
27318e93258fSBjoern A. Zeeb 	cfo->cfo_avg_pre = 0;
27328e93258fSBjoern A. Zeeb }
27338e93258fSBjoern A. Zeeb 
27348e93258fSBjoern A. Zeeb static void rtw89_phy_cfo_dm(struct rtw89_dev *rtwdev)
27358e93258fSBjoern A. Zeeb {
27368e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
27378e93258fSBjoern A. Zeeb 	s32 new_cfo = 0;
27388e93258fSBjoern A. Zeeb 	bool x_cap_update = false;
27398e93258fSBjoern A. Zeeb 	u8 pre_x_cap = cfo->crystal_cap;
2740e2340276SBjoern A. Zeeb 	u8 dcfo_comp_sft = rtwdev->chip->dcfo_comp_sft;
27418e93258fSBjoern A. Zeeb 
2742e2340276SBjoern A. Zeeb 	cfo->dcfo_avg = 0;
27438e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "CFO:total_sta_assoc=%d\n",
27448e93258fSBjoern A. Zeeb 		    rtwdev->total_sta_assoc);
27458e93258fSBjoern A. Zeeb 	if (rtwdev->total_sta_assoc == 0) {
27468e93258fSBjoern A. Zeeb 		rtw89_phy_cfo_reset(rtwdev);
27478e93258fSBjoern A. Zeeb 		return;
27488e93258fSBjoern A. Zeeb 	}
27498e93258fSBjoern A. Zeeb 	if (cfo->packet_count == 0) {
27508e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "Pkt cnt = 0\n");
27518e93258fSBjoern A. Zeeb 		return;
27528e93258fSBjoern A. Zeeb 	}
27538e93258fSBjoern A. Zeeb 	if (cfo->packet_count == cfo->packet_count_pre) {
27548e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "Pkt cnt doesn't change\n");
27558e93258fSBjoern A. Zeeb 		return;
27568e93258fSBjoern A. Zeeb 	}
27578e93258fSBjoern A. Zeeb 	if (rtwdev->total_sta_assoc == 1)
27588e93258fSBjoern A. Zeeb 		new_cfo = rtw89_phy_average_cfo_calc(rtwdev);
27598e93258fSBjoern A. Zeeb 	else
27608e93258fSBjoern A. Zeeb 		new_cfo = rtw89_phy_multi_sta_cfo_calc(rtwdev);
27618e93258fSBjoern A. Zeeb 	if (new_cfo == 0) {
27628e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_CFO, "curr_cfo=0\n");
27638e93258fSBjoern A. Zeeb 		return;
27648e93258fSBjoern A. Zeeb 	}
27658e93258fSBjoern A. Zeeb 	if (cfo->divergence_lock_en) {
27668e93258fSBjoern A. Zeeb 		cfo->lock_cnt++;
27678e93258fSBjoern A. Zeeb 		if (cfo->lock_cnt > CFO_PERIOD_CNT) {
27688e93258fSBjoern A. Zeeb 			cfo->divergence_lock_en = false;
27698e93258fSBjoern A. Zeeb 			cfo->lock_cnt = 0;
27708e93258fSBjoern A. Zeeb 		} else {
27718e93258fSBjoern A. Zeeb 			rtw89_phy_cfo_reset(rtwdev);
27728e93258fSBjoern A. Zeeb 		}
27738e93258fSBjoern A. Zeeb 		return;
27748e93258fSBjoern A. Zeeb 	}
27758e93258fSBjoern A. Zeeb 	if (cfo->crystal_cap >= cfo->x_cap_ub ||
27768e93258fSBjoern A. Zeeb 	    cfo->crystal_cap <= cfo->x_cap_lb) {
27778e93258fSBjoern A. Zeeb 		cfo->divergence_lock_en = true;
27788e93258fSBjoern A. Zeeb 		rtw89_phy_cfo_reset(rtwdev);
27798e93258fSBjoern A. Zeeb 		return;
27808e93258fSBjoern A. Zeeb 	}
27818e93258fSBjoern A. Zeeb 
27828e93258fSBjoern A. Zeeb 	rtw89_phy_cfo_crystal_cap_adjust(rtwdev, new_cfo);
27838e93258fSBjoern A. Zeeb 	cfo->cfo_avg_pre = new_cfo;
2784e2340276SBjoern A. Zeeb 	cfo->dcfo_avg_pre = cfo->dcfo_avg;
27858e93258fSBjoern A. Zeeb 	x_cap_update =  cfo->crystal_cap != pre_x_cap;
27868e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "Xcap_up=%d\n", x_cap_update);
27878e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO, "Xcap: D:%x C:%x->%x, ofst=%d\n",
27888e93258fSBjoern A. Zeeb 		    cfo->def_x_cap, pre_x_cap, cfo->crystal_cap,
27898e93258fSBjoern A. Zeeb 		    cfo->x_cap_ofst);
27908e93258fSBjoern A. Zeeb 	if (x_cap_update) {
2791e2340276SBjoern A. Zeeb 		if (cfo->dcfo_avg > 0)
2792e2340276SBjoern A. Zeeb 			cfo->dcfo_avg -= CFO_SW_COMP_FINE_TUNE << dcfo_comp_sft;
27938e93258fSBjoern A. Zeeb 		else
2794e2340276SBjoern A. Zeeb 			cfo->dcfo_avg += CFO_SW_COMP_FINE_TUNE << dcfo_comp_sft;
27958e93258fSBjoern A. Zeeb 	}
2796e2340276SBjoern A. Zeeb 	rtw89_dcfo_comp(rtwdev, cfo->dcfo_avg);
27978e93258fSBjoern A. Zeeb 	rtw89_phy_cfo_statistics_reset(rtwdev);
27988e93258fSBjoern A. Zeeb }
27998e93258fSBjoern A. Zeeb 
28008e93258fSBjoern A. Zeeb void rtw89_phy_cfo_track_work(struct work_struct *work)
28018e93258fSBjoern A. Zeeb {
28028e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
28038e93258fSBjoern A. Zeeb 						cfo_track_work.work);
28048e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
28058e93258fSBjoern A. Zeeb 
28068e93258fSBjoern A. Zeeb 	mutex_lock(&rtwdev->mutex);
28078e93258fSBjoern A. Zeeb 	if (!cfo->cfo_trig_by_timer_en)
28088e93258fSBjoern A. Zeeb 		goto out;
28098e93258fSBjoern A. Zeeb 	rtw89_leave_ps_mode(rtwdev);
28108e93258fSBjoern A. Zeeb 	rtw89_phy_cfo_dm(rtwdev);
28118e93258fSBjoern A. Zeeb 	ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->cfo_track_work,
28128e93258fSBjoern A. Zeeb 				     msecs_to_jiffies(cfo->cfo_timer_ms));
28138e93258fSBjoern A. Zeeb out:
28148e93258fSBjoern A. Zeeb 	mutex_unlock(&rtwdev->mutex);
28158e93258fSBjoern A. Zeeb }
28168e93258fSBjoern A. Zeeb 
28178e93258fSBjoern A. Zeeb static void rtw89_phy_cfo_start_work(struct rtw89_dev *rtwdev)
28188e93258fSBjoern A. Zeeb {
28198e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
28208e93258fSBjoern A. Zeeb 
28218e93258fSBjoern A. Zeeb 	ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->cfo_track_work,
28228e93258fSBjoern A. Zeeb 				     msecs_to_jiffies(cfo->cfo_timer_ms));
28238e93258fSBjoern A. Zeeb }
28248e93258fSBjoern A. Zeeb 
28258e93258fSBjoern A. Zeeb void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev)
28268e93258fSBjoern A. Zeeb {
28278e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
28288e93258fSBjoern A. Zeeb 	struct rtw89_traffic_stats *stats = &rtwdev->stats;
28298e93258fSBjoern A. Zeeb 	bool is_ul_ofdma = false, ofdma_acc_en = false;
28308e93258fSBjoern A. Zeeb 
28318e93258fSBjoern A. Zeeb 	if (stats->rx_tf_periodic > CFO_TF_CNT_TH)
28328e93258fSBjoern A. Zeeb 		is_ul_ofdma = true;
28338e93258fSBjoern A. Zeeb 	if (cfo->cfo_ul_ofdma_acc_mode == RTW89_CFO_UL_OFDMA_ACC_ENABLE &&
28348e93258fSBjoern A. Zeeb 	    is_ul_ofdma)
28358e93258fSBjoern A. Zeeb 		ofdma_acc_en = true;
28368e93258fSBjoern A. Zeeb 
28378e93258fSBjoern A. Zeeb 	switch (cfo->phy_cfo_status) {
28388e93258fSBjoern A. Zeeb 	case RTW89_PHY_DCFO_STATE_NORMAL:
28398e93258fSBjoern A. Zeeb 		if (stats->tx_throughput >= CFO_TP_UPPER) {
28408e93258fSBjoern A. Zeeb 			cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_ENHANCE;
28418e93258fSBjoern A. Zeeb 			cfo->cfo_trig_by_timer_en = true;
28428e93258fSBjoern A. Zeeb 			cfo->cfo_timer_ms = CFO_COMP_PERIOD;
28438e93258fSBjoern A. Zeeb 			rtw89_phy_cfo_start_work(rtwdev);
28448e93258fSBjoern A. Zeeb 		}
28458e93258fSBjoern A. Zeeb 		break;
28468e93258fSBjoern A. Zeeb 	case RTW89_PHY_DCFO_STATE_ENHANCE:
28478e93258fSBjoern A. Zeeb 		if (stats->tx_throughput <= CFO_TP_LOWER)
28488e93258fSBjoern A. Zeeb 			cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_NORMAL;
28498e93258fSBjoern A. Zeeb 		else if (ofdma_acc_en &&
28508e93258fSBjoern A. Zeeb 			 cfo->phy_cfo_trk_cnt >= CFO_PERIOD_CNT)
28518e93258fSBjoern A. Zeeb 			cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_HOLD;
28528e93258fSBjoern A. Zeeb 		else
28538e93258fSBjoern A. Zeeb 			cfo->phy_cfo_trk_cnt++;
28548e93258fSBjoern A. Zeeb 
28558e93258fSBjoern A. Zeeb 		if (cfo->phy_cfo_status == RTW89_PHY_DCFO_STATE_NORMAL) {
28568e93258fSBjoern A. Zeeb 			cfo->phy_cfo_trk_cnt = 0;
28578e93258fSBjoern A. Zeeb 			cfo->cfo_trig_by_timer_en = false;
28588e93258fSBjoern A. Zeeb 		}
28598e93258fSBjoern A. Zeeb 		break;
28608e93258fSBjoern A. Zeeb 	case RTW89_PHY_DCFO_STATE_HOLD:
28618e93258fSBjoern A. Zeeb 		if (stats->tx_throughput <= CFO_TP_LOWER) {
28628e93258fSBjoern A. Zeeb 			cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_NORMAL;
28638e93258fSBjoern A. Zeeb 			cfo->phy_cfo_trk_cnt = 0;
28648e93258fSBjoern A. Zeeb 			cfo->cfo_trig_by_timer_en = false;
28658e93258fSBjoern A. Zeeb 		} else {
28668e93258fSBjoern A. Zeeb 			cfo->phy_cfo_trk_cnt++;
28678e93258fSBjoern A. Zeeb 		}
28688e93258fSBjoern A. Zeeb 		break;
28698e93258fSBjoern A. Zeeb 	default:
28708e93258fSBjoern A. Zeeb 		cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_NORMAL;
28718e93258fSBjoern A. Zeeb 		cfo->phy_cfo_trk_cnt = 0;
28728e93258fSBjoern A. Zeeb 		break;
28738e93258fSBjoern A. Zeeb 	}
28748e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_CFO,
28758e93258fSBjoern A. Zeeb 		    "[CFO]WatchDog tp=%d,state=%d,timer_en=%d,trk_cnt=%d,thermal=%ld\n",
28768e93258fSBjoern A. Zeeb 		    stats->tx_throughput, cfo->phy_cfo_status,
28778e93258fSBjoern A. Zeeb 		    cfo->cfo_trig_by_timer_en, cfo->phy_cfo_trk_cnt,
28788e93258fSBjoern A. Zeeb 		    ewma_thermal_read(&rtwdev->phystat.avg_thermal[0]));
28798e93258fSBjoern A. Zeeb 	if (cfo->cfo_trig_by_timer_en)
28808e93258fSBjoern A. Zeeb 		return;
28818e93258fSBjoern A. Zeeb 	rtw89_phy_cfo_dm(rtwdev);
28828e93258fSBjoern A. Zeeb }
28838e93258fSBjoern A. Zeeb 
28848e93258fSBjoern A. Zeeb void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val,
28858e93258fSBjoern A. Zeeb 			 struct rtw89_rx_phy_ppdu *phy_ppdu)
28868e93258fSBjoern A. Zeeb {
28878e93258fSBjoern A. Zeeb 	struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
28888e93258fSBjoern A. Zeeb 	u8 macid = phy_ppdu->mac_id;
28898e93258fSBjoern A. Zeeb 
28908e93258fSBjoern A. Zeeb 	if (macid >= CFO_TRACK_MAX_USER) {
28918e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "mac_id %d is out of range\n", macid);
28928e93258fSBjoern A. Zeeb 		return;
28938e93258fSBjoern A. Zeeb 	}
28948e93258fSBjoern A. Zeeb 
28958e93258fSBjoern A. Zeeb 	cfo->cfo_tail[macid] += cfo_val;
28968e93258fSBjoern A. Zeeb 	cfo->cfo_cnt[macid]++;
28978e93258fSBjoern A. Zeeb 	cfo->packet_count++;
28988e93258fSBjoern A. Zeeb }
28998e93258fSBjoern A. Zeeb 
2900e2340276SBjoern A. Zeeb void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
2901e2340276SBjoern A. Zeeb {
2902e2340276SBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
2903e2340276SBjoern A. Zeeb 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
2904e2340276SBjoern A. Zeeb 	struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info;
2905e2340276SBjoern A. Zeeb 
2906e2340276SBjoern A. Zeeb 	if (!chip->support_ul_tb_ctrl)
2907e2340276SBjoern A. Zeeb 		return;
2908e2340276SBjoern A. Zeeb 
2909e2340276SBjoern A. Zeeb 	rtwvif->def_tri_idx =
2910e2340276SBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG);
2911e2340276SBjoern A. Zeeb 
2912e2340276SBjoern A. Zeeb 	if (chip->chip_id == RTL8852B && rtwdev->hal.cv > CHIP_CBV)
2913e2340276SBjoern A. Zeeb 		rtwvif->dyn_tb_bedge_en = false;
2914e2340276SBjoern A. Zeeb 	else if (chan->band_type >= RTW89_BAND_5G &&
2915e2340276SBjoern A. Zeeb 		 chan->band_width >= RTW89_CHANNEL_WIDTH_40)
2916e2340276SBjoern A. Zeeb 		rtwvif->dyn_tb_bedge_en = true;
2917e2340276SBjoern A. Zeeb 	else
2918e2340276SBjoern A. Zeeb 		rtwvif->dyn_tb_bedge_en = false;
2919e2340276SBjoern A. Zeeb 
2920e2340276SBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
2921e2340276SBjoern A. Zeeb 		    "[ULTB] def_if_bandedge=%d, def_tri_idx=%d\n",
2922e2340276SBjoern A. Zeeb 		    ul_tb_info->def_if_bandedge, rtwvif->def_tri_idx);
2923e2340276SBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
2924e2340276SBjoern A. Zeeb 		    "[ULTB] dyn_tb_begde_en=%d, dyn_tb_tri_en=%d\n",
2925e2340276SBjoern A. Zeeb 		    rtwvif->dyn_tb_bedge_en, ul_tb_info->dyn_tb_tri_en);
2926e2340276SBjoern A. Zeeb }
2927e2340276SBjoern A. Zeeb 
2928e2340276SBjoern A. Zeeb struct rtw89_phy_ul_tb_check_data {
2929e2340276SBjoern A. Zeeb 	bool valid;
2930e2340276SBjoern A. Zeeb 	bool high_tf_client;
2931e2340276SBjoern A. Zeeb 	bool low_tf_client;
2932e2340276SBjoern A. Zeeb 	bool dyn_tb_bedge_en;
2933e2340276SBjoern A. Zeeb 	u8 def_tri_idx;
2934e2340276SBjoern A. Zeeb };
2935e2340276SBjoern A. Zeeb 
2936e2340276SBjoern A. Zeeb static
2937e2340276SBjoern A. Zeeb void rtw89_phy_ul_tb_ctrl_check(struct rtw89_dev *rtwdev,
2938e2340276SBjoern A. Zeeb 				struct rtw89_vif *rtwvif,
2939e2340276SBjoern A. Zeeb 				struct rtw89_phy_ul_tb_check_data *ul_tb_data)
2940e2340276SBjoern A. Zeeb {
2941e2340276SBjoern A. Zeeb 	struct rtw89_traffic_stats *stats = &rtwdev->stats;
2942e2340276SBjoern A. Zeeb 	struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
2943e2340276SBjoern A. Zeeb 
2944e2340276SBjoern A. Zeeb 	if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION)
2945e2340276SBjoern A. Zeeb 		return;
2946e2340276SBjoern A. Zeeb 
2947e2340276SBjoern A. Zeeb 	if (!vif->cfg.assoc)
2948e2340276SBjoern A. Zeeb 		return;
2949e2340276SBjoern A. Zeeb 
2950e2340276SBjoern A. Zeeb 	if (stats->rx_tf_periodic > UL_TB_TF_CNT_L2H_TH)
2951e2340276SBjoern A. Zeeb 		ul_tb_data->high_tf_client = true;
2952e2340276SBjoern A. Zeeb 	else if (stats->rx_tf_periodic < UL_TB_TF_CNT_H2L_TH)
2953e2340276SBjoern A. Zeeb 		ul_tb_data->low_tf_client = true;
2954e2340276SBjoern A. Zeeb 
2955e2340276SBjoern A. Zeeb 	ul_tb_data->valid = true;
2956e2340276SBjoern A. Zeeb 	ul_tb_data->def_tri_idx = rtwvif->def_tri_idx;
2957e2340276SBjoern A. Zeeb 	ul_tb_data->dyn_tb_bedge_en = rtwvif->dyn_tb_bedge_en;
2958e2340276SBjoern A. Zeeb }
2959e2340276SBjoern A. Zeeb 
2960e2340276SBjoern A. Zeeb void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev)
2961e2340276SBjoern A. Zeeb {
2962e2340276SBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
2963e2340276SBjoern A. Zeeb 	struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info;
2964e2340276SBjoern A. Zeeb 	struct rtw89_phy_ul_tb_check_data ul_tb_data = {};
2965e2340276SBjoern A. Zeeb 	struct rtw89_vif *rtwvif;
2966e2340276SBjoern A. Zeeb 
2967e2340276SBjoern A. Zeeb 	if (!chip->support_ul_tb_ctrl)
2968e2340276SBjoern A. Zeeb 		return;
2969e2340276SBjoern A. Zeeb 
2970e2340276SBjoern A. Zeeb 	if (rtwdev->total_sta_assoc != 1)
2971e2340276SBjoern A. Zeeb 		return;
2972e2340276SBjoern A. Zeeb 
2973e2340276SBjoern A. Zeeb 	rtw89_for_each_rtwvif(rtwdev, rtwvif)
2974e2340276SBjoern A. Zeeb 		rtw89_phy_ul_tb_ctrl_check(rtwdev, rtwvif, &ul_tb_data);
2975e2340276SBjoern A. Zeeb 
2976e2340276SBjoern A. Zeeb 	if (!ul_tb_data.valid)
2977e2340276SBjoern A. Zeeb 		return;
2978e2340276SBjoern A. Zeeb 
2979e2340276SBjoern A. Zeeb 	if (ul_tb_data.dyn_tb_bedge_en) {
2980e2340276SBjoern A. Zeeb 		if (ul_tb_data.high_tf_client) {
2981e2340276SBjoern A. Zeeb 			rtw89_phy_write32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN, 0);
2982e2340276SBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
2983e2340276SBjoern A. Zeeb 				    "[ULTB] Turn off if_bandedge\n");
2984e2340276SBjoern A. Zeeb 		} else if (ul_tb_data.low_tf_client) {
2985e2340276SBjoern A. Zeeb 			rtw89_phy_write32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN,
2986e2340276SBjoern A. Zeeb 					       ul_tb_info->def_if_bandedge);
2987e2340276SBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
2988e2340276SBjoern A. Zeeb 				    "[ULTB] Set to default if_bandedge = %d\n",
2989e2340276SBjoern A. Zeeb 				    ul_tb_info->def_if_bandedge);
2990e2340276SBjoern A. Zeeb 		}
2991e2340276SBjoern A. Zeeb 	}
2992e2340276SBjoern A. Zeeb 
2993e2340276SBjoern A. Zeeb 	if (ul_tb_info->dyn_tb_tri_en) {
2994e2340276SBjoern A. Zeeb 		if (ul_tb_data.high_tf_client) {
2995e2340276SBjoern A. Zeeb 			rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT,
2996e2340276SBjoern A. Zeeb 					       B_TXSHAPE_TRIANGULAR_CFG, 0);
2997e2340276SBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
2998e2340276SBjoern A. Zeeb 				    "[ULTB] Turn off Tx triangle\n");
2999e2340276SBjoern A. Zeeb 		} else if (ul_tb_data.low_tf_client) {
3000e2340276SBjoern A. Zeeb 			rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT,
3001e2340276SBjoern A. Zeeb 					       B_TXSHAPE_TRIANGULAR_CFG,
3002e2340276SBjoern A. Zeeb 					       ul_tb_data.def_tri_idx);
3003e2340276SBjoern A. Zeeb 			rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
3004e2340276SBjoern A. Zeeb 				    "[ULTB] Set to default tx_shap_idx = %d\n",
3005e2340276SBjoern A. Zeeb 				    ul_tb_data.def_tri_idx);
3006e2340276SBjoern A. Zeeb 		}
3007e2340276SBjoern A. Zeeb 	}
3008e2340276SBjoern A. Zeeb }
3009e2340276SBjoern A. Zeeb 
3010e2340276SBjoern A. Zeeb static void rtw89_phy_ul_tb_info_init(struct rtw89_dev *rtwdev)
3011e2340276SBjoern A. Zeeb {
3012e2340276SBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
3013e2340276SBjoern A. Zeeb 	struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info;
3014e2340276SBjoern A. Zeeb 
3015e2340276SBjoern A. Zeeb 	if (!chip->support_ul_tb_ctrl)
3016e2340276SBjoern A. Zeeb 		return;
3017e2340276SBjoern A. Zeeb 
3018e2340276SBjoern A. Zeeb 	ul_tb_info->dyn_tb_tri_en = true;
3019e2340276SBjoern A. Zeeb 	ul_tb_info->def_if_bandedge =
3020e2340276SBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN);
3021e2340276SBjoern A. Zeeb }
3022e2340276SBjoern A. Zeeb 
3023e2340276SBjoern A. Zeeb static
3024e2340276SBjoern A. Zeeb void rtw89_phy_antdiv_sts_instance_reset(struct rtw89_antdiv_stats *antdiv_sts)
3025e2340276SBjoern A. Zeeb {
3026e2340276SBjoern A. Zeeb 	ewma_rssi_init(&antdiv_sts->cck_rssi_avg);
3027e2340276SBjoern A. Zeeb 	ewma_rssi_init(&antdiv_sts->ofdm_rssi_avg);
3028e2340276SBjoern A. Zeeb 	ewma_rssi_init(&antdiv_sts->non_legacy_rssi_avg);
3029e2340276SBjoern A. Zeeb 	antdiv_sts->pkt_cnt_cck = 0;
3030e2340276SBjoern A. Zeeb 	antdiv_sts->pkt_cnt_ofdm = 0;
3031e2340276SBjoern A. Zeeb 	antdiv_sts->pkt_cnt_non_legacy = 0;
3032e2340276SBjoern A. Zeeb 	antdiv_sts->evm = 0;
3033e2340276SBjoern A. Zeeb }
3034e2340276SBjoern A. Zeeb 
3035e2340276SBjoern A. Zeeb static void rtw89_phy_antdiv_sts_instance_add(struct rtw89_dev *rtwdev,
3036e2340276SBjoern A. Zeeb 					      struct rtw89_rx_phy_ppdu *phy_ppdu,
3037e2340276SBjoern A. Zeeb 					      struct rtw89_antdiv_stats *stats)
3038e2340276SBjoern A. Zeeb {
3039e2340276SBjoern A. Zeeb 	if (rtw89_get_data_rate_mode(rtwdev, phy_ppdu->rate) == DATA_RATE_MODE_NON_HT) {
3040e2340276SBjoern A. Zeeb 		if (phy_ppdu->rate < RTW89_HW_RATE_OFDM6) {
3041e2340276SBjoern A. Zeeb 			ewma_rssi_add(&stats->cck_rssi_avg, phy_ppdu->rssi_avg);
3042e2340276SBjoern A. Zeeb 			stats->pkt_cnt_cck++;
3043e2340276SBjoern A. Zeeb 		} else {
3044e2340276SBjoern A. Zeeb 			ewma_rssi_add(&stats->ofdm_rssi_avg, phy_ppdu->rssi_avg);
3045e2340276SBjoern A. Zeeb 			stats->pkt_cnt_ofdm++;
3046e2340276SBjoern A. Zeeb 			stats->evm += phy_ppdu->ofdm.evm_min;
3047e2340276SBjoern A. Zeeb 		}
3048e2340276SBjoern A. Zeeb 	} else {
3049e2340276SBjoern A. Zeeb 		ewma_rssi_add(&stats->non_legacy_rssi_avg, phy_ppdu->rssi_avg);
3050e2340276SBjoern A. Zeeb 		stats->pkt_cnt_non_legacy++;
3051e2340276SBjoern A. Zeeb 		stats->evm += phy_ppdu->ofdm.evm_min;
3052e2340276SBjoern A. Zeeb 	}
3053e2340276SBjoern A. Zeeb }
3054e2340276SBjoern A. Zeeb 
3055e2340276SBjoern A. Zeeb static u8 rtw89_phy_antdiv_sts_instance_get_rssi(struct rtw89_antdiv_stats *stats)
3056e2340276SBjoern A. Zeeb {
3057e2340276SBjoern A. Zeeb 	if (stats->pkt_cnt_non_legacy >= stats->pkt_cnt_cck &&
3058e2340276SBjoern A. Zeeb 	    stats->pkt_cnt_non_legacy >= stats->pkt_cnt_ofdm)
3059e2340276SBjoern A. Zeeb 		return ewma_rssi_read(&stats->non_legacy_rssi_avg);
3060e2340276SBjoern A. Zeeb 	else if (stats->pkt_cnt_ofdm >= stats->pkt_cnt_cck &&
3061e2340276SBjoern A. Zeeb 		 stats->pkt_cnt_ofdm >= stats->pkt_cnt_non_legacy)
3062e2340276SBjoern A. Zeeb 		return ewma_rssi_read(&stats->ofdm_rssi_avg);
3063e2340276SBjoern A. Zeeb 	else
3064e2340276SBjoern A. Zeeb 		return ewma_rssi_read(&stats->cck_rssi_avg);
3065e2340276SBjoern A. Zeeb }
3066e2340276SBjoern A. Zeeb 
3067e2340276SBjoern A. Zeeb static u8 rtw89_phy_antdiv_sts_instance_get_evm(struct rtw89_antdiv_stats *stats)
3068e2340276SBjoern A. Zeeb {
3069e2340276SBjoern A. Zeeb 	return phy_div(stats->evm, stats->pkt_cnt_non_legacy + stats->pkt_cnt_ofdm);
3070e2340276SBjoern A. Zeeb }
3071e2340276SBjoern A. Zeeb 
3072e2340276SBjoern A. Zeeb void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev,
3073e2340276SBjoern A. Zeeb 			    struct rtw89_rx_phy_ppdu *phy_ppdu)
3074e2340276SBjoern A. Zeeb {
3075e2340276SBjoern A. Zeeb 	struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
3076e2340276SBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
3077e2340276SBjoern A. Zeeb 
3078e2340276SBjoern A. Zeeb 	if (!hal->ant_diversity || hal->ant_diversity_fixed)
3079e2340276SBjoern A. Zeeb 		return;
3080e2340276SBjoern A. Zeeb 
3081e2340276SBjoern A. Zeeb 	rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->target_stats);
3082e2340276SBjoern A. Zeeb 
3083e2340276SBjoern A. Zeeb 	if (!antdiv->get_stats)
3084e2340276SBjoern A. Zeeb 		return;
3085e2340276SBjoern A. Zeeb 
3086e2340276SBjoern A. Zeeb 	if (hal->antenna_rx == RF_A)
3087e2340276SBjoern A. Zeeb 		rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->main_stats);
3088e2340276SBjoern A. Zeeb 	else if (hal->antenna_rx == RF_B)
3089e2340276SBjoern A. Zeeb 		rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->aux_stats);
3090e2340276SBjoern A. Zeeb }
3091e2340276SBjoern A. Zeeb 
3092e2340276SBjoern A. Zeeb static void rtw89_phy_antdiv_reg_init(struct rtw89_dev *rtwdev)
3093e2340276SBjoern A. Zeeb {
3094e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_ANT_TRAIN_EN,
3095e2340276SBjoern A. Zeeb 			      0x0, RTW89_PHY_0);
3096e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_TX_ANT_SEL,
3097e2340276SBjoern A. Zeeb 			      0x0, RTW89_PHY_0);
3098e2340276SBjoern A. Zeeb 
3099e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_ANT_SW, B_P0_TRSW_TX_EXTEND,
3100e2340276SBjoern A. Zeeb 			      0x0, RTW89_PHY_0);
3101e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_ANT_SW, B_P0_HW_ANTSW_DIS_BY_GNT_BT,
3102e2340276SBjoern A. Zeeb 			      0x0, RTW89_PHY_0);
3103e2340276SBjoern A. Zeeb 
3104e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_BT_FORCE_ANTIDX_EN,
3105e2340276SBjoern A. Zeeb 			      0x0, RTW89_PHY_0);
3106e2340276SBjoern A. Zeeb 
3107e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_RFSW_CTRL_ANT0_BASE, B_RFSW_CTRL_ANT_MAPPING,
3108e2340276SBjoern A. Zeeb 			      0x0100, RTW89_PHY_0);
3109e2340276SBjoern A. Zeeb 
3110e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_BTG_TRX,
3111e2340276SBjoern A. Zeeb 			      0x1, RTW89_PHY_0);
3112e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_HW_CTRL,
3113e2340276SBjoern A. Zeeb 			      0x0, RTW89_PHY_0);
3114e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_SW_2G,
3115e2340276SBjoern A. Zeeb 			      0x0, RTW89_PHY_0);
3116e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_SW_5G,
3117e2340276SBjoern A. Zeeb 			      0x0, RTW89_PHY_0);
3118e2340276SBjoern A. Zeeb }
3119e2340276SBjoern A. Zeeb 
3120e2340276SBjoern A. Zeeb static void rtw89_phy_antdiv_sts_reset(struct rtw89_dev *rtwdev)
3121e2340276SBjoern A. Zeeb {
3122e2340276SBjoern A. Zeeb 	struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
3123e2340276SBjoern A. Zeeb 
3124e2340276SBjoern A. Zeeb 	rtw89_phy_antdiv_sts_instance_reset(&antdiv->target_stats);
3125e2340276SBjoern A. Zeeb 	rtw89_phy_antdiv_sts_instance_reset(&antdiv->main_stats);
3126e2340276SBjoern A. Zeeb 	rtw89_phy_antdiv_sts_instance_reset(&antdiv->aux_stats);
3127e2340276SBjoern A. Zeeb }
3128e2340276SBjoern A. Zeeb 
3129e2340276SBjoern A. Zeeb static void rtw89_phy_antdiv_init(struct rtw89_dev *rtwdev)
3130e2340276SBjoern A. Zeeb {
3131e2340276SBjoern A. Zeeb 	struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
3132e2340276SBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
3133e2340276SBjoern A. Zeeb 
3134e2340276SBjoern A. Zeeb 	if (!hal->ant_diversity)
3135e2340276SBjoern A. Zeeb 		return;
3136e2340276SBjoern A. Zeeb 
3137e2340276SBjoern A. Zeeb 	antdiv->get_stats = false;
3138e2340276SBjoern A. Zeeb 	antdiv->rssi_pre = 0;
3139e2340276SBjoern A. Zeeb 	rtw89_phy_antdiv_sts_reset(rtwdev);
3140e2340276SBjoern A. Zeeb 	rtw89_phy_antdiv_reg_init(rtwdev);
3141e2340276SBjoern A. Zeeb }
3142e2340276SBjoern A. Zeeb 
31438e93258fSBjoern A. Zeeb static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev)
31448e93258fSBjoern A. Zeeb {
31458e93258fSBjoern A. Zeeb 	struct rtw89_phy_stat *phystat = &rtwdev->phystat;
31468e93258fSBjoern A. Zeeb 	int i;
31478e93258fSBjoern A. Zeeb 	u8 th;
31488e93258fSBjoern A. Zeeb 
31498e93258fSBjoern A. Zeeb 	for (i = 0; i < rtwdev->chip->rf_path_num; i++) {
31508e93258fSBjoern A. Zeeb 		th = rtw89_chip_get_thermal(rtwdev, i);
31518e93258fSBjoern A. Zeeb 		if (th)
31528e93258fSBjoern A. Zeeb 			ewma_thermal_add(&phystat->avg_thermal[i], th);
31538e93258fSBjoern A. Zeeb 
31548e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK,
31558e93258fSBjoern A. Zeeb 			    "path(%d) thermal cur=%u avg=%ld", i, th,
31568e93258fSBjoern A. Zeeb 			    ewma_thermal_read(&phystat->avg_thermal[i]));
31578e93258fSBjoern A. Zeeb 	}
31588e93258fSBjoern A. Zeeb }
31598e93258fSBjoern A. Zeeb 
31608e93258fSBjoern A. Zeeb struct rtw89_phy_iter_rssi_data {
31618e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev;
31628e93258fSBjoern A. Zeeb 	struct rtw89_phy_ch_info *ch_info;
31638e93258fSBjoern A. Zeeb 	bool rssi_changed;
31648e93258fSBjoern A. Zeeb };
31658e93258fSBjoern A. Zeeb 
31668e93258fSBjoern A. Zeeb static void rtw89_phy_stat_rssi_update_iter(void *data,
31678e93258fSBjoern A. Zeeb 					    struct ieee80211_sta *sta)
31688e93258fSBjoern A. Zeeb {
31698e93258fSBjoern A. Zeeb 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
31708e93258fSBjoern A. Zeeb 	struct rtw89_phy_iter_rssi_data *rssi_data =
31718e93258fSBjoern A. Zeeb 					(struct rtw89_phy_iter_rssi_data *)data;
31728e93258fSBjoern A. Zeeb 	struct rtw89_phy_ch_info *ch_info = rssi_data->ch_info;
31738e93258fSBjoern A. Zeeb 	unsigned long rssi_curr;
31748e93258fSBjoern A. Zeeb 
31758e93258fSBjoern A. Zeeb 	rssi_curr = ewma_rssi_read(&rtwsta->avg_rssi);
31768e93258fSBjoern A. Zeeb 
31778e93258fSBjoern A. Zeeb 	if (rssi_curr < ch_info->rssi_min) {
31788e93258fSBjoern A. Zeeb 		ch_info->rssi_min = rssi_curr;
31798e93258fSBjoern A. Zeeb 		ch_info->rssi_min_macid = rtwsta->mac_id;
31808e93258fSBjoern A. Zeeb 	}
31818e93258fSBjoern A. Zeeb 
31828e93258fSBjoern A. Zeeb 	if (rtwsta->prev_rssi == 0) {
31838e93258fSBjoern A. Zeeb 		rtwsta->prev_rssi = rssi_curr;
31848e93258fSBjoern A. Zeeb 	} else if (abs((int)rtwsta->prev_rssi - (int)rssi_curr) > (3 << RSSI_FACTOR)) {
31858e93258fSBjoern A. Zeeb 		rtwsta->prev_rssi = rssi_curr;
31868e93258fSBjoern A. Zeeb 		rssi_data->rssi_changed = true;
31878e93258fSBjoern A. Zeeb 	}
31888e93258fSBjoern A. Zeeb }
31898e93258fSBjoern A. Zeeb 
31908e93258fSBjoern A. Zeeb static void rtw89_phy_stat_rssi_update(struct rtw89_dev *rtwdev)
31918e93258fSBjoern A. Zeeb {
31928e93258fSBjoern A. Zeeb 	struct rtw89_phy_iter_rssi_data rssi_data = {0};
31938e93258fSBjoern A. Zeeb 
31948e93258fSBjoern A. Zeeb 	rssi_data.rtwdev = rtwdev;
31958e93258fSBjoern A. Zeeb 	rssi_data.ch_info = &rtwdev->ch_info;
31968e93258fSBjoern A. Zeeb 	rssi_data.ch_info->rssi_min = U8_MAX;
31978e93258fSBjoern A. Zeeb 	ieee80211_iterate_stations_atomic(rtwdev->hw,
31988e93258fSBjoern A. Zeeb 					  rtw89_phy_stat_rssi_update_iter,
31998e93258fSBjoern A. Zeeb 					  &rssi_data);
32008e93258fSBjoern A. Zeeb 	if (rssi_data.rssi_changed)
32018e93258fSBjoern A. Zeeb 		rtw89_btc_ntfy_wl_sta(rtwdev);
32028e93258fSBjoern A. Zeeb }
32038e93258fSBjoern A. Zeeb 
32048e93258fSBjoern A. Zeeb static void rtw89_phy_stat_init(struct rtw89_dev *rtwdev)
32058e93258fSBjoern A. Zeeb {
32068e93258fSBjoern A. Zeeb 	struct rtw89_phy_stat *phystat = &rtwdev->phystat;
32078e93258fSBjoern A. Zeeb 	int i;
32088e93258fSBjoern A. Zeeb 
32098e93258fSBjoern A. Zeeb 	for (i = 0; i < rtwdev->chip->rf_path_num; i++)
32108e93258fSBjoern A. Zeeb 		ewma_thermal_init(&phystat->avg_thermal[i]);
32118e93258fSBjoern A. Zeeb 
32128e93258fSBjoern A. Zeeb 	rtw89_phy_stat_thermal_update(rtwdev);
32138e93258fSBjoern A. Zeeb 
32148e93258fSBjoern A. Zeeb 	memset(&phystat->cur_pkt_stat, 0, sizeof(phystat->cur_pkt_stat));
32158e93258fSBjoern A. Zeeb 	memset(&phystat->last_pkt_stat, 0, sizeof(phystat->last_pkt_stat));
32168e93258fSBjoern A. Zeeb }
32178e93258fSBjoern A. Zeeb 
32188e93258fSBjoern A. Zeeb void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
32198e93258fSBjoern A. Zeeb {
32208e93258fSBjoern A. Zeeb 	struct rtw89_phy_stat *phystat = &rtwdev->phystat;
32218e93258fSBjoern A. Zeeb 
32228e93258fSBjoern A. Zeeb 	rtw89_phy_stat_thermal_update(rtwdev);
32238e93258fSBjoern A. Zeeb 	rtw89_phy_stat_rssi_update(rtwdev);
32248e93258fSBjoern A. Zeeb 
32258e93258fSBjoern A. Zeeb 	phystat->last_pkt_stat = phystat->cur_pkt_stat;
32268e93258fSBjoern A. Zeeb 	memset(&phystat->cur_pkt_stat, 0, sizeof(phystat->cur_pkt_stat));
32278e93258fSBjoern A. Zeeb }
32288e93258fSBjoern A. Zeeb 
32298e93258fSBjoern A. Zeeb static u16 rtw89_phy_ccx_us_to_idx(struct rtw89_dev *rtwdev, u32 time_us)
32308e93258fSBjoern A. Zeeb {
32318e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
32328e93258fSBjoern A. Zeeb 
32338e93258fSBjoern A. Zeeb 	return time_us >> (ilog2(CCX_US_BASE_RATIO) + env->ccx_unit_idx);
32348e93258fSBjoern A. Zeeb }
32358e93258fSBjoern A. Zeeb 
32368e93258fSBjoern A. Zeeb static u32 rtw89_phy_ccx_idx_to_us(struct rtw89_dev *rtwdev, u16 idx)
32378e93258fSBjoern A. Zeeb {
32388e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
32398e93258fSBjoern A. Zeeb 
32408e93258fSBjoern A. Zeeb 	return idx << (ilog2(CCX_US_BASE_RATIO) + env->ccx_unit_idx);
32418e93258fSBjoern A. Zeeb }
32428e93258fSBjoern A. Zeeb 
32438e93258fSBjoern A. Zeeb static void rtw89_phy_ccx_top_setting_init(struct rtw89_dev *rtwdev)
32448e93258fSBjoern A. Zeeb {
32458e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
32468e93258fSBjoern A. Zeeb 
32478e93258fSBjoern A. Zeeb 	env->ccx_manual_ctrl = false;
32488e93258fSBjoern A. Zeeb 	env->ccx_ongoing = false;
32498e93258fSBjoern A. Zeeb 	env->ccx_rac_lv = RTW89_RAC_RELEASE;
32508e93258fSBjoern A. Zeeb 	env->ccx_period = 0;
32518e93258fSBjoern A. Zeeb 	env->ccx_unit_idx = RTW89_CCX_32_US;
32528e93258fSBjoern A. Zeeb 
32538e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_EN_MSK, 1);
32548e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_TRIG_OPT_MSK, 1);
32558e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_MEASUREMENT_TRIG_MSK, 1);
32568e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_EDCCA_OPT_MSK,
32578e93258fSBjoern A. Zeeb 			       RTW89_CCX_EDCCA_BW20_0);
32588e93258fSBjoern A. Zeeb }
32598e93258fSBjoern A. Zeeb 
32608e93258fSBjoern A. Zeeb static u16 rtw89_phy_ccx_get_report(struct rtw89_dev *rtwdev, u16 report,
32618e93258fSBjoern A. Zeeb 				    u16 score)
32628e93258fSBjoern A. Zeeb {
32638e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
32648e93258fSBjoern A. Zeeb 	u32 numer = 0;
32658e93258fSBjoern A. Zeeb 	u16 ret = 0;
32668e93258fSBjoern A. Zeeb 
32678e93258fSBjoern A. Zeeb 	numer = report * score + (env->ccx_period >> 1);
32688e93258fSBjoern A. Zeeb 	if (env->ccx_period)
32698e93258fSBjoern A. Zeeb 		ret = numer / env->ccx_period;
32708e93258fSBjoern A. Zeeb 
32718e93258fSBjoern A. Zeeb 	return ret >= score ? score - 1 : ret;
32728e93258fSBjoern A. Zeeb }
32738e93258fSBjoern A. Zeeb 
32748e93258fSBjoern A. Zeeb static void rtw89_phy_ccx_ms_to_period_unit(struct rtw89_dev *rtwdev,
32758e93258fSBjoern A. Zeeb 					    u16 time_ms, u32 *period,
32768e93258fSBjoern A. Zeeb 					    u32 *unit_idx)
32778e93258fSBjoern A. Zeeb {
32788e93258fSBjoern A. Zeeb 	u32 idx;
32798e93258fSBjoern A. Zeeb 	u8 quotient;
32808e93258fSBjoern A. Zeeb 
32818e93258fSBjoern A. Zeeb 	if (time_ms >= CCX_MAX_PERIOD)
32828e93258fSBjoern A. Zeeb 		time_ms = CCX_MAX_PERIOD;
32838e93258fSBjoern A. Zeeb 
32848e93258fSBjoern A. Zeeb 	quotient = CCX_MAX_PERIOD_UNIT * time_ms / CCX_MAX_PERIOD;
32858e93258fSBjoern A. Zeeb 
32868e93258fSBjoern A. Zeeb 	if (quotient < 4)
32878e93258fSBjoern A. Zeeb 		idx = RTW89_CCX_4_US;
32888e93258fSBjoern A. Zeeb 	else if (quotient < 8)
32898e93258fSBjoern A. Zeeb 		idx = RTW89_CCX_8_US;
32908e93258fSBjoern A. Zeeb 	else if (quotient < 16)
32918e93258fSBjoern A. Zeeb 		idx = RTW89_CCX_16_US;
32928e93258fSBjoern A. Zeeb 	else
32938e93258fSBjoern A. Zeeb 		idx = RTW89_CCX_32_US;
32948e93258fSBjoern A. Zeeb 
32958e93258fSBjoern A. Zeeb 	*unit_idx = idx;
32968e93258fSBjoern A. Zeeb 	*period = (time_ms * MS_TO_4US_RATIO) >> idx;
32978e93258fSBjoern A. Zeeb 
32988e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
32998e93258fSBjoern A. Zeeb 		    "[Trigger Time] period:%d, unit_idx:%d\n",
33008e93258fSBjoern A. Zeeb 		    *period, *unit_idx);
33018e93258fSBjoern A. Zeeb }
33028e93258fSBjoern A. Zeeb 
33038e93258fSBjoern A. Zeeb static void rtw89_phy_ccx_racing_release(struct rtw89_dev *rtwdev)
33048e93258fSBjoern A. Zeeb {
33058e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
33068e93258fSBjoern A. Zeeb 
33078e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
33088e93258fSBjoern A. Zeeb 		    "lv:(%d)->(0)\n", env->ccx_rac_lv);
33098e93258fSBjoern A. Zeeb 
33108e93258fSBjoern A. Zeeb 	env->ccx_ongoing = false;
33118e93258fSBjoern A. Zeeb 	env->ccx_rac_lv = RTW89_RAC_RELEASE;
33128e93258fSBjoern A. Zeeb 	env->ifs_clm_app = RTW89_IFS_CLM_BACKGROUND;
33138e93258fSBjoern A. Zeeb }
33148e93258fSBjoern A. Zeeb 
33158e93258fSBjoern A. Zeeb static bool rtw89_phy_ifs_clm_th_update_check(struct rtw89_dev *rtwdev,
33168e93258fSBjoern A. Zeeb 					      struct rtw89_ccx_para_info *para)
33178e93258fSBjoern A. Zeeb {
33188e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
33198e93258fSBjoern A. Zeeb 	bool is_update = env->ifs_clm_app != para->ifs_clm_app;
33208e93258fSBjoern A. Zeeb 	u8 i = 0;
33218e93258fSBjoern A. Zeeb 	u16 *ifs_th_l = env->ifs_clm_th_l;
33228e93258fSBjoern A. Zeeb 	u16 *ifs_th_h = env->ifs_clm_th_h;
33238e93258fSBjoern A. Zeeb 	u32 ifs_th0_us = 0, ifs_th_times = 0;
33248e93258fSBjoern A. Zeeb 	u32 ifs_th_h_us[RTW89_IFS_CLM_NUM] = {0};
33258e93258fSBjoern A. Zeeb 
33268e93258fSBjoern A. Zeeb 	if (!is_update)
33278e93258fSBjoern A. Zeeb 		goto ifs_update_finished;
33288e93258fSBjoern A. Zeeb 
33298e93258fSBjoern A. Zeeb 	switch (para->ifs_clm_app) {
33308e93258fSBjoern A. Zeeb 	case RTW89_IFS_CLM_INIT:
33318e93258fSBjoern A. Zeeb 	case RTW89_IFS_CLM_BACKGROUND:
33328e93258fSBjoern A. Zeeb 	case RTW89_IFS_CLM_ACS:
33338e93258fSBjoern A. Zeeb 	case RTW89_IFS_CLM_DBG:
33348e93258fSBjoern A. Zeeb 	case RTW89_IFS_CLM_DIG:
33358e93258fSBjoern A. Zeeb 	case RTW89_IFS_CLM_TDMA_DIG:
33368e93258fSBjoern A. Zeeb 		ifs_th0_us = IFS_CLM_TH0_UPPER;
33378e93258fSBjoern A. Zeeb 		ifs_th_times = IFS_CLM_TH_MUL;
33388e93258fSBjoern A. Zeeb 		break;
33398e93258fSBjoern A. Zeeb 	case RTW89_IFS_CLM_DBG_MANUAL:
33408e93258fSBjoern A. Zeeb 		ifs_th0_us = para->ifs_clm_manual_th0;
33418e93258fSBjoern A. Zeeb 		ifs_th_times = para->ifs_clm_manual_th_times;
33428e93258fSBjoern A. Zeeb 		break;
33438e93258fSBjoern A. Zeeb 	default:
33448e93258fSBjoern A. Zeeb 		break;
33458e93258fSBjoern A. Zeeb 	}
33468e93258fSBjoern A. Zeeb 
33478e93258fSBjoern A. Zeeb 	/* Set sampling threshold for 4 different regions, unit in idx_cnt.
33488e93258fSBjoern A. Zeeb 	 * low[i] = high[i-1] + 1
33498e93258fSBjoern A. Zeeb 	 * high[i] = high[i-1] * ifs_th_times
33508e93258fSBjoern A. Zeeb 	 */
33518e93258fSBjoern A. Zeeb 	ifs_th_l[IFS_CLM_TH_START_IDX] = 0;
33528e93258fSBjoern A. Zeeb 	ifs_th_h_us[IFS_CLM_TH_START_IDX] = ifs_th0_us;
33538e93258fSBjoern A. Zeeb 	ifs_th_h[IFS_CLM_TH_START_IDX] = rtw89_phy_ccx_us_to_idx(rtwdev,
33548e93258fSBjoern A. Zeeb 								 ifs_th0_us);
33558e93258fSBjoern A. Zeeb 	for (i = 1; i < RTW89_IFS_CLM_NUM; i++) {
33568e93258fSBjoern A. Zeeb 		ifs_th_l[i] = ifs_th_h[i - 1] + 1;
33578e93258fSBjoern A. Zeeb 		ifs_th_h_us[i] = ifs_th_h_us[i - 1] * ifs_th_times;
33588e93258fSBjoern A. Zeeb 		ifs_th_h[i] = rtw89_phy_ccx_us_to_idx(rtwdev, ifs_th_h_us[i]);
33598e93258fSBjoern A. Zeeb 	}
33608e93258fSBjoern A. Zeeb 
33618e93258fSBjoern A. Zeeb ifs_update_finished:
33628e93258fSBjoern A. Zeeb 	if (!is_update)
33638e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
33648e93258fSBjoern A. Zeeb 			    "No need to update IFS_TH\n");
33658e93258fSBjoern A. Zeeb 
33668e93258fSBjoern A. Zeeb 	return is_update;
33678e93258fSBjoern A. Zeeb }
33688e93258fSBjoern A. Zeeb 
33698e93258fSBjoern A. Zeeb static void rtw89_phy_ifs_clm_set_th_reg(struct rtw89_dev *rtwdev)
33708e93258fSBjoern A. Zeeb {
33718e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
33728e93258fSBjoern A. Zeeb 	u8 i = 0;
33738e93258fSBjoern A. Zeeb 
33748e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T1, B_IFS_T1_TH_LOW_MSK,
33758e93258fSBjoern A. Zeeb 			       env->ifs_clm_th_l[0]);
33768e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T2, B_IFS_T2_TH_LOW_MSK,
33778e93258fSBjoern A. Zeeb 			       env->ifs_clm_th_l[1]);
33788e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T3, B_IFS_T3_TH_LOW_MSK,
33798e93258fSBjoern A. Zeeb 			       env->ifs_clm_th_l[2]);
33808e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T4, B_IFS_T4_TH_LOW_MSK,
33818e93258fSBjoern A. Zeeb 			       env->ifs_clm_th_l[3]);
33828e93258fSBjoern A. Zeeb 
33838e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T1, B_IFS_T1_TH_HIGH_MSK,
33848e93258fSBjoern A. Zeeb 			       env->ifs_clm_th_h[0]);
33858e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T2, B_IFS_T2_TH_HIGH_MSK,
33868e93258fSBjoern A. Zeeb 			       env->ifs_clm_th_h[1]);
33878e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T3, B_IFS_T3_TH_HIGH_MSK,
33888e93258fSBjoern A. Zeeb 			       env->ifs_clm_th_h[2]);
33898e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T4, B_IFS_T4_TH_HIGH_MSK,
33908e93258fSBjoern A. Zeeb 			       env->ifs_clm_th_h[3]);
33918e93258fSBjoern A. Zeeb 
33928e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_IFS_CLM_NUM; i++)
33938e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
33948e93258fSBjoern A. Zeeb 			    "Update IFS_T%d_th{low, high} : {%d, %d}\n",
33958e93258fSBjoern A. Zeeb 			    i + 1, env->ifs_clm_th_l[i], env->ifs_clm_th_h[i]);
33968e93258fSBjoern A. Zeeb }
33978e93258fSBjoern A. Zeeb 
33988e93258fSBjoern A. Zeeb static void rtw89_phy_ifs_clm_setting_init(struct rtw89_dev *rtwdev)
33998e93258fSBjoern A. Zeeb {
34008e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
34018e93258fSBjoern A. Zeeb 	struct rtw89_ccx_para_info para = {0};
34028e93258fSBjoern A. Zeeb 
34038e93258fSBjoern A. Zeeb 	env->ifs_clm_app = RTW89_IFS_CLM_BACKGROUND;
34048e93258fSBjoern A. Zeeb 	env->ifs_clm_mntr_time = 0;
34058e93258fSBjoern A. Zeeb 
34068e93258fSBjoern A. Zeeb 	para.ifs_clm_app = RTW89_IFS_CLM_INIT;
34078e93258fSBjoern A. Zeeb 	if (rtw89_phy_ifs_clm_th_update_check(rtwdev, &para))
34088e93258fSBjoern A. Zeeb 		rtw89_phy_ifs_clm_set_th_reg(rtwdev);
34098e93258fSBjoern A. Zeeb 
34108e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER, B_IFS_COLLECT_EN,
34118e93258fSBjoern A. Zeeb 			       true);
34128e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T1, B_IFS_T1_EN_MSK, true);
34138e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T2, B_IFS_T2_EN_MSK, true);
34148e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T3, B_IFS_T3_EN_MSK, true);
34158e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_T4, B_IFS_T4_EN_MSK, true);
34168e93258fSBjoern A. Zeeb }
34178e93258fSBjoern A. Zeeb 
34188e93258fSBjoern A. Zeeb static int rtw89_phy_ccx_racing_ctrl(struct rtw89_dev *rtwdev,
34198e93258fSBjoern A. Zeeb 				     enum rtw89_env_racing_lv level)
34208e93258fSBjoern A. Zeeb {
34218e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
34228e93258fSBjoern A. Zeeb 	int ret = 0;
34238e93258fSBjoern A. Zeeb 
34248e93258fSBjoern A. Zeeb 	if (level >= RTW89_RAC_MAX_NUM) {
34258e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
34268e93258fSBjoern A. Zeeb 			    "[WARNING] Wrong LV=%d\n", level);
34278e93258fSBjoern A. Zeeb 		return -EINVAL;
34288e93258fSBjoern A. Zeeb 	}
34298e93258fSBjoern A. Zeeb 
34308e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
34318e93258fSBjoern A. Zeeb 		    "ccx_ongoing=%d, level:(%d)->(%d)\n", env->ccx_ongoing,
34328e93258fSBjoern A. Zeeb 		    env->ccx_rac_lv, level);
34338e93258fSBjoern A. Zeeb 
34348e93258fSBjoern A. Zeeb 	if (env->ccx_ongoing) {
34358e93258fSBjoern A. Zeeb 		if (level <= env->ccx_rac_lv)
34368e93258fSBjoern A. Zeeb 			ret = -EINVAL;
34378e93258fSBjoern A. Zeeb 		else
34388e93258fSBjoern A. Zeeb 			env->ccx_ongoing = false;
34398e93258fSBjoern A. Zeeb 	}
34408e93258fSBjoern A. Zeeb 
34418e93258fSBjoern A. Zeeb 	if (ret == 0)
34428e93258fSBjoern A. Zeeb 		env->ccx_rac_lv = level;
34438e93258fSBjoern A. Zeeb 
34448e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "ccx racing success=%d\n",
34458e93258fSBjoern A. Zeeb 		    !ret);
34468e93258fSBjoern A. Zeeb 
34478e93258fSBjoern A. Zeeb 	return ret;
34488e93258fSBjoern A. Zeeb }
34498e93258fSBjoern A. Zeeb 
34508e93258fSBjoern A. Zeeb static void rtw89_phy_ccx_trigger(struct rtw89_dev *rtwdev)
34518e93258fSBjoern A. Zeeb {
34528e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
34538e93258fSBjoern A. Zeeb 
34548e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER, B_IFS_COUNTER_CLR_MSK, 0);
34558e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_MEASUREMENT_TRIG_MSK, 0);
34568e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER, B_IFS_COUNTER_CLR_MSK, 1);
34578e93258fSBjoern A. Zeeb 	rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_MEASUREMENT_TRIG_MSK, 1);
34588e93258fSBjoern A. Zeeb 
34598e93258fSBjoern A. Zeeb 	env->ccx_ongoing = true;
34608e93258fSBjoern A. Zeeb }
34618e93258fSBjoern A. Zeeb 
34628e93258fSBjoern A. Zeeb static void rtw89_phy_ifs_clm_get_utility(struct rtw89_dev *rtwdev)
34638e93258fSBjoern A. Zeeb {
34648e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
34658e93258fSBjoern A. Zeeb 	u8 i = 0;
34668e93258fSBjoern A. Zeeb 	u32 res = 0;
34678e93258fSBjoern A. Zeeb 
34688e93258fSBjoern A. Zeeb 	env->ifs_clm_tx_ratio =
34698e93258fSBjoern A. Zeeb 		rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_tx, PERCENT);
34708e93258fSBjoern A. Zeeb 	env->ifs_clm_edcca_excl_cca_ratio =
34718e93258fSBjoern A. Zeeb 		rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_edcca_excl_cca,
34728e93258fSBjoern A. Zeeb 					 PERCENT);
34738e93258fSBjoern A. Zeeb 	env->ifs_clm_cck_fa_ratio =
34748e93258fSBjoern A. Zeeb 		rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_cckfa, PERCENT);
34758e93258fSBjoern A. Zeeb 	env->ifs_clm_ofdm_fa_ratio =
34768e93258fSBjoern A. Zeeb 		rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_ofdmfa, PERCENT);
34778e93258fSBjoern A. Zeeb 	env->ifs_clm_cck_cca_excl_fa_ratio =
34788e93258fSBjoern A. Zeeb 		rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_cckcca_excl_fa,
34798e93258fSBjoern A. Zeeb 					 PERCENT);
34808e93258fSBjoern A. Zeeb 	env->ifs_clm_ofdm_cca_excl_fa_ratio =
34818e93258fSBjoern A. Zeeb 		rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_ofdmcca_excl_fa,
34828e93258fSBjoern A. Zeeb 					 PERCENT);
34838e93258fSBjoern A. Zeeb 	env->ifs_clm_cck_fa_permil =
34848e93258fSBjoern A. Zeeb 		rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_cckfa, PERMIL);
34858e93258fSBjoern A. Zeeb 	env->ifs_clm_ofdm_fa_permil =
34868e93258fSBjoern A. Zeeb 		rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_ofdmfa, PERMIL);
34878e93258fSBjoern A. Zeeb 
34888e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_IFS_CLM_NUM; i++) {
34898e93258fSBjoern A. Zeeb 		if (env->ifs_clm_his[i] > ENV_MNTR_IFSCLM_HIS_MAX) {
34908e93258fSBjoern A. Zeeb 			env->ifs_clm_ifs_avg[i] = ENV_MNTR_FAIL_DWORD;
34918e93258fSBjoern A. Zeeb 		} else {
34928e93258fSBjoern A. Zeeb 			env->ifs_clm_ifs_avg[i] =
34938e93258fSBjoern A. Zeeb 				rtw89_phy_ccx_idx_to_us(rtwdev,
34948e93258fSBjoern A. Zeeb 							env->ifs_clm_avg[i]);
34958e93258fSBjoern A. Zeeb 		}
34968e93258fSBjoern A. Zeeb 
34978e93258fSBjoern A. Zeeb 		res = rtw89_phy_ccx_idx_to_us(rtwdev, env->ifs_clm_cca[i]);
34988e93258fSBjoern A. Zeeb 		res += env->ifs_clm_his[i] >> 1;
34998e93258fSBjoern A. Zeeb 		if (env->ifs_clm_his[i])
35008e93258fSBjoern A. Zeeb 			res /= env->ifs_clm_his[i];
35018e93258fSBjoern A. Zeeb 		else
35028e93258fSBjoern A. Zeeb 			res = 0;
35038e93258fSBjoern A. Zeeb 		env->ifs_clm_cca_avg[i] = res;
35048e93258fSBjoern A. Zeeb 	}
35058e93258fSBjoern A. Zeeb 
35068e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
35078e93258fSBjoern A. Zeeb 		    "IFS-CLM ratio {Tx, EDCCA_exclu_cca} = {%d, %d}\n",
35088e93258fSBjoern A. Zeeb 		    env->ifs_clm_tx_ratio, env->ifs_clm_edcca_excl_cca_ratio);
35098e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
35108e93258fSBjoern A. Zeeb 		    "IFS-CLM FA ratio {CCK, OFDM} = {%d, %d}\n",
35118e93258fSBjoern A. Zeeb 		    env->ifs_clm_cck_fa_ratio, env->ifs_clm_ofdm_fa_ratio);
35128e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
35138e93258fSBjoern A. Zeeb 		    "IFS-CLM FA permil {CCK, OFDM} = {%d, %d}\n",
35148e93258fSBjoern A. Zeeb 		    env->ifs_clm_cck_fa_permil, env->ifs_clm_ofdm_fa_permil);
35158e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
35168e93258fSBjoern A. Zeeb 		    "IFS-CLM CCA_exclu_FA ratio {CCK, OFDM} = {%d, %d}\n",
35178e93258fSBjoern A. Zeeb 		    env->ifs_clm_cck_cca_excl_fa_ratio,
35188e93258fSBjoern A. Zeeb 		    env->ifs_clm_ofdm_cca_excl_fa_ratio);
35198e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
35208e93258fSBjoern A. Zeeb 		    "Time:[his, ifs_avg(us), cca_avg(us)]\n");
35218e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_IFS_CLM_NUM; i++)
35228e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "T%d:[%d, %d, %d]\n",
35238e93258fSBjoern A. Zeeb 			    i + 1, env->ifs_clm_his[i], env->ifs_clm_ifs_avg[i],
35248e93258fSBjoern A. Zeeb 			    env->ifs_clm_cca_avg[i]);
35258e93258fSBjoern A. Zeeb }
35268e93258fSBjoern A. Zeeb 
35278e93258fSBjoern A. Zeeb static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev)
35288e93258fSBjoern A. Zeeb {
35298e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
35308e93258fSBjoern A. Zeeb 	u8 i = 0;
35318e93258fSBjoern A. Zeeb 
35328e93258fSBjoern A. Zeeb 	if (rtw89_phy_read32_mask(rtwdev, R_IFSCNT, B_IFSCNT_DONE_MSK) == 0) {
35338e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
35348e93258fSBjoern A. Zeeb 			    "Get IFS_CLM report Fail\n");
35358e93258fSBjoern A. Zeeb 		return false;
35368e93258fSBjoern A. Zeeb 	}
35378e93258fSBjoern A. Zeeb 
35388e93258fSBjoern A. Zeeb 	env->ifs_clm_tx =
35398e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_TX_CNT,
35408e93258fSBjoern A. Zeeb 				      B_IFS_CLM_TX_CNT_MSK);
35418e93258fSBjoern A. Zeeb 	env->ifs_clm_edcca_excl_cca =
35428e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_TX_CNT,
35438e93258fSBjoern A. Zeeb 				      B_IFS_CLM_EDCCA_EXCLUDE_CCA_FA_MSK);
35448e93258fSBjoern A. Zeeb 	env->ifs_clm_cckcca_excl_fa =
35458e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_CCA,
35468e93258fSBjoern A. Zeeb 				      B_IFS_CLM_CCKCCA_EXCLUDE_FA_MSK);
35478e93258fSBjoern A. Zeeb 	env->ifs_clm_ofdmcca_excl_fa =
35488e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_CCA,
35498e93258fSBjoern A. Zeeb 				      B_IFS_CLM_OFDMCCA_EXCLUDE_FA_MSK);
35508e93258fSBjoern A. Zeeb 	env->ifs_clm_cckfa =
35518e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_FA,
35528e93258fSBjoern A. Zeeb 				      B_IFS_CLM_CCK_FA_MSK);
35538e93258fSBjoern A. Zeeb 	env->ifs_clm_ofdmfa =
35548e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_FA,
35558e93258fSBjoern A. Zeeb 				      B_IFS_CLM_OFDM_FA_MSK);
35568e93258fSBjoern A. Zeeb 
35578e93258fSBjoern A. Zeeb 	env->ifs_clm_his[0] =
35588e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T1_HIS_MSK);
35598e93258fSBjoern A. Zeeb 	env->ifs_clm_his[1] =
35608e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T2_HIS_MSK);
35618e93258fSBjoern A. Zeeb 	env->ifs_clm_his[2] =
35628e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T3_HIS_MSK);
35638e93258fSBjoern A. Zeeb 	env->ifs_clm_his[3] =
35648e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T4_HIS_MSK);
35658e93258fSBjoern A. Zeeb 
35668e93258fSBjoern A. Zeeb 	env->ifs_clm_avg[0] =
35678e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_L, B_IFS_T1_AVG_MSK);
35688e93258fSBjoern A. Zeeb 	env->ifs_clm_avg[1] =
35698e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_L, B_IFS_T2_AVG_MSK);
35708e93258fSBjoern A. Zeeb 	env->ifs_clm_avg[2] =
35718e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_H, B_IFS_T3_AVG_MSK);
35728e93258fSBjoern A. Zeeb 	env->ifs_clm_avg[3] =
35738e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_H, B_IFS_T4_AVG_MSK);
35748e93258fSBjoern A. Zeeb 
35758e93258fSBjoern A. Zeeb 	env->ifs_clm_cca[0] =
35768e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_L, B_IFS_T1_CCA_MSK);
35778e93258fSBjoern A. Zeeb 	env->ifs_clm_cca[1] =
35788e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_L, B_IFS_T2_CCA_MSK);
35798e93258fSBjoern A. Zeeb 	env->ifs_clm_cca[2] =
35808e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_H, B_IFS_T3_CCA_MSK);
35818e93258fSBjoern A. Zeeb 	env->ifs_clm_cca[3] =
35828e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_H, B_IFS_T4_CCA_MSK);
35838e93258fSBjoern A. Zeeb 
35848e93258fSBjoern A. Zeeb 	env->ifs_clm_total_ifs =
35858e93258fSBjoern A. Zeeb 		rtw89_phy_read32_mask(rtwdev, R_IFSCNT, B_IFSCNT_TOTAL_CNT_MSK);
35868e93258fSBjoern A. Zeeb 
35878e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "IFS-CLM total_ifs = %d\n",
35888e93258fSBjoern A. Zeeb 		    env->ifs_clm_total_ifs);
35898e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
35908e93258fSBjoern A. Zeeb 		    "{Tx, EDCCA_exclu_cca} = {%d, %d}\n",
35918e93258fSBjoern A. Zeeb 		    env->ifs_clm_tx, env->ifs_clm_edcca_excl_cca);
35928e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
35938e93258fSBjoern A. Zeeb 		    "IFS-CLM FA{CCK, OFDM} = {%d, %d}\n",
35948e93258fSBjoern A. Zeeb 		    env->ifs_clm_cckfa, env->ifs_clm_ofdmfa);
35958e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
35968e93258fSBjoern A. Zeeb 		    "IFS-CLM CCA_exclu_FA{CCK, OFDM} = {%d, %d}\n",
35978e93258fSBjoern A. Zeeb 		    env->ifs_clm_cckcca_excl_fa, env->ifs_clm_ofdmcca_excl_fa);
35988e93258fSBjoern A. Zeeb 
35998e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "Time:[his, avg, cca]\n");
36008e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_IFS_CLM_NUM; i++)
36018e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
36028e93258fSBjoern A. Zeeb 			    "T%d:[%d, %d, %d]\n", i + 1, env->ifs_clm_his[i],
36038e93258fSBjoern A. Zeeb 			    env->ifs_clm_avg[i], env->ifs_clm_cca[i]);
36048e93258fSBjoern A. Zeeb 
36058e93258fSBjoern A. Zeeb 	rtw89_phy_ifs_clm_get_utility(rtwdev);
36068e93258fSBjoern A. Zeeb 
36078e93258fSBjoern A. Zeeb 	return true;
36088e93258fSBjoern A. Zeeb }
36098e93258fSBjoern A. Zeeb 
36108e93258fSBjoern A. Zeeb static int rtw89_phy_ifs_clm_set(struct rtw89_dev *rtwdev,
36118e93258fSBjoern A. Zeeb 				 struct rtw89_ccx_para_info *para)
36128e93258fSBjoern A. Zeeb {
36138e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
36148e93258fSBjoern A. Zeeb 	u32 period = 0;
36158e93258fSBjoern A. Zeeb 	u32 unit_idx = 0;
36168e93258fSBjoern A. Zeeb 
36178e93258fSBjoern A. Zeeb 	if (para->mntr_time == 0) {
36188e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
36198e93258fSBjoern A. Zeeb 			    "[WARN] MNTR_TIME is 0\n");
36208e93258fSBjoern A. Zeeb 		return -EINVAL;
36218e93258fSBjoern A. Zeeb 	}
36228e93258fSBjoern A. Zeeb 
36238e93258fSBjoern A. Zeeb 	if (rtw89_phy_ccx_racing_ctrl(rtwdev, para->rac_lv))
36248e93258fSBjoern A. Zeeb 		return -EINVAL;
36258e93258fSBjoern A. Zeeb 
36268e93258fSBjoern A. Zeeb 	if (para->mntr_time != env->ifs_clm_mntr_time) {
36278e93258fSBjoern A. Zeeb 		rtw89_phy_ccx_ms_to_period_unit(rtwdev, para->mntr_time,
36288e93258fSBjoern A. Zeeb 						&period, &unit_idx);
36298e93258fSBjoern A. Zeeb 		rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER,
36308e93258fSBjoern A. Zeeb 				       B_IFS_CLM_PERIOD_MSK, period);
36318e93258fSBjoern A. Zeeb 		rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER,
36328e93258fSBjoern A. Zeeb 				       B_IFS_CLM_COUNTER_UNIT_MSK, unit_idx);
36338e93258fSBjoern A. Zeeb 
36348e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
36358e93258fSBjoern A. Zeeb 			    "Update IFS-CLM time ((%d)) -> ((%d))\n",
36368e93258fSBjoern A. Zeeb 			    env->ifs_clm_mntr_time, para->mntr_time);
36378e93258fSBjoern A. Zeeb 
36388e93258fSBjoern A. Zeeb 		env->ifs_clm_mntr_time = para->mntr_time;
36398e93258fSBjoern A. Zeeb 		env->ccx_period = (u16)period;
36408e93258fSBjoern A. Zeeb 		env->ccx_unit_idx = (u8)unit_idx;
36418e93258fSBjoern A. Zeeb 	}
36428e93258fSBjoern A. Zeeb 
36438e93258fSBjoern A. Zeeb 	if (rtw89_phy_ifs_clm_th_update_check(rtwdev, para)) {
36448e93258fSBjoern A. Zeeb 		env->ifs_clm_app = para->ifs_clm_app;
36458e93258fSBjoern A. Zeeb 		rtw89_phy_ifs_clm_set_th_reg(rtwdev);
36468e93258fSBjoern A. Zeeb 	}
36478e93258fSBjoern A. Zeeb 
36488e93258fSBjoern A. Zeeb 	return 0;
36498e93258fSBjoern A. Zeeb }
36508e93258fSBjoern A. Zeeb 
36518e93258fSBjoern A. Zeeb void rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev)
36528e93258fSBjoern A. Zeeb {
36538e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
36548e93258fSBjoern A. Zeeb 	struct rtw89_ccx_para_info para = {0};
36558e93258fSBjoern A. Zeeb 	u8 chk_result = RTW89_PHY_ENV_MON_CCX_FAIL;
36568e93258fSBjoern A. Zeeb 
36578e93258fSBjoern A. Zeeb 	env->ccx_watchdog_result = RTW89_PHY_ENV_MON_CCX_FAIL;
36588e93258fSBjoern A. Zeeb 	if (env->ccx_manual_ctrl) {
36598e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
36608e93258fSBjoern A. Zeeb 			    "CCX in manual ctrl\n");
36618e93258fSBjoern A. Zeeb 		return;
36628e93258fSBjoern A. Zeeb 	}
36638e93258fSBjoern A. Zeeb 
36648e93258fSBjoern A. Zeeb 	/* only ifs_clm for now */
36658e93258fSBjoern A. Zeeb 	if (rtw89_phy_ifs_clm_get_result(rtwdev))
36668e93258fSBjoern A. Zeeb 		env->ccx_watchdog_result |= RTW89_PHY_ENV_MON_IFS_CLM;
36678e93258fSBjoern A. Zeeb 
36688e93258fSBjoern A. Zeeb 	rtw89_phy_ccx_racing_release(rtwdev);
36698e93258fSBjoern A. Zeeb 	para.mntr_time = 1900;
36708e93258fSBjoern A. Zeeb 	para.rac_lv = RTW89_RAC_LV_1;
36718e93258fSBjoern A. Zeeb 	para.ifs_clm_app = RTW89_IFS_CLM_BACKGROUND;
36728e93258fSBjoern A. Zeeb 
36738e93258fSBjoern A. Zeeb 	if (rtw89_phy_ifs_clm_set(rtwdev, &para) == 0)
36748e93258fSBjoern A. Zeeb 		chk_result |= RTW89_PHY_ENV_MON_IFS_CLM;
36758e93258fSBjoern A. Zeeb 	if (chk_result)
36768e93258fSBjoern A. Zeeb 		rtw89_phy_ccx_trigger(rtwdev);
36778e93258fSBjoern A. Zeeb 
36788e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
36798e93258fSBjoern A. Zeeb 		    "get_result=0x%x, chk_result:0x%x\n",
36808e93258fSBjoern A. Zeeb 		    env->ccx_watchdog_result, chk_result);
36818e93258fSBjoern A. Zeeb }
36828e93258fSBjoern A. Zeeb 
36838e93258fSBjoern A. Zeeb static bool rtw89_physts_ie_page_valid(enum rtw89_phy_status_bitmap *ie_page)
36848e93258fSBjoern A. Zeeb {
3685e2340276SBjoern A. Zeeb 	if (*ie_page >= RTW89_PHYSTS_BITMAP_NUM ||
36868e93258fSBjoern A. Zeeb 	    *ie_page == RTW89_RSVD_9)
36878e93258fSBjoern A. Zeeb 		return false;
36888e93258fSBjoern A. Zeeb 	else if (*ie_page > RTW89_RSVD_9)
36898e93258fSBjoern A. Zeeb 		*ie_page -= 1;
36908e93258fSBjoern A. Zeeb 
36918e93258fSBjoern A. Zeeb 	return true;
36928e93258fSBjoern A. Zeeb }
36938e93258fSBjoern A. Zeeb 
36948e93258fSBjoern A. Zeeb static u32 rtw89_phy_get_ie_bitmap_addr(enum rtw89_phy_status_bitmap ie_page)
36958e93258fSBjoern A. Zeeb {
36968e93258fSBjoern A. Zeeb 	static const u8 ie_page_shift = 2;
36978e93258fSBjoern A. Zeeb 
36988e93258fSBjoern A. Zeeb 	return R_PHY_STS_BITMAP_ADDR_START + (ie_page << ie_page_shift);
36998e93258fSBjoern A. Zeeb }
37008e93258fSBjoern A. Zeeb 
37018e93258fSBjoern A. Zeeb static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev,
37028e93258fSBjoern A. Zeeb 				      enum rtw89_phy_status_bitmap ie_page)
37038e93258fSBjoern A. Zeeb {
37048e93258fSBjoern A. Zeeb 	u32 addr;
37058e93258fSBjoern A. Zeeb 
37068e93258fSBjoern A. Zeeb 	if (!rtw89_physts_ie_page_valid(&ie_page))
37078e93258fSBjoern A. Zeeb 		return 0;
37088e93258fSBjoern A. Zeeb 
37098e93258fSBjoern A. Zeeb 	addr = rtw89_phy_get_ie_bitmap_addr(ie_page);
37108e93258fSBjoern A. Zeeb 
37118e93258fSBjoern A. Zeeb 	return rtw89_phy_read32(rtwdev, addr);
37128e93258fSBjoern A. Zeeb }
37138e93258fSBjoern A. Zeeb 
37148e93258fSBjoern A. Zeeb static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev,
37158e93258fSBjoern A. Zeeb 				       enum rtw89_phy_status_bitmap ie_page,
37168e93258fSBjoern A. Zeeb 				       u32 val)
37178e93258fSBjoern A. Zeeb {
37188e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
37198e93258fSBjoern A. Zeeb 	u32 addr;
37208e93258fSBjoern A. Zeeb 
37218e93258fSBjoern A. Zeeb 	if (!rtw89_physts_ie_page_valid(&ie_page))
37228e93258fSBjoern A. Zeeb 		return;
37238e93258fSBjoern A. Zeeb 
37248e93258fSBjoern A. Zeeb 	if (chip->chip_id == RTL8852A)
37258e93258fSBjoern A. Zeeb 		val &= B_PHY_STS_BITMAP_MSK_52A;
37268e93258fSBjoern A. Zeeb 
37278e93258fSBjoern A. Zeeb 	addr = rtw89_phy_get_ie_bitmap_addr(ie_page);
37288e93258fSBjoern A. Zeeb 	rtw89_phy_write32(rtwdev, addr, val);
37298e93258fSBjoern A. Zeeb }
37308e93258fSBjoern A. Zeeb 
37318e93258fSBjoern A. Zeeb static void rtw89_physts_enable_ie_bitmap(struct rtw89_dev *rtwdev,
37328e93258fSBjoern A. Zeeb 					  enum rtw89_phy_status_bitmap bitmap,
37338e93258fSBjoern A. Zeeb 					  enum rtw89_phy_status_ie_type ie,
37348e93258fSBjoern A. Zeeb 					  bool enable)
37358e93258fSBjoern A. Zeeb {
37368e93258fSBjoern A. Zeeb 	u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap);
37378e93258fSBjoern A. Zeeb 
37388e93258fSBjoern A. Zeeb 	if (enable)
37398e93258fSBjoern A. Zeeb 		val |= BIT(ie);
37408e93258fSBjoern A. Zeeb 	else
37418e93258fSBjoern A. Zeeb 		val &= ~BIT(ie);
37428e93258fSBjoern A. Zeeb 
37438e93258fSBjoern A. Zeeb 	rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val);
37448e93258fSBjoern A. Zeeb }
37458e93258fSBjoern A. Zeeb 
37468e93258fSBjoern A. Zeeb static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev,
37478e93258fSBjoern A. Zeeb 					    bool enable,
37488e93258fSBjoern A. Zeeb 					    enum rtw89_phy_idx phy_idx)
37498e93258fSBjoern A. Zeeb {
37508e93258fSBjoern A. Zeeb 	if (enable) {
37518e93258fSBjoern A. Zeeb 		rtw89_phy_write32_clr(rtwdev, R_PLCP_HISTOGRAM,
37528e93258fSBjoern A. Zeeb 				      B_STS_DIS_TRIG_BY_FAIL);
37538e93258fSBjoern A. Zeeb 		rtw89_phy_write32_clr(rtwdev, R_PLCP_HISTOGRAM,
37548e93258fSBjoern A. Zeeb 				      B_STS_DIS_TRIG_BY_BRK);
37558e93258fSBjoern A. Zeeb 	} else {
37568e93258fSBjoern A. Zeeb 		rtw89_phy_write32_set(rtwdev, R_PLCP_HISTOGRAM,
37578e93258fSBjoern A. Zeeb 				      B_STS_DIS_TRIG_BY_FAIL);
37588e93258fSBjoern A. Zeeb 		rtw89_phy_write32_set(rtwdev, R_PLCP_HISTOGRAM,
37598e93258fSBjoern A. Zeeb 				      B_STS_DIS_TRIG_BY_BRK);
37608e93258fSBjoern A. Zeeb 	}
37618e93258fSBjoern A. Zeeb }
37628e93258fSBjoern A. Zeeb 
37638e93258fSBjoern A. Zeeb static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev)
37648e93258fSBjoern A. Zeeb {
37658e93258fSBjoern A. Zeeb 	u8 i;
37668e93258fSBjoern A. Zeeb 
37678e93258fSBjoern A. Zeeb 	rtw89_physts_enable_fail_report(rtwdev, false, RTW89_PHY_0);
37688e93258fSBjoern A. Zeeb 
37698e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_PHYSTS_BITMAP_NUM; i++) {
37708e93258fSBjoern A. Zeeb 		if (i >= RTW89_CCK_PKT)
37718e93258fSBjoern A. Zeeb 			rtw89_physts_enable_ie_bitmap(rtwdev, i,
37728e93258fSBjoern A. Zeeb 						      RTW89_PHYSTS_IE09_FTR_0,
37738e93258fSBjoern A. Zeeb 						      true);
37748e93258fSBjoern A. Zeeb 		if ((i >= RTW89_CCK_BRK && i <= RTW89_VHT_MU) ||
37758e93258fSBjoern A. Zeeb 		    (i >= RTW89_RSVD_9 && i <= RTW89_CCK_PKT))
37768e93258fSBjoern A. Zeeb 			continue;
37778e93258fSBjoern A. Zeeb 		rtw89_physts_enable_ie_bitmap(rtwdev, i,
37788e93258fSBjoern A. Zeeb 					      RTW89_PHYSTS_IE24_OFDM_TD_PATH_A,
37798e93258fSBjoern A. Zeeb 					      true);
37808e93258fSBjoern A. Zeeb 	}
37818e93258fSBjoern A. Zeeb 	rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_VHT_PKT,
37828e93258fSBjoern A. Zeeb 				      RTW89_PHYSTS_IE13_DL_MU_DEF, true);
37838e93258fSBjoern A. Zeeb 	rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_HE_PKT,
37848e93258fSBjoern A. Zeeb 				      RTW89_PHYSTS_IE13_DL_MU_DEF, true);
37858e93258fSBjoern A. Zeeb 
37868e93258fSBjoern A. Zeeb 	/* force IE01 for channel index, only channel field is valid */
37878e93258fSBjoern A. Zeeb 	rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_CCK_PKT,
37888e93258fSBjoern A. Zeeb 				      RTW89_PHYSTS_IE01_CMN_OFDM, true);
37898e93258fSBjoern A. Zeeb }
37908e93258fSBjoern A. Zeeb 
37918e93258fSBjoern A. Zeeb static void rtw89_phy_dig_read_gain_table(struct rtw89_dev *rtwdev, int type)
37928e93258fSBjoern A. Zeeb {
37938e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
37948e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
37958e93258fSBjoern A. Zeeb 	const struct rtw89_phy_dig_gain_cfg *cfg;
37968e93258fSBjoern A. Zeeb 	const char *msg;
37978e93258fSBjoern A. Zeeb 	u8 i;
37988e93258fSBjoern A. Zeeb 	s8 gain_base;
37998e93258fSBjoern A. Zeeb 	s8 *gain_arr;
38008e93258fSBjoern A. Zeeb 	u32 tmp;
38018e93258fSBjoern A. Zeeb 
38028e93258fSBjoern A. Zeeb 	switch (type) {
38038e93258fSBjoern A. Zeeb 	case RTW89_DIG_GAIN_LNA_G:
38048e93258fSBjoern A. Zeeb 		gain_arr = dig->lna_gain_g;
38058e93258fSBjoern A. Zeeb 		gain_base = LNA0_GAIN;
38068e93258fSBjoern A. Zeeb 		cfg = chip->dig_table->cfg_lna_g;
38078e93258fSBjoern A. Zeeb 		msg = "lna_gain_g";
38088e93258fSBjoern A. Zeeb 		break;
38098e93258fSBjoern A. Zeeb 	case RTW89_DIG_GAIN_TIA_G:
38108e93258fSBjoern A. Zeeb 		gain_arr = dig->tia_gain_g;
38118e93258fSBjoern A. Zeeb 		gain_base = TIA0_GAIN_G;
38128e93258fSBjoern A. Zeeb 		cfg = chip->dig_table->cfg_tia_g;
38138e93258fSBjoern A. Zeeb 		msg = "tia_gain_g";
38148e93258fSBjoern A. Zeeb 		break;
38158e93258fSBjoern A. Zeeb 	case RTW89_DIG_GAIN_LNA_A:
38168e93258fSBjoern A. Zeeb 		gain_arr = dig->lna_gain_a;
38178e93258fSBjoern A. Zeeb 		gain_base = LNA0_GAIN;
38188e93258fSBjoern A. Zeeb 		cfg = chip->dig_table->cfg_lna_a;
38198e93258fSBjoern A. Zeeb 		msg = "lna_gain_a";
38208e93258fSBjoern A. Zeeb 		break;
38218e93258fSBjoern A. Zeeb 	case RTW89_DIG_GAIN_TIA_A:
38228e93258fSBjoern A. Zeeb 		gain_arr = dig->tia_gain_a;
38238e93258fSBjoern A. Zeeb 		gain_base = TIA0_GAIN_A;
38248e93258fSBjoern A. Zeeb 		cfg = chip->dig_table->cfg_tia_a;
38258e93258fSBjoern A. Zeeb 		msg = "tia_gain_a";
38268e93258fSBjoern A. Zeeb 		break;
38278e93258fSBjoern A. Zeeb 	default:
38288e93258fSBjoern A. Zeeb 		return;
38298e93258fSBjoern A. Zeeb 	}
38308e93258fSBjoern A. Zeeb 
38318e93258fSBjoern A. Zeeb 	for (i = 0; i < cfg->size; i++) {
38328e93258fSBjoern A. Zeeb 		tmp = rtw89_phy_read32_mask(rtwdev, cfg->table[i].addr,
38338e93258fSBjoern A. Zeeb 					    cfg->table[i].mask);
38348e93258fSBjoern A. Zeeb 		tmp >>= DIG_GAIN_SHIFT;
38358e93258fSBjoern A. Zeeb 		gain_arr[i] = sign_extend32(tmp, U4_MAX_BIT) + gain_base;
38368e93258fSBjoern A. Zeeb 		gain_base += DIG_GAIN;
38378e93258fSBjoern A. Zeeb 
38388e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_DIG, "%s[%d]=%d\n",
38398e93258fSBjoern A. Zeeb 			    msg, i, gain_arr[i]);
38408e93258fSBjoern A. Zeeb 	}
38418e93258fSBjoern A. Zeeb }
38428e93258fSBjoern A. Zeeb 
38438e93258fSBjoern A. Zeeb static void rtw89_phy_dig_update_gain_para(struct rtw89_dev *rtwdev)
38448e93258fSBjoern A. Zeeb {
38458e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
38468e93258fSBjoern A. Zeeb 	u32 tmp;
38478e93258fSBjoern A. Zeeb 	u8 i;
38488e93258fSBjoern A. Zeeb 
38498e93258fSBjoern A. Zeeb 	if (!rtwdev->hal.support_igi)
38508e93258fSBjoern A. Zeeb 		return;
38518e93258fSBjoern A. Zeeb 
38528e93258fSBjoern A. Zeeb 	tmp = rtw89_phy_read32_mask(rtwdev, R_PATH0_IB_PKPW,
38538e93258fSBjoern A. Zeeb 				    B_PATH0_IB_PKPW_MSK);
38548e93258fSBjoern A. Zeeb 	dig->ib_pkpwr = sign_extend32(tmp >> DIG_GAIN_SHIFT, U8_MAX_BIT);
38558e93258fSBjoern A. Zeeb 	dig->ib_pbk = rtw89_phy_read32_mask(rtwdev, R_PATH0_IB_PBK,
38568e93258fSBjoern A. Zeeb 					    B_PATH0_IB_PBK_MSK);
38578e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_DIG, "ib_pkpwr=%d, ib_pbk=%d\n",
38588e93258fSBjoern A. Zeeb 		    dig->ib_pkpwr, dig->ib_pbk);
38598e93258fSBjoern A. Zeeb 
38608e93258fSBjoern A. Zeeb 	for (i = RTW89_DIG_GAIN_LNA_G; i < RTW89_DIG_GAIN_MAX; i++)
38618e93258fSBjoern A. Zeeb 		rtw89_phy_dig_read_gain_table(rtwdev, i);
38628e93258fSBjoern A. Zeeb }
38638e93258fSBjoern A. Zeeb 
38648e93258fSBjoern A. Zeeb static const u8 rssi_nolink = 22;
38658e93258fSBjoern A. Zeeb static const u8 igi_rssi_th[IGI_RSSI_TH_NUM] = {68, 84, 90, 98, 104};
38668e93258fSBjoern A. Zeeb static const u16 fa_th_2g[FA_TH_NUM] = {22, 44, 66, 88};
38678e93258fSBjoern A. Zeeb static const u16 fa_th_5g[FA_TH_NUM] = {4, 8, 12, 16};
38688e93258fSBjoern A. Zeeb static const u16 fa_th_nolink[FA_TH_NUM] = {196, 352, 440, 528};
38698e93258fSBjoern A. Zeeb 
38708e93258fSBjoern A. Zeeb static void rtw89_phy_dig_update_rssi_info(struct rtw89_dev *rtwdev)
38718e93258fSBjoern A. Zeeb {
38728e93258fSBjoern A. Zeeb 	struct rtw89_phy_ch_info *ch_info = &rtwdev->ch_info;
38738e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
38748e93258fSBjoern A. Zeeb 	bool is_linked = rtwdev->total_sta_assoc > 0;
38758e93258fSBjoern A. Zeeb 
38768e93258fSBjoern A. Zeeb 	if (is_linked) {
38778e93258fSBjoern A. Zeeb 		dig->igi_rssi = ch_info->rssi_min >> 1;
38788e93258fSBjoern A. Zeeb 	} else {
38798e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_DIG, "RSSI update : NO Link\n");
38808e93258fSBjoern A. Zeeb 		dig->igi_rssi = rssi_nolink;
38818e93258fSBjoern A. Zeeb 	}
38828e93258fSBjoern A. Zeeb }
38838e93258fSBjoern A. Zeeb 
38848e93258fSBjoern A. Zeeb static void rtw89_phy_dig_update_para(struct rtw89_dev *rtwdev)
38858e93258fSBjoern A. Zeeb {
38868e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
38878e93258fSBjoern A. Zeeb 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
38888e93258fSBjoern A. Zeeb 	bool is_linked = rtwdev->total_sta_assoc > 0;
38898e93258fSBjoern A. Zeeb 	const u16 *fa_th_src = NULL;
38908e93258fSBjoern A. Zeeb 
38918e93258fSBjoern A. Zeeb 	switch (chan->band_type) {
38928e93258fSBjoern A. Zeeb 	case RTW89_BAND_2G:
38938e93258fSBjoern A. Zeeb 		dig->lna_gain = dig->lna_gain_g;
38948e93258fSBjoern A. Zeeb 		dig->tia_gain = dig->tia_gain_g;
38958e93258fSBjoern A. Zeeb 		fa_th_src = is_linked ? fa_th_2g : fa_th_nolink;
38968e93258fSBjoern A. Zeeb 		dig->force_gaincode_idx_en = false;
38978e93258fSBjoern A. Zeeb 		dig->dyn_pd_th_en = true;
38988e93258fSBjoern A. Zeeb 		break;
38998e93258fSBjoern A. Zeeb 	case RTW89_BAND_5G:
39008e93258fSBjoern A. Zeeb 	default:
39018e93258fSBjoern A. Zeeb 		dig->lna_gain = dig->lna_gain_a;
39028e93258fSBjoern A. Zeeb 		dig->tia_gain = dig->tia_gain_a;
39038e93258fSBjoern A. Zeeb 		fa_th_src = is_linked ? fa_th_5g : fa_th_nolink;
39048e93258fSBjoern A. Zeeb 		dig->force_gaincode_idx_en = true;
39058e93258fSBjoern A. Zeeb 		dig->dyn_pd_th_en = true;
39068e93258fSBjoern A. Zeeb 		break;
39078e93258fSBjoern A. Zeeb 	}
39088e93258fSBjoern A. Zeeb 	memcpy(dig->fa_th, fa_th_src, sizeof(dig->fa_th));
39098e93258fSBjoern A. Zeeb 	memcpy(dig->igi_rssi_th, igi_rssi_th, sizeof(dig->igi_rssi_th));
39108e93258fSBjoern A. Zeeb }
39118e93258fSBjoern A. Zeeb 
39128e93258fSBjoern A. Zeeb static const u8 pd_low_th_offset = 20, dynamic_igi_min = 0x20;
39138e93258fSBjoern A. Zeeb static const u8 igi_max_performance_mode = 0x5a;
39148e93258fSBjoern A. Zeeb static const u8 dynamic_pd_threshold_max;
39158e93258fSBjoern A. Zeeb 
39168e93258fSBjoern A. Zeeb static void rtw89_phy_dig_para_reset(struct rtw89_dev *rtwdev)
39178e93258fSBjoern A. Zeeb {
39188e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
39198e93258fSBjoern A. Zeeb 
39208e93258fSBjoern A. Zeeb 	dig->cur_gaincode.lna_idx = LNA_IDX_MAX;
39218e93258fSBjoern A. Zeeb 	dig->cur_gaincode.tia_idx = TIA_IDX_MAX;
39228e93258fSBjoern A. Zeeb 	dig->cur_gaincode.rxb_idx = RXB_IDX_MAX;
39238e93258fSBjoern A. Zeeb 	dig->force_gaincode.lna_idx = LNA_IDX_MAX;
39248e93258fSBjoern A. Zeeb 	dig->force_gaincode.tia_idx = TIA_IDX_MAX;
39258e93258fSBjoern A. Zeeb 	dig->force_gaincode.rxb_idx = RXB_IDX_MAX;
39268e93258fSBjoern A. Zeeb 
39278e93258fSBjoern A. Zeeb 	dig->dyn_igi_max = igi_max_performance_mode;
39288e93258fSBjoern A. Zeeb 	dig->dyn_igi_min = dynamic_igi_min;
39298e93258fSBjoern A. Zeeb 	dig->dyn_pd_th_max = dynamic_pd_threshold_max;
39308e93258fSBjoern A. Zeeb 	dig->pd_low_th_ofst = pd_low_th_offset;
39318e93258fSBjoern A. Zeeb 	dig->is_linked_pre = false;
39328e93258fSBjoern A. Zeeb }
39338e93258fSBjoern A. Zeeb 
39348e93258fSBjoern A. Zeeb static void rtw89_phy_dig_init(struct rtw89_dev *rtwdev)
39358e93258fSBjoern A. Zeeb {
39368e93258fSBjoern A. Zeeb 	rtw89_phy_dig_update_gain_para(rtwdev);
39378e93258fSBjoern A. Zeeb 	rtw89_phy_dig_reset(rtwdev);
39388e93258fSBjoern A. Zeeb }
39398e93258fSBjoern A. Zeeb 
39408e93258fSBjoern A. Zeeb static u8 rtw89_phy_dig_lna_idx_by_rssi(struct rtw89_dev *rtwdev, u8 rssi)
39418e93258fSBjoern A. Zeeb {
39428e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
39438e93258fSBjoern A. Zeeb 	u8 lna_idx;
39448e93258fSBjoern A. Zeeb 
39458e93258fSBjoern A. Zeeb 	if (rssi < dig->igi_rssi_th[0])
39468e93258fSBjoern A. Zeeb 		lna_idx = RTW89_DIG_GAIN_LNA_IDX6;
39478e93258fSBjoern A. Zeeb 	else if (rssi < dig->igi_rssi_th[1])
39488e93258fSBjoern A. Zeeb 		lna_idx = RTW89_DIG_GAIN_LNA_IDX5;
39498e93258fSBjoern A. Zeeb 	else if (rssi < dig->igi_rssi_th[2])
39508e93258fSBjoern A. Zeeb 		lna_idx = RTW89_DIG_GAIN_LNA_IDX4;
39518e93258fSBjoern A. Zeeb 	else if (rssi < dig->igi_rssi_th[3])
39528e93258fSBjoern A. Zeeb 		lna_idx = RTW89_DIG_GAIN_LNA_IDX3;
39538e93258fSBjoern A. Zeeb 	else if (rssi < dig->igi_rssi_th[4])
39548e93258fSBjoern A. Zeeb 		lna_idx = RTW89_DIG_GAIN_LNA_IDX2;
39558e93258fSBjoern A. Zeeb 	else
39568e93258fSBjoern A. Zeeb 		lna_idx = RTW89_DIG_GAIN_LNA_IDX1;
39578e93258fSBjoern A. Zeeb 
39588e93258fSBjoern A. Zeeb 	return lna_idx;
39598e93258fSBjoern A. Zeeb }
39608e93258fSBjoern A. Zeeb 
39618e93258fSBjoern A. Zeeb static u8 rtw89_phy_dig_tia_idx_by_rssi(struct rtw89_dev *rtwdev, u8 rssi)
39628e93258fSBjoern A. Zeeb {
39638e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
39648e93258fSBjoern A. Zeeb 	u8 tia_idx;
39658e93258fSBjoern A. Zeeb 
39668e93258fSBjoern A. Zeeb 	if (rssi < dig->igi_rssi_th[0])
39678e93258fSBjoern A. Zeeb 		tia_idx = RTW89_DIG_GAIN_TIA_IDX1;
39688e93258fSBjoern A. Zeeb 	else
39698e93258fSBjoern A. Zeeb 		tia_idx = RTW89_DIG_GAIN_TIA_IDX0;
39708e93258fSBjoern A. Zeeb 
39718e93258fSBjoern A. Zeeb 	return tia_idx;
39728e93258fSBjoern A. Zeeb }
39738e93258fSBjoern A. Zeeb 
39748e93258fSBjoern A. Zeeb #define IB_PBK_BASE 110
39758e93258fSBjoern A. Zeeb #define WB_RSSI_BASE 10
39768e93258fSBjoern A. Zeeb static u8 rtw89_phy_dig_rxb_idx_by_rssi(struct rtw89_dev *rtwdev, u8 rssi,
39778e93258fSBjoern A. Zeeb 					struct rtw89_agc_gaincode_set *set)
39788e93258fSBjoern A. Zeeb {
39798e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
39808e93258fSBjoern A. Zeeb 	s8 lna_gain = dig->lna_gain[set->lna_idx];
39818e93258fSBjoern A. Zeeb 	s8 tia_gain = dig->tia_gain[set->tia_idx];
39828e93258fSBjoern A. Zeeb 	s32 wb_rssi = rssi + lna_gain + tia_gain;
39838e93258fSBjoern A. Zeeb 	s32 rxb_idx_tmp = IB_PBK_BASE + WB_RSSI_BASE;
39848e93258fSBjoern A. Zeeb 	u8 rxb_idx;
39858e93258fSBjoern A. Zeeb 
39868e93258fSBjoern A. Zeeb 	rxb_idx_tmp += dig->ib_pkpwr - dig->ib_pbk - wb_rssi;
39878e93258fSBjoern A. Zeeb 	rxb_idx = clamp_t(s32, rxb_idx_tmp, RXB_IDX_MIN, RXB_IDX_MAX);
39888e93258fSBjoern A. Zeeb 
39898e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_DIG, "wb_rssi=%03d, rxb_idx_tmp=%03d\n",
39908e93258fSBjoern A. Zeeb 		    wb_rssi, rxb_idx_tmp);
39918e93258fSBjoern A. Zeeb 
39928e93258fSBjoern A. Zeeb 	return rxb_idx;
39938e93258fSBjoern A. Zeeb }
39948e93258fSBjoern A. Zeeb 
39958e93258fSBjoern A. Zeeb static void rtw89_phy_dig_gaincode_by_rssi(struct rtw89_dev *rtwdev, u8 rssi,
39968e93258fSBjoern A. Zeeb 					   struct rtw89_agc_gaincode_set *set)
39978e93258fSBjoern A. Zeeb {
39988e93258fSBjoern A. Zeeb 	set->lna_idx = rtw89_phy_dig_lna_idx_by_rssi(rtwdev, rssi);
39998e93258fSBjoern A. Zeeb 	set->tia_idx = rtw89_phy_dig_tia_idx_by_rssi(rtwdev, rssi);
40008e93258fSBjoern A. Zeeb 	set->rxb_idx = rtw89_phy_dig_rxb_idx_by_rssi(rtwdev, rssi, set);
40018e93258fSBjoern A. Zeeb 
40028e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_DIG,
40038e93258fSBjoern A. Zeeb 		    "final_rssi=%03d, (lna,tia,rab)=(%d,%d,%02d)\n",
40048e93258fSBjoern A. Zeeb 		    rssi, set->lna_idx, set->tia_idx, set->rxb_idx);
40058e93258fSBjoern A. Zeeb }
40068e93258fSBjoern A. Zeeb 
40078e93258fSBjoern A. Zeeb #define IGI_OFFSET_MAX 25
40088e93258fSBjoern A. Zeeb #define IGI_OFFSET_MUL 2
40098e93258fSBjoern A. Zeeb static void rtw89_phy_dig_igi_offset_by_env(struct rtw89_dev *rtwdev)
40108e93258fSBjoern A. Zeeb {
40118e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
40128e93258fSBjoern A. Zeeb 	struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
40138e93258fSBjoern A. Zeeb 	enum rtw89_dig_noisy_level noisy_lv;
40148e93258fSBjoern A. Zeeb 	u8 igi_offset = dig->fa_rssi_ofst;
40158e93258fSBjoern A. Zeeb 	u16 fa_ratio = 0;
40168e93258fSBjoern A. Zeeb 
40178e93258fSBjoern A. Zeeb 	fa_ratio = env->ifs_clm_cck_fa_permil + env->ifs_clm_ofdm_fa_permil;
40188e93258fSBjoern A. Zeeb 
40198e93258fSBjoern A. Zeeb 	if (fa_ratio < dig->fa_th[0])
40208e93258fSBjoern A. Zeeb 		noisy_lv = RTW89_DIG_NOISY_LEVEL0;
40218e93258fSBjoern A. Zeeb 	else if (fa_ratio < dig->fa_th[1])
40228e93258fSBjoern A. Zeeb 		noisy_lv = RTW89_DIG_NOISY_LEVEL1;
40238e93258fSBjoern A. Zeeb 	else if (fa_ratio < dig->fa_th[2])
40248e93258fSBjoern A. Zeeb 		noisy_lv = RTW89_DIG_NOISY_LEVEL2;
40258e93258fSBjoern A. Zeeb 	else if (fa_ratio < dig->fa_th[3])
40268e93258fSBjoern A. Zeeb 		noisy_lv = RTW89_DIG_NOISY_LEVEL3;
40278e93258fSBjoern A. Zeeb 	else
40288e93258fSBjoern A. Zeeb 		noisy_lv = RTW89_DIG_NOISY_LEVEL_MAX;
40298e93258fSBjoern A. Zeeb 
40308e93258fSBjoern A. Zeeb 	if (noisy_lv == RTW89_DIG_NOISY_LEVEL0 && igi_offset < 2)
40318e93258fSBjoern A. Zeeb 		igi_offset = 0;
40328e93258fSBjoern A. Zeeb 	else
40338e93258fSBjoern A. Zeeb 		igi_offset += noisy_lv * IGI_OFFSET_MUL;
40348e93258fSBjoern A. Zeeb 
40358e93258fSBjoern A. Zeeb 	igi_offset = min_t(u8, igi_offset, IGI_OFFSET_MAX);
40368e93258fSBjoern A. Zeeb 	dig->fa_rssi_ofst = igi_offset;
40378e93258fSBjoern A. Zeeb 
40388e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_DIG,
40398e93258fSBjoern A. Zeeb 		    "fa_th: [+6 (%d) +4 (%d) +2 (%d) 0 (%d) -2 ]\n",
40408e93258fSBjoern A. Zeeb 		    dig->fa_th[3], dig->fa_th[2], dig->fa_th[1], dig->fa_th[0]);
40418e93258fSBjoern A. Zeeb 
40428e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_DIG,
40438e93258fSBjoern A. Zeeb 		    "fa(CCK,OFDM,ALL)=(%d,%d,%d)%%, noisy_lv=%d, ofst=%d\n",
40448e93258fSBjoern A. Zeeb 		    env->ifs_clm_cck_fa_permil, env->ifs_clm_ofdm_fa_permil,
40458e93258fSBjoern A. Zeeb 		    env->ifs_clm_cck_fa_permil + env->ifs_clm_ofdm_fa_permil,
40468e93258fSBjoern A. Zeeb 		    noisy_lv, igi_offset);
40478e93258fSBjoern A. Zeeb }
40488e93258fSBjoern A. Zeeb 
40498e93258fSBjoern A. Zeeb static void rtw89_phy_dig_set_lna_idx(struct rtw89_dev *rtwdev, u8 lna_idx)
40508e93258fSBjoern A. Zeeb {
4051e2340276SBjoern A. Zeeb 	const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
4052e2340276SBjoern A. Zeeb 
4053e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->p0_lna_init.addr,
4054e2340276SBjoern A. Zeeb 			       dig_regs->p0_lna_init.mask, lna_idx);
4055e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->p1_lna_init.addr,
4056e2340276SBjoern A. Zeeb 			       dig_regs->p1_lna_init.mask, lna_idx);
40578e93258fSBjoern A. Zeeb }
40588e93258fSBjoern A. Zeeb 
40598e93258fSBjoern A. Zeeb static void rtw89_phy_dig_set_tia_idx(struct rtw89_dev *rtwdev, u8 tia_idx)
40608e93258fSBjoern A. Zeeb {
4061e2340276SBjoern A. Zeeb 	const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
4062e2340276SBjoern A. Zeeb 
4063e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->p0_tia_init.addr,
4064e2340276SBjoern A. Zeeb 			       dig_regs->p0_tia_init.mask, tia_idx);
4065e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->p1_tia_init.addr,
4066e2340276SBjoern A. Zeeb 			       dig_regs->p1_tia_init.mask, tia_idx);
40678e93258fSBjoern A. Zeeb }
40688e93258fSBjoern A. Zeeb 
40698e93258fSBjoern A. Zeeb static void rtw89_phy_dig_set_rxb_idx(struct rtw89_dev *rtwdev, u8 rxb_idx)
40708e93258fSBjoern A. Zeeb {
4071e2340276SBjoern A. Zeeb 	const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
4072e2340276SBjoern A. Zeeb 
4073e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->p0_rxb_init.addr,
4074e2340276SBjoern A. Zeeb 			       dig_regs->p0_rxb_init.mask, rxb_idx);
4075e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->p1_rxb_init.addr,
4076e2340276SBjoern A. Zeeb 			       dig_regs->p1_rxb_init.mask, rxb_idx);
40778e93258fSBjoern A. Zeeb }
40788e93258fSBjoern A. Zeeb 
40798e93258fSBjoern A. Zeeb static void rtw89_phy_dig_set_igi_cr(struct rtw89_dev *rtwdev,
40808e93258fSBjoern A. Zeeb 				     const struct rtw89_agc_gaincode_set set)
40818e93258fSBjoern A. Zeeb {
40828e93258fSBjoern A. Zeeb 	rtw89_phy_dig_set_lna_idx(rtwdev, set.lna_idx);
40838e93258fSBjoern A. Zeeb 	rtw89_phy_dig_set_tia_idx(rtwdev, set.tia_idx);
40848e93258fSBjoern A. Zeeb 	rtw89_phy_dig_set_rxb_idx(rtwdev, set.rxb_idx);
40858e93258fSBjoern A. Zeeb 
40868e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_DIG, "Set (lna,tia,rxb)=((%d,%d,%02d))\n",
40878e93258fSBjoern A. Zeeb 		    set.lna_idx, set.tia_idx, set.rxb_idx);
40888e93258fSBjoern A. Zeeb }
40898e93258fSBjoern A. Zeeb 
40908e93258fSBjoern A. Zeeb static void rtw89_phy_dig_sdagc_follow_pagc_config(struct rtw89_dev *rtwdev,
40918e93258fSBjoern A. Zeeb 						   bool enable)
40928e93258fSBjoern A. Zeeb {
4093e2340276SBjoern A. Zeeb 	const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
40948e93258fSBjoern A. Zeeb 
4095e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->p0_p20_pagcugc_en.addr,
4096e2340276SBjoern A. Zeeb 			       dig_regs->p0_p20_pagcugc_en.mask, enable);
4097e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->p0_s20_pagcugc_en.addr,
4098e2340276SBjoern A. Zeeb 			       dig_regs->p0_s20_pagcugc_en.mask, enable);
4099e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->p1_p20_pagcugc_en.addr,
4100e2340276SBjoern A. Zeeb 			       dig_regs->p1_p20_pagcugc_en.mask, enable);
4101e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->p1_s20_pagcugc_en.addr,
4102e2340276SBjoern A. Zeeb 			       dig_regs->p1_s20_pagcugc_en.mask, enable);
41038e93258fSBjoern A. Zeeb 
41048e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_DIG, "sdagc_follow_pagc=%d\n", enable);
41058e93258fSBjoern A. Zeeb }
41068e93258fSBjoern A. Zeeb 
41078e93258fSBjoern A. Zeeb static void rtw89_phy_dig_config_igi(struct rtw89_dev *rtwdev)
41088e93258fSBjoern A. Zeeb {
41098e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
41108e93258fSBjoern A. Zeeb 
41118e93258fSBjoern A. Zeeb 	if (!rtwdev->hal.support_igi)
41128e93258fSBjoern A. Zeeb 		return;
41138e93258fSBjoern A. Zeeb 
41148e93258fSBjoern A. Zeeb 	if (dig->force_gaincode_idx_en) {
41158e93258fSBjoern A. Zeeb 		rtw89_phy_dig_set_igi_cr(rtwdev, dig->force_gaincode);
41168e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_DIG,
41178e93258fSBjoern A. Zeeb 			    "Force gaincode index enabled.\n");
41188e93258fSBjoern A. Zeeb 	} else {
41198e93258fSBjoern A. Zeeb 		rtw89_phy_dig_gaincode_by_rssi(rtwdev, dig->igi_fa_rssi,
41208e93258fSBjoern A. Zeeb 					       &dig->cur_gaincode);
41218e93258fSBjoern A. Zeeb 		rtw89_phy_dig_set_igi_cr(rtwdev, dig->cur_gaincode);
41228e93258fSBjoern A. Zeeb 	}
41238e93258fSBjoern A. Zeeb }
41248e93258fSBjoern A. Zeeb 
41258e93258fSBjoern A. Zeeb static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, u8 rssi,
41268e93258fSBjoern A. Zeeb 				    bool enable)
41278e93258fSBjoern A. Zeeb {
41288e93258fSBjoern A. Zeeb 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
4129e2340276SBjoern A. Zeeb 	const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
41308e93258fSBjoern A. Zeeb 	enum rtw89_bandwidth cbw = chan->band_width;
41318e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
41328e93258fSBjoern A. Zeeb 	u8 final_rssi = 0, under_region = dig->pd_low_th_ofst;
41338e93258fSBjoern A. Zeeb 	u8 ofdm_cca_th;
41348e93258fSBjoern A. Zeeb 	s8 cck_cca_th;
41358e93258fSBjoern A. Zeeb 	u32 pd_val = 0;
41368e93258fSBjoern A. Zeeb 
41378e93258fSBjoern A. Zeeb 	under_region += PD_TH_SB_FLTR_CMP_VAL;
41388e93258fSBjoern A. Zeeb 
41398e93258fSBjoern A. Zeeb 	switch (cbw) {
41408e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_40:
41418e93258fSBjoern A. Zeeb 		under_region += PD_TH_BW40_CMP_VAL;
41428e93258fSBjoern A. Zeeb 		break;
41438e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_80:
41448e93258fSBjoern A. Zeeb 		under_region += PD_TH_BW80_CMP_VAL;
41458e93258fSBjoern A. Zeeb 		break;
41468e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_160:
41478e93258fSBjoern A. Zeeb 		under_region += PD_TH_BW160_CMP_VAL;
41488e93258fSBjoern A. Zeeb 		break;
41498e93258fSBjoern A. Zeeb 	case RTW89_CHANNEL_WIDTH_20:
41508e93258fSBjoern A. Zeeb 		fallthrough;
41518e93258fSBjoern A. Zeeb 	default:
41528e93258fSBjoern A. Zeeb 		under_region += PD_TH_BW20_CMP_VAL;
41538e93258fSBjoern A. Zeeb 		break;
41548e93258fSBjoern A. Zeeb 	}
41558e93258fSBjoern A. Zeeb 
41568e93258fSBjoern A. Zeeb 	dig->dyn_pd_th_max = dig->igi_rssi;
41578e93258fSBjoern A. Zeeb 
41588e93258fSBjoern A. Zeeb 	final_rssi = min_t(u8, rssi, dig->igi_rssi);
41598e93258fSBjoern A. Zeeb 	ofdm_cca_th = clamp_t(u8, final_rssi, PD_TH_MIN_RSSI + under_region,
41608e93258fSBjoern A. Zeeb 			      PD_TH_MAX_RSSI + under_region);
41618e93258fSBjoern A. Zeeb 
41628e93258fSBjoern A. Zeeb 	if (enable) {
41638e93258fSBjoern A. Zeeb 		pd_val = (ofdm_cca_th - under_region - PD_TH_MIN_RSSI) >> 1;
41648e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_DIG,
41658e93258fSBjoern A. Zeeb 			    "igi=%d, ofdm_ccaTH=%d, backoff=%d, PD_low=%d\n",
41668e93258fSBjoern A. Zeeb 			    final_rssi, ofdm_cca_th, under_region, pd_val);
41678e93258fSBjoern A. Zeeb 	} else {
41688e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_DIG,
41698e93258fSBjoern A. Zeeb 			    "Dynamic PD th disabled, Set PD_low_bd=0\n");
41708e93258fSBjoern A. Zeeb 	}
41718e93258fSBjoern A. Zeeb 
4172e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->seg0_pd_reg,
4173e2340276SBjoern A. Zeeb 			       dig_regs->pd_lower_bound_mask, pd_val);
4174e2340276SBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, dig_regs->seg0_pd_reg,
4175e2340276SBjoern A. Zeeb 			       dig_regs->pd_spatial_reuse_en, enable);
41768e93258fSBjoern A. Zeeb 
41778e93258fSBjoern A. Zeeb 	if (!rtwdev->hal.support_cckpd)
41788e93258fSBjoern A. Zeeb 		return;
41798e93258fSBjoern A. Zeeb 
41808e93258fSBjoern A. Zeeb 	cck_cca_th = max_t(s8, final_rssi - under_region, CCKPD_TH_MIN_RSSI);
41818e93258fSBjoern A. Zeeb 	pd_val = (u32)(cck_cca_th - IGI_RSSI_MAX);
41828e93258fSBjoern A. Zeeb 
41838e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_DIG,
41848e93258fSBjoern A. Zeeb 		    "igi=%d, cck_ccaTH=%d, backoff=%d, cck_PD_low=((%d))dB\n",
41858e93258fSBjoern A. Zeeb 		    final_rssi, cck_cca_th, under_region, pd_val);
41868e93258fSBjoern A. Zeeb 
41878e93258fSBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, R_BMODE_PDTH_EN_V1,
41888e93258fSBjoern A. Zeeb 			       B_BMODE_PDTH_LIMIT_EN_MSK_V1, enable);
41898e93258fSBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, R_BMODE_PDTH_V1,
41908e93258fSBjoern A. Zeeb 			       B_BMODE_PDTH_LOWER_BOUND_MSK_V1, pd_val);
41918e93258fSBjoern A. Zeeb }
41928e93258fSBjoern A. Zeeb 
41938e93258fSBjoern A. Zeeb void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev)
41948e93258fSBjoern A. Zeeb {
41958e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
41968e93258fSBjoern A. Zeeb 
41978e93258fSBjoern A. Zeeb 	dig->bypass_dig = false;
41988e93258fSBjoern A. Zeeb 	rtw89_phy_dig_para_reset(rtwdev);
41998e93258fSBjoern A. Zeeb 	rtw89_phy_dig_set_igi_cr(rtwdev, dig->force_gaincode);
42008e93258fSBjoern A. Zeeb 	rtw89_phy_dig_dyn_pd_th(rtwdev, rssi_nolink, false);
42018e93258fSBjoern A. Zeeb 	rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, false);
42028e93258fSBjoern A. Zeeb 	rtw89_phy_dig_update_para(rtwdev);
42038e93258fSBjoern A. Zeeb }
42048e93258fSBjoern A. Zeeb 
42058e93258fSBjoern A. Zeeb #define IGI_RSSI_MIN 10
42068e93258fSBjoern A. Zeeb void rtw89_phy_dig(struct rtw89_dev *rtwdev)
42078e93258fSBjoern A. Zeeb {
42088e93258fSBjoern A. Zeeb 	struct rtw89_dig_info *dig = &rtwdev->dig;
42098e93258fSBjoern A. Zeeb 	bool is_linked = rtwdev->total_sta_assoc > 0;
42108e93258fSBjoern A. Zeeb 
42118e93258fSBjoern A. Zeeb 	if (unlikely(dig->bypass_dig)) {
42128e93258fSBjoern A. Zeeb 		dig->bypass_dig = false;
42138e93258fSBjoern A. Zeeb 		return;
42148e93258fSBjoern A. Zeeb 	}
42158e93258fSBjoern A. Zeeb 
42168e93258fSBjoern A. Zeeb 	if (!dig->is_linked_pre && is_linked) {
42178e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_DIG, "First connected\n");
42188e93258fSBjoern A. Zeeb 		rtw89_phy_dig_update_para(rtwdev);
42198e93258fSBjoern A. Zeeb 	} else if (dig->is_linked_pre && !is_linked) {
42208e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_DIG, "First disconnected\n");
42218e93258fSBjoern A. Zeeb 		rtw89_phy_dig_update_para(rtwdev);
42228e93258fSBjoern A. Zeeb 	}
42238e93258fSBjoern A. Zeeb 	dig->is_linked_pre = is_linked;
42248e93258fSBjoern A. Zeeb 
42258e93258fSBjoern A. Zeeb 	rtw89_phy_dig_igi_offset_by_env(rtwdev);
42268e93258fSBjoern A. Zeeb 	rtw89_phy_dig_update_rssi_info(rtwdev);
42278e93258fSBjoern A. Zeeb 
42288e93258fSBjoern A. Zeeb 	dig->dyn_igi_min = (dig->igi_rssi > IGI_RSSI_MIN) ?
42298e93258fSBjoern A. Zeeb 			    dig->igi_rssi - IGI_RSSI_MIN : 0;
42308e93258fSBjoern A. Zeeb 	dig->dyn_igi_max = dig->dyn_igi_min + IGI_OFFSET_MAX;
42318e93258fSBjoern A. Zeeb 	dig->igi_fa_rssi = dig->dyn_igi_min + dig->fa_rssi_ofst;
42328e93258fSBjoern A. Zeeb 
42338e93258fSBjoern A. Zeeb 	dig->igi_fa_rssi = clamp(dig->igi_fa_rssi, dig->dyn_igi_min,
42348e93258fSBjoern A. Zeeb 				 dig->dyn_igi_max);
42358e93258fSBjoern A. Zeeb 
42368e93258fSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_DIG,
42378e93258fSBjoern A. Zeeb 		    "rssi=%03d, dyn(max,min)=(%d,%d), final_rssi=%d\n",
42388e93258fSBjoern A. Zeeb 		    dig->igi_rssi, dig->dyn_igi_max, dig->dyn_igi_min,
42398e93258fSBjoern A. Zeeb 		    dig->igi_fa_rssi);
42408e93258fSBjoern A. Zeeb 
42418e93258fSBjoern A. Zeeb 	rtw89_phy_dig_config_igi(rtwdev);
42428e93258fSBjoern A. Zeeb 
42438e93258fSBjoern A. Zeeb 	rtw89_phy_dig_dyn_pd_th(rtwdev, dig->igi_fa_rssi, dig->dyn_pd_th_en);
42448e93258fSBjoern A. Zeeb 
42458e93258fSBjoern A. Zeeb 	if (dig->dyn_pd_th_en && dig->igi_fa_rssi > dig->dyn_pd_th_max)
42468e93258fSBjoern A. Zeeb 		rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, true);
42478e93258fSBjoern A. Zeeb 	else
42488e93258fSBjoern A. Zeeb 		rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, false);
42498e93258fSBjoern A. Zeeb }
42508e93258fSBjoern A. Zeeb 
4251e2340276SBjoern A. Zeeb static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta)
4252e2340276SBjoern A. Zeeb {
4253e2340276SBjoern A. Zeeb 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
4254e2340276SBjoern A. Zeeb 	struct rtw89_dev *rtwdev = rtwsta->rtwdev;
4255e2340276SBjoern A. Zeeb 	struct rtw89_vif *rtwvif = rtwsta->rtwvif;
4256e2340276SBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
4257e2340276SBjoern A. Zeeb 	bool *done = data;
4258e2340276SBjoern A. Zeeb 	u8 rssi_a, rssi_b;
4259e2340276SBjoern A. Zeeb 	u32 candidate;
4260e2340276SBjoern A. Zeeb 
4261e2340276SBjoern A. Zeeb 	if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION || sta->tdls)
4262e2340276SBjoern A. Zeeb 		return;
4263e2340276SBjoern A. Zeeb 
4264e2340276SBjoern A. Zeeb 	if (*done)
4265e2340276SBjoern A. Zeeb 		return;
4266e2340276SBjoern A. Zeeb 
4267e2340276SBjoern A. Zeeb 	*done = true;
4268e2340276SBjoern A. Zeeb 
4269e2340276SBjoern A. Zeeb 	rssi_a = ewma_rssi_read(&rtwsta->rssi[RF_PATH_A]);
4270e2340276SBjoern A. Zeeb 	rssi_b = ewma_rssi_read(&rtwsta->rssi[RF_PATH_B]);
4271e2340276SBjoern A. Zeeb 
4272e2340276SBjoern A. Zeeb 	if (rssi_a > rssi_b + RTW89_TX_DIV_RSSI_RAW_TH)
4273e2340276SBjoern A. Zeeb 		candidate = RF_A;
4274e2340276SBjoern A. Zeeb 	else if (rssi_b > rssi_a + RTW89_TX_DIV_RSSI_RAW_TH)
4275e2340276SBjoern A. Zeeb 		candidate = RF_B;
4276e2340276SBjoern A. Zeeb 	else
4277e2340276SBjoern A. Zeeb 		return;
4278e2340276SBjoern A. Zeeb 
4279e2340276SBjoern A. Zeeb 	if (hal->antenna_tx == candidate)
4280e2340276SBjoern A. Zeeb 		return;
4281e2340276SBjoern A. Zeeb 
4282e2340276SBjoern A. Zeeb 	hal->antenna_tx = candidate;
4283e2340276SBjoern A. Zeeb 	rtw89_fw_h2c_txpath_cmac_tbl(rtwdev, rtwsta);
4284e2340276SBjoern A. Zeeb 
4285e2340276SBjoern A. Zeeb 	if (hal->antenna_tx == RF_A) {
4286e2340276SBjoern A. Zeeb 		rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, B_P0_RFMODE_MUX, 0x12);
4287e2340276SBjoern A. Zeeb 		rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, B_P1_RFMODE_MUX, 0x11);
4288e2340276SBjoern A. Zeeb 	} else if (hal->antenna_tx == RF_B) {
4289e2340276SBjoern A. Zeeb 		rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, B_P0_RFMODE_MUX, 0x11);
4290e2340276SBjoern A. Zeeb 		rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, B_P1_RFMODE_MUX, 0x12);
4291e2340276SBjoern A. Zeeb 	}
4292e2340276SBjoern A. Zeeb }
4293e2340276SBjoern A. Zeeb 
4294e2340276SBjoern A. Zeeb void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev)
4295e2340276SBjoern A. Zeeb {
4296e2340276SBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
4297e2340276SBjoern A. Zeeb 	bool done = false;
4298e2340276SBjoern A. Zeeb 
4299e2340276SBjoern A. Zeeb 	if (!hal->tx_path_diversity)
4300e2340276SBjoern A. Zeeb 		return;
4301e2340276SBjoern A. Zeeb 
4302e2340276SBjoern A. Zeeb 	ieee80211_iterate_stations_atomic(rtwdev->hw,
4303e2340276SBjoern A. Zeeb 					  rtw89_phy_tx_path_div_sta_iter,
4304e2340276SBjoern A. Zeeb 					  &done);
4305e2340276SBjoern A. Zeeb }
4306e2340276SBjoern A. Zeeb 
4307e2340276SBjoern A. Zeeb #define ANTDIV_MAIN 0
4308e2340276SBjoern A. Zeeb #define ANTDIV_AUX 1
4309e2340276SBjoern A. Zeeb 
4310e2340276SBjoern A. Zeeb static void rtw89_phy_antdiv_set_ant(struct rtw89_dev *rtwdev)
4311e2340276SBjoern A. Zeeb {
4312e2340276SBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
4313e2340276SBjoern A. Zeeb 	u8 default_ant, optional_ant;
4314e2340276SBjoern A. Zeeb 
4315e2340276SBjoern A. Zeeb 	if (!hal->ant_diversity || hal->antenna_tx == 0)
4316e2340276SBjoern A. Zeeb 		return;
4317e2340276SBjoern A. Zeeb 
4318e2340276SBjoern A. Zeeb 	if (hal->antenna_tx == RF_B) {
4319e2340276SBjoern A. Zeeb 		default_ant = ANTDIV_AUX;
4320e2340276SBjoern A. Zeeb 		optional_ant = ANTDIV_MAIN;
4321e2340276SBjoern A. Zeeb 	} else {
4322e2340276SBjoern A. Zeeb 		default_ant = ANTDIV_MAIN;
4323e2340276SBjoern A. Zeeb 		optional_ant = ANTDIV_AUX;
4324e2340276SBjoern A. Zeeb 	}
4325e2340276SBjoern A. Zeeb 
4326e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_CGCS_CTRL,
4327e2340276SBjoern A. Zeeb 			      default_ant, RTW89_PHY_0);
4328e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_RX_ORI,
4329e2340276SBjoern A. Zeeb 			      default_ant, RTW89_PHY_0);
4330e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_RX_ALT,
4331e2340276SBjoern A. Zeeb 			      optional_ant, RTW89_PHY_0);
4332e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_TX_ORI,
4333e2340276SBjoern A. Zeeb 			      default_ant, RTW89_PHY_0);
4334e2340276SBjoern A. Zeeb }
4335e2340276SBjoern A. Zeeb 
4336e2340276SBjoern A. Zeeb static void rtw89_phy_swap_hal_antenna(struct rtw89_dev *rtwdev)
4337e2340276SBjoern A. Zeeb {
4338e2340276SBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
4339e2340276SBjoern A. Zeeb 
4340e2340276SBjoern A. Zeeb 	hal->antenna_rx = hal->antenna_rx == RF_A ? RF_B : RF_A;
4341e2340276SBjoern A. Zeeb 	hal->antenna_tx = hal->antenna_rx;
4342e2340276SBjoern A. Zeeb }
4343e2340276SBjoern A. Zeeb 
4344e2340276SBjoern A. Zeeb static void rtw89_phy_antdiv_decision_state(struct rtw89_dev *rtwdev)
4345e2340276SBjoern A. Zeeb {
4346e2340276SBjoern A. Zeeb 	struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
4347e2340276SBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
4348e2340276SBjoern A. Zeeb 	bool no_change = false;
4349e2340276SBjoern A. Zeeb 	u8 main_rssi, aux_rssi;
4350e2340276SBjoern A. Zeeb 	u8 main_evm, aux_evm;
4351e2340276SBjoern A. Zeeb 	u32 candidate;
4352e2340276SBjoern A. Zeeb 
4353e2340276SBjoern A. Zeeb 	antdiv->get_stats = false;
4354e2340276SBjoern A. Zeeb 	antdiv->training_count = 0;
4355e2340276SBjoern A. Zeeb 
4356e2340276SBjoern A. Zeeb 	main_rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->main_stats);
4357e2340276SBjoern A. Zeeb 	main_evm = rtw89_phy_antdiv_sts_instance_get_evm(&antdiv->main_stats);
4358e2340276SBjoern A. Zeeb 	aux_rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->aux_stats);
4359e2340276SBjoern A. Zeeb 	aux_evm = rtw89_phy_antdiv_sts_instance_get_evm(&antdiv->aux_stats);
4360e2340276SBjoern A. Zeeb 
4361e2340276SBjoern A. Zeeb 	if (main_evm > aux_evm + ANTDIV_EVM_DIFF_TH)
4362e2340276SBjoern A. Zeeb 		candidate = RF_A;
4363e2340276SBjoern A. Zeeb 	else if (aux_evm > main_evm + ANTDIV_EVM_DIFF_TH)
4364e2340276SBjoern A. Zeeb 		candidate = RF_B;
4365e2340276SBjoern A. Zeeb 	else if (main_rssi > aux_rssi + RTW89_TX_DIV_RSSI_RAW_TH)
4366e2340276SBjoern A. Zeeb 		candidate = RF_A;
4367e2340276SBjoern A. Zeeb 	else if (aux_rssi > main_rssi + RTW89_TX_DIV_RSSI_RAW_TH)
4368e2340276SBjoern A. Zeeb 		candidate = RF_B;
4369e2340276SBjoern A. Zeeb 	else
4370e2340276SBjoern A. Zeeb 		no_change = true;
4371e2340276SBjoern A. Zeeb 
4372e2340276SBjoern A. Zeeb 	if (no_change) {
4373e2340276SBjoern A. Zeeb 		/* swap back from training antenna to original */
4374e2340276SBjoern A. Zeeb 		rtw89_phy_swap_hal_antenna(rtwdev);
4375e2340276SBjoern A. Zeeb 		return;
4376e2340276SBjoern A. Zeeb 	}
4377e2340276SBjoern A. Zeeb 
4378e2340276SBjoern A. Zeeb 	hal->antenna_tx = candidate;
4379e2340276SBjoern A. Zeeb 	hal->antenna_rx = candidate;
4380e2340276SBjoern A. Zeeb }
4381e2340276SBjoern A. Zeeb 
4382e2340276SBjoern A. Zeeb static void rtw89_phy_antdiv_training_state(struct rtw89_dev *rtwdev)
4383e2340276SBjoern A. Zeeb {
4384e2340276SBjoern A. Zeeb 	struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
4385e2340276SBjoern A. Zeeb 	u64 state_period;
4386e2340276SBjoern A. Zeeb 
4387e2340276SBjoern A. Zeeb 	if (antdiv->training_count % 2 == 0) {
4388e2340276SBjoern A. Zeeb 		if (antdiv->training_count == 0)
4389e2340276SBjoern A. Zeeb 			rtw89_phy_antdiv_sts_reset(rtwdev);
4390e2340276SBjoern A. Zeeb 
4391e2340276SBjoern A. Zeeb 		antdiv->get_stats = true;
4392e2340276SBjoern A. Zeeb 		state_period = msecs_to_jiffies(ANTDIV_TRAINNING_INTVL);
4393e2340276SBjoern A. Zeeb 	} else {
4394e2340276SBjoern A. Zeeb 		antdiv->get_stats = false;
4395e2340276SBjoern A. Zeeb 		state_period = msecs_to_jiffies(ANTDIV_DELAY);
4396e2340276SBjoern A. Zeeb 
4397e2340276SBjoern A. Zeeb 		rtw89_phy_swap_hal_antenna(rtwdev);
4398e2340276SBjoern A. Zeeb 		rtw89_phy_antdiv_set_ant(rtwdev);
4399e2340276SBjoern A. Zeeb 	}
4400e2340276SBjoern A. Zeeb 
4401e2340276SBjoern A. Zeeb 	antdiv->training_count++;
4402e2340276SBjoern A. Zeeb 	ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->antdiv_work,
4403e2340276SBjoern A. Zeeb 				     state_period);
4404e2340276SBjoern A. Zeeb }
4405e2340276SBjoern A. Zeeb 
4406e2340276SBjoern A. Zeeb void rtw89_phy_antdiv_work(struct work_struct *work)
4407e2340276SBjoern A. Zeeb {
4408e2340276SBjoern A. Zeeb 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4409e2340276SBjoern A. Zeeb 						antdiv_work.work);
4410e2340276SBjoern A. Zeeb 	struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
4411e2340276SBjoern A. Zeeb 
4412e2340276SBjoern A. Zeeb 	mutex_lock(&rtwdev->mutex);
4413e2340276SBjoern A. Zeeb 
4414e2340276SBjoern A. Zeeb 	if (antdiv->training_count <= ANTDIV_TRAINNING_CNT) {
4415e2340276SBjoern A. Zeeb 		rtw89_phy_antdiv_training_state(rtwdev);
4416e2340276SBjoern A. Zeeb 	} else {
4417e2340276SBjoern A. Zeeb 		rtw89_phy_antdiv_decision_state(rtwdev);
4418e2340276SBjoern A. Zeeb 		rtw89_phy_antdiv_set_ant(rtwdev);
4419e2340276SBjoern A. Zeeb 	}
4420e2340276SBjoern A. Zeeb 
4421e2340276SBjoern A. Zeeb 	mutex_unlock(&rtwdev->mutex);
4422e2340276SBjoern A. Zeeb }
4423e2340276SBjoern A. Zeeb 
4424e2340276SBjoern A. Zeeb void rtw89_phy_antdiv_track(struct rtw89_dev *rtwdev)
4425e2340276SBjoern A. Zeeb {
4426e2340276SBjoern A. Zeeb 	struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
4427e2340276SBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
4428e2340276SBjoern A. Zeeb 	u8 rssi, rssi_pre;
4429e2340276SBjoern A. Zeeb 
4430e2340276SBjoern A. Zeeb 	if (!hal->ant_diversity || hal->ant_diversity_fixed)
4431e2340276SBjoern A. Zeeb 		return;
4432e2340276SBjoern A. Zeeb 
4433e2340276SBjoern A. Zeeb 	rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->target_stats);
4434e2340276SBjoern A. Zeeb 	rssi_pre = antdiv->rssi_pre;
4435e2340276SBjoern A. Zeeb 	antdiv->rssi_pre = rssi;
4436e2340276SBjoern A. Zeeb 	rtw89_phy_antdiv_sts_instance_reset(&antdiv->target_stats);
4437e2340276SBjoern A. Zeeb 
4438e2340276SBjoern A. Zeeb 	if (abs((int)rssi - (int)rssi_pre) < ANTDIV_RSSI_DIFF_TH)
4439e2340276SBjoern A. Zeeb 		return;
4440e2340276SBjoern A. Zeeb 
4441e2340276SBjoern A. Zeeb 	antdiv->training_count = 0;
4442e2340276SBjoern A. Zeeb 	ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->antdiv_work, 0);
4443e2340276SBjoern A. Zeeb }
4444e2340276SBjoern A. Zeeb 
44458e93258fSBjoern A. Zeeb static void rtw89_phy_env_monitor_init(struct rtw89_dev *rtwdev)
44468e93258fSBjoern A. Zeeb {
44478e93258fSBjoern A. Zeeb 	rtw89_phy_ccx_top_setting_init(rtwdev);
44488e93258fSBjoern A. Zeeb 	rtw89_phy_ifs_clm_setting_init(rtwdev);
44498e93258fSBjoern A. Zeeb }
44508e93258fSBjoern A. Zeeb 
44518e93258fSBjoern A. Zeeb void rtw89_phy_dm_init(struct rtw89_dev *rtwdev)
44528e93258fSBjoern A. Zeeb {
44538e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
44548e93258fSBjoern A. Zeeb 
44558e93258fSBjoern A. Zeeb 	rtw89_phy_stat_init(rtwdev);
44568e93258fSBjoern A. Zeeb 
44578e93258fSBjoern A. Zeeb 	rtw89_chip_bb_sethw(rtwdev);
44588e93258fSBjoern A. Zeeb 
44598e93258fSBjoern A. Zeeb 	rtw89_phy_env_monitor_init(rtwdev);
44608e93258fSBjoern A. Zeeb 	rtw89_physts_parsing_init(rtwdev);
44618e93258fSBjoern A. Zeeb 	rtw89_phy_dig_init(rtwdev);
44628e93258fSBjoern A. Zeeb 	rtw89_phy_cfo_init(rtwdev);
4463e2340276SBjoern A. Zeeb 	rtw89_phy_ul_tb_info_init(rtwdev);
4464e2340276SBjoern A. Zeeb 	rtw89_phy_antdiv_init(rtwdev);
4465e2340276SBjoern A. Zeeb 	rtw89_chip_rfe_gpio(rtwdev);
4466e2340276SBjoern A. Zeeb 	rtw89_phy_antdiv_set_ant(rtwdev);
44678e93258fSBjoern A. Zeeb 
44688e93258fSBjoern A. Zeeb 	rtw89_phy_init_rf_nctl(rtwdev);
44698e93258fSBjoern A. Zeeb 	rtw89_chip_rfk_init(rtwdev);
44708e93258fSBjoern A. Zeeb 	rtw89_load_txpwr_table(rtwdev, chip->byr_table);
44718e93258fSBjoern A. Zeeb 	rtw89_chip_set_txpwr_ctrl(rtwdev);
44728e93258fSBjoern A. Zeeb 	rtw89_chip_power_trim(rtwdev);
44738e93258fSBjoern A. Zeeb 	rtw89_chip_cfg_txrx_path(rtwdev);
44748e93258fSBjoern A. Zeeb }
44758e93258fSBjoern A. Zeeb 
44768e93258fSBjoern A. Zeeb void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
44778e93258fSBjoern A. Zeeb {
4478e2340276SBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
44798e93258fSBjoern A. Zeeb 	enum rtw89_phy_idx phy_idx = RTW89_PHY_0;
44808e93258fSBjoern A. Zeeb 	u8 bss_color;
44818e93258fSBjoern A. Zeeb 
44828e93258fSBjoern A. Zeeb 	if (!vif->bss_conf.he_support || !vif->cfg.assoc)
44838e93258fSBjoern A. Zeeb 		return;
44848e93258fSBjoern A. Zeeb 
44858e93258fSBjoern A. Zeeb 	bss_color = vif->bss_conf.he_bss_color.color;
44868e93258fSBjoern A. Zeeb 
4487e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_VLD0, 0x1,
44888e93258fSBjoern A. Zeeb 			      phy_idx);
4489e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_TGT,
4490e2340276SBjoern A. Zeeb 			      bss_color, phy_idx);
4491e2340276SBjoern A. Zeeb 	rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_STAID,
44928e93258fSBjoern A. Zeeb 			      vif->cfg.aid, phy_idx);
44938e93258fSBjoern A. Zeeb }
44948e93258fSBjoern A. Zeeb 
44958e93258fSBjoern A. Zeeb static void
44968e93258fSBjoern A. Zeeb _rfk_write_rf(struct rtw89_dev *rtwdev, const struct rtw89_reg5_def *def)
44978e93258fSBjoern A. Zeeb {
44988e93258fSBjoern A. Zeeb 	rtw89_write_rf(rtwdev, def->path, def->addr, def->mask, def->data);
44998e93258fSBjoern A. Zeeb }
45008e93258fSBjoern A. Zeeb 
45018e93258fSBjoern A. Zeeb static void
45028e93258fSBjoern A. Zeeb _rfk_write32_mask(struct rtw89_dev *rtwdev, const struct rtw89_reg5_def *def)
45038e93258fSBjoern A. Zeeb {
45048e93258fSBjoern A. Zeeb 	rtw89_phy_write32_mask(rtwdev, def->addr, def->mask, def->data);
45058e93258fSBjoern A. Zeeb }
45068e93258fSBjoern A. Zeeb 
45078e93258fSBjoern A. Zeeb static void
45088e93258fSBjoern A. Zeeb _rfk_write32_set(struct rtw89_dev *rtwdev, const struct rtw89_reg5_def *def)
45098e93258fSBjoern A. Zeeb {
45108e93258fSBjoern A. Zeeb 	rtw89_phy_write32_set(rtwdev, def->addr, def->mask);
45118e93258fSBjoern A. Zeeb }
45128e93258fSBjoern A. Zeeb 
45138e93258fSBjoern A. Zeeb static void
45148e93258fSBjoern A. Zeeb _rfk_write32_clr(struct rtw89_dev *rtwdev, const struct rtw89_reg5_def *def)
45158e93258fSBjoern A. Zeeb {
45168e93258fSBjoern A. Zeeb 	rtw89_phy_write32_clr(rtwdev, def->addr, def->mask);
45178e93258fSBjoern A. Zeeb }
45188e93258fSBjoern A. Zeeb 
45198e93258fSBjoern A. Zeeb static void
45208e93258fSBjoern A. Zeeb _rfk_delay(struct rtw89_dev *rtwdev, const struct rtw89_reg5_def *def)
45218e93258fSBjoern A. Zeeb {
45228e93258fSBjoern A. Zeeb 	udelay(def->data);
45238e93258fSBjoern A. Zeeb }
45248e93258fSBjoern A. Zeeb 
45258e93258fSBjoern A. Zeeb static void
45268e93258fSBjoern A. Zeeb (*_rfk_handler[])(struct rtw89_dev *rtwdev, const struct rtw89_reg5_def *def) = {
45278e93258fSBjoern A. Zeeb 	[RTW89_RFK_F_WRF] = _rfk_write_rf,
45288e93258fSBjoern A. Zeeb 	[RTW89_RFK_F_WM] = _rfk_write32_mask,
45298e93258fSBjoern A. Zeeb 	[RTW89_RFK_F_WS] = _rfk_write32_set,
45308e93258fSBjoern A. Zeeb 	[RTW89_RFK_F_WC] = _rfk_write32_clr,
45318e93258fSBjoern A. Zeeb 	[RTW89_RFK_F_DELAY] = _rfk_delay,
45328e93258fSBjoern A. Zeeb };
45338e93258fSBjoern A. Zeeb 
45348e93258fSBjoern A. Zeeb #if defined(__linux__)
45358e93258fSBjoern A. Zeeb static_assert(ARRAY_SIZE(_rfk_handler) == RTW89_RFK_F_NUM);
45368e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
45378e93258fSBjoern A. Zeeb rtw89_static_assert(ARRAY_SIZE(_rfk_handler) == RTW89_RFK_F_NUM);
45388e93258fSBjoern A. Zeeb #endif
45398e93258fSBjoern A. Zeeb 
45408e93258fSBjoern A. Zeeb void
45418e93258fSBjoern A. Zeeb rtw89_rfk_parser(struct rtw89_dev *rtwdev, const struct rtw89_rfk_tbl *tbl)
45428e93258fSBjoern A. Zeeb {
45438e93258fSBjoern A. Zeeb 	const struct rtw89_reg5_def *p = tbl->defs;
45448e93258fSBjoern A. Zeeb 	const struct rtw89_reg5_def *end = tbl->defs + tbl->size;
45458e93258fSBjoern A. Zeeb 
45468e93258fSBjoern A. Zeeb 	for (; p < end; p++)
45478e93258fSBjoern A. Zeeb 		_rfk_handler[p->flag](rtwdev, p);
45488e93258fSBjoern A. Zeeb }
45498e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_rfk_parser);
45508e93258fSBjoern A. Zeeb 
45518e93258fSBjoern A. Zeeb #define RTW89_TSSI_FAST_MODE_NUM 4
45528e93258fSBjoern A. Zeeb 
45538e93258fSBjoern A. Zeeb static const struct rtw89_reg_def rtw89_tssi_fastmode_regs_flat[RTW89_TSSI_FAST_MODE_NUM] = {
45548e93258fSBjoern A. Zeeb 	{0xD934, 0xff0000},
45558e93258fSBjoern A. Zeeb 	{0xD934, 0xff000000},
45568e93258fSBjoern A. Zeeb 	{0xD938, 0xff},
45578e93258fSBjoern A. Zeeb 	{0xD934, 0xff00},
45588e93258fSBjoern A. Zeeb };
45598e93258fSBjoern A. Zeeb 
45608e93258fSBjoern A. Zeeb static const struct rtw89_reg_def rtw89_tssi_fastmode_regs_level[RTW89_TSSI_FAST_MODE_NUM] = {
45618e93258fSBjoern A. Zeeb 	{0xD930, 0xff0000},
45628e93258fSBjoern A. Zeeb 	{0xD930, 0xff000000},
45638e93258fSBjoern A. Zeeb 	{0xD934, 0xff},
45648e93258fSBjoern A. Zeeb 	{0xD930, 0xff00},
45658e93258fSBjoern A. Zeeb };
45668e93258fSBjoern A. Zeeb 
45678e93258fSBjoern A. Zeeb static
45688e93258fSBjoern A. Zeeb void rtw89_phy_tssi_ctrl_set_fast_mode_cfg(struct rtw89_dev *rtwdev,
45698e93258fSBjoern A. Zeeb 					   enum rtw89_mac_idx mac_idx,
45708e93258fSBjoern A. Zeeb 					   enum rtw89_tssi_bandedge_cfg bandedge_cfg,
45718e93258fSBjoern A. Zeeb 					   u32 val)
45728e93258fSBjoern A. Zeeb {
45738e93258fSBjoern A. Zeeb 	const struct rtw89_reg_def *regs;
45748e93258fSBjoern A. Zeeb 	u32 reg;
45758e93258fSBjoern A. Zeeb 	int i;
45768e93258fSBjoern A. Zeeb 
45778e93258fSBjoern A. Zeeb 	if (bandedge_cfg == RTW89_TSSI_BANDEDGE_FLAT)
45788e93258fSBjoern A. Zeeb 		regs = rtw89_tssi_fastmode_regs_flat;
45798e93258fSBjoern A. Zeeb 	else
45808e93258fSBjoern A. Zeeb 		regs = rtw89_tssi_fastmode_regs_level;
45818e93258fSBjoern A. Zeeb 
45828e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_TSSI_FAST_MODE_NUM; i++) {
45838e93258fSBjoern A. Zeeb 		reg = rtw89_mac_reg_by_idx(regs[i].addr, mac_idx);
45848e93258fSBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, reg, regs[i].mask, val);
45858e93258fSBjoern A. Zeeb 	}
45868e93258fSBjoern A. Zeeb }
45878e93258fSBjoern A. Zeeb 
45888e93258fSBjoern A. Zeeb static const struct rtw89_reg_def rtw89_tssi_bandedge_regs_flat[RTW89_TSSI_SBW_NUM] = {
45898e93258fSBjoern A. Zeeb 	{0xD91C, 0xff000000},
45908e93258fSBjoern A. Zeeb 	{0xD920, 0xff},
45918e93258fSBjoern A. Zeeb 	{0xD920, 0xff00},
45928e93258fSBjoern A. Zeeb 	{0xD920, 0xff0000},
45938e93258fSBjoern A. Zeeb 	{0xD920, 0xff000000},
45948e93258fSBjoern A. Zeeb 	{0xD924, 0xff},
45958e93258fSBjoern A. Zeeb 	{0xD924, 0xff00},
45968e93258fSBjoern A. Zeeb 	{0xD914, 0xff000000},
45978e93258fSBjoern A. Zeeb 	{0xD918, 0xff},
45988e93258fSBjoern A. Zeeb 	{0xD918, 0xff00},
45998e93258fSBjoern A. Zeeb 	{0xD918, 0xff0000},
46008e93258fSBjoern A. Zeeb 	{0xD918, 0xff000000},
46018e93258fSBjoern A. Zeeb 	{0xD91C, 0xff},
46028e93258fSBjoern A. Zeeb 	{0xD91C, 0xff00},
46038e93258fSBjoern A. Zeeb 	{0xD91C, 0xff0000},
46048e93258fSBjoern A. Zeeb };
46058e93258fSBjoern A. Zeeb 
46068e93258fSBjoern A. Zeeb static const struct rtw89_reg_def rtw89_tssi_bandedge_regs_level[RTW89_TSSI_SBW_NUM] = {
46078e93258fSBjoern A. Zeeb 	{0xD910, 0xff},
46088e93258fSBjoern A. Zeeb 	{0xD910, 0xff00},
46098e93258fSBjoern A. Zeeb 	{0xD910, 0xff0000},
46108e93258fSBjoern A. Zeeb 	{0xD910, 0xff000000},
46118e93258fSBjoern A. Zeeb 	{0xD914, 0xff},
46128e93258fSBjoern A. Zeeb 	{0xD914, 0xff00},
46138e93258fSBjoern A. Zeeb 	{0xD914, 0xff0000},
46148e93258fSBjoern A. Zeeb 	{0xD908, 0xff},
46158e93258fSBjoern A. Zeeb 	{0xD908, 0xff00},
46168e93258fSBjoern A. Zeeb 	{0xD908, 0xff0000},
46178e93258fSBjoern A. Zeeb 	{0xD908, 0xff000000},
46188e93258fSBjoern A. Zeeb 	{0xD90C, 0xff},
46198e93258fSBjoern A. Zeeb 	{0xD90C, 0xff00},
46208e93258fSBjoern A. Zeeb 	{0xD90C, 0xff0000},
46218e93258fSBjoern A. Zeeb 	{0xD90C, 0xff000000},
46228e93258fSBjoern A. Zeeb };
46238e93258fSBjoern A. Zeeb 
46248e93258fSBjoern A. Zeeb void rtw89_phy_tssi_ctrl_set_bandedge_cfg(struct rtw89_dev *rtwdev,
46258e93258fSBjoern A. Zeeb 					  enum rtw89_mac_idx mac_idx,
46268e93258fSBjoern A. Zeeb 					  enum rtw89_tssi_bandedge_cfg bandedge_cfg)
46278e93258fSBjoern A. Zeeb {
46288e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
46298e93258fSBjoern A. Zeeb 	const struct rtw89_reg_def *regs;
46308e93258fSBjoern A. Zeeb 	const u32 *data;
46318e93258fSBjoern A. Zeeb 	u32 reg;
46328e93258fSBjoern A. Zeeb 	int i;
46338e93258fSBjoern A. Zeeb 
46348e93258fSBjoern A. Zeeb 	if (bandedge_cfg >= RTW89_TSSI_CFG_NUM)
46358e93258fSBjoern A. Zeeb 		return;
46368e93258fSBjoern A. Zeeb 
46378e93258fSBjoern A. Zeeb 	if (bandedge_cfg == RTW89_TSSI_BANDEDGE_FLAT)
46388e93258fSBjoern A. Zeeb 		regs = rtw89_tssi_bandedge_regs_flat;
46398e93258fSBjoern A. Zeeb 	else
46408e93258fSBjoern A. Zeeb 		regs = rtw89_tssi_bandedge_regs_level;
46418e93258fSBjoern A. Zeeb 
46428e93258fSBjoern A. Zeeb 	data = chip->tssi_dbw_table->data[bandedge_cfg];
46438e93258fSBjoern A. Zeeb 
46448e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_TSSI_SBW_NUM; i++) {
46458e93258fSBjoern A. Zeeb 		reg = rtw89_mac_reg_by_idx(regs[i].addr, mac_idx);
46468e93258fSBjoern A. Zeeb 		rtw89_write32_mask(rtwdev, reg, regs[i].mask, data[i]);
46478e93258fSBjoern A. Zeeb 	}
46488e93258fSBjoern A. Zeeb 
46498e93258fSBjoern A. Zeeb 	reg = rtw89_mac_reg_by_idx(R_AX_BANDEDGE_CFG, mac_idx);
46508e93258fSBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, reg, B_AX_BANDEDGE_CFG_IDX_MASK, bandedge_cfg);
46518e93258fSBjoern A. Zeeb 
46528e93258fSBjoern A. Zeeb 	rtw89_phy_tssi_ctrl_set_fast_mode_cfg(rtwdev, mac_idx, bandedge_cfg,
46538e93258fSBjoern A. Zeeb 					      data[RTW89_TSSI_SBW20]);
46548e93258fSBjoern A. Zeeb }
46558e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_phy_tssi_ctrl_set_bandedge_cfg);
4656e2340276SBjoern A. Zeeb 
4657e2340276SBjoern A. Zeeb static
4658e2340276SBjoern A. Zeeb const u8 rtw89_ch_base_table[16] = {1, 0xff,
4659e2340276SBjoern A. Zeeb 				    36, 100, 132, 149, 0xff,
4660e2340276SBjoern A. Zeeb 				    1, 33, 65, 97, 129, 161, 193, 225, 0xff};
4661e2340276SBjoern A. Zeeb #define RTW89_CH_BASE_IDX_2G		0
4662e2340276SBjoern A. Zeeb #define RTW89_CH_BASE_IDX_5G_FIRST	2
4663e2340276SBjoern A. Zeeb #define RTW89_CH_BASE_IDX_5G_LAST	5
4664e2340276SBjoern A. Zeeb #define RTW89_CH_BASE_IDX_6G_FIRST	7
4665e2340276SBjoern A. Zeeb #define RTW89_CH_BASE_IDX_6G_LAST	14
4666e2340276SBjoern A. Zeeb 
4667e2340276SBjoern A. Zeeb #define RTW89_CH_BASE_IDX_MASK		GENMASK(7, 4)
4668e2340276SBjoern A. Zeeb #define RTW89_CH_OFFSET_MASK		GENMASK(3, 0)
4669e2340276SBjoern A. Zeeb 
4670e2340276SBjoern A. Zeeb u8 rtw89_encode_chan_idx(struct rtw89_dev *rtwdev, u8 central_ch, u8 band)
4671e2340276SBjoern A. Zeeb {
4672e2340276SBjoern A. Zeeb 	u8 chan_idx;
4673e2340276SBjoern A. Zeeb 	u8 last, first;
4674e2340276SBjoern A. Zeeb 	u8 idx;
4675e2340276SBjoern A. Zeeb 
4676e2340276SBjoern A. Zeeb 	switch (band) {
4677e2340276SBjoern A. Zeeb 	case RTW89_BAND_2G:
4678e2340276SBjoern A. Zeeb 		chan_idx = FIELD_PREP(RTW89_CH_BASE_IDX_MASK, RTW89_CH_BASE_IDX_2G) |
4679e2340276SBjoern A. Zeeb 			   FIELD_PREP(RTW89_CH_OFFSET_MASK, central_ch);
4680e2340276SBjoern A. Zeeb 		return chan_idx;
4681e2340276SBjoern A. Zeeb 	case RTW89_BAND_5G:
4682e2340276SBjoern A. Zeeb 		first = RTW89_CH_BASE_IDX_5G_FIRST;
4683e2340276SBjoern A. Zeeb 		last = RTW89_CH_BASE_IDX_5G_LAST;
4684e2340276SBjoern A. Zeeb 		break;
4685e2340276SBjoern A. Zeeb 	case RTW89_BAND_6G:
4686e2340276SBjoern A. Zeeb 		first = RTW89_CH_BASE_IDX_6G_FIRST;
4687e2340276SBjoern A. Zeeb 		last = RTW89_CH_BASE_IDX_6G_LAST;
4688e2340276SBjoern A. Zeeb 		break;
4689e2340276SBjoern A. Zeeb 	default:
4690e2340276SBjoern A. Zeeb 		rtw89_warn(rtwdev, "Unsupported band %d\n", band);
4691e2340276SBjoern A. Zeeb 		return 0;
4692e2340276SBjoern A. Zeeb 	}
4693e2340276SBjoern A. Zeeb 
4694e2340276SBjoern A. Zeeb 	for (idx = last; idx >= first; idx--)
4695e2340276SBjoern A. Zeeb 		if (central_ch >= rtw89_ch_base_table[idx])
4696e2340276SBjoern A. Zeeb 			break;
4697e2340276SBjoern A. Zeeb 
4698e2340276SBjoern A. Zeeb 	if (idx < first) {
4699e2340276SBjoern A. Zeeb 		rtw89_warn(rtwdev, "Unknown band %d channel %d\n", band, central_ch);
4700e2340276SBjoern A. Zeeb 		return 0;
4701e2340276SBjoern A. Zeeb 	}
4702e2340276SBjoern A. Zeeb 
4703e2340276SBjoern A. Zeeb 	chan_idx = FIELD_PREP(RTW89_CH_BASE_IDX_MASK, idx) |
4704e2340276SBjoern A. Zeeb 		   FIELD_PREP(RTW89_CH_OFFSET_MASK,
4705e2340276SBjoern A. Zeeb 			      (central_ch - rtw89_ch_base_table[idx]) >> 1);
4706e2340276SBjoern A. Zeeb 	return chan_idx;
4707e2340276SBjoern A. Zeeb }
4708e2340276SBjoern A. Zeeb EXPORT_SYMBOL(rtw89_encode_chan_idx);
4709e2340276SBjoern A. Zeeb 
4710e2340276SBjoern A. Zeeb void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx,
4711e2340276SBjoern A. Zeeb 			   u8 *ch, enum nl80211_band *band)
4712e2340276SBjoern A. Zeeb {
4713e2340276SBjoern A. Zeeb 	u8 idx, offset;
4714e2340276SBjoern A. Zeeb 
4715e2340276SBjoern A. Zeeb 	idx = FIELD_GET(RTW89_CH_BASE_IDX_MASK, chan_idx);
4716e2340276SBjoern A. Zeeb 	offset = FIELD_GET(RTW89_CH_OFFSET_MASK, chan_idx);
4717e2340276SBjoern A. Zeeb 
4718e2340276SBjoern A. Zeeb 	if (idx == RTW89_CH_BASE_IDX_2G) {
4719e2340276SBjoern A. Zeeb 		*band = NL80211_BAND_2GHZ;
4720e2340276SBjoern A. Zeeb 		*ch = offset;
4721e2340276SBjoern A. Zeeb 		return;
4722e2340276SBjoern A. Zeeb 	}
4723e2340276SBjoern A. Zeeb 
4724e2340276SBjoern A. Zeeb 	*band = idx <= RTW89_CH_BASE_IDX_5G_LAST ? NL80211_BAND_5GHZ : NL80211_BAND_6GHZ;
4725e2340276SBjoern A. Zeeb 	*ch = rtw89_ch_base_table[idx] + (offset << 1);
4726e2340276SBjoern A. Zeeb }
4727e2340276SBjoern A. Zeeb EXPORT_SYMBOL(rtw89_decode_chan_idx);
4728e2340276SBjoern A. Zeeb 
4729e2340276SBjoern A. Zeeb #define EDCCA_DEFAULT 249
4730e2340276SBjoern A. Zeeb void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan)
4731e2340276SBjoern A. Zeeb {
4732e2340276SBjoern A. Zeeb 	u32 reg = rtwdev->chip->edcca_lvl_reg;
4733e2340276SBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
4734e2340276SBjoern A. Zeeb 	u32 val;
4735e2340276SBjoern A. Zeeb 
4736e2340276SBjoern A. Zeeb 	if (scan) {
4737e2340276SBjoern A. Zeeb 		hal->edcca_bak = rtw89_phy_read32(rtwdev, reg);
4738e2340276SBjoern A. Zeeb 		val = hal->edcca_bak;
4739e2340276SBjoern A. Zeeb 		u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_A_MSK);
4740e2340276SBjoern A. Zeeb 		u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_P_MSK);
4741e2340276SBjoern A. Zeeb 		u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_PPDU_LVL_MSK);
4742e2340276SBjoern A. Zeeb 		rtw89_phy_write32(rtwdev, reg, val);
4743e2340276SBjoern A. Zeeb 	} else {
4744e2340276SBjoern A. Zeeb 		rtw89_phy_write32(rtwdev, reg, hal->edcca_bak);
4745e2340276SBjoern A. Zeeb 	}
4746e2340276SBjoern A. Zeeb }
4747