162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci/* Copyright(c) 2018-2019  Realtek Corporation
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/bcd.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "main.h"
862306a36Sopenharmony_ci#include "reg.h"
962306a36Sopenharmony_ci#include "fw.h"
1062306a36Sopenharmony_ci#include "phy.h"
1162306a36Sopenharmony_ci#include "debug.h"
1262306a36Sopenharmony_ci#include "regd.h"
1362306a36Sopenharmony_ci#include "sar.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct phy_cfg_pair {
1662306a36Sopenharmony_ci	u32 addr;
1762306a36Sopenharmony_ci	u32 data;
1862306a36Sopenharmony_ci};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ciunion phy_table_tile {
2162306a36Sopenharmony_ci	struct rtw_phy_cond cond;
2262306a36Sopenharmony_ci	struct phy_cfg_pair cfg;
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic const u32 db_invert_table[12][8] = {
2662306a36Sopenharmony_ci	{10,		13,		16,		20,
2762306a36Sopenharmony_ci	 25,		32,		40,		50},
2862306a36Sopenharmony_ci	{64,		80,		101,		128,
2962306a36Sopenharmony_ci	 160,		201,		256,		318},
3062306a36Sopenharmony_ci	{401,		505,		635,		800,
3162306a36Sopenharmony_ci	 1007,		1268,		1596,		2010},
3262306a36Sopenharmony_ci	{316,		398,		501,		631,
3362306a36Sopenharmony_ci	 794,		1000,		1259,		1585},
3462306a36Sopenharmony_ci	{1995,		2512,		3162,		3981,
3562306a36Sopenharmony_ci	 5012,		6310,		7943,		10000},
3662306a36Sopenharmony_ci	{12589,		15849,		19953,		25119,
3762306a36Sopenharmony_ci	 31623,		39811,		50119,		63098},
3862306a36Sopenharmony_ci	{79433,		100000,		125893,		158489,
3962306a36Sopenharmony_ci	 199526,	251189,		316228,		398107},
4062306a36Sopenharmony_ci	{501187,	630957,		794328,		1000000,
4162306a36Sopenharmony_ci	 1258925,	1584893,	1995262,	2511886},
4262306a36Sopenharmony_ci	{3162278,	3981072,	5011872,	6309573,
4362306a36Sopenharmony_ci	 7943282,	1000000,	12589254,	15848932},
4462306a36Sopenharmony_ci	{19952623,	25118864,	31622777,	39810717,
4562306a36Sopenharmony_ci	 50118723,	63095734,	79432823,	100000000},
4662306a36Sopenharmony_ci	{125892541,	158489319,	199526232,	251188643,
4762306a36Sopenharmony_ci	 316227766,	398107171,	501187234,	630957345},
4862306a36Sopenharmony_ci	{794328235,	1000000000,	1258925412,	1584893192,
4962306a36Sopenharmony_ci	 1995262315,	2511886432U,	3162277660U,	3981071706U}
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciu8 rtw_cck_rates[] = { DESC_RATE1M, DESC_RATE2M, DESC_RATE5_5M, DESC_RATE11M };
5362306a36Sopenharmony_ciu8 rtw_ofdm_rates[] = {
5462306a36Sopenharmony_ci	DESC_RATE6M,  DESC_RATE9M,  DESC_RATE12M,
5562306a36Sopenharmony_ci	DESC_RATE18M, DESC_RATE24M, DESC_RATE36M,
5662306a36Sopenharmony_ci	DESC_RATE48M, DESC_RATE54M
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ciu8 rtw_ht_1s_rates[] = {
5962306a36Sopenharmony_ci	DESC_RATEMCS0, DESC_RATEMCS1, DESC_RATEMCS2,
6062306a36Sopenharmony_ci	DESC_RATEMCS3, DESC_RATEMCS4, DESC_RATEMCS5,
6162306a36Sopenharmony_ci	DESC_RATEMCS6, DESC_RATEMCS7
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ciu8 rtw_ht_2s_rates[] = {
6462306a36Sopenharmony_ci	DESC_RATEMCS8,  DESC_RATEMCS9,  DESC_RATEMCS10,
6562306a36Sopenharmony_ci	DESC_RATEMCS11, DESC_RATEMCS12, DESC_RATEMCS13,
6662306a36Sopenharmony_ci	DESC_RATEMCS14, DESC_RATEMCS15
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ciu8 rtw_vht_1s_rates[] = {
6962306a36Sopenharmony_ci	DESC_RATEVHT1SS_MCS0, DESC_RATEVHT1SS_MCS1,
7062306a36Sopenharmony_ci	DESC_RATEVHT1SS_MCS2, DESC_RATEVHT1SS_MCS3,
7162306a36Sopenharmony_ci	DESC_RATEVHT1SS_MCS4, DESC_RATEVHT1SS_MCS5,
7262306a36Sopenharmony_ci	DESC_RATEVHT1SS_MCS6, DESC_RATEVHT1SS_MCS7,
7362306a36Sopenharmony_ci	DESC_RATEVHT1SS_MCS8, DESC_RATEVHT1SS_MCS9
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ciu8 rtw_vht_2s_rates[] = {
7662306a36Sopenharmony_ci	DESC_RATEVHT2SS_MCS0, DESC_RATEVHT2SS_MCS1,
7762306a36Sopenharmony_ci	DESC_RATEVHT2SS_MCS2, DESC_RATEVHT2SS_MCS3,
7862306a36Sopenharmony_ci	DESC_RATEVHT2SS_MCS4, DESC_RATEVHT2SS_MCS5,
7962306a36Sopenharmony_ci	DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7,
8062306a36Sopenharmony_ci	DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ciu8 *rtw_rate_section[RTW_RATE_SECTION_MAX] = {
8362306a36Sopenharmony_ci	rtw_cck_rates, rtw_ofdm_rates,
8462306a36Sopenharmony_ci	rtw_ht_1s_rates, rtw_ht_2s_rates,
8562306a36Sopenharmony_ci	rtw_vht_1s_rates, rtw_vht_2s_rates
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_rate_section);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ciu8 rtw_rate_size[RTW_RATE_SECTION_MAX] = {
9062306a36Sopenharmony_ci	ARRAY_SIZE(rtw_cck_rates),
9162306a36Sopenharmony_ci	ARRAY_SIZE(rtw_ofdm_rates),
9262306a36Sopenharmony_ci	ARRAY_SIZE(rtw_ht_1s_rates),
9362306a36Sopenharmony_ci	ARRAY_SIZE(rtw_ht_2s_rates),
9462306a36Sopenharmony_ci	ARRAY_SIZE(rtw_vht_1s_rates),
9562306a36Sopenharmony_ci	ARRAY_SIZE(rtw_vht_2s_rates)
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_rate_size);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic const u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates);
10062306a36Sopenharmony_cistatic const u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates);
10162306a36Sopenharmony_cistatic const u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates);
10262306a36Sopenharmony_cistatic const u8 rtw_ht_2s_size = ARRAY_SIZE(rtw_ht_2s_rates);
10362306a36Sopenharmony_cistatic const u8 rtw_vht_1s_size = ARRAY_SIZE(rtw_vht_1s_rates);
10462306a36Sopenharmony_cistatic const u8 rtw_vht_2s_size = ARRAY_SIZE(rtw_vht_2s_rates);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cienum rtw_phy_band_type {
10762306a36Sopenharmony_ci	PHY_BAND_2G	= 0,
10862306a36Sopenharmony_ci	PHY_BAND_5G	= 1,
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic void rtw_phy_cck_pd_init(struct rtw_dev *rtwdev)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
11462306a36Sopenharmony_ci	u8 i, j;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	for (i = 0; i <= RTW_CHANNEL_WIDTH_40; i++) {
11762306a36Sopenharmony_ci		for (j = 0; j < RTW_RF_PATH_MAX; j++)
11862306a36Sopenharmony_ci			dm_info->cck_pd_lv[i][j] = CCK_PD_LV0;
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	dm_info->cck_fa_avg = CCK_FA_AVG_RESET;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_civoid rtw_phy_set_edcca_th(struct rtw_dev *rtwdev, u8 l2h, u8 h2l)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	rtw_write32_mask(rtwdev,
12962306a36Sopenharmony_ci			 edcca_th[EDCCA_TH_L2H_IDX].hw_reg.addr,
13062306a36Sopenharmony_ci			 edcca_th[EDCCA_TH_L2H_IDX].hw_reg.mask,
13162306a36Sopenharmony_ci			 l2h + edcca_th[EDCCA_TH_L2H_IDX].offset);
13262306a36Sopenharmony_ci	rtw_write32_mask(rtwdev,
13362306a36Sopenharmony_ci			 edcca_th[EDCCA_TH_H2L_IDX].hw_reg.addr,
13462306a36Sopenharmony_ci			 edcca_th[EDCCA_TH_H2L_IDX].hw_reg.mask,
13562306a36Sopenharmony_ci			 h2l + edcca_th[EDCCA_TH_H2L_IDX].offset);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_set_edcca_th);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_civoid rtw_phy_adaptivity_set_mode(struct rtw_dev *rtwdev)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
14262306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* turn off in debugfs for debug usage */
14562306a36Sopenharmony_ci	if (!rtw_edcca_enabled) {
14662306a36Sopenharmony_ci		dm_info->edcca_mode = RTW_EDCCA_NORMAL;
14762306a36Sopenharmony_ci		rtw_dbg(rtwdev, RTW_DBG_PHY, "EDCCA disabled, cannot be set\n");
14862306a36Sopenharmony_ci		return;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	switch (rtwdev->regd.dfs_region) {
15262306a36Sopenharmony_ci	case NL80211_DFS_ETSI:
15362306a36Sopenharmony_ci		dm_info->edcca_mode = RTW_EDCCA_ADAPTIVITY;
15462306a36Sopenharmony_ci		dm_info->l2h_th_ini = chip->l2h_th_ini_ad;
15562306a36Sopenharmony_ci		break;
15662306a36Sopenharmony_ci	case NL80211_DFS_JP:
15762306a36Sopenharmony_ci		dm_info->edcca_mode = RTW_EDCCA_ADAPTIVITY;
15862306a36Sopenharmony_ci		dm_info->l2h_th_ini = chip->l2h_th_ini_cs;
15962306a36Sopenharmony_ci		break;
16062306a36Sopenharmony_ci	default:
16162306a36Sopenharmony_ci		dm_info->edcca_mode = RTW_EDCCA_NORMAL;
16262306a36Sopenharmony_ci		break;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic void rtw_phy_adaptivity_init(struct rtw_dev *rtwdev)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	rtw_phy_adaptivity_set_mode(rtwdev);
17162306a36Sopenharmony_ci	if (chip->ops->adaptivity_init)
17262306a36Sopenharmony_ci		chip->ops->adaptivity_init(rtwdev);
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic void rtw_phy_adaptivity(struct rtw_dev *rtwdev)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	if (rtwdev->chip->ops->adaptivity)
17862306a36Sopenharmony_ci		rtwdev->chip->ops->adaptivity(rtwdev);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic void rtw_phy_cfo_init(struct rtw_dev *rtwdev)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (chip->ops->cfo_init)
18662306a36Sopenharmony_ci		chip->ops->cfo_init(rtwdev);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic void rtw_phy_tx_path_div_init(struct rtw_dev *rtwdev)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct rtw_path_div *path_div = &rtwdev->dm_path_div;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	path_div->current_tx_path = rtwdev->chip->default_1ss_tx_path;
19462306a36Sopenharmony_ci	path_div->path_a_cnt = 0;
19562306a36Sopenharmony_ci	path_div->path_a_sum = 0;
19662306a36Sopenharmony_ci	path_div->path_b_cnt = 0;
19762306a36Sopenharmony_ci	path_div->path_b_sum = 0;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_civoid rtw_phy_init(struct rtw_dev *rtwdev)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
20362306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
20462306a36Sopenharmony_ci	u32 addr, mask;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	dm_info->fa_history[3] = 0;
20762306a36Sopenharmony_ci	dm_info->fa_history[2] = 0;
20862306a36Sopenharmony_ci	dm_info->fa_history[1] = 0;
20962306a36Sopenharmony_ci	dm_info->fa_history[0] = 0;
21062306a36Sopenharmony_ci	dm_info->igi_bitmap = 0;
21162306a36Sopenharmony_ci	dm_info->igi_history[3] = 0;
21262306a36Sopenharmony_ci	dm_info->igi_history[2] = 0;
21362306a36Sopenharmony_ci	dm_info->igi_history[1] = 0;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	addr = chip->dig[0].addr;
21662306a36Sopenharmony_ci	mask = chip->dig[0].mask;
21762306a36Sopenharmony_ci	dm_info->igi_history[0] = rtw_read32_mask(rtwdev, addr, mask);
21862306a36Sopenharmony_ci	rtw_phy_cck_pd_init(rtwdev);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	dm_info->iqk.done = false;
22162306a36Sopenharmony_ci	rtw_phy_adaptivity_init(rtwdev);
22262306a36Sopenharmony_ci	rtw_phy_cfo_init(rtwdev);
22362306a36Sopenharmony_ci	rtw_phy_tx_path_div_init(rtwdev);
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_init);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_civoid rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
23062306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
23162306a36Sopenharmony_ci	u32 addr, mask;
23262306a36Sopenharmony_ci	u8 path;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (chip->dig_cck) {
23562306a36Sopenharmony_ci		const struct rtw_hw_reg *dig_cck = &chip->dig_cck[0];
23662306a36Sopenharmony_ci		rtw_write32_mask(rtwdev, dig_cck->addr, dig_cck->mask, igi >> 1);
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	for (path = 0; path < hal->rf_path_num; path++) {
24062306a36Sopenharmony_ci		addr = chip->dig[path].addr;
24162306a36Sopenharmony_ci		mask = chip->dig[path].mask;
24262306a36Sopenharmony_ci		rtw_write32_mask(rtwdev, addr, mask, igi);
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic void rtw_phy_stat_false_alarm(struct rtw_dev *rtwdev)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	chip->ops->false_alarm_statistics(rtwdev);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci#define RA_FLOOR_TABLE_SIZE	7
25462306a36Sopenharmony_ci#define RA_FLOOR_UP_GAP		3
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic u8 rtw_phy_get_rssi_level(u8 old_level, u8 rssi)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	u8 table[RA_FLOOR_TABLE_SIZE] = {20, 34, 38, 42, 46, 50, 100};
25962306a36Sopenharmony_ci	u8 new_level = 0;
26062306a36Sopenharmony_ci	int i;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++)
26362306a36Sopenharmony_ci		if (i >= old_level)
26462306a36Sopenharmony_ci			table[i] += RA_FLOOR_UP_GAP;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++) {
26762306a36Sopenharmony_ci		if (rssi < table[i]) {
26862306a36Sopenharmony_ci			new_level = i;
26962306a36Sopenharmony_ci			break;
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return new_level;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistruct rtw_phy_stat_iter_data {
27762306a36Sopenharmony_ci	struct rtw_dev *rtwdev;
27862306a36Sopenharmony_ci	u8 min_rssi;
27962306a36Sopenharmony_ci};
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic void rtw_phy_stat_rssi_iter(void *data, struct ieee80211_sta *sta)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct rtw_phy_stat_iter_data *iter_data = data;
28462306a36Sopenharmony_ci	struct rtw_dev *rtwdev = iter_data->rtwdev;
28562306a36Sopenharmony_ci	struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
28662306a36Sopenharmony_ci	u8 rssi;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	rssi = ewma_rssi_read(&si->avg_rssi);
28962306a36Sopenharmony_ci	si->rssi_level = rtw_phy_get_rssi_level(si->rssi_level, rssi);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	rtw_fw_send_rssi_info(rtwdev, si);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	iter_data->min_rssi = min_t(u8, rssi, iter_data->min_rssi);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void rtw_phy_stat_rssi(struct rtw_dev *rtwdev)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
29962306a36Sopenharmony_ci	struct rtw_phy_stat_iter_data data = {};
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	data.rtwdev = rtwdev;
30262306a36Sopenharmony_ci	data.min_rssi = U8_MAX;
30362306a36Sopenharmony_ci	rtw_iterate_stas(rtwdev, rtw_phy_stat_rssi_iter, &data);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	dm_info->pre_min_rssi = dm_info->min_rssi;
30662306a36Sopenharmony_ci	dm_info->min_rssi = data.min_rssi;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic void rtw_phy_stat_rate_cnt(struct rtw_dev *rtwdev)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	dm_info->last_pkt_count = dm_info->cur_pkt_count;
31462306a36Sopenharmony_ci	memset(&dm_info->cur_pkt_count, 0, sizeof(dm_info->cur_pkt_count));
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic void rtw_phy_statistics(struct rtw_dev *rtwdev)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	rtw_phy_stat_rssi(rtwdev);
32062306a36Sopenharmony_ci	rtw_phy_stat_false_alarm(rtwdev);
32162306a36Sopenharmony_ci	rtw_phy_stat_rate_cnt(rtwdev);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci#define DIG_PERF_FA_TH_LOW			250
32562306a36Sopenharmony_ci#define DIG_PERF_FA_TH_HIGH			500
32662306a36Sopenharmony_ci#define DIG_PERF_FA_TH_EXTRA_HIGH		750
32762306a36Sopenharmony_ci#define DIG_PERF_MAX				0x5a
32862306a36Sopenharmony_ci#define DIG_PERF_MID				0x40
32962306a36Sopenharmony_ci#define DIG_CVRG_FA_TH_LOW			2000
33062306a36Sopenharmony_ci#define DIG_CVRG_FA_TH_HIGH			4000
33162306a36Sopenharmony_ci#define DIG_CVRG_FA_TH_EXTRA_HIGH		5000
33262306a36Sopenharmony_ci#define DIG_CVRG_MAX				0x2a
33362306a36Sopenharmony_ci#define DIG_CVRG_MID				0x26
33462306a36Sopenharmony_ci#define DIG_CVRG_MIN				0x1c
33562306a36Sopenharmony_ci#define DIG_RSSI_GAIN_OFFSET			15
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic bool
33862306a36Sopenharmony_cirtw_phy_dig_check_damping(struct rtw_dm_info *dm_info)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	u16 fa_lo = DIG_PERF_FA_TH_LOW;
34162306a36Sopenharmony_ci	u16 fa_hi = DIG_PERF_FA_TH_HIGH;
34262306a36Sopenharmony_ci	u16 *fa_history;
34362306a36Sopenharmony_ci	u8 *igi_history;
34462306a36Sopenharmony_ci	u8 damping_rssi;
34562306a36Sopenharmony_ci	u8 min_rssi;
34662306a36Sopenharmony_ci	u8 diff;
34762306a36Sopenharmony_ci	u8 igi_bitmap;
34862306a36Sopenharmony_ci	bool damping = false;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	min_rssi = dm_info->min_rssi;
35162306a36Sopenharmony_ci	if (dm_info->damping) {
35262306a36Sopenharmony_ci		damping_rssi = dm_info->damping_rssi;
35362306a36Sopenharmony_ci		diff = min_rssi > damping_rssi ? min_rssi - damping_rssi :
35462306a36Sopenharmony_ci						 damping_rssi - min_rssi;
35562306a36Sopenharmony_ci		if (diff > 3 || dm_info->damping_cnt++ > 20) {
35662306a36Sopenharmony_ci			dm_info->damping = false;
35762306a36Sopenharmony_ci			return false;
35862306a36Sopenharmony_ci		}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci		return true;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	igi_history = dm_info->igi_history;
36462306a36Sopenharmony_ci	fa_history = dm_info->fa_history;
36562306a36Sopenharmony_ci	igi_bitmap = dm_info->igi_bitmap & 0xf;
36662306a36Sopenharmony_ci	switch (igi_bitmap) {
36762306a36Sopenharmony_ci	case 5:
36862306a36Sopenharmony_ci		/* down -> up -> down -> up */
36962306a36Sopenharmony_ci		if (igi_history[0] > igi_history[1] &&
37062306a36Sopenharmony_ci		    igi_history[2] > igi_history[3] &&
37162306a36Sopenharmony_ci		    igi_history[0] - igi_history[1] >= 2 &&
37262306a36Sopenharmony_ci		    igi_history[2] - igi_history[3] >= 2 &&
37362306a36Sopenharmony_ci		    fa_history[0] > fa_hi && fa_history[1] < fa_lo &&
37462306a36Sopenharmony_ci		    fa_history[2] > fa_hi && fa_history[3] < fa_lo)
37562306a36Sopenharmony_ci			damping = true;
37662306a36Sopenharmony_ci		break;
37762306a36Sopenharmony_ci	case 9:
37862306a36Sopenharmony_ci		/* up -> down -> down -> up */
37962306a36Sopenharmony_ci		if (igi_history[0] > igi_history[1] &&
38062306a36Sopenharmony_ci		    igi_history[3] > igi_history[2] &&
38162306a36Sopenharmony_ci		    igi_history[0] - igi_history[1] >= 4 &&
38262306a36Sopenharmony_ci		    igi_history[3] - igi_history[2] >= 2 &&
38362306a36Sopenharmony_ci		    fa_history[0] > fa_hi && fa_history[1] < fa_lo &&
38462306a36Sopenharmony_ci		    fa_history[2] < fa_lo && fa_history[3] > fa_hi)
38562306a36Sopenharmony_ci			damping = true;
38662306a36Sopenharmony_ci		break;
38762306a36Sopenharmony_ci	default:
38862306a36Sopenharmony_ci		return false;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (damping) {
39262306a36Sopenharmony_ci		dm_info->damping = true;
39362306a36Sopenharmony_ci		dm_info->damping_cnt = 0;
39462306a36Sopenharmony_ci		dm_info->damping_rssi = min_rssi;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	return damping;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic void rtw_phy_dig_get_boundary(struct rtw_dev *rtwdev,
40162306a36Sopenharmony_ci				     struct rtw_dm_info *dm_info,
40262306a36Sopenharmony_ci				     u8 *upper, u8 *lower, bool linked)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	u8 dig_max, dig_min, dig_mid;
40562306a36Sopenharmony_ci	u8 min_rssi;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (linked) {
40862306a36Sopenharmony_ci		dig_max = DIG_PERF_MAX;
40962306a36Sopenharmony_ci		dig_mid = DIG_PERF_MID;
41062306a36Sopenharmony_ci		dig_min = rtwdev->chip->dig_min;
41162306a36Sopenharmony_ci		min_rssi = max_t(u8, dm_info->min_rssi, dig_min);
41262306a36Sopenharmony_ci	} else {
41362306a36Sopenharmony_ci		dig_max = DIG_CVRG_MAX;
41462306a36Sopenharmony_ci		dig_mid = DIG_CVRG_MID;
41562306a36Sopenharmony_ci		dig_min = DIG_CVRG_MIN;
41662306a36Sopenharmony_ci		min_rssi = dig_min;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/* DIG MAX should be bounded by minimum RSSI with offset +15 */
42062306a36Sopenharmony_ci	dig_max = min_t(u8, dig_max, min_rssi + DIG_RSSI_GAIN_OFFSET);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	*lower = clamp_t(u8, min_rssi, dig_min, dig_mid);
42362306a36Sopenharmony_ci	*upper = clamp_t(u8, *lower + DIG_RSSI_GAIN_OFFSET, dig_min, dig_max);
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic void rtw_phy_dig_get_threshold(struct rtw_dm_info *dm_info,
42762306a36Sopenharmony_ci				      u16 *fa_th, u8 *step, bool linked)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	u8 min_rssi, pre_min_rssi;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	min_rssi = dm_info->min_rssi;
43262306a36Sopenharmony_ci	pre_min_rssi = dm_info->pre_min_rssi;
43362306a36Sopenharmony_ci	step[0] = 4;
43462306a36Sopenharmony_ci	step[1] = 3;
43562306a36Sopenharmony_ci	step[2] = 2;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	if (linked) {
43862306a36Sopenharmony_ci		fa_th[0] = DIG_PERF_FA_TH_EXTRA_HIGH;
43962306a36Sopenharmony_ci		fa_th[1] = DIG_PERF_FA_TH_HIGH;
44062306a36Sopenharmony_ci		fa_th[2] = DIG_PERF_FA_TH_LOW;
44162306a36Sopenharmony_ci		if (pre_min_rssi > min_rssi) {
44262306a36Sopenharmony_ci			step[0] = 6;
44362306a36Sopenharmony_ci			step[1] = 4;
44462306a36Sopenharmony_ci			step[2] = 2;
44562306a36Sopenharmony_ci		}
44662306a36Sopenharmony_ci	} else {
44762306a36Sopenharmony_ci		fa_th[0] = DIG_CVRG_FA_TH_EXTRA_HIGH;
44862306a36Sopenharmony_ci		fa_th[1] = DIG_CVRG_FA_TH_HIGH;
44962306a36Sopenharmony_ci		fa_th[2] = DIG_CVRG_FA_TH_LOW;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic void rtw_phy_dig_recorder(struct rtw_dm_info *dm_info, u8 igi, u16 fa)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	u8 *igi_history;
45662306a36Sopenharmony_ci	u16 *fa_history;
45762306a36Sopenharmony_ci	u8 igi_bitmap;
45862306a36Sopenharmony_ci	bool up;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	igi_bitmap = dm_info->igi_bitmap << 1 & 0xfe;
46162306a36Sopenharmony_ci	igi_history = dm_info->igi_history;
46262306a36Sopenharmony_ci	fa_history = dm_info->fa_history;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	up = igi > igi_history[0];
46562306a36Sopenharmony_ci	igi_bitmap |= up;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	igi_history[3] = igi_history[2];
46862306a36Sopenharmony_ci	igi_history[2] = igi_history[1];
46962306a36Sopenharmony_ci	igi_history[1] = igi_history[0];
47062306a36Sopenharmony_ci	igi_history[0] = igi;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	fa_history[3] = fa_history[2];
47362306a36Sopenharmony_ci	fa_history[2] = fa_history[1];
47462306a36Sopenharmony_ci	fa_history[1] = fa_history[0];
47562306a36Sopenharmony_ci	fa_history[0] = fa;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	dm_info->igi_bitmap = igi_bitmap;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic void rtw_phy_dig(struct rtw_dev *rtwdev)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
48362306a36Sopenharmony_ci	u8 upper_bound, lower_bound;
48462306a36Sopenharmony_ci	u8 pre_igi, cur_igi;
48562306a36Sopenharmony_ci	u16 fa_th[3], fa_cnt;
48662306a36Sopenharmony_ci	u8 level;
48762306a36Sopenharmony_ci	u8 step[3];
48862306a36Sopenharmony_ci	bool linked;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (test_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags))
49162306a36Sopenharmony_ci		return;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (rtw_phy_dig_check_damping(dm_info))
49462306a36Sopenharmony_ci		return;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	linked = !!rtwdev->sta_cnt;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	fa_cnt = dm_info->total_fa_cnt;
49962306a36Sopenharmony_ci	pre_igi = dm_info->igi_history[0];
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	rtw_phy_dig_get_threshold(dm_info, fa_th, step, linked);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* test the false alarm count from the highest threshold level first,
50462306a36Sopenharmony_ci	 * and increase it by corresponding step size
50562306a36Sopenharmony_ci	 *
50662306a36Sopenharmony_ci	 * note that the step size is offset by -2, compensate it afterall
50762306a36Sopenharmony_ci	 */
50862306a36Sopenharmony_ci	cur_igi = pre_igi;
50962306a36Sopenharmony_ci	for (level = 0; level < 3; level++) {
51062306a36Sopenharmony_ci		if (fa_cnt > fa_th[level]) {
51162306a36Sopenharmony_ci			cur_igi += step[level];
51262306a36Sopenharmony_ci			break;
51362306a36Sopenharmony_ci		}
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci	cur_igi -= 2;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* calculate the upper/lower bound by the minimum rssi we have among
51862306a36Sopenharmony_ci	 * the peers connected with us, meanwhile make sure the igi value does
51962306a36Sopenharmony_ci	 * not beyond the hardware limitation
52062306a36Sopenharmony_ci	 */
52162306a36Sopenharmony_ci	rtw_phy_dig_get_boundary(rtwdev, dm_info, &upper_bound, &lower_bound,
52262306a36Sopenharmony_ci				 linked);
52362306a36Sopenharmony_ci	cur_igi = clamp_t(u8, cur_igi, lower_bound, upper_bound);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* record current igi value and false alarm statistics for further
52662306a36Sopenharmony_ci	 * damping checks, and record the trend of igi values
52762306a36Sopenharmony_ci	 */
52862306a36Sopenharmony_ci	rtw_phy_dig_recorder(dm_info, cur_igi, fa_cnt);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (cur_igi != pre_igi)
53162306a36Sopenharmony_ci		rtw_phy_dig_write(rtwdev, cur_igi);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic void rtw_phy_ra_info_update_iter(void *data, struct ieee80211_sta *sta)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	struct rtw_dev *rtwdev = data;
53762306a36Sopenharmony_ci	struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	rtw_update_sta_info(rtwdev, si, false);
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic void rtw_phy_ra_info_update(struct rtw_dev *rtwdev)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	if (rtwdev->watch_dog_cnt & 0x3)
54562306a36Sopenharmony_ci		return;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	rtw_iterate_stas(rtwdev, rtw_phy_ra_info_update_iter, rtwdev);
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic u32 rtw_phy_get_rrsr_mask(struct rtw_dev *rtwdev, u8 rate_idx)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	u8 rate_order;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	rate_order = rate_idx;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (rate_idx >= DESC_RATEVHT4SS_MCS0)
55762306a36Sopenharmony_ci		rate_order -= DESC_RATEVHT4SS_MCS0;
55862306a36Sopenharmony_ci	else if (rate_idx >= DESC_RATEVHT3SS_MCS0)
55962306a36Sopenharmony_ci		rate_order -= DESC_RATEVHT3SS_MCS0;
56062306a36Sopenharmony_ci	else if (rate_idx >= DESC_RATEVHT2SS_MCS0)
56162306a36Sopenharmony_ci		rate_order -= DESC_RATEVHT2SS_MCS0;
56262306a36Sopenharmony_ci	else if (rate_idx >= DESC_RATEVHT1SS_MCS0)
56362306a36Sopenharmony_ci		rate_order -= DESC_RATEVHT1SS_MCS0;
56462306a36Sopenharmony_ci	else if (rate_idx >= DESC_RATEMCS24)
56562306a36Sopenharmony_ci		rate_order -= DESC_RATEMCS24;
56662306a36Sopenharmony_ci	else if (rate_idx >= DESC_RATEMCS16)
56762306a36Sopenharmony_ci		rate_order -= DESC_RATEMCS16;
56862306a36Sopenharmony_ci	else if (rate_idx >= DESC_RATEMCS8)
56962306a36Sopenharmony_ci		rate_order -= DESC_RATEMCS8;
57062306a36Sopenharmony_ci	else if (rate_idx >= DESC_RATEMCS0)
57162306a36Sopenharmony_ci		rate_order -= DESC_RATEMCS0;
57262306a36Sopenharmony_ci	else if (rate_idx >= DESC_RATE6M)
57362306a36Sopenharmony_ci		rate_order -= DESC_RATE6M;
57462306a36Sopenharmony_ci	else
57562306a36Sopenharmony_ci		rate_order -= DESC_RATE1M;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	if (rate_idx >= DESC_RATEMCS0 || rate_order == 0)
57862306a36Sopenharmony_ci		rate_order++;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	return GENMASK(rate_order + RRSR_RATE_ORDER_CCK_LEN - 1, 0);
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic void rtw_phy_rrsr_mask_min_iter(void *data, struct ieee80211_sta *sta)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct rtw_dev *rtwdev = (struct rtw_dev *)data;
58662306a36Sopenharmony_ci	struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
58762306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
58862306a36Sopenharmony_ci	u32 mask = 0;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	mask = rtw_phy_get_rrsr_mask(rtwdev, si->ra_report.desc_rate);
59162306a36Sopenharmony_ci	if (mask < dm_info->rrsr_mask_min)
59262306a36Sopenharmony_ci		dm_info->rrsr_mask_min = mask;
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic void rtw_phy_rrsr_update(struct rtw_dev *rtwdev)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	dm_info->rrsr_mask_min = RRSR_RATE_ORDER_MAX;
60062306a36Sopenharmony_ci	rtw_iterate_stas(rtwdev, rtw_phy_rrsr_mask_min_iter, rtwdev);
60162306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_RRSR, dm_info->rrsr_val_init & dm_info->rrsr_mask_min);
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic void rtw_phy_dpk_track(struct rtw_dev *rtwdev)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (chip->ops->dpk_track)
60962306a36Sopenharmony_ci		chip->ops->dpk_track(rtwdev);
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistruct rtw_rx_addr_match_data {
61362306a36Sopenharmony_ci	struct rtw_dev *rtwdev;
61462306a36Sopenharmony_ci	struct ieee80211_hdr *hdr;
61562306a36Sopenharmony_ci	struct rtw_rx_pkt_stat *pkt_stat;
61662306a36Sopenharmony_ci	u8 *bssid;
61762306a36Sopenharmony_ci};
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic void rtw_phy_parsing_cfo_iter(void *data, u8 *mac,
62062306a36Sopenharmony_ci				     struct ieee80211_vif *vif)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	struct rtw_rx_addr_match_data *iter_data = data;
62362306a36Sopenharmony_ci	struct rtw_dev *rtwdev = iter_data->rtwdev;
62462306a36Sopenharmony_ci	struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat;
62562306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
62662306a36Sopenharmony_ci	struct rtw_cfo_track *cfo = &dm_info->cfo_track;
62762306a36Sopenharmony_ci	u8 *bssid = iter_data->bssid;
62862306a36Sopenharmony_ci	u8 i;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
63162306a36Sopenharmony_ci		return;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	for (i = 0; i < rtwdev->hal.rf_path_num; i++) {
63462306a36Sopenharmony_ci		cfo->cfo_tail[i] += pkt_stat->cfo_tail[i];
63562306a36Sopenharmony_ci		cfo->cfo_cnt[i]++;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	cfo->packet_count++;
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_civoid rtw_phy_parsing_cfo(struct rtw_dev *rtwdev,
64262306a36Sopenharmony_ci			 struct rtw_rx_pkt_stat *pkt_stat)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = pkt_stat->hdr;
64562306a36Sopenharmony_ci	struct rtw_rx_addr_match_data data = {};
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	if (pkt_stat->crc_err || pkt_stat->icv_err || !pkt_stat->phy_status ||
64862306a36Sopenharmony_ci	    ieee80211_is_ctl(hdr->frame_control))
64962306a36Sopenharmony_ci		return;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	data.rtwdev = rtwdev;
65262306a36Sopenharmony_ci	data.hdr = hdr;
65362306a36Sopenharmony_ci	data.pkt_stat = pkt_stat;
65462306a36Sopenharmony_ci	data.bssid = get_hdr_bssid(hdr);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	rtw_iterate_vifs_atomic(rtwdev, rtw_phy_parsing_cfo_iter, &data);
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_parsing_cfo);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic void rtw_phy_cfo_track(struct rtw_dev *rtwdev)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (chip->ops->cfo_track)
66562306a36Sopenharmony_ci		chip->ops->cfo_track(rtwdev);
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci#define CCK_PD_FA_LV1_MIN	1000
66962306a36Sopenharmony_ci#define CCK_PD_FA_LV0_MAX	500
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic u8 rtw_phy_cck_pd_lv_unlink(struct rtw_dev *rtwdev)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
67462306a36Sopenharmony_ci	u32 cck_fa_avg = dm_info->cck_fa_avg;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	if (cck_fa_avg > CCK_PD_FA_LV1_MIN)
67762306a36Sopenharmony_ci		return CCK_PD_LV1;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (cck_fa_avg < CCK_PD_FA_LV0_MAX)
68062306a36Sopenharmony_ci		return CCK_PD_LV0;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	return CCK_PD_LV_MAX;
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci#define CCK_PD_IGI_LV4_VAL 0x38
68662306a36Sopenharmony_ci#define CCK_PD_IGI_LV3_VAL 0x2a
68762306a36Sopenharmony_ci#define CCK_PD_IGI_LV2_VAL 0x24
68862306a36Sopenharmony_ci#define CCK_PD_RSSI_LV4_VAL 32
68962306a36Sopenharmony_ci#define CCK_PD_RSSI_LV3_VAL 32
69062306a36Sopenharmony_ci#define CCK_PD_RSSI_LV2_VAL 24
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic u8 rtw_phy_cck_pd_lv_link(struct rtw_dev *rtwdev)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
69562306a36Sopenharmony_ci	u8 igi = dm_info->igi_history[0];
69662306a36Sopenharmony_ci	u8 rssi = dm_info->min_rssi;
69762306a36Sopenharmony_ci	u32 cck_fa_avg = dm_info->cck_fa_avg;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	if (igi > CCK_PD_IGI_LV4_VAL && rssi > CCK_PD_RSSI_LV4_VAL)
70062306a36Sopenharmony_ci		return CCK_PD_LV4;
70162306a36Sopenharmony_ci	if (igi > CCK_PD_IGI_LV3_VAL && rssi > CCK_PD_RSSI_LV3_VAL)
70262306a36Sopenharmony_ci		return CCK_PD_LV3;
70362306a36Sopenharmony_ci	if (igi > CCK_PD_IGI_LV2_VAL || rssi > CCK_PD_RSSI_LV2_VAL)
70462306a36Sopenharmony_ci		return CCK_PD_LV2;
70562306a36Sopenharmony_ci	if (cck_fa_avg > CCK_PD_FA_LV1_MIN)
70662306a36Sopenharmony_ci		return CCK_PD_LV1;
70762306a36Sopenharmony_ci	if (cck_fa_avg < CCK_PD_FA_LV0_MAX)
70862306a36Sopenharmony_ci		return CCK_PD_LV0;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	return CCK_PD_LV_MAX;
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistatic u8 rtw_phy_cck_pd_lv(struct rtw_dev *rtwdev)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	if (!rtw_is_assoc(rtwdev))
71662306a36Sopenharmony_ci		return rtw_phy_cck_pd_lv_unlink(rtwdev);
71762306a36Sopenharmony_ci	else
71862306a36Sopenharmony_ci		return rtw_phy_cck_pd_lv_link(rtwdev);
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic void rtw_phy_cck_pd(struct rtw_dev *rtwdev)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
72462306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
72562306a36Sopenharmony_ci	u32 cck_fa = dm_info->cck_fa_cnt;
72662306a36Sopenharmony_ci	u8 level;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (rtwdev->hal.current_band_type != RTW_BAND_2G)
72962306a36Sopenharmony_ci		return;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (dm_info->cck_fa_avg == CCK_FA_AVG_RESET)
73262306a36Sopenharmony_ci		dm_info->cck_fa_avg = cck_fa;
73362306a36Sopenharmony_ci	else
73462306a36Sopenharmony_ci		dm_info->cck_fa_avg = (dm_info->cck_fa_avg * 3 + cck_fa) >> 2;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	rtw_dbg(rtwdev, RTW_DBG_PHY, "IGI=0x%x, rssi_min=%d, cck_fa=%d\n",
73762306a36Sopenharmony_ci		dm_info->igi_history[0], dm_info->min_rssi,
73862306a36Sopenharmony_ci		dm_info->fa_history[0]);
73962306a36Sopenharmony_ci	rtw_dbg(rtwdev, RTW_DBG_PHY, "cck_fa_avg=%d, cck_pd_default=%d\n",
74062306a36Sopenharmony_ci		dm_info->cck_fa_avg, dm_info->cck_pd_default);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	level = rtw_phy_cck_pd_lv(rtwdev);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	if (level >= CCK_PD_LV_MAX)
74562306a36Sopenharmony_ci		return;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (chip->ops->cck_pd_set)
74862306a36Sopenharmony_ci		chip->ops->cck_pd_set(rtwdev, level);
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic void rtw_phy_pwr_track(struct rtw_dev *rtwdev)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	rtwdev->chip->ops->pwr_track(rtwdev);
75462306a36Sopenharmony_ci}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_cistatic void rtw_phy_ra_track(struct rtw_dev *rtwdev)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	rtw_fw_update_wl_phy_info(rtwdev);
75962306a36Sopenharmony_ci	rtw_phy_ra_info_update(rtwdev);
76062306a36Sopenharmony_ci	rtw_phy_rrsr_update(rtwdev);
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_civoid rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	/* for further calculation */
76662306a36Sopenharmony_ci	rtw_phy_statistics(rtwdev);
76762306a36Sopenharmony_ci	rtw_phy_dig(rtwdev);
76862306a36Sopenharmony_ci	rtw_phy_cck_pd(rtwdev);
76962306a36Sopenharmony_ci	rtw_phy_ra_track(rtwdev);
77062306a36Sopenharmony_ci	rtw_phy_tx_path_diversity(rtwdev);
77162306a36Sopenharmony_ci	rtw_phy_cfo_track(rtwdev);
77262306a36Sopenharmony_ci	rtw_phy_dpk_track(rtwdev);
77362306a36Sopenharmony_ci	rtw_phy_pwr_track(rtwdev);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_ADAPTIVITY))
77662306a36Sopenharmony_ci		rtw_fw_adaptivity(rtwdev);
77762306a36Sopenharmony_ci	else
77862306a36Sopenharmony_ci		rtw_phy_adaptivity(rtwdev);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci#define FRAC_BITS 3
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic u8 rtw_phy_power_2_db(s8 power)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	if (power <= -100 || power >= 20)
78662306a36Sopenharmony_ci		return 0;
78762306a36Sopenharmony_ci	else if (power >= 0)
78862306a36Sopenharmony_ci		return 100;
78962306a36Sopenharmony_ci	else
79062306a36Sopenharmony_ci		return 100 + power;
79162306a36Sopenharmony_ci}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic u64 rtw_phy_db_2_linear(u8 power_db)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	u8 i, j;
79662306a36Sopenharmony_ci	u64 linear;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (power_db > 96)
79962306a36Sopenharmony_ci		power_db = 96;
80062306a36Sopenharmony_ci	else if (power_db < 1)
80162306a36Sopenharmony_ci		return 1;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	/* 1dB ~ 96dB */
80462306a36Sopenharmony_ci	i = (power_db - 1) >> 3;
80562306a36Sopenharmony_ci	j = (power_db - 1) - (i << 3);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	linear = db_invert_table[i][j];
80862306a36Sopenharmony_ci	linear = i > 2 ? linear << FRAC_BITS : linear;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	return linear;
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_cistatic u8 rtw_phy_linear_2_db(u64 linear)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	u8 i;
81662306a36Sopenharmony_ci	u8 j;
81762306a36Sopenharmony_ci	u32 dB;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	for (i = 0; i < 12; i++) {
82062306a36Sopenharmony_ci		for (j = 0; j < 8; j++) {
82162306a36Sopenharmony_ci			if (i <= 2 && (linear << FRAC_BITS) <= db_invert_table[i][j])
82262306a36Sopenharmony_ci				goto cnt;
82362306a36Sopenharmony_ci			else if (i > 2 && linear <= db_invert_table[i][j])
82462306a36Sopenharmony_ci				goto cnt;
82562306a36Sopenharmony_ci		}
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	return 96; /* maximum 96 dB */
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cicnt:
83162306a36Sopenharmony_ci	if (j == 0 && i == 0)
83262306a36Sopenharmony_ci		goto end;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	if (j == 0) {
83562306a36Sopenharmony_ci		if (i != 3) {
83662306a36Sopenharmony_ci			if (db_invert_table[i][0] - linear >
83762306a36Sopenharmony_ci			    linear - db_invert_table[i - 1][7]) {
83862306a36Sopenharmony_ci				i = i - 1;
83962306a36Sopenharmony_ci				j = 7;
84062306a36Sopenharmony_ci			}
84162306a36Sopenharmony_ci		} else {
84262306a36Sopenharmony_ci			if (db_invert_table[3][0] - linear >
84362306a36Sopenharmony_ci			    linear - db_invert_table[2][7]) {
84462306a36Sopenharmony_ci				i = 2;
84562306a36Sopenharmony_ci				j = 7;
84662306a36Sopenharmony_ci			}
84762306a36Sopenharmony_ci		}
84862306a36Sopenharmony_ci	} else {
84962306a36Sopenharmony_ci		if (db_invert_table[i][j] - linear >
85062306a36Sopenharmony_ci		    linear - db_invert_table[i][j - 1]) {
85162306a36Sopenharmony_ci			j = j - 1;
85262306a36Sopenharmony_ci		}
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ciend:
85562306a36Sopenharmony_ci	dB = (i << 3) + j + 1;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	return dB;
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ciu8 rtw_phy_rf_power_2_rssi(s8 *rf_power, u8 path_num)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	s8 power;
86362306a36Sopenharmony_ci	u8 power_db;
86462306a36Sopenharmony_ci	u64 linear;
86562306a36Sopenharmony_ci	u64 sum = 0;
86662306a36Sopenharmony_ci	u8 path;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	for (path = 0; path < path_num; path++) {
86962306a36Sopenharmony_ci		power = rf_power[path];
87062306a36Sopenharmony_ci		power_db = rtw_phy_power_2_db(power);
87162306a36Sopenharmony_ci		linear = rtw_phy_db_2_linear(power_db);
87262306a36Sopenharmony_ci		sum += linear;
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	sum = (sum + (1 << (FRAC_BITS - 1))) >> FRAC_BITS;
87662306a36Sopenharmony_ci	switch (path_num) {
87762306a36Sopenharmony_ci	case 2:
87862306a36Sopenharmony_ci		sum >>= 1;
87962306a36Sopenharmony_ci		break;
88062306a36Sopenharmony_ci	case 3:
88162306a36Sopenharmony_ci		sum = ((sum) + ((sum) << 1) + ((sum) << 3)) >> 5;
88262306a36Sopenharmony_ci		break;
88362306a36Sopenharmony_ci	case 4:
88462306a36Sopenharmony_ci		sum >>= 2;
88562306a36Sopenharmony_ci		break;
88662306a36Sopenharmony_ci	default:
88762306a36Sopenharmony_ci		break;
88862306a36Sopenharmony_ci	}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	return rtw_phy_linear_2_db(sum);
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_rf_power_2_rssi);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ciu32 rtw_phy_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
89562306a36Sopenharmony_ci		    u32 addr, u32 mask)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
89862306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
89962306a36Sopenharmony_ci	const u32 *base_addr = chip->rf_base_addr;
90062306a36Sopenharmony_ci	u32 val, direct_addr;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (rf_path >= hal->rf_phy_num) {
90362306a36Sopenharmony_ci		rtw_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
90462306a36Sopenharmony_ci		return INV_RF_DATA;
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	addr &= 0xff;
90862306a36Sopenharmony_ci	direct_addr = base_addr[rf_path] + (addr << 2);
90962306a36Sopenharmony_ci	mask &= RFREG_MASK;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	val = rtw_read32_mask(rtwdev, direct_addr, mask);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	return val;
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_read_rf);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ciu32 rtw_phy_read_rf_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
91862306a36Sopenharmony_ci			 u32 addr, u32 mask)
91962306a36Sopenharmony_ci{
92062306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
92162306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
92262306a36Sopenharmony_ci	const struct rtw_rf_sipi_addr *rf_sipi_addr;
92362306a36Sopenharmony_ci	const struct rtw_rf_sipi_addr *rf_sipi_addr_a;
92462306a36Sopenharmony_ci	u32 val32;
92562306a36Sopenharmony_ci	u32 en_pi;
92662306a36Sopenharmony_ci	u32 r_addr;
92762306a36Sopenharmony_ci	u32 shift;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	if (rf_path >= hal->rf_phy_num) {
93062306a36Sopenharmony_ci		rtw_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
93162306a36Sopenharmony_ci		return INV_RF_DATA;
93262306a36Sopenharmony_ci	}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	if (!chip->rf_sipi_read_addr) {
93562306a36Sopenharmony_ci		rtw_err(rtwdev, "rf_sipi_read_addr isn't defined\n");
93662306a36Sopenharmony_ci		return INV_RF_DATA;
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	rf_sipi_addr = &chip->rf_sipi_read_addr[rf_path];
94062306a36Sopenharmony_ci	rf_sipi_addr_a = &chip->rf_sipi_read_addr[RF_PATH_A];
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	addr &= 0xff;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	val32 = rtw_read32(rtwdev, rf_sipi_addr->hssi_2);
94562306a36Sopenharmony_ci	val32 = (val32 & ~LSSI_READ_ADDR_MASK) | (addr << 23);
94662306a36Sopenharmony_ci	rtw_write32(rtwdev, rf_sipi_addr->hssi_2, val32);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	/* toggle read edge of path A */
94962306a36Sopenharmony_ci	val32 = rtw_read32(rtwdev, rf_sipi_addr_a->hssi_2);
95062306a36Sopenharmony_ci	rtw_write32(rtwdev, rf_sipi_addr_a->hssi_2, val32 & ~LSSI_READ_EDGE_MASK);
95162306a36Sopenharmony_ci	rtw_write32(rtwdev, rf_sipi_addr_a->hssi_2, val32 | LSSI_READ_EDGE_MASK);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	udelay(120);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	en_pi = rtw_read32_mask(rtwdev, rf_sipi_addr->hssi_1, BIT(8));
95662306a36Sopenharmony_ci	r_addr = en_pi ? rf_sipi_addr->lssi_read_pi : rf_sipi_addr->lssi_read;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	val32 = rtw_read32_mask(rtwdev, r_addr, LSSI_READ_DATA_MASK);
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	shift = __ffs(mask);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	return (val32 & mask) >> shift;
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_read_rf_sipi);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cibool rtw_phy_write_rf_reg_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
96762306a36Sopenharmony_ci			       u32 addr, u32 mask, u32 data)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
97062306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
97162306a36Sopenharmony_ci	const u32 *sipi_addr = chip->rf_sipi_addr;
97262306a36Sopenharmony_ci	u32 data_and_addr;
97362306a36Sopenharmony_ci	u32 old_data = 0;
97462306a36Sopenharmony_ci	u32 shift;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	if (rf_path >= hal->rf_phy_num) {
97762306a36Sopenharmony_ci		rtw_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
97862306a36Sopenharmony_ci		return false;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	addr &= 0xff;
98262306a36Sopenharmony_ci	mask &= RFREG_MASK;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	if (mask != RFREG_MASK) {
98562306a36Sopenharmony_ci		old_data = chip->ops->read_rf(rtwdev, rf_path, addr, RFREG_MASK);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		if (old_data == INV_RF_DATA) {
98862306a36Sopenharmony_ci			rtw_err(rtwdev, "Write fail, rf is disabled\n");
98962306a36Sopenharmony_ci			return false;
99062306a36Sopenharmony_ci		}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		shift = __ffs(mask);
99362306a36Sopenharmony_ci		data = ((old_data) & (~mask)) | (data << shift);
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	data_and_addr = ((addr << 20) | (data & 0x000fffff)) & 0x0fffffff;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	rtw_write32(rtwdev, sipi_addr[rf_path], data_and_addr);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	udelay(13);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	return true;
100362306a36Sopenharmony_ci}
100462306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_write_rf_reg_sipi);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_cibool rtw_phy_write_rf_reg(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
100762306a36Sopenharmony_ci			  u32 addr, u32 mask, u32 data)
100862306a36Sopenharmony_ci{
100962306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
101062306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
101162306a36Sopenharmony_ci	const u32 *base_addr = chip->rf_base_addr;
101262306a36Sopenharmony_ci	u32 direct_addr;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	if (rf_path >= hal->rf_phy_num) {
101562306a36Sopenharmony_ci		rtw_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
101662306a36Sopenharmony_ci		return false;
101762306a36Sopenharmony_ci	}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	addr &= 0xff;
102062306a36Sopenharmony_ci	direct_addr = base_addr[rf_path] + (addr << 2);
102162306a36Sopenharmony_ci	mask &= RFREG_MASK;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	rtw_write32_mask(rtwdev, direct_addr, mask, data);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	udelay(1);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return true;
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cibool rtw_phy_write_rf_reg_mix(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
103162306a36Sopenharmony_ci			      u32 addr, u32 mask, u32 data)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	if (addr != 0x00)
103462306a36Sopenharmony_ci		return rtw_phy_write_rf_reg(rtwdev, rf_path, addr, mask, data);
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	return rtw_phy_write_rf_reg_sipi(rtwdev, rf_path, addr, mask, data);
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_write_rf_reg_mix);
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_civoid rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
104362306a36Sopenharmony_ci	struct rtw_efuse *efuse = &rtwdev->efuse;
104462306a36Sopenharmony_ci	struct rtw_phy_cond cond = {0};
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	cond.cut = hal->cut_version ? hal->cut_version : 15;
104762306a36Sopenharmony_ci	cond.pkg = pkg ? pkg : 15;
104862306a36Sopenharmony_ci	cond.plat = 0x04;
104962306a36Sopenharmony_ci	cond.rfe = efuse->rfe_option;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	switch (rtw_hci_type(rtwdev)) {
105262306a36Sopenharmony_ci	case RTW_HCI_TYPE_USB:
105362306a36Sopenharmony_ci		cond.intf = INTF_USB;
105462306a36Sopenharmony_ci		break;
105562306a36Sopenharmony_ci	case RTW_HCI_TYPE_SDIO:
105662306a36Sopenharmony_ci		cond.intf = INTF_SDIO;
105762306a36Sopenharmony_ci		break;
105862306a36Sopenharmony_ci	case RTW_HCI_TYPE_PCIE:
105962306a36Sopenharmony_ci	default:
106062306a36Sopenharmony_ci		cond.intf = INTF_PCIE;
106162306a36Sopenharmony_ci		break;
106262306a36Sopenharmony_ci	}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	hal->phy_cond = cond;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	rtw_dbg(rtwdev, RTW_DBG_PHY, "phy cond=0x%08x\n", *((u32 *)&hal->phy_cond));
106762306a36Sopenharmony_ci}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_cistatic bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
107262306a36Sopenharmony_ci	struct rtw_phy_cond drv_cond = hal->phy_cond;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (cond.cut && cond.cut != drv_cond.cut)
107562306a36Sopenharmony_ci		return false;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	if (cond.pkg && cond.pkg != drv_cond.pkg)
107862306a36Sopenharmony_ci		return false;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	if (cond.intf && cond.intf != drv_cond.intf)
108162306a36Sopenharmony_ci		return false;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	if (cond.rfe != drv_cond.rfe)
108462306a36Sopenharmony_ci		return false;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	return true;
108762306a36Sopenharmony_ci}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_civoid rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
109062306a36Sopenharmony_ci{
109162306a36Sopenharmony_ci	const union phy_table_tile *p = tbl->data;
109262306a36Sopenharmony_ci	const union phy_table_tile *end = p + tbl->size / 2;
109362306a36Sopenharmony_ci	struct rtw_phy_cond pos_cond = {0};
109462306a36Sopenharmony_ci	bool is_matched = true, is_skipped = false;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(union phy_table_tile) != sizeof(struct phy_cfg_pair));
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	for (; p < end; p++) {
109962306a36Sopenharmony_ci		if (p->cond.pos) {
110062306a36Sopenharmony_ci			switch (p->cond.branch) {
110162306a36Sopenharmony_ci			case BRANCH_ENDIF:
110262306a36Sopenharmony_ci				is_matched = true;
110362306a36Sopenharmony_ci				is_skipped = false;
110462306a36Sopenharmony_ci				break;
110562306a36Sopenharmony_ci			case BRANCH_ELSE:
110662306a36Sopenharmony_ci				is_matched = is_skipped ? false : true;
110762306a36Sopenharmony_ci				break;
110862306a36Sopenharmony_ci			case BRANCH_IF:
110962306a36Sopenharmony_ci			case BRANCH_ELIF:
111062306a36Sopenharmony_ci			default:
111162306a36Sopenharmony_ci				pos_cond = p->cond;
111262306a36Sopenharmony_ci				break;
111362306a36Sopenharmony_ci			}
111462306a36Sopenharmony_ci		} else if (p->cond.neg) {
111562306a36Sopenharmony_ci			if (!is_skipped) {
111662306a36Sopenharmony_ci				if (check_positive(rtwdev, pos_cond)) {
111762306a36Sopenharmony_ci					is_matched = true;
111862306a36Sopenharmony_ci					is_skipped = true;
111962306a36Sopenharmony_ci				} else {
112062306a36Sopenharmony_ci					is_matched = false;
112162306a36Sopenharmony_ci					is_skipped = false;
112262306a36Sopenharmony_ci				}
112362306a36Sopenharmony_ci			} else {
112462306a36Sopenharmony_ci				is_matched = false;
112562306a36Sopenharmony_ci			}
112662306a36Sopenharmony_ci		} else if (is_matched) {
112762306a36Sopenharmony_ci			(*tbl->do_cfg)(rtwdev, tbl, p->cfg.addr, p->cfg.data);
112862306a36Sopenharmony_ci		}
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci}
113162306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_parse_tbl_phy_cond);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci#define bcd_to_dec_pwr_by_rate(val, i) bcd2bin(val >> (i * 8))
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_cistatic u8 tbl_to_dec_pwr_by_rate(struct rtw_dev *rtwdev, u32 hex, u8 i)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci	if (rtwdev->chip->is_pwr_by_rate_dec)
113862306a36Sopenharmony_ci		return bcd_to_dec_pwr_by_rate(hex, i);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	return (hex >> (i * 8)) & 0xFF;
114162306a36Sopenharmony_ci}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_cistatic void
114462306a36Sopenharmony_cirtw_phy_get_rate_values_of_txpwr_by_rate(struct rtw_dev *rtwdev,
114562306a36Sopenharmony_ci					 u32 addr, u32 mask, u32 val, u8 *rate,
114662306a36Sopenharmony_ci					 u8 *pwr_by_rate, u8 *rate_num)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	int i;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	switch (addr) {
115162306a36Sopenharmony_ci	case 0xE00:
115262306a36Sopenharmony_ci	case 0x830:
115362306a36Sopenharmony_ci		rate[0] = DESC_RATE6M;
115462306a36Sopenharmony_ci		rate[1] = DESC_RATE9M;
115562306a36Sopenharmony_ci		rate[2] = DESC_RATE12M;
115662306a36Sopenharmony_ci		rate[3] = DESC_RATE18M;
115762306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
115862306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
115962306a36Sopenharmony_ci		*rate_num = 4;
116062306a36Sopenharmony_ci		break;
116162306a36Sopenharmony_ci	case 0xE04:
116262306a36Sopenharmony_ci	case 0x834:
116362306a36Sopenharmony_ci		rate[0] = DESC_RATE24M;
116462306a36Sopenharmony_ci		rate[1] = DESC_RATE36M;
116562306a36Sopenharmony_ci		rate[2] = DESC_RATE48M;
116662306a36Sopenharmony_ci		rate[3] = DESC_RATE54M;
116762306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
116862306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
116962306a36Sopenharmony_ci		*rate_num = 4;
117062306a36Sopenharmony_ci		break;
117162306a36Sopenharmony_ci	case 0xE08:
117262306a36Sopenharmony_ci		rate[0] = DESC_RATE1M;
117362306a36Sopenharmony_ci		pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 1);
117462306a36Sopenharmony_ci		*rate_num = 1;
117562306a36Sopenharmony_ci		break;
117662306a36Sopenharmony_ci	case 0x86C:
117762306a36Sopenharmony_ci		if (mask == 0xffffff00) {
117862306a36Sopenharmony_ci			rate[0] = DESC_RATE2M;
117962306a36Sopenharmony_ci			rate[1] = DESC_RATE5_5M;
118062306a36Sopenharmony_ci			rate[2] = DESC_RATE11M;
118162306a36Sopenharmony_ci			for (i = 1; i < 4; ++i)
118262306a36Sopenharmony_ci				pwr_by_rate[i - 1] =
118362306a36Sopenharmony_ci					tbl_to_dec_pwr_by_rate(rtwdev, val, i);
118462306a36Sopenharmony_ci			*rate_num = 3;
118562306a36Sopenharmony_ci		} else if (mask == 0x000000ff) {
118662306a36Sopenharmony_ci			rate[0] = DESC_RATE11M;
118762306a36Sopenharmony_ci			pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 0);
118862306a36Sopenharmony_ci			*rate_num = 1;
118962306a36Sopenharmony_ci		}
119062306a36Sopenharmony_ci		break;
119162306a36Sopenharmony_ci	case 0xE10:
119262306a36Sopenharmony_ci	case 0x83C:
119362306a36Sopenharmony_ci		rate[0] = DESC_RATEMCS0;
119462306a36Sopenharmony_ci		rate[1] = DESC_RATEMCS1;
119562306a36Sopenharmony_ci		rate[2] = DESC_RATEMCS2;
119662306a36Sopenharmony_ci		rate[3] = DESC_RATEMCS3;
119762306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
119862306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
119962306a36Sopenharmony_ci		*rate_num = 4;
120062306a36Sopenharmony_ci		break;
120162306a36Sopenharmony_ci	case 0xE14:
120262306a36Sopenharmony_ci	case 0x848:
120362306a36Sopenharmony_ci		rate[0] = DESC_RATEMCS4;
120462306a36Sopenharmony_ci		rate[1] = DESC_RATEMCS5;
120562306a36Sopenharmony_ci		rate[2] = DESC_RATEMCS6;
120662306a36Sopenharmony_ci		rate[3] = DESC_RATEMCS7;
120762306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
120862306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
120962306a36Sopenharmony_ci		*rate_num = 4;
121062306a36Sopenharmony_ci		break;
121162306a36Sopenharmony_ci	case 0xE18:
121262306a36Sopenharmony_ci	case 0x84C:
121362306a36Sopenharmony_ci		rate[0] = DESC_RATEMCS8;
121462306a36Sopenharmony_ci		rate[1] = DESC_RATEMCS9;
121562306a36Sopenharmony_ci		rate[2] = DESC_RATEMCS10;
121662306a36Sopenharmony_ci		rate[3] = DESC_RATEMCS11;
121762306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
121862306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
121962306a36Sopenharmony_ci		*rate_num = 4;
122062306a36Sopenharmony_ci		break;
122162306a36Sopenharmony_ci	case 0xE1C:
122262306a36Sopenharmony_ci	case 0x868:
122362306a36Sopenharmony_ci		rate[0] = DESC_RATEMCS12;
122462306a36Sopenharmony_ci		rate[1] = DESC_RATEMCS13;
122562306a36Sopenharmony_ci		rate[2] = DESC_RATEMCS14;
122662306a36Sopenharmony_ci		rate[3] = DESC_RATEMCS15;
122762306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
122862306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
122962306a36Sopenharmony_ci		*rate_num = 4;
123062306a36Sopenharmony_ci		break;
123162306a36Sopenharmony_ci	case 0x838:
123262306a36Sopenharmony_ci		rate[0] = DESC_RATE1M;
123362306a36Sopenharmony_ci		rate[1] = DESC_RATE2M;
123462306a36Sopenharmony_ci		rate[2] = DESC_RATE5_5M;
123562306a36Sopenharmony_ci		for (i = 1; i < 4; ++i)
123662306a36Sopenharmony_ci			pwr_by_rate[i - 1] = tbl_to_dec_pwr_by_rate(rtwdev,
123762306a36Sopenharmony_ci								    val, i);
123862306a36Sopenharmony_ci		*rate_num = 3;
123962306a36Sopenharmony_ci		break;
124062306a36Sopenharmony_ci	case 0xC20:
124162306a36Sopenharmony_ci	case 0xE20:
124262306a36Sopenharmony_ci	case 0x1820:
124362306a36Sopenharmony_ci	case 0x1A20:
124462306a36Sopenharmony_ci		rate[0] = DESC_RATE1M;
124562306a36Sopenharmony_ci		rate[1] = DESC_RATE2M;
124662306a36Sopenharmony_ci		rate[2] = DESC_RATE5_5M;
124762306a36Sopenharmony_ci		rate[3] = DESC_RATE11M;
124862306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
124962306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
125062306a36Sopenharmony_ci		*rate_num = 4;
125162306a36Sopenharmony_ci		break;
125262306a36Sopenharmony_ci	case 0xC24:
125362306a36Sopenharmony_ci	case 0xE24:
125462306a36Sopenharmony_ci	case 0x1824:
125562306a36Sopenharmony_ci	case 0x1A24:
125662306a36Sopenharmony_ci		rate[0] = DESC_RATE6M;
125762306a36Sopenharmony_ci		rate[1] = DESC_RATE9M;
125862306a36Sopenharmony_ci		rate[2] = DESC_RATE12M;
125962306a36Sopenharmony_ci		rate[3] = DESC_RATE18M;
126062306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
126162306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
126262306a36Sopenharmony_ci		*rate_num = 4;
126362306a36Sopenharmony_ci		break;
126462306a36Sopenharmony_ci	case 0xC28:
126562306a36Sopenharmony_ci	case 0xE28:
126662306a36Sopenharmony_ci	case 0x1828:
126762306a36Sopenharmony_ci	case 0x1A28:
126862306a36Sopenharmony_ci		rate[0] = DESC_RATE24M;
126962306a36Sopenharmony_ci		rate[1] = DESC_RATE36M;
127062306a36Sopenharmony_ci		rate[2] = DESC_RATE48M;
127162306a36Sopenharmony_ci		rate[3] = DESC_RATE54M;
127262306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
127362306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
127462306a36Sopenharmony_ci		*rate_num = 4;
127562306a36Sopenharmony_ci		break;
127662306a36Sopenharmony_ci	case 0xC2C:
127762306a36Sopenharmony_ci	case 0xE2C:
127862306a36Sopenharmony_ci	case 0x182C:
127962306a36Sopenharmony_ci	case 0x1A2C:
128062306a36Sopenharmony_ci		rate[0] = DESC_RATEMCS0;
128162306a36Sopenharmony_ci		rate[1] = DESC_RATEMCS1;
128262306a36Sopenharmony_ci		rate[2] = DESC_RATEMCS2;
128362306a36Sopenharmony_ci		rate[3] = DESC_RATEMCS3;
128462306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
128562306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
128662306a36Sopenharmony_ci		*rate_num = 4;
128762306a36Sopenharmony_ci		break;
128862306a36Sopenharmony_ci	case 0xC30:
128962306a36Sopenharmony_ci	case 0xE30:
129062306a36Sopenharmony_ci	case 0x1830:
129162306a36Sopenharmony_ci	case 0x1A30:
129262306a36Sopenharmony_ci		rate[0] = DESC_RATEMCS4;
129362306a36Sopenharmony_ci		rate[1] = DESC_RATEMCS5;
129462306a36Sopenharmony_ci		rate[2] = DESC_RATEMCS6;
129562306a36Sopenharmony_ci		rate[3] = DESC_RATEMCS7;
129662306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
129762306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
129862306a36Sopenharmony_ci		*rate_num = 4;
129962306a36Sopenharmony_ci		break;
130062306a36Sopenharmony_ci	case 0xC34:
130162306a36Sopenharmony_ci	case 0xE34:
130262306a36Sopenharmony_ci	case 0x1834:
130362306a36Sopenharmony_ci	case 0x1A34:
130462306a36Sopenharmony_ci		rate[0] = DESC_RATEMCS8;
130562306a36Sopenharmony_ci		rate[1] = DESC_RATEMCS9;
130662306a36Sopenharmony_ci		rate[2] = DESC_RATEMCS10;
130762306a36Sopenharmony_ci		rate[3] = DESC_RATEMCS11;
130862306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
130962306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
131062306a36Sopenharmony_ci		*rate_num = 4;
131162306a36Sopenharmony_ci		break;
131262306a36Sopenharmony_ci	case 0xC38:
131362306a36Sopenharmony_ci	case 0xE38:
131462306a36Sopenharmony_ci	case 0x1838:
131562306a36Sopenharmony_ci	case 0x1A38:
131662306a36Sopenharmony_ci		rate[0] = DESC_RATEMCS12;
131762306a36Sopenharmony_ci		rate[1] = DESC_RATEMCS13;
131862306a36Sopenharmony_ci		rate[2] = DESC_RATEMCS14;
131962306a36Sopenharmony_ci		rate[3] = DESC_RATEMCS15;
132062306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
132162306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
132262306a36Sopenharmony_ci		*rate_num = 4;
132362306a36Sopenharmony_ci		break;
132462306a36Sopenharmony_ci	case 0xC3C:
132562306a36Sopenharmony_ci	case 0xE3C:
132662306a36Sopenharmony_ci	case 0x183C:
132762306a36Sopenharmony_ci	case 0x1A3C:
132862306a36Sopenharmony_ci		rate[0] = DESC_RATEVHT1SS_MCS0;
132962306a36Sopenharmony_ci		rate[1] = DESC_RATEVHT1SS_MCS1;
133062306a36Sopenharmony_ci		rate[2] = DESC_RATEVHT1SS_MCS2;
133162306a36Sopenharmony_ci		rate[3] = DESC_RATEVHT1SS_MCS3;
133262306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
133362306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
133462306a36Sopenharmony_ci		*rate_num = 4;
133562306a36Sopenharmony_ci		break;
133662306a36Sopenharmony_ci	case 0xC40:
133762306a36Sopenharmony_ci	case 0xE40:
133862306a36Sopenharmony_ci	case 0x1840:
133962306a36Sopenharmony_ci	case 0x1A40:
134062306a36Sopenharmony_ci		rate[0] = DESC_RATEVHT1SS_MCS4;
134162306a36Sopenharmony_ci		rate[1] = DESC_RATEVHT1SS_MCS5;
134262306a36Sopenharmony_ci		rate[2] = DESC_RATEVHT1SS_MCS6;
134362306a36Sopenharmony_ci		rate[3] = DESC_RATEVHT1SS_MCS7;
134462306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
134562306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
134662306a36Sopenharmony_ci		*rate_num = 4;
134762306a36Sopenharmony_ci		break;
134862306a36Sopenharmony_ci	case 0xC44:
134962306a36Sopenharmony_ci	case 0xE44:
135062306a36Sopenharmony_ci	case 0x1844:
135162306a36Sopenharmony_ci	case 0x1A44:
135262306a36Sopenharmony_ci		rate[0] = DESC_RATEVHT1SS_MCS8;
135362306a36Sopenharmony_ci		rate[1] = DESC_RATEVHT1SS_MCS9;
135462306a36Sopenharmony_ci		rate[2] = DESC_RATEVHT2SS_MCS0;
135562306a36Sopenharmony_ci		rate[3] = DESC_RATEVHT2SS_MCS1;
135662306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
135762306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
135862306a36Sopenharmony_ci		*rate_num = 4;
135962306a36Sopenharmony_ci		break;
136062306a36Sopenharmony_ci	case 0xC48:
136162306a36Sopenharmony_ci	case 0xE48:
136262306a36Sopenharmony_ci	case 0x1848:
136362306a36Sopenharmony_ci	case 0x1A48:
136462306a36Sopenharmony_ci		rate[0] = DESC_RATEVHT2SS_MCS2;
136562306a36Sopenharmony_ci		rate[1] = DESC_RATEVHT2SS_MCS3;
136662306a36Sopenharmony_ci		rate[2] = DESC_RATEVHT2SS_MCS4;
136762306a36Sopenharmony_ci		rate[3] = DESC_RATEVHT2SS_MCS5;
136862306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
136962306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
137062306a36Sopenharmony_ci		*rate_num = 4;
137162306a36Sopenharmony_ci		break;
137262306a36Sopenharmony_ci	case 0xC4C:
137362306a36Sopenharmony_ci	case 0xE4C:
137462306a36Sopenharmony_ci	case 0x184C:
137562306a36Sopenharmony_ci	case 0x1A4C:
137662306a36Sopenharmony_ci		rate[0] = DESC_RATEVHT2SS_MCS6;
137762306a36Sopenharmony_ci		rate[1] = DESC_RATEVHT2SS_MCS7;
137862306a36Sopenharmony_ci		rate[2] = DESC_RATEVHT2SS_MCS8;
137962306a36Sopenharmony_ci		rate[3] = DESC_RATEVHT2SS_MCS9;
138062306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
138162306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
138262306a36Sopenharmony_ci		*rate_num = 4;
138362306a36Sopenharmony_ci		break;
138462306a36Sopenharmony_ci	case 0xCD8:
138562306a36Sopenharmony_ci	case 0xED8:
138662306a36Sopenharmony_ci	case 0x18D8:
138762306a36Sopenharmony_ci	case 0x1AD8:
138862306a36Sopenharmony_ci		rate[0] = DESC_RATEMCS16;
138962306a36Sopenharmony_ci		rate[1] = DESC_RATEMCS17;
139062306a36Sopenharmony_ci		rate[2] = DESC_RATEMCS18;
139162306a36Sopenharmony_ci		rate[3] = DESC_RATEMCS19;
139262306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
139362306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
139462306a36Sopenharmony_ci		*rate_num = 4;
139562306a36Sopenharmony_ci		break;
139662306a36Sopenharmony_ci	case 0xCDC:
139762306a36Sopenharmony_ci	case 0xEDC:
139862306a36Sopenharmony_ci	case 0x18DC:
139962306a36Sopenharmony_ci	case 0x1ADC:
140062306a36Sopenharmony_ci		rate[0] = DESC_RATEMCS20;
140162306a36Sopenharmony_ci		rate[1] = DESC_RATEMCS21;
140262306a36Sopenharmony_ci		rate[2] = DESC_RATEMCS22;
140362306a36Sopenharmony_ci		rate[3] = DESC_RATEMCS23;
140462306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
140562306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
140662306a36Sopenharmony_ci		*rate_num = 4;
140762306a36Sopenharmony_ci		break;
140862306a36Sopenharmony_ci	case 0xCE0:
140962306a36Sopenharmony_ci	case 0xEE0:
141062306a36Sopenharmony_ci	case 0x18E0:
141162306a36Sopenharmony_ci	case 0x1AE0:
141262306a36Sopenharmony_ci		rate[0] = DESC_RATEVHT3SS_MCS0;
141362306a36Sopenharmony_ci		rate[1] = DESC_RATEVHT3SS_MCS1;
141462306a36Sopenharmony_ci		rate[2] = DESC_RATEVHT3SS_MCS2;
141562306a36Sopenharmony_ci		rate[3] = DESC_RATEVHT3SS_MCS3;
141662306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
141762306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
141862306a36Sopenharmony_ci		*rate_num = 4;
141962306a36Sopenharmony_ci		break;
142062306a36Sopenharmony_ci	case 0xCE4:
142162306a36Sopenharmony_ci	case 0xEE4:
142262306a36Sopenharmony_ci	case 0x18E4:
142362306a36Sopenharmony_ci	case 0x1AE4:
142462306a36Sopenharmony_ci		rate[0] = DESC_RATEVHT3SS_MCS4;
142562306a36Sopenharmony_ci		rate[1] = DESC_RATEVHT3SS_MCS5;
142662306a36Sopenharmony_ci		rate[2] = DESC_RATEVHT3SS_MCS6;
142762306a36Sopenharmony_ci		rate[3] = DESC_RATEVHT3SS_MCS7;
142862306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
142962306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
143062306a36Sopenharmony_ci		*rate_num = 4;
143162306a36Sopenharmony_ci		break;
143262306a36Sopenharmony_ci	case 0xCE8:
143362306a36Sopenharmony_ci	case 0xEE8:
143462306a36Sopenharmony_ci	case 0x18E8:
143562306a36Sopenharmony_ci	case 0x1AE8:
143662306a36Sopenharmony_ci		rate[0] = DESC_RATEVHT3SS_MCS8;
143762306a36Sopenharmony_ci		rate[1] = DESC_RATEVHT3SS_MCS9;
143862306a36Sopenharmony_ci		for (i = 0; i < 2; ++i)
143962306a36Sopenharmony_ci			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
144062306a36Sopenharmony_ci		*rate_num = 2;
144162306a36Sopenharmony_ci		break;
144262306a36Sopenharmony_ci	default:
144362306a36Sopenharmony_ci		rtw_warn(rtwdev, "invalid tx power index addr 0x%08x\n", addr);
144462306a36Sopenharmony_ci		break;
144562306a36Sopenharmony_ci	}
144662306a36Sopenharmony_ci}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_cistatic void rtw_phy_store_tx_power_by_rate(struct rtw_dev *rtwdev,
144962306a36Sopenharmony_ci					   u32 band, u32 rfpath, u32 txnum,
145062306a36Sopenharmony_ci					   u32 regaddr, u32 bitmask, u32 data)
145162306a36Sopenharmony_ci{
145262306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
145362306a36Sopenharmony_ci	u8 rate_num = 0;
145462306a36Sopenharmony_ci	u8 rate;
145562306a36Sopenharmony_ci	u8 rates[RTW_RF_PATH_MAX] = {0};
145662306a36Sopenharmony_ci	s8 offset;
145762306a36Sopenharmony_ci	s8 pwr_by_rate[RTW_RF_PATH_MAX] = {0};
145862306a36Sopenharmony_ci	int i;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	rtw_phy_get_rate_values_of_txpwr_by_rate(rtwdev, regaddr, bitmask, data,
146162306a36Sopenharmony_ci						 rates, pwr_by_rate, &rate_num);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	if (WARN_ON(rfpath >= RTW_RF_PATH_MAX ||
146462306a36Sopenharmony_ci		    (band != PHY_BAND_2G && band != PHY_BAND_5G) ||
146562306a36Sopenharmony_ci		    rate_num > RTW_RF_PATH_MAX))
146662306a36Sopenharmony_ci		return;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	for (i = 0; i < rate_num; i++) {
146962306a36Sopenharmony_ci		offset = pwr_by_rate[i];
147062306a36Sopenharmony_ci		rate = rates[i];
147162306a36Sopenharmony_ci		if (band == PHY_BAND_2G)
147262306a36Sopenharmony_ci			hal->tx_pwr_by_rate_offset_2g[rfpath][rate] = offset;
147362306a36Sopenharmony_ci		else if (band == PHY_BAND_5G)
147462306a36Sopenharmony_ci			hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset;
147562306a36Sopenharmony_ci		else
147662306a36Sopenharmony_ci			continue;
147762306a36Sopenharmony_ci	}
147862306a36Sopenharmony_ci}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_civoid rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
148162306a36Sopenharmony_ci{
148262306a36Sopenharmony_ci	const struct rtw_phy_pg_cfg_pair *p = tbl->data;
148362306a36Sopenharmony_ci	const struct rtw_phy_pg_cfg_pair *end = p + tbl->size;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	for (; p < end; p++) {
148662306a36Sopenharmony_ci		if (p->addr == 0xfe || p->addr == 0xffe) {
148762306a36Sopenharmony_ci			msleep(50);
148862306a36Sopenharmony_ci			continue;
148962306a36Sopenharmony_ci		}
149062306a36Sopenharmony_ci		rtw_phy_store_tx_power_by_rate(rtwdev, p->band, p->rf_path,
149162306a36Sopenharmony_ci					       p->tx_num, p->addr, p->bitmask,
149262306a36Sopenharmony_ci					       p->data);
149362306a36Sopenharmony_ci	}
149462306a36Sopenharmony_ci}
149562306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_parse_tbl_bb_pg);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_cistatic const u8 rtw_channel_idx_5g[RTW_MAX_CHANNEL_NUM_5G] = {
149862306a36Sopenharmony_ci	36,  38,  40,  42,  44,  46,  48, /* Band 1 */
149962306a36Sopenharmony_ci	52,  54,  56,  58,  60,  62,  64, /* Band 2 */
150062306a36Sopenharmony_ci	100, 102, 104, 106, 108, 110, 112, /* Band 3 */
150162306a36Sopenharmony_ci	116, 118, 120, 122, 124, 126, 128, /* Band 3 */
150262306a36Sopenharmony_ci	132, 134, 136, 138, 140, 142, 144, /* Band 3 */
150362306a36Sopenharmony_ci	149, 151, 153, 155, 157, 159, 161, /* Band 4 */
150462306a36Sopenharmony_ci	165, 167, 169, 171, 173, 175, 177}; /* Band 4 */
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_cistatic int rtw_channel_to_idx(u8 band, u8 channel)
150762306a36Sopenharmony_ci{
150862306a36Sopenharmony_ci	int ch_idx;
150962306a36Sopenharmony_ci	u8 n_channel;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	if (band == PHY_BAND_2G) {
151262306a36Sopenharmony_ci		ch_idx = channel - 1;
151362306a36Sopenharmony_ci		n_channel = RTW_MAX_CHANNEL_NUM_2G;
151462306a36Sopenharmony_ci	} else if (band == PHY_BAND_5G) {
151562306a36Sopenharmony_ci		n_channel = RTW_MAX_CHANNEL_NUM_5G;
151662306a36Sopenharmony_ci		for (ch_idx = 0; ch_idx < n_channel; ch_idx++)
151762306a36Sopenharmony_ci			if (rtw_channel_idx_5g[ch_idx] == channel)
151862306a36Sopenharmony_ci				break;
151962306a36Sopenharmony_ci	} else {
152062306a36Sopenharmony_ci		return -1;
152162306a36Sopenharmony_ci	}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	if (ch_idx >= n_channel)
152462306a36Sopenharmony_ci		return -1;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	return ch_idx;
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cistatic void rtw_phy_set_tx_power_limit(struct rtw_dev *rtwdev, u8 regd, u8 band,
153062306a36Sopenharmony_ci				       u8 bw, u8 rs, u8 ch, s8 pwr_limit)
153162306a36Sopenharmony_ci{
153262306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
153362306a36Sopenharmony_ci	u8 max_power_index = rtwdev->chip->max_power_index;
153462306a36Sopenharmony_ci	s8 ww;
153562306a36Sopenharmony_ci	int ch_idx;
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	pwr_limit = clamp_t(s8, pwr_limit,
153862306a36Sopenharmony_ci			    -max_power_index, max_power_index);
153962306a36Sopenharmony_ci	ch_idx = rtw_channel_to_idx(band, ch);
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	if (regd >= RTW_REGD_MAX || bw >= RTW_CHANNEL_WIDTH_MAX ||
154262306a36Sopenharmony_ci	    rs >= RTW_RATE_SECTION_MAX || ch_idx < 0) {
154362306a36Sopenharmony_ci		WARN(1,
154462306a36Sopenharmony_ci		     "wrong txpwr_lmt regd=%u, band=%u bw=%u, rs=%u, ch_idx=%u, pwr_limit=%d\n",
154562306a36Sopenharmony_ci		     regd, band, bw, rs, ch_idx, pwr_limit);
154662306a36Sopenharmony_ci		return;
154762306a36Sopenharmony_ci	}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	if (band == PHY_BAND_2G) {
155062306a36Sopenharmony_ci		hal->tx_pwr_limit_2g[regd][bw][rs][ch_idx] = pwr_limit;
155162306a36Sopenharmony_ci		ww = hal->tx_pwr_limit_2g[RTW_REGD_WW][bw][rs][ch_idx];
155262306a36Sopenharmony_ci		ww = min_t(s8, ww, pwr_limit);
155362306a36Sopenharmony_ci		hal->tx_pwr_limit_2g[RTW_REGD_WW][bw][rs][ch_idx] = ww;
155462306a36Sopenharmony_ci	} else if (band == PHY_BAND_5G) {
155562306a36Sopenharmony_ci		hal->tx_pwr_limit_5g[regd][bw][rs][ch_idx] = pwr_limit;
155662306a36Sopenharmony_ci		ww = hal->tx_pwr_limit_5g[RTW_REGD_WW][bw][rs][ch_idx];
155762306a36Sopenharmony_ci		ww = min_t(s8, ww, pwr_limit);
155862306a36Sopenharmony_ci		hal->tx_pwr_limit_5g[RTW_REGD_WW][bw][rs][ch_idx] = ww;
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci/* cross-reference 5G power limits if values are not assigned */
156362306a36Sopenharmony_cistatic void
156462306a36Sopenharmony_cirtw_xref_5g_txpwr_lmt(struct rtw_dev *rtwdev, u8 regd,
156562306a36Sopenharmony_ci		      u8 bw, u8 ch_idx, u8 rs_ht, u8 rs_vht)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
156862306a36Sopenharmony_ci	u8 max_power_index = rtwdev->chip->max_power_index;
156962306a36Sopenharmony_ci	s8 lmt_ht = hal->tx_pwr_limit_5g[regd][bw][rs_ht][ch_idx];
157062306a36Sopenharmony_ci	s8 lmt_vht = hal->tx_pwr_limit_5g[regd][bw][rs_vht][ch_idx];
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	if (lmt_ht == lmt_vht)
157362306a36Sopenharmony_ci		return;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	if (lmt_ht == max_power_index)
157662306a36Sopenharmony_ci		hal->tx_pwr_limit_5g[regd][bw][rs_ht][ch_idx] = lmt_vht;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	else if (lmt_vht == max_power_index)
157962306a36Sopenharmony_ci		hal->tx_pwr_limit_5g[regd][bw][rs_vht][ch_idx] = lmt_ht;
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci/* cross-reference power limits for ht and vht */
158362306a36Sopenharmony_cistatic void
158462306a36Sopenharmony_cirtw_xref_txpwr_lmt_by_rs(struct rtw_dev *rtwdev, u8 regd, u8 bw, u8 ch_idx)
158562306a36Sopenharmony_ci{
158662306a36Sopenharmony_ci	u8 rs_idx, rs_ht, rs_vht;
158762306a36Sopenharmony_ci	u8 rs_cmp[2][2] = {{RTW_RATE_SECTION_HT_1S, RTW_RATE_SECTION_VHT_1S},
158862306a36Sopenharmony_ci			   {RTW_RATE_SECTION_HT_2S, RTW_RATE_SECTION_VHT_2S} };
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	for (rs_idx = 0; rs_idx < 2; rs_idx++) {
159162306a36Sopenharmony_ci		rs_ht = rs_cmp[rs_idx][0];
159262306a36Sopenharmony_ci		rs_vht = rs_cmp[rs_idx][1];
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci		rtw_xref_5g_txpwr_lmt(rtwdev, regd, bw, ch_idx, rs_ht, rs_vht);
159562306a36Sopenharmony_ci	}
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci/* cross-reference power limits for 5G channels */
159962306a36Sopenharmony_cistatic void
160062306a36Sopenharmony_cirtw_xref_5g_txpwr_lmt_by_ch(struct rtw_dev *rtwdev, u8 regd, u8 bw)
160162306a36Sopenharmony_ci{
160262306a36Sopenharmony_ci	u8 ch_idx;
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	for (ch_idx = 0; ch_idx < RTW_MAX_CHANNEL_NUM_5G; ch_idx++)
160562306a36Sopenharmony_ci		rtw_xref_txpwr_lmt_by_rs(rtwdev, regd, bw, ch_idx);
160662306a36Sopenharmony_ci}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci/* cross-reference power limits for 20/40M bandwidth */
160962306a36Sopenharmony_cistatic void
161062306a36Sopenharmony_cirtw_xref_txpwr_lmt_by_bw(struct rtw_dev *rtwdev, u8 regd)
161162306a36Sopenharmony_ci{
161262306a36Sopenharmony_ci	u8 bw;
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	for (bw = RTW_CHANNEL_WIDTH_20; bw <= RTW_CHANNEL_WIDTH_40; bw++)
161562306a36Sopenharmony_ci		rtw_xref_5g_txpwr_lmt_by_ch(rtwdev, regd, bw);
161662306a36Sopenharmony_ci}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci/* cross-reference power limits */
161962306a36Sopenharmony_cistatic void rtw_xref_txpwr_lmt(struct rtw_dev *rtwdev)
162062306a36Sopenharmony_ci{
162162306a36Sopenharmony_ci	u8 regd;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	for (regd = 0; regd < RTW_REGD_MAX; regd++)
162462306a36Sopenharmony_ci		rtw_xref_txpwr_lmt_by_bw(rtwdev, regd);
162562306a36Sopenharmony_ci}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_cistatic void
162862306a36Sopenharmony_ci__cfg_txpwr_lmt_by_alt(struct rtw_hal *hal, u8 regd, u8 regd_alt, u8 bw, u8 rs)
162962306a36Sopenharmony_ci{
163062306a36Sopenharmony_ci	u8 ch;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_2G; ch++)
163362306a36Sopenharmony_ci		hal->tx_pwr_limit_2g[regd][bw][rs][ch] =
163462306a36Sopenharmony_ci			hal->tx_pwr_limit_2g[regd_alt][bw][rs][ch];
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_5G; ch++)
163762306a36Sopenharmony_ci		hal->tx_pwr_limit_5g[regd][bw][rs][ch] =
163862306a36Sopenharmony_ci			hal->tx_pwr_limit_5g[regd_alt][bw][rs][ch];
163962306a36Sopenharmony_ci}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_cistatic void
164262306a36Sopenharmony_cirtw_cfg_txpwr_lmt_by_alt(struct rtw_dev *rtwdev, u8 regd, u8 regd_alt)
164362306a36Sopenharmony_ci{
164462306a36Sopenharmony_ci	u8 bw, rs;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	for (bw = 0; bw < RTW_CHANNEL_WIDTH_MAX; bw++)
164762306a36Sopenharmony_ci		for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++)
164862306a36Sopenharmony_ci			__cfg_txpwr_lmt_by_alt(&rtwdev->hal, regd, regd_alt,
164962306a36Sopenharmony_ci					       bw, rs);
165062306a36Sopenharmony_ci}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_civoid rtw_parse_tbl_txpwr_lmt(struct rtw_dev *rtwdev,
165362306a36Sopenharmony_ci			     const struct rtw_table *tbl)
165462306a36Sopenharmony_ci{
165562306a36Sopenharmony_ci	const struct rtw_txpwr_lmt_cfg_pair *p = tbl->data;
165662306a36Sopenharmony_ci	const struct rtw_txpwr_lmt_cfg_pair *end = p + tbl->size;
165762306a36Sopenharmony_ci	u32 regd_cfg_flag = 0;
165862306a36Sopenharmony_ci	u8 regd_alt;
165962306a36Sopenharmony_ci	u8 i;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	for (; p < end; p++) {
166262306a36Sopenharmony_ci		regd_cfg_flag |= BIT(p->regd);
166362306a36Sopenharmony_ci		rtw_phy_set_tx_power_limit(rtwdev, p->regd, p->band,
166462306a36Sopenharmony_ci					   p->bw, p->rs, p->ch, p->txpwr_lmt);
166562306a36Sopenharmony_ci	}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	for (i = 0; i < RTW_REGD_MAX; i++) {
166862306a36Sopenharmony_ci		if (i == RTW_REGD_WW)
166962306a36Sopenharmony_ci			continue;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci		if (regd_cfg_flag & BIT(i))
167262306a36Sopenharmony_ci			continue;
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci		rtw_dbg(rtwdev, RTW_DBG_REGD,
167562306a36Sopenharmony_ci			"txpwr regd %d does not be configured\n", i);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci		if (rtw_regd_has_alt(i, &regd_alt) &&
167862306a36Sopenharmony_ci		    regd_cfg_flag & BIT(regd_alt)) {
167962306a36Sopenharmony_ci			rtw_dbg(rtwdev, RTW_DBG_REGD,
168062306a36Sopenharmony_ci				"cfg txpwr regd %d by regd %d as alternative\n",
168162306a36Sopenharmony_ci				i, regd_alt);
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci			rtw_cfg_txpwr_lmt_by_alt(rtwdev, i, regd_alt);
168462306a36Sopenharmony_ci			continue;
168562306a36Sopenharmony_ci		}
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci		rtw_dbg(rtwdev, RTW_DBG_REGD, "cfg txpwr regd %d by WW\n", i);
168862306a36Sopenharmony_ci		rtw_cfg_txpwr_lmt_by_alt(rtwdev, i, RTW_REGD_WW);
168962306a36Sopenharmony_ci	}
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	rtw_xref_txpwr_lmt(rtwdev);
169262306a36Sopenharmony_ci}
169362306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_parse_tbl_txpwr_lmt);
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_civoid rtw_phy_cfg_mac(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
169662306a36Sopenharmony_ci		     u32 addr, u32 data)
169762306a36Sopenharmony_ci{
169862306a36Sopenharmony_ci	rtw_write8(rtwdev, addr, data);
169962306a36Sopenharmony_ci}
170062306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_cfg_mac);
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_civoid rtw_phy_cfg_agc(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
170362306a36Sopenharmony_ci		     u32 addr, u32 data)
170462306a36Sopenharmony_ci{
170562306a36Sopenharmony_ci	rtw_write32(rtwdev, addr, data);
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_cfg_agc);
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_civoid rtw_phy_cfg_bb(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
171062306a36Sopenharmony_ci		    u32 addr, u32 data)
171162306a36Sopenharmony_ci{
171262306a36Sopenharmony_ci	if (addr == 0xfe)
171362306a36Sopenharmony_ci		msleep(50);
171462306a36Sopenharmony_ci	else if (addr == 0xfd)
171562306a36Sopenharmony_ci		mdelay(5);
171662306a36Sopenharmony_ci	else if (addr == 0xfc)
171762306a36Sopenharmony_ci		mdelay(1);
171862306a36Sopenharmony_ci	else if (addr == 0xfb)
171962306a36Sopenharmony_ci		usleep_range(50, 60);
172062306a36Sopenharmony_ci	else if (addr == 0xfa)
172162306a36Sopenharmony_ci		udelay(5);
172262306a36Sopenharmony_ci	else if (addr == 0xf9)
172362306a36Sopenharmony_ci		udelay(1);
172462306a36Sopenharmony_ci	else
172562306a36Sopenharmony_ci		rtw_write32(rtwdev, addr, data);
172662306a36Sopenharmony_ci}
172762306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_cfg_bb);
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_civoid rtw_phy_cfg_rf(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
173062306a36Sopenharmony_ci		    u32 addr, u32 data)
173162306a36Sopenharmony_ci{
173262306a36Sopenharmony_ci	if (addr == 0xffe) {
173362306a36Sopenharmony_ci		msleep(50);
173462306a36Sopenharmony_ci	} else if (addr == 0xfe) {
173562306a36Sopenharmony_ci		usleep_range(100, 110);
173662306a36Sopenharmony_ci	} else {
173762306a36Sopenharmony_ci		rtw_write_rf(rtwdev, tbl->rf_path, addr, RFREG_MASK, data);
173862306a36Sopenharmony_ci		udelay(1);
173962306a36Sopenharmony_ci	}
174062306a36Sopenharmony_ci}
174162306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_cfg_rf);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_cistatic void rtw_load_rfk_table(struct rtw_dev *rtwdev)
174462306a36Sopenharmony_ci{
174562306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
174662306a36Sopenharmony_ci	struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	if (!chip->rfk_init_tbl)
174962306a36Sopenharmony_ci		return;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	rtw_write32_mask(rtwdev, 0x1e24, BIT(17), 0x1);
175262306a36Sopenharmony_ci	rtw_write32_mask(rtwdev, 0x1cd0, BIT(28), 0x1);
175362306a36Sopenharmony_ci	rtw_write32_mask(rtwdev, 0x1cd0, BIT(29), 0x1);
175462306a36Sopenharmony_ci	rtw_write32_mask(rtwdev, 0x1cd0, BIT(30), 0x1);
175562306a36Sopenharmony_ci	rtw_write32_mask(rtwdev, 0x1cd0, BIT(31), 0x0);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	rtw_load_table(rtwdev, chip->rfk_init_tbl);
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	dpk_info->is_dpk_pwr_on = true;
176062306a36Sopenharmony_ci}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_civoid rtw_phy_load_tables(struct rtw_dev *rtwdev)
176362306a36Sopenharmony_ci{
176462306a36Sopenharmony_ci	const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev);
176562306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
176662306a36Sopenharmony_ci	u8 rf_path;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	rtw_load_table(rtwdev, chip->mac_tbl);
176962306a36Sopenharmony_ci	rtw_load_table(rtwdev, chip->bb_tbl);
177062306a36Sopenharmony_ci	rtw_load_table(rtwdev, chip->agc_tbl);
177162306a36Sopenharmony_ci	if (rfe_def->agc_btg_tbl)
177262306a36Sopenharmony_ci		rtw_load_table(rtwdev, rfe_def->agc_btg_tbl);
177362306a36Sopenharmony_ci	rtw_load_rfk_table(rtwdev);
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	for (rf_path = 0; rf_path < rtwdev->hal.rf_path_num; rf_path++) {
177662306a36Sopenharmony_ci		const struct rtw_table *tbl;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci		tbl = chip->rf_tbl[rf_path];
177962306a36Sopenharmony_ci		rtw_load_table(rtwdev, tbl);
178062306a36Sopenharmony_ci	}
178162306a36Sopenharmony_ci}
178262306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_load_tables);
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_cistatic u8 rtw_get_channel_group(u8 channel, u8 rate)
178562306a36Sopenharmony_ci{
178662306a36Sopenharmony_ci	switch (channel) {
178762306a36Sopenharmony_ci	default:
178862306a36Sopenharmony_ci		WARN_ON(1);
178962306a36Sopenharmony_ci		fallthrough;
179062306a36Sopenharmony_ci	case 1:
179162306a36Sopenharmony_ci	case 2:
179262306a36Sopenharmony_ci	case 36:
179362306a36Sopenharmony_ci	case 38:
179462306a36Sopenharmony_ci	case 40:
179562306a36Sopenharmony_ci	case 42:
179662306a36Sopenharmony_ci		return 0;
179762306a36Sopenharmony_ci	case 3:
179862306a36Sopenharmony_ci	case 4:
179962306a36Sopenharmony_ci	case 5:
180062306a36Sopenharmony_ci	case 44:
180162306a36Sopenharmony_ci	case 46:
180262306a36Sopenharmony_ci	case 48:
180362306a36Sopenharmony_ci	case 50:
180462306a36Sopenharmony_ci		return 1;
180562306a36Sopenharmony_ci	case 6:
180662306a36Sopenharmony_ci	case 7:
180762306a36Sopenharmony_ci	case 8:
180862306a36Sopenharmony_ci	case 52:
180962306a36Sopenharmony_ci	case 54:
181062306a36Sopenharmony_ci	case 56:
181162306a36Sopenharmony_ci	case 58:
181262306a36Sopenharmony_ci		return 2;
181362306a36Sopenharmony_ci	case 9:
181462306a36Sopenharmony_ci	case 10:
181562306a36Sopenharmony_ci	case 11:
181662306a36Sopenharmony_ci	case 60:
181762306a36Sopenharmony_ci	case 62:
181862306a36Sopenharmony_ci	case 64:
181962306a36Sopenharmony_ci		return 3;
182062306a36Sopenharmony_ci	case 12:
182162306a36Sopenharmony_ci	case 13:
182262306a36Sopenharmony_ci	case 100:
182362306a36Sopenharmony_ci	case 102:
182462306a36Sopenharmony_ci	case 104:
182562306a36Sopenharmony_ci	case 106:
182662306a36Sopenharmony_ci		return 4;
182762306a36Sopenharmony_ci	case 14:
182862306a36Sopenharmony_ci		return rate <= DESC_RATE11M ? 5 : 4;
182962306a36Sopenharmony_ci	case 108:
183062306a36Sopenharmony_ci	case 110:
183162306a36Sopenharmony_ci	case 112:
183262306a36Sopenharmony_ci	case 114:
183362306a36Sopenharmony_ci		return 5;
183462306a36Sopenharmony_ci	case 116:
183562306a36Sopenharmony_ci	case 118:
183662306a36Sopenharmony_ci	case 120:
183762306a36Sopenharmony_ci	case 122:
183862306a36Sopenharmony_ci		return 6;
183962306a36Sopenharmony_ci	case 124:
184062306a36Sopenharmony_ci	case 126:
184162306a36Sopenharmony_ci	case 128:
184262306a36Sopenharmony_ci	case 130:
184362306a36Sopenharmony_ci		return 7;
184462306a36Sopenharmony_ci	case 132:
184562306a36Sopenharmony_ci	case 134:
184662306a36Sopenharmony_ci	case 136:
184762306a36Sopenharmony_ci	case 138:
184862306a36Sopenharmony_ci		return 8;
184962306a36Sopenharmony_ci	case 140:
185062306a36Sopenharmony_ci	case 142:
185162306a36Sopenharmony_ci	case 144:
185262306a36Sopenharmony_ci		return 9;
185362306a36Sopenharmony_ci	case 149:
185462306a36Sopenharmony_ci	case 151:
185562306a36Sopenharmony_ci	case 153:
185662306a36Sopenharmony_ci	case 155:
185762306a36Sopenharmony_ci		return 10;
185862306a36Sopenharmony_ci	case 157:
185962306a36Sopenharmony_ci	case 159:
186062306a36Sopenharmony_ci	case 161:
186162306a36Sopenharmony_ci		return 11;
186262306a36Sopenharmony_ci	case 165:
186362306a36Sopenharmony_ci	case 167:
186462306a36Sopenharmony_ci	case 169:
186562306a36Sopenharmony_ci	case 171:
186662306a36Sopenharmony_ci		return 12;
186762306a36Sopenharmony_ci	case 173:
186862306a36Sopenharmony_ci	case 175:
186962306a36Sopenharmony_ci	case 177:
187062306a36Sopenharmony_ci		return 13;
187162306a36Sopenharmony_ci	}
187262306a36Sopenharmony_ci}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_cistatic s8 rtw_phy_get_dis_dpd_by_rate_diff(struct rtw_dev *rtwdev, u16 rate)
187562306a36Sopenharmony_ci{
187662306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
187762306a36Sopenharmony_ci	s8 dpd_diff = 0;
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	if (!chip->en_dis_dpd)
188062306a36Sopenharmony_ci		return 0;
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci#define RTW_DPD_RATE_CHECK(_rate)					\
188362306a36Sopenharmony_ci	case DESC_RATE ## _rate:					\
188462306a36Sopenharmony_ci	if (DIS_DPD_RATE ## _rate & chip->dpd_ratemask)			\
188562306a36Sopenharmony_ci		dpd_diff = -6 * chip->txgi_factor;			\
188662306a36Sopenharmony_ci	break
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	switch (rate) {
188962306a36Sopenharmony_ci	RTW_DPD_RATE_CHECK(6M);
189062306a36Sopenharmony_ci	RTW_DPD_RATE_CHECK(9M);
189162306a36Sopenharmony_ci	RTW_DPD_RATE_CHECK(MCS0);
189262306a36Sopenharmony_ci	RTW_DPD_RATE_CHECK(MCS1);
189362306a36Sopenharmony_ci	RTW_DPD_RATE_CHECK(MCS8);
189462306a36Sopenharmony_ci	RTW_DPD_RATE_CHECK(MCS9);
189562306a36Sopenharmony_ci	RTW_DPD_RATE_CHECK(VHT1SS_MCS0);
189662306a36Sopenharmony_ci	RTW_DPD_RATE_CHECK(VHT1SS_MCS1);
189762306a36Sopenharmony_ci	RTW_DPD_RATE_CHECK(VHT2SS_MCS0);
189862306a36Sopenharmony_ci	RTW_DPD_RATE_CHECK(VHT2SS_MCS1);
189962306a36Sopenharmony_ci	}
190062306a36Sopenharmony_ci#undef RTW_DPD_RATE_CHECK
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	return dpd_diff;
190362306a36Sopenharmony_ci}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_cistatic u8 rtw_phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
190662306a36Sopenharmony_ci					struct rtw_2g_txpwr_idx *pwr_idx_2g,
190762306a36Sopenharmony_ci					enum rtw_bandwidth bandwidth,
190862306a36Sopenharmony_ci					u8 rate, u8 group)
190962306a36Sopenharmony_ci{
191062306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
191162306a36Sopenharmony_ci	u8 tx_power;
191262306a36Sopenharmony_ci	bool mcs_rate;
191362306a36Sopenharmony_ci	bool above_2ss;
191462306a36Sopenharmony_ci	u8 factor = chip->txgi_factor;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	if (rate <= DESC_RATE11M)
191762306a36Sopenharmony_ci		tx_power = pwr_idx_2g->cck_base[group];
191862306a36Sopenharmony_ci	else
191962306a36Sopenharmony_ci		tx_power = pwr_idx_2g->bw40_base[group];
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	if (rate >= DESC_RATE6M && rate <= DESC_RATE54M)
192262306a36Sopenharmony_ci		tx_power += pwr_idx_2g->ht_1s_diff.ofdm * factor;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) ||
192562306a36Sopenharmony_ci		   (rate >= DESC_RATEVHT1SS_MCS0 &&
192662306a36Sopenharmony_ci		    rate <= DESC_RATEVHT2SS_MCS9);
192762306a36Sopenharmony_ci	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
192862306a36Sopenharmony_ci		    (rate >= DESC_RATEVHT2SS_MCS0);
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	if (!mcs_rate)
193162306a36Sopenharmony_ci		return tx_power;
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	switch (bandwidth) {
193462306a36Sopenharmony_ci	default:
193562306a36Sopenharmony_ci		WARN_ON(1);
193662306a36Sopenharmony_ci		fallthrough;
193762306a36Sopenharmony_ci	case RTW_CHANNEL_WIDTH_20:
193862306a36Sopenharmony_ci		tx_power += pwr_idx_2g->ht_1s_diff.bw20 * factor;
193962306a36Sopenharmony_ci		if (above_2ss)
194062306a36Sopenharmony_ci			tx_power += pwr_idx_2g->ht_2s_diff.bw20 * factor;
194162306a36Sopenharmony_ci		break;
194262306a36Sopenharmony_ci	case RTW_CHANNEL_WIDTH_40:
194362306a36Sopenharmony_ci		/* bw40 is the base power */
194462306a36Sopenharmony_ci		if (above_2ss)
194562306a36Sopenharmony_ci			tx_power += pwr_idx_2g->ht_2s_diff.bw40 * factor;
194662306a36Sopenharmony_ci		break;
194762306a36Sopenharmony_ci	}
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	return tx_power;
195062306a36Sopenharmony_ci}
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_cistatic u8 rtw_phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
195362306a36Sopenharmony_ci					struct rtw_5g_txpwr_idx *pwr_idx_5g,
195462306a36Sopenharmony_ci					enum rtw_bandwidth bandwidth,
195562306a36Sopenharmony_ci					u8 rate, u8 group)
195662306a36Sopenharmony_ci{
195762306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
195862306a36Sopenharmony_ci	u8 tx_power;
195962306a36Sopenharmony_ci	u8 upper, lower;
196062306a36Sopenharmony_ci	bool mcs_rate;
196162306a36Sopenharmony_ci	bool above_2ss;
196262306a36Sopenharmony_ci	u8 factor = chip->txgi_factor;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	tx_power = pwr_idx_5g->bw40_base[group];
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) ||
196762306a36Sopenharmony_ci		   (rate >= DESC_RATEVHT1SS_MCS0 &&
196862306a36Sopenharmony_ci		    rate <= DESC_RATEVHT2SS_MCS9);
196962306a36Sopenharmony_ci	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
197062306a36Sopenharmony_ci		    (rate >= DESC_RATEVHT2SS_MCS0);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	if (!mcs_rate) {
197362306a36Sopenharmony_ci		tx_power += pwr_idx_5g->ht_1s_diff.ofdm * factor;
197462306a36Sopenharmony_ci		return tx_power;
197562306a36Sopenharmony_ci	}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	switch (bandwidth) {
197862306a36Sopenharmony_ci	default:
197962306a36Sopenharmony_ci		WARN_ON(1);
198062306a36Sopenharmony_ci		fallthrough;
198162306a36Sopenharmony_ci	case RTW_CHANNEL_WIDTH_20:
198262306a36Sopenharmony_ci		tx_power += pwr_idx_5g->ht_1s_diff.bw20 * factor;
198362306a36Sopenharmony_ci		if (above_2ss)
198462306a36Sopenharmony_ci			tx_power += pwr_idx_5g->ht_2s_diff.bw20 * factor;
198562306a36Sopenharmony_ci		break;
198662306a36Sopenharmony_ci	case RTW_CHANNEL_WIDTH_40:
198762306a36Sopenharmony_ci		/* bw40 is the base power */
198862306a36Sopenharmony_ci		if (above_2ss)
198962306a36Sopenharmony_ci			tx_power += pwr_idx_5g->ht_2s_diff.bw40 * factor;
199062306a36Sopenharmony_ci		break;
199162306a36Sopenharmony_ci	case RTW_CHANNEL_WIDTH_80:
199262306a36Sopenharmony_ci		/* the base idx of bw80 is the average of bw40+/bw40- */
199362306a36Sopenharmony_ci		lower = pwr_idx_5g->bw40_base[group];
199462306a36Sopenharmony_ci		upper = pwr_idx_5g->bw40_base[group + 1];
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci		tx_power = (lower + upper) / 2;
199762306a36Sopenharmony_ci		tx_power += pwr_idx_5g->vht_1s_diff.bw80 * factor;
199862306a36Sopenharmony_ci		if (above_2ss)
199962306a36Sopenharmony_ci			tx_power += pwr_idx_5g->vht_2s_diff.bw80 * factor;
200062306a36Sopenharmony_ci		break;
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	return tx_power;
200462306a36Sopenharmony_ci}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci/* return RTW_RATE_SECTION_MAX to indicate rate is invalid */
200762306a36Sopenharmony_cistatic u8 rtw_phy_rate_to_rate_section(u8 rate)
200862306a36Sopenharmony_ci{
200962306a36Sopenharmony_ci	if (rate >= DESC_RATE1M && rate <= DESC_RATE11M)
201062306a36Sopenharmony_ci		return RTW_RATE_SECTION_CCK;
201162306a36Sopenharmony_ci	else if (rate >= DESC_RATE6M && rate <= DESC_RATE54M)
201262306a36Sopenharmony_ci		return RTW_RATE_SECTION_OFDM;
201362306a36Sopenharmony_ci	else if (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS7)
201462306a36Sopenharmony_ci		return RTW_RATE_SECTION_HT_1S;
201562306a36Sopenharmony_ci	else if (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15)
201662306a36Sopenharmony_ci		return RTW_RATE_SECTION_HT_2S;
201762306a36Sopenharmony_ci	else if (rate >= DESC_RATEVHT1SS_MCS0 && rate <= DESC_RATEVHT1SS_MCS9)
201862306a36Sopenharmony_ci		return RTW_RATE_SECTION_VHT_1S;
201962306a36Sopenharmony_ci	else if (rate >= DESC_RATEVHT2SS_MCS0 && rate <= DESC_RATEVHT2SS_MCS9)
202062306a36Sopenharmony_ci		return RTW_RATE_SECTION_VHT_2S;
202162306a36Sopenharmony_ci	else
202262306a36Sopenharmony_ci		return RTW_RATE_SECTION_MAX;
202362306a36Sopenharmony_ci}
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_cistatic s8 rtw_phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band,
202662306a36Sopenharmony_ci				     enum rtw_bandwidth bw, u8 rf_path,
202762306a36Sopenharmony_ci				     u8 rate, u8 channel, u8 regd)
202862306a36Sopenharmony_ci{
202962306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
203062306a36Sopenharmony_ci	u8 *cch_by_bw = hal->cch_by_bw;
203162306a36Sopenharmony_ci	s8 power_limit = (s8)rtwdev->chip->max_power_index;
203262306a36Sopenharmony_ci	u8 rs = rtw_phy_rate_to_rate_section(rate);
203362306a36Sopenharmony_ci	int ch_idx;
203462306a36Sopenharmony_ci	u8 cur_bw, cur_ch;
203562306a36Sopenharmony_ci	s8 cur_lmt;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	if (regd > RTW_REGD_WW)
203862306a36Sopenharmony_ci		return power_limit;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	if (rs == RTW_RATE_SECTION_MAX)
204162306a36Sopenharmony_ci		goto err;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	/* only 20M BW with cck and ofdm */
204462306a36Sopenharmony_ci	if (rs == RTW_RATE_SECTION_CCK || rs == RTW_RATE_SECTION_OFDM)
204562306a36Sopenharmony_ci		bw = RTW_CHANNEL_WIDTH_20;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	/* only 20/40M BW with ht */
204862306a36Sopenharmony_ci	if (rs == RTW_RATE_SECTION_HT_1S || rs == RTW_RATE_SECTION_HT_2S)
204962306a36Sopenharmony_ci		bw = min_t(u8, bw, RTW_CHANNEL_WIDTH_40);
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	/* select min power limit among [20M BW ~ current BW] */
205262306a36Sopenharmony_ci	for (cur_bw = RTW_CHANNEL_WIDTH_20; cur_bw <= bw; cur_bw++) {
205362306a36Sopenharmony_ci		cur_ch = cch_by_bw[cur_bw];
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci		ch_idx = rtw_channel_to_idx(band, cur_ch);
205662306a36Sopenharmony_ci		if (ch_idx < 0)
205762306a36Sopenharmony_ci			goto err;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci		cur_lmt = cur_ch <= RTW_MAX_CHANNEL_NUM_2G ?
206062306a36Sopenharmony_ci			hal->tx_pwr_limit_2g[regd][cur_bw][rs][ch_idx] :
206162306a36Sopenharmony_ci			hal->tx_pwr_limit_5g[regd][cur_bw][rs][ch_idx];
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci		power_limit = min_t(s8, cur_lmt, power_limit);
206462306a36Sopenharmony_ci	}
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	return power_limit;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_cierr:
206962306a36Sopenharmony_ci	WARN(1, "invalid arguments, band=%d, bw=%d, path=%d, rate=%d, ch=%d\n",
207062306a36Sopenharmony_ci	     band, bw, rf_path, rate, channel);
207162306a36Sopenharmony_ci	return (s8)rtwdev->chip->max_power_index;
207262306a36Sopenharmony_ci}
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_cistatic s8 rtw_phy_get_tx_power_sar(struct rtw_dev *rtwdev, u8 sar_band,
207562306a36Sopenharmony_ci				   u8 rf_path, u8 rate)
207662306a36Sopenharmony_ci{
207762306a36Sopenharmony_ci	u8 rs = rtw_phy_rate_to_rate_section(rate);
207862306a36Sopenharmony_ci	struct rtw_sar_arg arg = {
207962306a36Sopenharmony_ci		.sar_band = sar_band,
208062306a36Sopenharmony_ci		.path = rf_path,
208162306a36Sopenharmony_ci		.rs = rs,
208262306a36Sopenharmony_ci	};
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	if (rs == RTW_RATE_SECTION_MAX)
208562306a36Sopenharmony_ci		goto err;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	return rtw_query_sar(rtwdev, &arg);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_cierr:
209062306a36Sopenharmony_ci	WARN(1, "invalid arguments, sar_band=%d, path=%d, rate=%d\n",
209162306a36Sopenharmony_ci	     sar_band, rf_path, rate);
209262306a36Sopenharmony_ci	return (s8)rtwdev->chip->max_power_index;
209362306a36Sopenharmony_ci}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_civoid rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw,
209662306a36Sopenharmony_ci			     u8 ch, u8 regd, struct rtw_power_params *pwr_param)
209762306a36Sopenharmony_ci{
209862306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
209962306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
210062306a36Sopenharmony_ci	struct rtw_txpwr_idx *pwr_idx;
210162306a36Sopenharmony_ci	u8 group, band;
210262306a36Sopenharmony_ci	u8 *base = &pwr_param->pwr_base;
210362306a36Sopenharmony_ci	s8 *offset = &pwr_param->pwr_offset;
210462306a36Sopenharmony_ci	s8 *limit = &pwr_param->pwr_limit;
210562306a36Sopenharmony_ci	s8 *remnant = &pwr_param->pwr_remnant;
210662306a36Sopenharmony_ci	s8 *sar = &pwr_param->pwr_sar;
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	pwr_idx = &rtwdev->efuse.txpwr_idx_table[path];
210962306a36Sopenharmony_ci	group = rtw_get_channel_group(ch, rate);
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	/* base power index for 2.4G/5G */
211262306a36Sopenharmony_ci	if (IS_CH_2G_BAND(ch)) {
211362306a36Sopenharmony_ci		band = PHY_BAND_2G;
211462306a36Sopenharmony_ci		*base = rtw_phy_get_2g_tx_power_index(rtwdev,
211562306a36Sopenharmony_ci						      &pwr_idx->pwr_idx_2g,
211662306a36Sopenharmony_ci						      bw, rate, group);
211762306a36Sopenharmony_ci		*offset = hal->tx_pwr_by_rate_offset_2g[path][rate];
211862306a36Sopenharmony_ci	} else {
211962306a36Sopenharmony_ci		band = PHY_BAND_5G;
212062306a36Sopenharmony_ci		*base = rtw_phy_get_5g_tx_power_index(rtwdev,
212162306a36Sopenharmony_ci						      &pwr_idx->pwr_idx_5g,
212262306a36Sopenharmony_ci						      bw, rate, group);
212362306a36Sopenharmony_ci		*offset = hal->tx_pwr_by_rate_offset_5g[path][rate];
212462306a36Sopenharmony_ci	}
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	*limit = rtw_phy_get_tx_power_limit(rtwdev, band, bw, path,
212762306a36Sopenharmony_ci					    rate, ch, regd);
212862306a36Sopenharmony_ci	*remnant = (rate <= DESC_RATE11M ? dm_info->txagc_remnant_cck :
212962306a36Sopenharmony_ci		    dm_info->txagc_remnant_ofdm);
213062306a36Sopenharmony_ci	*sar = rtw_phy_get_tx_power_sar(rtwdev, hal->sar_band, path, rate);
213162306a36Sopenharmony_ci}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ciu8
213462306a36Sopenharmony_cirtw_phy_get_tx_power_index(struct rtw_dev *rtwdev, u8 rf_path, u8 rate,
213562306a36Sopenharmony_ci			   enum rtw_bandwidth bandwidth, u8 channel, u8 regd)
213662306a36Sopenharmony_ci{
213762306a36Sopenharmony_ci	struct rtw_power_params pwr_param = {0};
213862306a36Sopenharmony_ci	u8 tx_power;
213962306a36Sopenharmony_ci	s8 offset;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	rtw_get_tx_power_params(rtwdev, rf_path, rate, bandwidth,
214262306a36Sopenharmony_ci				channel, regd, &pwr_param);
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	tx_power = pwr_param.pwr_base;
214562306a36Sopenharmony_ci	offset = min3(pwr_param.pwr_offset,
214662306a36Sopenharmony_ci		      pwr_param.pwr_limit,
214762306a36Sopenharmony_ci		      pwr_param.pwr_sar);
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	if (rtwdev->chip->en_dis_dpd)
215062306a36Sopenharmony_ci		offset += rtw_phy_get_dis_dpd_by_rate_diff(rtwdev, rate);
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	tx_power += offset + pwr_param.pwr_remnant;
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	if (tx_power > rtwdev->chip->max_power_index)
215562306a36Sopenharmony_ci		tx_power = rtwdev->chip->max_power_index;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	return tx_power;
215862306a36Sopenharmony_ci}
215962306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_get_tx_power_index);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_cistatic void rtw_phy_set_tx_power_index_by_rs(struct rtw_dev *rtwdev,
216262306a36Sopenharmony_ci					     u8 ch, u8 path, u8 rs)
216362306a36Sopenharmony_ci{
216462306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
216562306a36Sopenharmony_ci	u8 regd = rtw_regd_get(rtwdev);
216662306a36Sopenharmony_ci	u8 *rates;
216762306a36Sopenharmony_ci	u8 size;
216862306a36Sopenharmony_ci	u8 rate;
216962306a36Sopenharmony_ci	u8 pwr_idx;
217062306a36Sopenharmony_ci	u8 bw;
217162306a36Sopenharmony_ci	int i;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	if (rs >= RTW_RATE_SECTION_MAX)
217462306a36Sopenharmony_ci		return;
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	rates = rtw_rate_section[rs];
217762306a36Sopenharmony_ci	size = rtw_rate_size[rs];
217862306a36Sopenharmony_ci	bw = hal->current_band_width;
217962306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
218062306a36Sopenharmony_ci		rate = rates[i];
218162306a36Sopenharmony_ci		pwr_idx = rtw_phy_get_tx_power_index(rtwdev, path, rate,
218262306a36Sopenharmony_ci						     bw, ch, regd);
218362306a36Sopenharmony_ci		hal->tx_pwr_tbl[path][rate] = pwr_idx;
218462306a36Sopenharmony_ci	}
218562306a36Sopenharmony_ci}
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci/* set tx power level by path for each rates, note that the order of the rates
218862306a36Sopenharmony_ci * are *very* important, bacause 8822B/8821C combines every four bytes of tx
218962306a36Sopenharmony_ci * power index into a four-byte power index register, and calls set_tx_agc to
219062306a36Sopenharmony_ci * write these values into hardware
219162306a36Sopenharmony_ci */
219262306a36Sopenharmony_cistatic void rtw_phy_set_tx_power_level_by_path(struct rtw_dev *rtwdev,
219362306a36Sopenharmony_ci					       u8 ch, u8 path)
219462306a36Sopenharmony_ci{
219562306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
219662306a36Sopenharmony_ci	u8 rs;
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	/* do not need cck rates if we are not in 2.4G */
219962306a36Sopenharmony_ci	if (hal->current_band_type == RTW_BAND_2G)
220062306a36Sopenharmony_ci		rs = RTW_RATE_SECTION_CCK;
220162306a36Sopenharmony_ci	else
220262306a36Sopenharmony_ci		rs = RTW_RATE_SECTION_OFDM;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	for (; rs < RTW_RATE_SECTION_MAX; rs++)
220562306a36Sopenharmony_ci		rtw_phy_set_tx_power_index_by_rs(rtwdev, ch, path, rs);
220662306a36Sopenharmony_ci}
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_civoid rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel)
220962306a36Sopenharmony_ci{
221062306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
221162306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
221262306a36Sopenharmony_ci	u8 path;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	mutex_lock(&hal->tx_power_mutex);
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	for (path = 0; path < hal->rf_path_num; path++)
221762306a36Sopenharmony_ci		rtw_phy_set_tx_power_level_by_path(rtwdev, channel, path);
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	chip->ops->set_tx_power_index(rtwdev);
222062306a36Sopenharmony_ci	mutex_unlock(&hal->tx_power_mutex);
222162306a36Sopenharmony_ci}
222262306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_set_tx_power_level);
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_cistatic void
222562306a36Sopenharmony_cirtw_phy_tx_power_by_rate_config_by_path(struct rtw_hal *hal, u8 path,
222662306a36Sopenharmony_ci					u8 rs, u8 size, u8 *rates)
222762306a36Sopenharmony_ci{
222862306a36Sopenharmony_ci	u8 rate;
222962306a36Sopenharmony_ci	u8 base_idx, rate_idx;
223062306a36Sopenharmony_ci	s8 base_2g, base_5g;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	if (rs >= RTW_RATE_SECTION_VHT_1S)
223362306a36Sopenharmony_ci		base_idx = rates[size - 3];
223462306a36Sopenharmony_ci	else
223562306a36Sopenharmony_ci		base_idx = rates[size - 1];
223662306a36Sopenharmony_ci	base_2g = hal->tx_pwr_by_rate_offset_2g[path][base_idx];
223762306a36Sopenharmony_ci	base_5g = hal->tx_pwr_by_rate_offset_5g[path][base_idx];
223862306a36Sopenharmony_ci	hal->tx_pwr_by_rate_base_2g[path][rs] = base_2g;
223962306a36Sopenharmony_ci	hal->tx_pwr_by_rate_base_5g[path][rs] = base_5g;
224062306a36Sopenharmony_ci	for (rate = 0; rate < size; rate++) {
224162306a36Sopenharmony_ci		rate_idx = rates[rate];
224262306a36Sopenharmony_ci		hal->tx_pwr_by_rate_offset_2g[path][rate_idx] -= base_2g;
224362306a36Sopenharmony_ci		hal->tx_pwr_by_rate_offset_5g[path][rate_idx] -= base_5g;
224462306a36Sopenharmony_ci	}
224562306a36Sopenharmony_ci}
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_civoid rtw_phy_tx_power_by_rate_config(struct rtw_hal *hal)
224862306a36Sopenharmony_ci{
224962306a36Sopenharmony_ci	u8 path;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	for (path = 0; path < RTW_RF_PATH_MAX; path++) {
225262306a36Sopenharmony_ci		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
225362306a36Sopenharmony_ci				RTW_RATE_SECTION_CCK,
225462306a36Sopenharmony_ci				rtw_cck_size, rtw_cck_rates);
225562306a36Sopenharmony_ci		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
225662306a36Sopenharmony_ci				RTW_RATE_SECTION_OFDM,
225762306a36Sopenharmony_ci				rtw_ofdm_size, rtw_ofdm_rates);
225862306a36Sopenharmony_ci		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
225962306a36Sopenharmony_ci				RTW_RATE_SECTION_HT_1S,
226062306a36Sopenharmony_ci				rtw_ht_1s_size, rtw_ht_1s_rates);
226162306a36Sopenharmony_ci		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
226262306a36Sopenharmony_ci				RTW_RATE_SECTION_HT_2S,
226362306a36Sopenharmony_ci				rtw_ht_2s_size, rtw_ht_2s_rates);
226462306a36Sopenharmony_ci		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
226562306a36Sopenharmony_ci				RTW_RATE_SECTION_VHT_1S,
226662306a36Sopenharmony_ci				rtw_vht_1s_size, rtw_vht_1s_rates);
226762306a36Sopenharmony_ci		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
226862306a36Sopenharmony_ci				RTW_RATE_SECTION_VHT_2S,
226962306a36Sopenharmony_ci				rtw_vht_2s_size, rtw_vht_2s_rates);
227062306a36Sopenharmony_ci	}
227162306a36Sopenharmony_ci}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_cistatic void
227462306a36Sopenharmony_ci__rtw_phy_tx_power_limit_config(struct rtw_hal *hal, u8 regd, u8 bw, u8 rs)
227562306a36Sopenharmony_ci{
227662306a36Sopenharmony_ci	s8 base;
227762306a36Sopenharmony_ci	u8 ch;
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_2G; ch++) {
228062306a36Sopenharmony_ci		base = hal->tx_pwr_by_rate_base_2g[0][rs];
228162306a36Sopenharmony_ci		hal->tx_pwr_limit_2g[regd][bw][rs][ch] -= base;
228262306a36Sopenharmony_ci	}
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_5G; ch++) {
228562306a36Sopenharmony_ci		base = hal->tx_pwr_by_rate_base_5g[0][rs];
228662306a36Sopenharmony_ci		hal->tx_pwr_limit_5g[regd][bw][rs][ch] -= base;
228762306a36Sopenharmony_ci	}
228862306a36Sopenharmony_ci}
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_civoid rtw_phy_tx_power_limit_config(struct rtw_hal *hal)
229162306a36Sopenharmony_ci{
229262306a36Sopenharmony_ci	u8 regd, bw, rs;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	/* default at channel 1 */
229562306a36Sopenharmony_ci	hal->cch_by_bw[RTW_CHANNEL_WIDTH_20] = 1;
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci	for (regd = 0; regd < RTW_REGD_MAX; regd++)
229862306a36Sopenharmony_ci		for (bw = 0; bw < RTW_CHANNEL_WIDTH_MAX; bw++)
229962306a36Sopenharmony_ci			for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++)
230062306a36Sopenharmony_ci				__rtw_phy_tx_power_limit_config(hal, regd, bw, rs);
230162306a36Sopenharmony_ci}
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_cistatic void rtw_phy_init_tx_power_limit(struct rtw_dev *rtwdev,
230462306a36Sopenharmony_ci					u8 regd, u8 bw, u8 rs)
230562306a36Sopenharmony_ci{
230662306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
230762306a36Sopenharmony_ci	s8 max_power_index = (s8)rtwdev->chip->max_power_index;
230862306a36Sopenharmony_ci	u8 ch;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	/* 2.4G channels */
231162306a36Sopenharmony_ci	for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_2G; ch++)
231262306a36Sopenharmony_ci		hal->tx_pwr_limit_2g[regd][bw][rs][ch] = max_power_index;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	/* 5G channels */
231562306a36Sopenharmony_ci	for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_5G; ch++)
231662306a36Sopenharmony_ci		hal->tx_pwr_limit_5g[regd][bw][rs][ch] = max_power_index;
231762306a36Sopenharmony_ci}
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_civoid rtw_phy_init_tx_power(struct rtw_dev *rtwdev)
232062306a36Sopenharmony_ci{
232162306a36Sopenharmony_ci	struct rtw_hal *hal = &rtwdev->hal;
232262306a36Sopenharmony_ci	u8 regd, path, rate, rs, bw;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	/* init tx power by rate offset */
232562306a36Sopenharmony_ci	for (path = 0; path < RTW_RF_PATH_MAX; path++) {
232662306a36Sopenharmony_ci		for (rate = 0; rate < DESC_RATE_MAX; rate++) {
232762306a36Sopenharmony_ci			hal->tx_pwr_by_rate_offset_2g[path][rate] = 0;
232862306a36Sopenharmony_ci			hal->tx_pwr_by_rate_offset_5g[path][rate] = 0;
232962306a36Sopenharmony_ci		}
233062306a36Sopenharmony_ci	}
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	/* init tx power limit */
233362306a36Sopenharmony_ci	for (regd = 0; regd < RTW_REGD_MAX; regd++)
233462306a36Sopenharmony_ci		for (bw = 0; bw < RTW_CHANNEL_WIDTH_MAX; bw++)
233562306a36Sopenharmony_ci			for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++)
233662306a36Sopenharmony_ci				rtw_phy_init_tx_power_limit(rtwdev, regd, bw,
233762306a36Sopenharmony_ci							    rs);
233862306a36Sopenharmony_ci}
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_civoid rtw_phy_config_swing_table(struct rtw_dev *rtwdev,
234162306a36Sopenharmony_ci				struct rtw_swing_table *swing_table)
234262306a36Sopenharmony_ci{
234362306a36Sopenharmony_ci	const struct rtw_pwr_track_tbl *tbl = rtwdev->chip->pwr_track_tbl;
234462306a36Sopenharmony_ci	u8 channel = rtwdev->hal.current_channel;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	if (IS_CH_2G_BAND(channel)) {
234762306a36Sopenharmony_ci		if (rtwdev->dm_info.tx_rate <= DESC_RATE11M) {
234862306a36Sopenharmony_ci			swing_table->p[RF_PATH_A] = tbl->pwrtrk_2g_ccka_p;
234962306a36Sopenharmony_ci			swing_table->n[RF_PATH_A] = tbl->pwrtrk_2g_ccka_n;
235062306a36Sopenharmony_ci			swing_table->p[RF_PATH_B] = tbl->pwrtrk_2g_cckb_p;
235162306a36Sopenharmony_ci			swing_table->n[RF_PATH_B] = tbl->pwrtrk_2g_cckb_n;
235262306a36Sopenharmony_ci		} else {
235362306a36Sopenharmony_ci			swing_table->p[RF_PATH_A] = tbl->pwrtrk_2ga_p;
235462306a36Sopenharmony_ci			swing_table->n[RF_PATH_A] = tbl->pwrtrk_2ga_n;
235562306a36Sopenharmony_ci			swing_table->p[RF_PATH_B] = tbl->pwrtrk_2gb_p;
235662306a36Sopenharmony_ci			swing_table->n[RF_PATH_B] = tbl->pwrtrk_2gb_n;
235762306a36Sopenharmony_ci		}
235862306a36Sopenharmony_ci	} else if (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel)) {
235962306a36Sopenharmony_ci		swing_table->p[RF_PATH_A] = tbl->pwrtrk_5ga_p[RTW_PWR_TRK_5G_1];
236062306a36Sopenharmony_ci		swing_table->n[RF_PATH_A] = tbl->pwrtrk_5ga_n[RTW_PWR_TRK_5G_1];
236162306a36Sopenharmony_ci		swing_table->p[RF_PATH_B] = tbl->pwrtrk_5gb_p[RTW_PWR_TRK_5G_1];
236262306a36Sopenharmony_ci		swing_table->n[RF_PATH_B] = tbl->pwrtrk_5gb_n[RTW_PWR_TRK_5G_1];
236362306a36Sopenharmony_ci	} else if (IS_CH_5G_BAND_3(channel)) {
236462306a36Sopenharmony_ci		swing_table->p[RF_PATH_A] = tbl->pwrtrk_5ga_p[RTW_PWR_TRK_5G_2];
236562306a36Sopenharmony_ci		swing_table->n[RF_PATH_A] = tbl->pwrtrk_5ga_n[RTW_PWR_TRK_5G_2];
236662306a36Sopenharmony_ci		swing_table->p[RF_PATH_B] = tbl->pwrtrk_5gb_p[RTW_PWR_TRK_5G_2];
236762306a36Sopenharmony_ci		swing_table->n[RF_PATH_B] = tbl->pwrtrk_5gb_n[RTW_PWR_TRK_5G_2];
236862306a36Sopenharmony_ci	} else if (IS_CH_5G_BAND_4(channel)) {
236962306a36Sopenharmony_ci		swing_table->p[RF_PATH_A] = tbl->pwrtrk_5ga_p[RTW_PWR_TRK_5G_3];
237062306a36Sopenharmony_ci		swing_table->n[RF_PATH_A] = tbl->pwrtrk_5ga_n[RTW_PWR_TRK_5G_3];
237162306a36Sopenharmony_ci		swing_table->p[RF_PATH_B] = tbl->pwrtrk_5gb_p[RTW_PWR_TRK_5G_3];
237262306a36Sopenharmony_ci		swing_table->n[RF_PATH_B] = tbl->pwrtrk_5gb_n[RTW_PWR_TRK_5G_3];
237362306a36Sopenharmony_ci	} else {
237462306a36Sopenharmony_ci		swing_table->p[RF_PATH_A] = tbl->pwrtrk_2ga_p;
237562306a36Sopenharmony_ci		swing_table->n[RF_PATH_A] = tbl->pwrtrk_2ga_n;
237662306a36Sopenharmony_ci		swing_table->p[RF_PATH_B] = tbl->pwrtrk_2gb_p;
237762306a36Sopenharmony_ci		swing_table->n[RF_PATH_B] = tbl->pwrtrk_2gb_n;
237862306a36Sopenharmony_ci	}
237962306a36Sopenharmony_ci}
238062306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_config_swing_table);
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_civoid rtw_phy_pwrtrack_avg(struct rtw_dev *rtwdev, u8 thermal, u8 path)
238362306a36Sopenharmony_ci{
238462306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	ewma_thermal_add(&dm_info->avg_thermal[path], thermal);
238762306a36Sopenharmony_ci	dm_info->thermal_avg[path] =
238862306a36Sopenharmony_ci		ewma_thermal_read(&dm_info->avg_thermal[path]);
238962306a36Sopenharmony_ci}
239062306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_pwrtrack_avg);
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_cibool rtw_phy_pwrtrack_thermal_changed(struct rtw_dev *rtwdev, u8 thermal,
239362306a36Sopenharmony_ci				      u8 path)
239462306a36Sopenharmony_ci{
239562306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
239662306a36Sopenharmony_ci	u8 avg = ewma_thermal_read(&dm_info->avg_thermal[path]);
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	if (avg == thermal)
239962306a36Sopenharmony_ci		return false;
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	return true;
240262306a36Sopenharmony_ci}
240362306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_pwrtrack_thermal_changed);
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ciu8 rtw_phy_pwrtrack_get_delta(struct rtw_dev *rtwdev, u8 path)
240662306a36Sopenharmony_ci{
240762306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
240862306a36Sopenharmony_ci	u8 therm_avg, therm_efuse, therm_delta;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	therm_avg = dm_info->thermal_avg[path];
241162306a36Sopenharmony_ci	therm_efuse = rtwdev->efuse.thermal_meter[path];
241262306a36Sopenharmony_ci	therm_delta = abs(therm_avg - therm_efuse);
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	return min_t(u8, therm_delta, RTW_PWR_TRK_TBL_SZ - 1);
241562306a36Sopenharmony_ci}
241662306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_pwrtrack_get_delta);
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_cis8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev,
241962306a36Sopenharmony_ci			       struct rtw_swing_table *swing_table,
242062306a36Sopenharmony_ci			       u8 tbl_path, u8 therm_path, u8 delta)
242162306a36Sopenharmony_ci{
242262306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
242362306a36Sopenharmony_ci	const u8 *delta_swing_table_idx_pos;
242462306a36Sopenharmony_ci	const u8 *delta_swing_table_idx_neg;
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	if (delta >= RTW_PWR_TRK_TBL_SZ) {
242762306a36Sopenharmony_ci		rtw_warn(rtwdev, "power track table overflow\n");
242862306a36Sopenharmony_ci		return 0;
242962306a36Sopenharmony_ci	}
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	if (!swing_table) {
243262306a36Sopenharmony_ci		rtw_warn(rtwdev, "swing table not configured\n");
243362306a36Sopenharmony_ci		return 0;
243462306a36Sopenharmony_ci	}
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	delta_swing_table_idx_pos = swing_table->p[tbl_path];
243762306a36Sopenharmony_ci	delta_swing_table_idx_neg = swing_table->n[tbl_path];
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	if (!delta_swing_table_idx_pos || !delta_swing_table_idx_neg) {
244062306a36Sopenharmony_ci		rtw_warn(rtwdev, "invalid swing table index\n");
244162306a36Sopenharmony_ci		return 0;
244262306a36Sopenharmony_ci	}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	if (dm_info->thermal_avg[therm_path] >
244562306a36Sopenharmony_ci	    rtwdev->efuse.thermal_meter[therm_path])
244662306a36Sopenharmony_ci		return delta_swing_table_idx_pos[delta];
244762306a36Sopenharmony_ci	else
244862306a36Sopenharmony_ci		return -delta_swing_table_idx_neg[delta];
244962306a36Sopenharmony_ci}
245062306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_pwrtrack_get_pwridx);
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_cibool rtw_phy_pwrtrack_need_lck(struct rtw_dev *rtwdev)
245362306a36Sopenharmony_ci{
245462306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
245562306a36Sopenharmony_ci	u8 delta_lck;
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	delta_lck = abs(dm_info->thermal_avg[0] - dm_info->thermal_meter_lck);
245862306a36Sopenharmony_ci	if (delta_lck >= rtwdev->chip->lck_threshold) {
245962306a36Sopenharmony_ci		dm_info->thermal_meter_lck = dm_info->thermal_avg[0];
246062306a36Sopenharmony_ci		return true;
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci	return false;
246362306a36Sopenharmony_ci}
246462306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_pwrtrack_need_lck);
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_cibool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev)
246762306a36Sopenharmony_ci{
246862306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
246962306a36Sopenharmony_ci	u8 delta_iqk;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	delta_iqk = abs(dm_info->thermal_avg[0] - dm_info->thermal_meter_k);
247262306a36Sopenharmony_ci	if (delta_iqk >= rtwdev->chip->iqk_threshold) {
247362306a36Sopenharmony_ci		dm_info->thermal_meter_k = dm_info->thermal_avg[0];
247462306a36Sopenharmony_ci		return true;
247562306a36Sopenharmony_ci	}
247662306a36Sopenharmony_ci	return false;
247762306a36Sopenharmony_ci}
247862306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_phy_pwrtrack_need_iqk);
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_cistatic void rtw_phy_set_tx_path_by_reg(struct rtw_dev *rtwdev,
248162306a36Sopenharmony_ci				       enum rtw_bb_path tx_path_sel_1ss)
248262306a36Sopenharmony_ci{
248362306a36Sopenharmony_ci	struct rtw_path_div *path_div = &rtwdev->dm_path_div;
248462306a36Sopenharmony_ci	enum rtw_bb_path tx_path_sel_cck = tx_path_sel_1ss;
248562306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	if (tx_path_sel_1ss == path_div->current_tx_path)
248862306a36Sopenharmony_ci		return;
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	path_div->current_tx_path = tx_path_sel_1ss;
249162306a36Sopenharmony_ci	rtw_dbg(rtwdev, RTW_DBG_PATH_DIV, "Switch TX path=%s\n",
249262306a36Sopenharmony_ci		tx_path_sel_1ss == BB_PATH_A ? "A" : "B");
249362306a36Sopenharmony_ci	chip->ops->config_tx_path(rtwdev, rtwdev->hal.antenna_tx,
249462306a36Sopenharmony_ci				  tx_path_sel_1ss, tx_path_sel_cck, false);
249562306a36Sopenharmony_ci}
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_cistatic void rtw_phy_tx_path_div_select(struct rtw_dev *rtwdev)
249862306a36Sopenharmony_ci{
249962306a36Sopenharmony_ci	struct rtw_path_div *path_div = &rtwdev->dm_path_div;
250062306a36Sopenharmony_ci	enum rtw_bb_path path = path_div->current_tx_path;
250162306a36Sopenharmony_ci	s32 rssi_a = 0, rssi_b = 0;
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	if (path_div->path_a_cnt)
250462306a36Sopenharmony_ci		rssi_a = path_div->path_a_sum / path_div->path_a_cnt;
250562306a36Sopenharmony_ci	else
250662306a36Sopenharmony_ci		rssi_a = 0;
250762306a36Sopenharmony_ci	if (path_div->path_b_cnt)
250862306a36Sopenharmony_ci		rssi_b = path_div->path_b_sum / path_div->path_b_cnt;
250962306a36Sopenharmony_ci	else
251062306a36Sopenharmony_ci		rssi_b = 0;
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	if (rssi_a != rssi_b)
251362306a36Sopenharmony_ci		path = (rssi_a > rssi_b) ? BB_PATH_A : BB_PATH_B;
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	path_div->path_a_cnt = 0;
251662306a36Sopenharmony_ci	path_div->path_a_sum = 0;
251762306a36Sopenharmony_ci	path_div->path_b_cnt = 0;
251862306a36Sopenharmony_ci	path_div->path_b_sum = 0;
251962306a36Sopenharmony_ci	rtw_phy_set_tx_path_by_reg(rtwdev, path);
252062306a36Sopenharmony_ci}
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_cistatic void rtw_phy_tx_path_diversity_2ss(struct rtw_dev *rtwdev)
252362306a36Sopenharmony_ci{
252462306a36Sopenharmony_ci	if (rtwdev->hal.antenna_rx != BB_PATH_AB) {
252562306a36Sopenharmony_ci		rtw_dbg(rtwdev, RTW_DBG_PATH_DIV,
252662306a36Sopenharmony_ci			"[Return] tx_Path_en=%d, rx_Path_en=%d\n",
252762306a36Sopenharmony_ci			rtwdev->hal.antenna_tx, rtwdev->hal.antenna_rx);
252862306a36Sopenharmony_ci		return;
252962306a36Sopenharmony_ci	}
253062306a36Sopenharmony_ci	if (rtwdev->sta_cnt == 0) {
253162306a36Sopenharmony_ci		rtw_dbg(rtwdev, RTW_DBG_PATH_DIV, "No Link\n");
253262306a36Sopenharmony_ci		return;
253362306a36Sopenharmony_ci	}
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	rtw_phy_tx_path_div_select(rtwdev);
253662306a36Sopenharmony_ci}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_civoid rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev)
253962306a36Sopenharmony_ci{
254062306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	if (!chip->path_div_supported)
254362306a36Sopenharmony_ci		return;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	rtw_phy_tx_path_diversity_2ss(rtwdev);
254662306a36Sopenharmony_ci}
2547