xref: /openbmc/linux/drivers/net/wireless/realtek/rtw88/phy.c (revision e3037485c68ec1a299ff41160d8fedbd4abc29b9)
1*e3037485SYan-Hsuan Chuang // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2*e3037485SYan-Hsuan Chuang /* Copyright(c) 2018-2019  Realtek Corporation
3*e3037485SYan-Hsuan Chuang  */
4*e3037485SYan-Hsuan Chuang 
5*e3037485SYan-Hsuan Chuang #include <linux/bcd.h>
6*e3037485SYan-Hsuan Chuang 
7*e3037485SYan-Hsuan Chuang #include "main.h"
8*e3037485SYan-Hsuan Chuang #include "reg.h"
9*e3037485SYan-Hsuan Chuang #include "fw.h"
10*e3037485SYan-Hsuan Chuang #include "phy.h"
11*e3037485SYan-Hsuan Chuang #include "debug.h"
12*e3037485SYan-Hsuan Chuang 
13*e3037485SYan-Hsuan Chuang struct phy_cfg_pair {
14*e3037485SYan-Hsuan Chuang 	u32 addr;
15*e3037485SYan-Hsuan Chuang 	u32 data;
16*e3037485SYan-Hsuan Chuang };
17*e3037485SYan-Hsuan Chuang 
18*e3037485SYan-Hsuan Chuang union phy_table_tile {
19*e3037485SYan-Hsuan Chuang 	struct rtw_phy_cond cond;
20*e3037485SYan-Hsuan Chuang 	struct phy_cfg_pair cfg;
21*e3037485SYan-Hsuan Chuang };
22*e3037485SYan-Hsuan Chuang 
23*e3037485SYan-Hsuan Chuang struct phy_pg_cfg_pair {
24*e3037485SYan-Hsuan Chuang 	u32 band;
25*e3037485SYan-Hsuan Chuang 	u32 rf_path;
26*e3037485SYan-Hsuan Chuang 	u32 tx_num;
27*e3037485SYan-Hsuan Chuang 	u32 addr;
28*e3037485SYan-Hsuan Chuang 	u32 bitmask;
29*e3037485SYan-Hsuan Chuang 	u32 data;
30*e3037485SYan-Hsuan Chuang };
31*e3037485SYan-Hsuan Chuang 
32*e3037485SYan-Hsuan Chuang struct txpwr_lmt_cfg_pair {
33*e3037485SYan-Hsuan Chuang 	u8 regd;
34*e3037485SYan-Hsuan Chuang 	u8 band;
35*e3037485SYan-Hsuan Chuang 	u8 bw;
36*e3037485SYan-Hsuan Chuang 	u8 rs;
37*e3037485SYan-Hsuan Chuang 	u8 ch;
38*e3037485SYan-Hsuan Chuang 	s8 txpwr_lmt;
39*e3037485SYan-Hsuan Chuang };
40*e3037485SYan-Hsuan Chuang 
41*e3037485SYan-Hsuan Chuang static const u32 db_invert_table[12][8] = {
42*e3037485SYan-Hsuan Chuang 	{10,		13,		16,		20,
43*e3037485SYan-Hsuan Chuang 	 25,		32,		40,		50},
44*e3037485SYan-Hsuan Chuang 	{64,		80,		101,		128,
45*e3037485SYan-Hsuan Chuang 	 160,		201,		256,		318},
46*e3037485SYan-Hsuan Chuang 	{401,		505,		635,		800,
47*e3037485SYan-Hsuan Chuang 	 1007,		1268,		1596,		2010},
48*e3037485SYan-Hsuan Chuang 	{316,		398,		501,		631,
49*e3037485SYan-Hsuan Chuang 	 794,		1000,		1259,		1585},
50*e3037485SYan-Hsuan Chuang 	{1995,		2512,		3162,		3981,
51*e3037485SYan-Hsuan Chuang 	 5012,		6310,		7943,		10000},
52*e3037485SYan-Hsuan Chuang 	{12589,		15849,		19953,		25119,
53*e3037485SYan-Hsuan Chuang 	 31623,		39811,		50119,		63098},
54*e3037485SYan-Hsuan Chuang 	{79433,		100000,		125893,		158489,
55*e3037485SYan-Hsuan Chuang 	 199526,	251189,		316228,		398107},
56*e3037485SYan-Hsuan Chuang 	{501187,	630957,		794328,		1000000,
57*e3037485SYan-Hsuan Chuang 	 1258925,	1584893,	1995262,	2511886},
58*e3037485SYan-Hsuan Chuang 	{3162278,	3981072,	5011872,	6309573,
59*e3037485SYan-Hsuan Chuang 	 7943282,	1000000,	12589254,	15848932},
60*e3037485SYan-Hsuan Chuang 	{19952623,	25118864,	31622777,	39810717,
61*e3037485SYan-Hsuan Chuang 	 50118723,	63095734,	79432823,	100000000},
62*e3037485SYan-Hsuan Chuang 	{125892541,	158489319,	199526232,	251188643,
63*e3037485SYan-Hsuan Chuang 	 316227766,	398107171,	501187234,	630957345},
64*e3037485SYan-Hsuan Chuang 	{794328235,	1000000000,	1258925412,	1584893192,
65*e3037485SYan-Hsuan Chuang 	 1995262315,	2511886432U,	3162277660U,	3981071706U}
66*e3037485SYan-Hsuan Chuang };
67*e3037485SYan-Hsuan Chuang 
68*e3037485SYan-Hsuan Chuang enum rtw_phy_band_type {
69*e3037485SYan-Hsuan Chuang 	PHY_BAND_2G	= 0,
70*e3037485SYan-Hsuan Chuang 	PHY_BAND_5G	= 1,
71*e3037485SYan-Hsuan Chuang };
72*e3037485SYan-Hsuan Chuang 
73*e3037485SYan-Hsuan Chuang void rtw_phy_init(struct rtw_dev *rtwdev)
74*e3037485SYan-Hsuan Chuang {
75*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
76*e3037485SYan-Hsuan Chuang 	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
77*e3037485SYan-Hsuan Chuang 	u32 addr, mask;
78*e3037485SYan-Hsuan Chuang 
79*e3037485SYan-Hsuan Chuang 	dm_info->fa_history[3] = 0;
80*e3037485SYan-Hsuan Chuang 	dm_info->fa_history[2] = 0;
81*e3037485SYan-Hsuan Chuang 	dm_info->fa_history[1] = 0;
82*e3037485SYan-Hsuan Chuang 	dm_info->fa_history[0] = 0;
83*e3037485SYan-Hsuan Chuang 	dm_info->igi_bitmap = 0;
84*e3037485SYan-Hsuan Chuang 	dm_info->igi_history[3] = 0;
85*e3037485SYan-Hsuan Chuang 	dm_info->igi_history[2] = 0;
86*e3037485SYan-Hsuan Chuang 	dm_info->igi_history[1] = 0;
87*e3037485SYan-Hsuan Chuang 
88*e3037485SYan-Hsuan Chuang 	addr = chip->dig[0].addr;
89*e3037485SYan-Hsuan Chuang 	mask = chip->dig[0].mask;
90*e3037485SYan-Hsuan Chuang 	dm_info->igi_history[0] = rtw_read32_mask(rtwdev, addr, mask);
91*e3037485SYan-Hsuan Chuang }
92*e3037485SYan-Hsuan Chuang 
93*e3037485SYan-Hsuan Chuang void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi)
94*e3037485SYan-Hsuan Chuang {
95*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
96*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
97*e3037485SYan-Hsuan Chuang 	u32 addr, mask;
98*e3037485SYan-Hsuan Chuang 	u8 path;
99*e3037485SYan-Hsuan Chuang 
100*e3037485SYan-Hsuan Chuang 	for (path = 0; path < hal->rf_path_num; path++) {
101*e3037485SYan-Hsuan Chuang 		addr = chip->dig[path].addr;
102*e3037485SYan-Hsuan Chuang 		mask = chip->dig[path].mask;
103*e3037485SYan-Hsuan Chuang 		rtw_write32_mask(rtwdev, addr, mask, igi);
104*e3037485SYan-Hsuan Chuang 	}
105*e3037485SYan-Hsuan Chuang }
106*e3037485SYan-Hsuan Chuang 
107*e3037485SYan-Hsuan Chuang static void rtw_phy_stat_false_alarm(struct rtw_dev *rtwdev)
108*e3037485SYan-Hsuan Chuang {
109*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
110*e3037485SYan-Hsuan Chuang 
111*e3037485SYan-Hsuan Chuang 	chip->ops->false_alarm_statistics(rtwdev);
112*e3037485SYan-Hsuan Chuang }
113*e3037485SYan-Hsuan Chuang 
114*e3037485SYan-Hsuan Chuang #define RA_FLOOR_TABLE_SIZE	7
115*e3037485SYan-Hsuan Chuang #define RA_FLOOR_UP_GAP		3
116*e3037485SYan-Hsuan Chuang 
117*e3037485SYan-Hsuan Chuang static u8 rtw_phy_get_rssi_level(u8 old_level, u8 rssi)
118*e3037485SYan-Hsuan Chuang {
119*e3037485SYan-Hsuan Chuang 	u8 table[RA_FLOOR_TABLE_SIZE] = {20, 34, 38, 42, 46, 50, 100};
120*e3037485SYan-Hsuan Chuang 	u8 new_level = 0;
121*e3037485SYan-Hsuan Chuang 	int i;
122*e3037485SYan-Hsuan Chuang 
123*e3037485SYan-Hsuan Chuang 	for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++)
124*e3037485SYan-Hsuan Chuang 		if (i >= old_level)
125*e3037485SYan-Hsuan Chuang 			table[i] += RA_FLOOR_UP_GAP;
126*e3037485SYan-Hsuan Chuang 
127*e3037485SYan-Hsuan Chuang 	for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++) {
128*e3037485SYan-Hsuan Chuang 		if (rssi < table[i]) {
129*e3037485SYan-Hsuan Chuang 			new_level = i;
130*e3037485SYan-Hsuan Chuang 			break;
131*e3037485SYan-Hsuan Chuang 		}
132*e3037485SYan-Hsuan Chuang 	}
133*e3037485SYan-Hsuan Chuang 
134*e3037485SYan-Hsuan Chuang 	return new_level;
135*e3037485SYan-Hsuan Chuang }
136*e3037485SYan-Hsuan Chuang 
137*e3037485SYan-Hsuan Chuang struct rtw_phy_stat_iter_data {
138*e3037485SYan-Hsuan Chuang 	struct rtw_dev *rtwdev;
139*e3037485SYan-Hsuan Chuang 	u8 min_rssi;
140*e3037485SYan-Hsuan Chuang };
141*e3037485SYan-Hsuan Chuang 
142*e3037485SYan-Hsuan Chuang static void rtw_phy_stat_rssi_iter(void *data, struct ieee80211_sta *sta)
143*e3037485SYan-Hsuan Chuang {
144*e3037485SYan-Hsuan Chuang 	struct rtw_phy_stat_iter_data *iter_data = data;
145*e3037485SYan-Hsuan Chuang 	struct rtw_dev *rtwdev = iter_data->rtwdev;
146*e3037485SYan-Hsuan Chuang 	struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
147*e3037485SYan-Hsuan Chuang 	u8 rssi, rssi_level;
148*e3037485SYan-Hsuan Chuang 
149*e3037485SYan-Hsuan Chuang 	rssi = ewma_rssi_read(&si->avg_rssi);
150*e3037485SYan-Hsuan Chuang 	rssi_level = rtw_phy_get_rssi_level(si->rssi_level, rssi);
151*e3037485SYan-Hsuan Chuang 
152*e3037485SYan-Hsuan Chuang 	rtw_fw_send_rssi_info(rtwdev, si);
153*e3037485SYan-Hsuan Chuang 
154*e3037485SYan-Hsuan Chuang 	iter_data->min_rssi = min_t(u8, rssi, iter_data->min_rssi);
155*e3037485SYan-Hsuan Chuang }
156*e3037485SYan-Hsuan Chuang 
157*e3037485SYan-Hsuan Chuang static void rtw_phy_stat_rssi(struct rtw_dev *rtwdev)
158*e3037485SYan-Hsuan Chuang {
159*e3037485SYan-Hsuan Chuang 	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
160*e3037485SYan-Hsuan Chuang 	struct rtw_phy_stat_iter_data data = {};
161*e3037485SYan-Hsuan Chuang 
162*e3037485SYan-Hsuan Chuang 	data.rtwdev = rtwdev;
163*e3037485SYan-Hsuan Chuang 	data.min_rssi = U8_MAX;
164*e3037485SYan-Hsuan Chuang 	rtw_iterate_stas_atomic(rtwdev, rtw_phy_stat_rssi_iter, &data);
165*e3037485SYan-Hsuan Chuang 
166*e3037485SYan-Hsuan Chuang 	dm_info->pre_min_rssi = dm_info->min_rssi;
167*e3037485SYan-Hsuan Chuang 	dm_info->min_rssi = data.min_rssi;
168*e3037485SYan-Hsuan Chuang }
169*e3037485SYan-Hsuan Chuang 
170*e3037485SYan-Hsuan Chuang static void rtw_phy_statistics(struct rtw_dev *rtwdev)
171*e3037485SYan-Hsuan Chuang {
172*e3037485SYan-Hsuan Chuang 	rtw_phy_stat_rssi(rtwdev);
173*e3037485SYan-Hsuan Chuang 	rtw_phy_stat_false_alarm(rtwdev);
174*e3037485SYan-Hsuan Chuang }
175*e3037485SYan-Hsuan Chuang 
176*e3037485SYan-Hsuan Chuang #define DIG_PERF_FA_TH_LOW			250
177*e3037485SYan-Hsuan Chuang #define DIG_PERF_FA_TH_HIGH			500
178*e3037485SYan-Hsuan Chuang #define DIG_PERF_FA_TH_EXTRA_HIGH		750
179*e3037485SYan-Hsuan Chuang #define DIG_PERF_MAX				0x5a
180*e3037485SYan-Hsuan Chuang #define DIG_PERF_MID				0x40
181*e3037485SYan-Hsuan Chuang #define DIG_CVRG_FA_TH_LOW			2000
182*e3037485SYan-Hsuan Chuang #define DIG_CVRG_FA_TH_HIGH			4000
183*e3037485SYan-Hsuan Chuang #define DIG_CVRG_FA_TH_EXTRA_HIGH		5000
184*e3037485SYan-Hsuan Chuang #define DIG_CVRG_MAX				0x2a
185*e3037485SYan-Hsuan Chuang #define DIG_CVRG_MID				0x26
186*e3037485SYan-Hsuan Chuang #define DIG_CVRG_MIN				0x1c
187*e3037485SYan-Hsuan Chuang #define DIG_RSSI_GAIN_OFFSET			15
188*e3037485SYan-Hsuan Chuang 
189*e3037485SYan-Hsuan Chuang static bool
190*e3037485SYan-Hsuan Chuang rtw_phy_dig_check_damping(struct rtw_dm_info *dm_info)
191*e3037485SYan-Hsuan Chuang {
192*e3037485SYan-Hsuan Chuang 	u16 fa_lo = DIG_PERF_FA_TH_LOW;
193*e3037485SYan-Hsuan Chuang 	u16 fa_hi = DIG_PERF_FA_TH_HIGH;
194*e3037485SYan-Hsuan Chuang 	u16 *fa_history;
195*e3037485SYan-Hsuan Chuang 	u8 *igi_history;
196*e3037485SYan-Hsuan Chuang 	u8 damping_rssi;
197*e3037485SYan-Hsuan Chuang 	u8 min_rssi;
198*e3037485SYan-Hsuan Chuang 	u8 diff;
199*e3037485SYan-Hsuan Chuang 	u8 igi_bitmap;
200*e3037485SYan-Hsuan Chuang 	bool damping = false;
201*e3037485SYan-Hsuan Chuang 
202*e3037485SYan-Hsuan Chuang 	min_rssi = dm_info->min_rssi;
203*e3037485SYan-Hsuan Chuang 	if (dm_info->damping) {
204*e3037485SYan-Hsuan Chuang 		damping_rssi = dm_info->damping_rssi;
205*e3037485SYan-Hsuan Chuang 		diff = min_rssi > damping_rssi ? min_rssi - damping_rssi :
206*e3037485SYan-Hsuan Chuang 						 damping_rssi - min_rssi;
207*e3037485SYan-Hsuan Chuang 		if (diff > 3 || dm_info->damping_cnt++ > 20) {
208*e3037485SYan-Hsuan Chuang 			dm_info->damping = false;
209*e3037485SYan-Hsuan Chuang 			return false;
210*e3037485SYan-Hsuan Chuang 		}
211*e3037485SYan-Hsuan Chuang 
212*e3037485SYan-Hsuan Chuang 		return true;
213*e3037485SYan-Hsuan Chuang 	}
214*e3037485SYan-Hsuan Chuang 
215*e3037485SYan-Hsuan Chuang 	igi_history = dm_info->igi_history;
216*e3037485SYan-Hsuan Chuang 	fa_history = dm_info->fa_history;
217*e3037485SYan-Hsuan Chuang 	igi_bitmap = dm_info->igi_bitmap & 0xf;
218*e3037485SYan-Hsuan Chuang 	switch (igi_bitmap) {
219*e3037485SYan-Hsuan Chuang 	case 5:
220*e3037485SYan-Hsuan Chuang 		/* down -> up -> down -> up */
221*e3037485SYan-Hsuan Chuang 		if (igi_history[0] > igi_history[1] &&
222*e3037485SYan-Hsuan Chuang 		    igi_history[2] > igi_history[3] &&
223*e3037485SYan-Hsuan Chuang 		    igi_history[0] - igi_history[1] >= 2 &&
224*e3037485SYan-Hsuan Chuang 		    igi_history[2] - igi_history[3] >= 2 &&
225*e3037485SYan-Hsuan Chuang 		    fa_history[0] > fa_hi && fa_history[1] < fa_lo &&
226*e3037485SYan-Hsuan Chuang 		    fa_history[2] > fa_hi && fa_history[3] < fa_lo)
227*e3037485SYan-Hsuan Chuang 			damping = true;
228*e3037485SYan-Hsuan Chuang 		break;
229*e3037485SYan-Hsuan Chuang 	case 9:
230*e3037485SYan-Hsuan Chuang 		/* up -> down -> down -> up */
231*e3037485SYan-Hsuan Chuang 		if (igi_history[0] > igi_history[1] &&
232*e3037485SYan-Hsuan Chuang 		    igi_history[3] > igi_history[2] &&
233*e3037485SYan-Hsuan Chuang 		    igi_history[0] - igi_history[1] >= 4 &&
234*e3037485SYan-Hsuan Chuang 		    igi_history[3] - igi_history[2] >= 2 &&
235*e3037485SYan-Hsuan Chuang 		    fa_history[0] > fa_hi && fa_history[1] < fa_lo &&
236*e3037485SYan-Hsuan Chuang 		    fa_history[2] < fa_lo && fa_history[3] > fa_hi)
237*e3037485SYan-Hsuan Chuang 			damping = true;
238*e3037485SYan-Hsuan Chuang 		break;
239*e3037485SYan-Hsuan Chuang 	default:
240*e3037485SYan-Hsuan Chuang 		return false;
241*e3037485SYan-Hsuan Chuang 	}
242*e3037485SYan-Hsuan Chuang 
243*e3037485SYan-Hsuan Chuang 	if (damping) {
244*e3037485SYan-Hsuan Chuang 		dm_info->damping = true;
245*e3037485SYan-Hsuan Chuang 		dm_info->damping_cnt = 0;
246*e3037485SYan-Hsuan Chuang 		dm_info->damping_rssi = min_rssi;
247*e3037485SYan-Hsuan Chuang 	}
248*e3037485SYan-Hsuan Chuang 
249*e3037485SYan-Hsuan Chuang 	return damping;
250*e3037485SYan-Hsuan Chuang }
251*e3037485SYan-Hsuan Chuang 
252*e3037485SYan-Hsuan Chuang static void rtw_phy_dig_get_boundary(struct rtw_dm_info *dm_info,
253*e3037485SYan-Hsuan Chuang 				     u8 *upper, u8 *lower, bool linked)
254*e3037485SYan-Hsuan Chuang {
255*e3037485SYan-Hsuan Chuang 	u8 dig_max, dig_min, dig_mid;
256*e3037485SYan-Hsuan Chuang 	u8 min_rssi;
257*e3037485SYan-Hsuan Chuang 
258*e3037485SYan-Hsuan Chuang 	if (linked) {
259*e3037485SYan-Hsuan Chuang 		dig_max = DIG_PERF_MAX;
260*e3037485SYan-Hsuan Chuang 		dig_mid = DIG_PERF_MID;
261*e3037485SYan-Hsuan Chuang 		/* 22B=0x1c, 22C=0x20 */
262*e3037485SYan-Hsuan Chuang 		dig_min = 0x1c;
263*e3037485SYan-Hsuan Chuang 		min_rssi = max_t(u8, dm_info->min_rssi, dig_min);
264*e3037485SYan-Hsuan Chuang 	} else {
265*e3037485SYan-Hsuan Chuang 		dig_max = DIG_CVRG_MAX;
266*e3037485SYan-Hsuan Chuang 		dig_mid = DIG_CVRG_MID;
267*e3037485SYan-Hsuan Chuang 		dig_min = DIG_CVRG_MIN;
268*e3037485SYan-Hsuan Chuang 		min_rssi = dig_min;
269*e3037485SYan-Hsuan Chuang 	}
270*e3037485SYan-Hsuan Chuang 
271*e3037485SYan-Hsuan Chuang 	/* DIG MAX should be bounded by minimum RSSI with offset +15 */
272*e3037485SYan-Hsuan Chuang 	dig_max = min_t(u8, dig_max, min_rssi + DIG_RSSI_GAIN_OFFSET);
273*e3037485SYan-Hsuan Chuang 
274*e3037485SYan-Hsuan Chuang 	*lower = clamp_t(u8, min_rssi, dig_min, dig_mid);
275*e3037485SYan-Hsuan Chuang 	*upper = clamp_t(u8, *lower + DIG_RSSI_GAIN_OFFSET, dig_min, dig_max);
276*e3037485SYan-Hsuan Chuang }
277*e3037485SYan-Hsuan Chuang 
278*e3037485SYan-Hsuan Chuang static void rtw_phy_dig_get_threshold(struct rtw_dm_info *dm_info,
279*e3037485SYan-Hsuan Chuang 				      u16 *fa_th, u8 *step, bool linked)
280*e3037485SYan-Hsuan Chuang {
281*e3037485SYan-Hsuan Chuang 	u8 min_rssi, pre_min_rssi;
282*e3037485SYan-Hsuan Chuang 
283*e3037485SYan-Hsuan Chuang 	min_rssi = dm_info->min_rssi;
284*e3037485SYan-Hsuan Chuang 	pre_min_rssi = dm_info->pre_min_rssi;
285*e3037485SYan-Hsuan Chuang 	step[0] = 4;
286*e3037485SYan-Hsuan Chuang 	step[1] = 3;
287*e3037485SYan-Hsuan Chuang 	step[2] = 2;
288*e3037485SYan-Hsuan Chuang 
289*e3037485SYan-Hsuan Chuang 	if (linked) {
290*e3037485SYan-Hsuan Chuang 		fa_th[0] = DIG_PERF_FA_TH_EXTRA_HIGH;
291*e3037485SYan-Hsuan Chuang 		fa_th[1] = DIG_PERF_FA_TH_HIGH;
292*e3037485SYan-Hsuan Chuang 		fa_th[2] = DIG_PERF_FA_TH_LOW;
293*e3037485SYan-Hsuan Chuang 		if (pre_min_rssi > min_rssi) {
294*e3037485SYan-Hsuan Chuang 			step[0] = 6;
295*e3037485SYan-Hsuan Chuang 			step[1] = 4;
296*e3037485SYan-Hsuan Chuang 			step[2] = 2;
297*e3037485SYan-Hsuan Chuang 		}
298*e3037485SYan-Hsuan Chuang 	} else {
299*e3037485SYan-Hsuan Chuang 		fa_th[0] = DIG_CVRG_FA_TH_EXTRA_HIGH;
300*e3037485SYan-Hsuan Chuang 		fa_th[1] = DIG_CVRG_FA_TH_HIGH;
301*e3037485SYan-Hsuan Chuang 		fa_th[2] = DIG_CVRG_FA_TH_LOW;
302*e3037485SYan-Hsuan Chuang 	}
303*e3037485SYan-Hsuan Chuang }
304*e3037485SYan-Hsuan Chuang 
305*e3037485SYan-Hsuan Chuang static void rtw_phy_dig_recorder(struct rtw_dm_info *dm_info, u8 igi, u16 fa)
306*e3037485SYan-Hsuan Chuang {
307*e3037485SYan-Hsuan Chuang 	u8 *igi_history;
308*e3037485SYan-Hsuan Chuang 	u16 *fa_history;
309*e3037485SYan-Hsuan Chuang 	u8 igi_bitmap;
310*e3037485SYan-Hsuan Chuang 	bool up;
311*e3037485SYan-Hsuan Chuang 
312*e3037485SYan-Hsuan Chuang 	igi_bitmap = dm_info->igi_bitmap << 1 & 0xfe;
313*e3037485SYan-Hsuan Chuang 	igi_history = dm_info->igi_history;
314*e3037485SYan-Hsuan Chuang 	fa_history = dm_info->fa_history;
315*e3037485SYan-Hsuan Chuang 
316*e3037485SYan-Hsuan Chuang 	up = igi > igi_history[0];
317*e3037485SYan-Hsuan Chuang 	igi_bitmap |= up;
318*e3037485SYan-Hsuan Chuang 
319*e3037485SYan-Hsuan Chuang 	igi_history[3] = igi_history[2];
320*e3037485SYan-Hsuan Chuang 	igi_history[2] = igi_history[1];
321*e3037485SYan-Hsuan Chuang 	igi_history[1] = igi_history[0];
322*e3037485SYan-Hsuan Chuang 	igi_history[0] = igi;
323*e3037485SYan-Hsuan Chuang 
324*e3037485SYan-Hsuan Chuang 	fa_history[3] = fa_history[2];
325*e3037485SYan-Hsuan Chuang 	fa_history[2] = fa_history[1];
326*e3037485SYan-Hsuan Chuang 	fa_history[1] = fa_history[0];
327*e3037485SYan-Hsuan Chuang 	fa_history[0] = fa;
328*e3037485SYan-Hsuan Chuang 
329*e3037485SYan-Hsuan Chuang 	dm_info->igi_bitmap = igi_bitmap;
330*e3037485SYan-Hsuan Chuang }
331*e3037485SYan-Hsuan Chuang 
332*e3037485SYan-Hsuan Chuang static void rtw_phy_dig(struct rtw_dev *rtwdev)
333*e3037485SYan-Hsuan Chuang {
334*e3037485SYan-Hsuan Chuang 	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
335*e3037485SYan-Hsuan Chuang 	u8 upper_bound, lower_bound;
336*e3037485SYan-Hsuan Chuang 	u8 pre_igi, cur_igi;
337*e3037485SYan-Hsuan Chuang 	u16 fa_th[3], fa_cnt;
338*e3037485SYan-Hsuan Chuang 	u8 level;
339*e3037485SYan-Hsuan Chuang 	u8 step[3];
340*e3037485SYan-Hsuan Chuang 	bool linked;
341*e3037485SYan-Hsuan Chuang 
342*e3037485SYan-Hsuan Chuang 	if (rtw_flag_check(rtwdev, RTW_FLAG_DIG_DISABLE))
343*e3037485SYan-Hsuan Chuang 		return;
344*e3037485SYan-Hsuan Chuang 
345*e3037485SYan-Hsuan Chuang 	if (rtw_phy_dig_check_damping(dm_info))
346*e3037485SYan-Hsuan Chuang 		return;
347*e3037485SYan-Hsuan Chuang 
348*e3037485SYan-Hsuan Chuang 	linked = !!rtwdev->sta_cnt;
349*e3037485SYan-Hsuan Chuang 
350*e3037485SYan-Hsuan Chuang 	fa_cnt = dm_info->total_fa_cnt;
351*e3037485SYan-Hsuan Chuang 	pre_igi = dm_info->igi_history[0];
352*e3037485SYan-Hsuan Chuang 
353*e3037485SYan-Hsuan Chuang 	rtw_phy_dig_get_threshold(dm_info, fa_th, step, linked);
354*e3037485SYan-Hsuan Chuang 
355*e3037485SYan-Hsuan Chuang 	/* test the false alarm count from the highest threshold level first,
356*e3037485SYan-Hsuan Chuang 	 * and increase it by corresponding step size
357*e3037485SYan-Hsuan Chuang 	 *
358*e3037485SYan-Hsuan Chuang 	 * note that the step size is offset by -2, compensate it afterall
359*e3037485SYan-Hsuan Chuang 	 */
360*e3037485SYan-Hsuan Chuang 	cur_igi = pre_igi;
361*e3037485SYan-Hsuan Chuang 	for (level = 0; level < 3; level++) {
362*e3037485SYan-Hsuan Chuang 		if (fa_cnt > fa_th[level]) {
363*e3037485SYan-Hsuan Chuang 			cur_igi += step[level];
364*e3037485SYan-Hsuan Chuang 			break;
365*e3037485SYan-Hsuan Chuang 		}
366*e3037485SYan-Hsuan Chuang 	}
367*e3037485SYan-Hsuan Chuang 	cur_igi -= 2;
368*e3037485SYan-Hsuan Chuang 
369*e3037485SYan-Hsuan Chuang 	/* calculate the upper/lower bound by the minimum rssi we have among
370*e3037485SYan-Hsuan Chuang 	 * the peers connected with us, meanwhile make sure the igi value does
371*e3037485SYan-Hsuan Chuang 	 * not beyond the hardware limitation
372*e3037485SYan-Hsuan Chuang 	 */
373*e3037485SYan-Hsuan Chuang 	rtw_phy_dig_get_boundary(dm_info, &upper_bound, &lower_bound, linked);
374*e3037485SYan-Hsuan Chuang 	cur_igi = clamp_t(u8, cur_igi, lower_bound, upper_bound);
375*e3037485SYan-Hsuan Chuang 
376*e3037485SYan-Hsuan Chuang 	/* record current igi value and false alarm statistics for further
377*e3037485SYan-Hsuan Chuang 	 * damping checks, and record the trend of igi values
378*e3037485SYan-Hsuan Chuang 	 */
379*e3037485SYan-Hsuan Chuang 	rtw_phy_dig_recorder(dm_info, cur_igi, fa_cnt);
380*e3037485SYan-Hsuan Chuang 
381*e3037485SYan-Hsuan Chuang 	if (cur_igi != pre_igi)
382*e3037485SYan-Hsuan Chuang 		rtw_phy_dig_write(rtwdev, cur_igi);
383*e3037485SYan-Hsuan Chuang }
384*e3037485SYan-Hsuan Chuang 
385*e3037485SYan-Hsuan Chuang static void rtw_phy_ra_info_update_iter(void *data, struct ieee80211_sta *sta)
386*e3037485SYan-Hsuan Chuang {
387*e3037485SYan-Hsuan Chuang 	struct rtw_dev *rtwdev = data;
388*e3037485SYan-Hsuan Chuang 	struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
389*e3037485SYan-Hsuan Chuang 
390*e3037485SYan-Hsuan Chuang 	rtw_update_sta_info(rtwdev, si);
391*e3037485SYan-Hsuan Chuang }
392*e3037485SYan-Hsuan Chuang 
393*e3037485SYan-Hsuan Chuang static void rtw_phy_ra_info_update(struct rtw_dev *rtwdev)
394*e3037485SYan-Hsuan Chuang {
395*e3037485SYan-Hsuan Chuang 	if (rtwdev->watch_dog_cnt & 0x3)
396*e3037485SYan-Hsuan Chuang 		return;
397*e3037485SYan-Hsuan Chuang 
398*e3037485SYan-Hsuan Chuang 	rtw_iterate_stas_atomic(rtwdev, rtw_phy_ra_info_update_iter, rtwdev);
399*e3037485SYan-Hsuan Chuang }
400*e3037485SYan-Hsuan Chuang 
401*e3037485SYan-Hsuan Chuang void rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev)
402*e3037485SYan-Hsuan Chuang {
403*e3037485SYan-Hsuan Chuang 	/* for further calculation */
404*e3037485SYan-Hsuan Chuang 	rtw_phy_statistics(rtwdev);
405*e3037485SYan-Hsuan Chuang 	rtw_phy_dig(rtwdev);
406*e3037485SYan-Hsuan Chuang 	rtw_phy_ra_info_update(rtwdev);
407*e3037485SYan-Hsuan Chuang }
408*e3037485SYan-Hsuan Chuang 
409*e3037485SYan-Hsuan Chuang #define FRAC_BITS 3
410*e3037485SYan-Hsuan Chuang 
411*e3037485SYan-Hsuan Chuang static u8 rtw_phy_power_2_db(s8 power)
412*e3037485SYan-Hsuan Chuang {
413*e3037485SYan-Hsuan Chuang 	if (power <= -100 || power >= 20)
414*e3037485SYan-Hsuan Chuang 		return 0;
415*e3037485SYan-Hsuan Chuang 	else if (power >= 0)
416*e3037485SYan-Hsuan Chuang 		return 100;
417*e3037485SYan-Hsuan Chuang 	else
418*e3037485SYan-Hsuan Chuang 		return 100 + power;
419*e3037485SYan-Hsuan Chuang }
420*e3037485SYan-Hsuan Chuang 
421*e3037485SYan-Hsuan Chuang static u64 rtw_phy_db_2_linear(u8 power_db)
422*e3037485SYan-Hsuan Chuang {
423*e3037485SYan-Hsuan Chuang 	u8 i, j;
424*e3037485SYan-Hsuan Chuang 	u64 linear;
425*e3037485SYan-Hsuan Chuang 
426*e3037485SYan-Hsuan Chuang 	/* 1dB ~ 96dB */
427*e3037485SYan-Hsuan Chuang 	i = (power_db - 1) >> 3;
428*e3037485SYan-Hsuan Chuang 	j = (power_db - 1) - (i << 3);
429*e3037485SYan-Hsuan Chuang 
430*e3037485SYan-Hsuan Chuang 	linear = db_invert_table[i][j];
431*e3037485SYan-Hsuan Chuang 	linear = i > 2 ? linear << FRAC_BITS : linear;
432*e3037485SYan-Hsuan Chuang 
433*e3037485SYan-Hsuan Chuang 	return linear;
434*e3037485SYan-Hsuan Chuang }
435*e3037485SYan-Hsuan Chuang 
436*e3037485SYan-Hsuan Chuang static u8 rtw_phy_linear_2_db(u64 linear)
437*e3037485SYan-Hsuan Chuang {
438*e3037485SYan-Hsuan Chuang 	u8 i;
439*e3037485SYan-Hsuan Chuang 	u8 j;
440*e3037485SYan-Hsuan Chuang 	u32 dB;
441*e3037485SYan-Hsuan Chuang 
442*e3037485SYan-Hsuan Chuang 	if (linear >= db_invert_table[11][7])
443*e3037485SYan-Hsuan Chuang 		return 96; /* maximum 96 dB */
444*e3037485SYan-Hsuan Chuang 
445*e3037485SYan-Hsuan Chuang 	for (i = 0; i < 12; i++) {
446*e3037485SYan-Hsuan Chuang 		if (i <= 2 && (linear << FRAC_BITS) <= db_invert_table[i][7])
447*e3037485SYan-Hsuan Chuang 			break;
448*e3037485SYan-Hsuan Chuang 		else if (i > 2 && linear <= db_invert_table[i][7])
449*e3037485SYan-Hsuan Chuang 			break;
450*e3037485SYan-Hsuan Chuang 	}
451*e3037485SYan-Hsuan Chuang 
452*e3037485SYan-Hsuan Chuang 	for (j = 0; j < 8; j++) {
453*e3037485SYan-Hsuan Chuang 		if (i <= 2 && (linear << FRAC_BITS) <= db_invert_table[i][j])
454*e3037485SYan-Hsuan Chuang 			break;
455*e3037485SYan-Hsuan Chuang 		else if (i > 2 && linear <= db_invert_table[i][j])
456*e3037485SYan-Hsuan Chuang 			break;
457*e3037485SYan-Hsuan Chuang 	}
458*e3037485SYan-Hsuan Chuang 
459*e3037485SYan-Hsuan Chuang 	if (j == 0 && i == 0)
460*e3037485SYan-Hsuan Chuang 		goto end;
461*e3037485SYan-Hsuan Chuang 
462*e3037485SYan-Hsuan Chuang 	if (j == 0) {
463*e3037485SYan-Hsuan Chuang 		if (i != 3) {
464*e3037485SYan-Hsuan Chuang 			if (db_invert_table[i][0] - linear >
465*e3037485SYan-Hsuan Chuang 			    linear - db_invert_table[i - 1][7]) {
466*e3037485SYan-Hsuan Chuang 				i = i - 1;
467*e3037485SYan-Hsuan Chuang 				j = 7;
468*e3037485SYan-Hsuan Chuang 			}
469*e3037485SYan-Hsuan Chuang 		} else {
470*e3037485SYan-Hsuan Chuang 			if (db_invert_table[3][0] - linear >
471*e3037485SYan-Hsuan Chuang 			    linear - db_invert_table[2][7]) {
472*e3037485SYan-Hsuan Chuang 				i = 2;
473*e3037485SYan-Hsuan Chuang 				j = 7;
474*e3037485SYan-Hsuan Chuang 			}
475*e3037485SYan-Hsuan Chuang 		}
476*e3037485SYan-Hsuan Chuang 	} else {
477*e3037485SYan-Hsuan Chuang 		if (db_invert_table[i][j] - linear >
478*e3037485SYan-Hsuan Chuang 		    linear - db_invert_table[i][j - 1]) {
479*e3037485SYan-Hsuan Chuang 			j = j - 1;
480*e3037485SYan-Hsuan Chuang 		}
481*e3037485SYan-Hsuan Chuang 	}
482*e3037485SYan-Hsuan Chuang end:
483*e3037485SYan-Hsuan Chuang 	dB = (i << 3) + j + 1;
484*e3037485SYan-Hsuan Chuang 
485*e3037485SYan-Hsuan Chuang 	return dB;
486*e3037485SYan-Hsuan Chuang }
487*e3037485SYan-Hsuan Chuang 
488*e3037485SYan-Hsuan Chuang u8 rtw_phy_rf_power_2_rssi(s8 *rf_power, u8 path_num)
489*e3037485SYan-Hsuan Chuang {
490*e3037485SYan-Hsuan Chuang 	s8 power;
491*e3037485SYan-Hsuan Chuang 	u8 power_db;
492*e3037485SYan-Hsuan Chuang 	u64 linear;
493*e3037485SYan-Hsuan Chuang 	u64 sum = 0;
494*e3037485SYan-Hsuan Chuang 	u8 path;
495*e3037485SYan-Hsuan Chuang 
496*e3037485SYan-Hsuan Chuang 	for (path = 0; path < path_num; path++) {
497*e3037485SYan-Hsuan Chuang 		power = rf_power[path];
498*e3037485SYan-Hsuan Chuang 		power_db = rtw_phy_power_2_db(power);
499*e3037485SYan-Hsuan Chuang 		linear = rtw_phy_db_2_linear(power_db);
500*e3037485SYan-Hsuan Chuang 		sum += linear;
501*e3037485SYan-Hsuan Chuang 	}
502*e3037485SYan-Hsuan Chuang 
503*e3037485SYan-Hsuan Chuang 	sum = (sum + (1 << (FRAC_BITS - 1))) >> FRAC_BITS;
504*e3037485SYan-Hsuan Chuang 	switch (path_num) {
505*e3037485SYan-Hsuan Chuang 	case 2:
506*e3037485SYan-Hsuan Chuang 		sum >>= 1;
507*e3037485SYan-Hsuan Chuang 		break;
508*e3037485SYan-Hsuan Chuang 	case 3:
509*e3037485SYan-Hsuan Chuang 		sum = ((sum) + ((sum) << 1) + ((sum) << 3)) >> 5;
510*e3037485SYan-Hsuan Chuang 		break;
511*e3037485SYan-Hsuan Chuang 	case 4:
512*e3037485SYan-Hsuan Chuang 		sum >>= 2;
513*e3037485SYan-Hsuan Chuang 		break;
514*e3037485SYan-Hsuan Chuang 	default:
515*e3037485SYan-Hsuan Chuang 		break;
516*e3037485SYan-Hsuan Chuang 	}
517*e3037485SYan-Hsuan Chuang 
518*e3037485SYan-Hsuan Chuang 	return rtw_phy_linear_2_db(sum);
519*e3037485SYan-Hsuan Chuang }
520*e3037485SYan-Hsuan Chuang 
521*e3037485SYan-Hsuan Chuang u32 rtw_phy_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
522*e3037485SYan-Hsuan Chuang 		    u32 addr, u32 mask)
523*e3037485SYan-Hsuan Chuang {
524*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
525*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
526*e3037485SYan-Hsuan Chuang 	const u32 *base_addr = chip->rf_base_addr;
527*e3037485SYan-Hsuan Chuang 	u32 val, direct_addr;
528*e3037485SYan-Hsuan Chuang 
529*e3037485SYan-Hsuan Chuang 	if (rf_path >= hal->rf_path_num) {
530*e3037485SYan-Hsuan Chuang 		rtw_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
531*e3037485SYan-Hsuan Chuang 		return INV_RF_DATA;
532*e3037485SYan-Hsuan Chuang 	}
533*e3037485SYan-Hsuan Chuang 
534*e3037485SYan-Hsuan Chuang 	addr &= 0xff;
535*e3037485SYan-Hsuan Chuang 	direct_addr = base_addr[rf_path] + (addr << 2);
536*e3037485SYan-Hsuan Chuang 	mask &= RFREG_MASK;
537*e3037485SYan-Hsuan Chuang 
538*e3037485SYan-Hsuan Chuang 	val = rtw_read32_mask(rtwdev, direct_addr, mask);
539*e3037485SYan-Hsuan Chuang 
540*e3037485SYan-Hsuan Chuang 	return val;
541*e3037485SYan-Hsuan Chuang }
542*e3037485SYan-Hsuan Chuang 
543*e3037485SYan-Hsuan Chuang bool rtw_phy_write_rf_reg_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
544*e3037485SYan-Hsuan Chuang 			       u32 addr, u32 mask, u32 data)
545*e3037485SYan-Hsuan Chuang {
546*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
547*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
548*e3037485SYan-Hsuan Chuang 	u32 *sipi_addr = chip->rf_sipi_addr;
549*e3037485SYan-Hsuan Chuang 	u32 data_and_addr;
550*e3037485SYan-Hsuan Chuang 	u32 old_data = 0;
551*e3037485SYan-Hsuan Chuang 	u32 shift;
552*e3037485SYan-Hsuan Chuang 
553*e3037485SYan-Hsuan Chuang 	if (rf_path >= hal->rf_path_num) {
554*e3037485SYan-Hsuan Chuang 		rtw_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
555*e3037485SYan-Hsuan Chuang 		return false;
556*e3037485SYan-Hsuan Chuang 	}
557*e3037485SYan-Hsuan Chuang 
558*e3037485SYan-Hsuan Chuang 	addr &= 0xff;
559*e3037485SYan-Hsuan Chuang 	mask &= RFREG_MASK;
560*e3037485SYan-Hsuan Chuang 
561*e3037485SYan-Hsuan Chuang 	if (mask != RFREG_MASK) {
562*e3037485SYan-Hsuan Chuang 		old_data = rtw_phy_read_rf(rtwdev, rf_path, addr, RFREG_MASK);
563*e3037485SYan-Hsuan Chuang 
564*e3037485SYan-Hsuan Chuang 		if (old_data == INV_RF_DATA) {
565*e3037485SYan-Hsuan Chuang 			rtw_err(rtwdev, "Write fail, rf is disabled\n");
566*e3037485SYan-Hsuan Chuang 			return false;
567*e3037485SYan-Hsuan Chuang 		}
568*e3037485SYan-Hsuan Chuang 
569*e3037485SYan-Hsuan Chuang 		shift = __ffs(mask);
570*e3037485SYan-Hsuan Chuang 		data = ((old_data) & (~mask)) | (data << shift);
571*e3037485SYan-Hsuan Chuang 	}
572*e3037485SYan-Hsuan Chuang 
573*e3037485SYan-Hsuan Chuang 	data_and_addr = ((addr << 20) | (data & 0x000fffff)) & 0x0fffffff;
574*e3037485SYan-Hsuan Chuang 
575*e3037485SYan-Hsuan Chuang 	rtw_write32(rtwdev, sipi_addr[rf_path], data_and_addr);
576*e3037485SYan-Hsuan Chuang 
577*e3037485SYan-Hsuan Chuang 	udelay(13);
578*e3037485SYan-Hsuan Chuang 
579*e3037485SYan-Hsuan Chuang 	return true;
580*e3037485SYan-Hsuan Chuang }
581*e3037485SYan-Hsuan Chuang 
582*e3037485SYan-Hsuan Chuang bool rtw_phy_write_rf_reg(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
583*e3037485SYan-Hsuan Chuang 			  u32 addr, u32 mask, u32 data)
584*e3037485SYan-Hsuan Chuang {
585*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
586*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
587*e3037485SYan-Hsuan Chuang 	const u32 *base_addr = chip->rf_base_addr;
588*e3037485SYan-Hsuan Chuang 	u32 direct_addr;
589*e3037485SYan-Hsuan Chuang 
590*e3037485SYan-Hsuan Chuang 	if (rf_path >= hal->rf_path_num) {
591*e3037485SYan-Hsuan Chuang 		rtw_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
592*e3037485SYan-Hsuan Chuang 		return false;
593*e3037485SYan-Hsuan Chuang 	}
594*e3037485SYan-Hsuan Chuang 
595*e3037485SYan-Hsuan Chuang 	addr &= 0xff;
596*e3037485SYan-Hsuan Chuang 	direct_addr = base_addr[rf_path] + (addr << 2);
597*e3037485SYan-Hsuan Chuang 	mask &= RFREG_MASK;
598*e3037485SYan-Hsuan Chuang 
599*e3037485SYan-Hsuan Chuang 	rtw_write32_mask(rtwdev, REG_RSV_CTRL, BITS_RFC_DIRECT, DISABLE_PI);
600*e3037485SYan-Hsuan Chuang 	rtw_write32_mask(rtwdev, REG_WLRF1, BITS_RFC_DIRECT, DISABLE_PI);
601*e3037485SYan-Hsuan Chuang 	rtw_write32_mask(rtwdev, direct_addr, mask, data);
602*e3037485SYan-Hsuan Chuang 
603*e3037485SYan-Hsuan Chuang 	udelay(1);
604*e3037485SYan-Hsuan Chuang 
605*e3037485SYan-Hsuan Chuang 	rtw_write32_mask(rtwdev, REG_RSV_CTRL, BITS_RFC_DIRECT, ENABLE_PI);
606*e3037485SYan-Hsuan Chuang 	rtw_write32_mask(rtwdev, REG_WLRF1, BITS_RFC_DIRECT, ENABLE_PI);
607*e3037485SYan-Hsuan Chuang 
608*e3037485SYan-Hsuan Chuang 	return true;
609*e3037485SYan-Hsuan Chuang }
610*e3037485SYan-Hsuan Chuang 
611*e3037485SYan-Hsuan Chuang bool rtw_phy_write_rf_reg_mix(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
612*e3037485SYan-Hsuan Chuang 			      u32 addr, u32 mask, u32 data)
613*e3037485SYan-Hsuan Chuang {
614*e3037485SYan-Hsuan Chuang 	if (addr != 0x00)
615*e3037485SYan-Hsuan Chuang 		return rtw_phy_write_rf_reg(rtwdev, rf_path, addr, mask, data);
616*e3037485SYan-Hsuan Chuang 
617*e3037485SYan-Hsuan Chuang 	return rtw_phy_write_rf_reg_sipi(rtwdev, rf_path, addr, mask, data);
618*e3037485SYan-Hsuan Chuang }
619*e3037485SYan-Hsuan Chuang 
620*e3037485SYan-Hsuan Chuang void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg)
621*e3037485SYan-Hsuan Chuang {
622*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
623*e3037485SYan-Hsuan Chuang 	struct rtw_efuse *efuse = &rtwdev->efuse;
624*e3037485SYan-Hsuan Chuang 	struct rtw_phy_cond cond = {0};
625*e3037485SYan-Hsuan Chuang 
626*e3037485SYan-Hsuan Chuang 	cond.cut = hal->cut_version ? hal->cut_version : 15;
627*e3037485SYan-Hsuan Chuang 	cond.pkg = pkg ? pkg : 15;
628*e3037485SYan-Hsuan Chuang 	cond.plat = 0x04;
629*e3037485SYan-Hsuan Chuang 	cond.rfe = efuse->rfe_option;
630*e3037485SYan-Hsuan Chuang 
631*e3037485SYan-Hsuan Chuang 	switch (rtw_hci_type(rtwdev)) {
632*e3037485SYan-Hsuan Chuang 	case RTW_HCI_TYPE_USB:
633*e3037485SYan-Hsuan Chuang 		cond.intf = INTF_USB;
634*e3037485SYan-Hsuan Chuang 		break;
635*e3037485SYan-Hsuan Chuang 	case RTW_HCI_TYPE_SDIO:
636*e3037485SYan-Hsuan Chuang 		cond.intf = INTF_SDIO;
637*e3037485SYan-Hsuan Chuang 		break;
638*e3037485SYan-Hsuan Chuang 	case RTW_HCI_TYPE_PCIE:
639*e3037485SYan-Hsuan Chuang 	default:
640*e3037485SYan-Hsuan Chuang 		cond.intf = INTF_PCIE;
641*e3037485SYan-Hsuan Chuang 		break;
642*e3037485SYan-Hsuan Chuang 	}
643*e3037485SYan-Hsuan Chuang 
644*e3037485SYan-Hsuan Chuang 	hal->phy_cond = cond;
645*e3037485SYan-Hsuan Chuang 
646*e3037485SYan-Hsuan Chuang 	rtw_dbg(rtwdev, RTW_DBG_PHY, "phy cond=0x%08x\n", *((u32 *)&hal->phy_cond));
647*e3037485SYan-Hsuan Chuang }
648*e3037485SYan-Hsuan Chuang 
649*e3037485SYan-Hsuan Chuang static bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond)
650*e3037485SYan-Hsuan Chuang {
651*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
652*e3037485SYan-Hsuan Chuang 	struct rtw_phy_cond drv_cond = hal->phy_cond;
653*e3037485SYan-Hsuan Chuang 
654*e3037485SYan-Hsuan Chuang 	if (cond.cut && cond.cut != drv_cond.cut)
655*e3037485SYan-Hsuan Chuang 		return false;
656*e3037485SYan-Hsuan Chuang 
657*e3037485SYan-Hsuan Chuang 	if (cond.pkg && cond.pkg != drv_cond.pkg)
658*e3037485SYan-Hsuan Chuang 		return false;
659*e3037485SYan-Hsuan Chuang 
660*e3037485SYan-Hsuan Chuang 	if (cond.intf && cond.intf != drv_cond.intf)
661*e3037485SYan-Hsuan Chuang 		return false;
662*e3037485SYan-Hsuan Chuang 
663*e3037485SYan-Hsuan Chuang 	if (cond.rfe != drv_cond.rfe)
664*e3037485SYan-Hsuan Chuang 		return false;
665*e3037485SYan-Hsuan Chuang 
666*e3037485SYan-Hsuan Chuang 	return true;
667*e3037485SYan-Hsuan Chuang }
668*e3037485SYan-Hsuan Chuang 
669*e3037485SYan-Hsuan Chuang void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
670*e3037485SYan-Hsuan Chuang {
671*e3037485SYan-Hsuan Chuang 	const union phy_table_tile *p = tbl->data;
672*e3037485SYan-Hsuan Chuang 	const union phy_table_tile *end = p + tbl->size / 2;
673*e3037485SYan-Hsuan Chuang 	struct rtw_phy_cond pos_cond = {0};
674*e3037485SYan-Hsuan Chuang 	bool is_matched = true, is_skipped = false;
675*e3037485SYan-Hsuan Chuang 
676*e3037485SYan-Hsuan Chuang 	BUILD_BUG_ON(sizeof(union phy_table_tile) != sizeof(struct phy_cfg_pair));
677*e3037485SYan-Hsuan Chuang 
678*e3037485SYan-Hsuan Chuang 	for (; p < end; p++) {
679*e3037485SYan-Hsuan Chuang 		if (p->cond.pos) {
680*e3037485SYan-Hsuan Chuang 			switch (p->cond.branch) {
681*e3037485SYan-Hsuan Chuang 			case BRANCH_ENDIF:
682*e3037485SYan-Hsuan Chuang 				is_matched = true;
683*e3037485SYan-Hsuan Chuang 				is_skipped = false;
684*e3037485SYan-Hsuan Chuang 				break;
685*e3037485SYan-Hsuan Chuang 			case BRANCH_ELSE:
686*e3037485SYan-Hsuan Chuang 				is_matched = is_skipped ? false : true;
687*e3037485SYan-Hsuan Chuang 				break;
688*e3037485SYan-Hsuan Chuang 			case BRANCH_IF:
689*e3037485SYan-Hsuan Chuang 			case BRANCH_ELIF:
690*e3037485SYan-Hsuan Chuang 			default:
691*e3037485SYan-Hsuan Chuang 				pos_cond = p->cond;
692*e3037485SYan-Hsuan Chuang 				break;
693*e3037485SYan-Hsuan Chuang 			}
694*e3037485SYan-Hsuan Chuang 		} else if (p->cond.neg) {
695*e3037485SYan-Hsuan Chuang 			if (!is_skipped) {
696*e3037485SYan-Hsuan Chuang 				if (check_positive(rtwdev, pos_cond)) {
697*e3037485SYan-Hsuan Chuang 					is_matched = true;
698*e3037485SYan-Hsuan Chuang 					is_skipped = true;
699*e3037485SYan-Hsuan Chuang 				} else {
700*e3037485SYan-Hsuan Chuang 					is_matched = false;
701*e3037485SYan-Hsuan Chuang 					is_skipped = false;
702*e3037485SYan-Hsuan Chuang 				}
703*e3037485SYan-Hsuan Chuang 			} else {
704*e3037485SYan-Hsuan Chuang 				is_matched = false;
705*e3037485SYan-Hsuan Chuang 			}
706*e3037485SYan-Hsuan Chuang 		} else if (is_matched) {
707*e3037485SYan-Hsuan Chuang 			(*tbl->do_cfg)(rtwdev, tbl, p->cfg.addr, p->cfg.data);
708*e3037485SYan-Hsuan Chuang 		}
709*e3037485SYan-Hsuan Chuang 	}
710*e3037485SYan-Hsuan Chuang }
711*e3037485SYan-Hsuan Chuang 
712*e3037485SYan-Hsuan Chuang void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
713*e3037485SYan-Hsuan Chuang {
714*e3037485SYan-Hsuan Chuang 	const struct phy_pg_cfg_pair *p = tbl->data;
715*e3037485SYan-Hsuan Chuang 	const struct phy_pg_cfg_pair *end = p + tbl->size / 6;
716*e3037485SYan-Hsuan Chuang 
717*e3037485SYan-Hsuan Chuang 	BUILD_BUG_ON(sizeof(struct phy_pg_cfg_pair) != sizeof(u32) * 6);
718*e3037485SYan-Hsuan Chuang 
719*e3037485SYan-Hsuan Chuang 	for (; p < end; p++) {
720*e3037485SYan-Hsuan Chuang 		if (p->addr == 0xfe || p->addr == 0xffe) {
721*e3037485SYan-Hsuan Chuang 			msleep(50);
722*e3037485SYan-Hsuan Chuang 			continue;
723*e3037485SYan-Hsuan Chuang 		}
724*e3037485SYan-Hsuan Chuang 		phy_store_tx_power_by_rate(rtwdev, p->band, p->rf_path,
725*e3037485SYan-Hsuan Chuang 					   p->tx_num, p->addr, p->bitmask,
726*e3037485SYan-Hsuan Chuang 					   p->data);
727*e3037485SYan-Hsuan Chuang 	}
728*e3037485SYan-Hsuan Chuang }
729*e3037485SYan-Hsuan Chuang 
730*e3037485SYan-Hsuan Chuang void rtw_parse_tbl_txpwr_lmt(struct rtw_dev *rtwdev,
731*e3037485SYan-Hsuan Chuang 			     const struct rtw_table *tbl)
732*e3037485SYan-Hsuan Chuang {
733*e3037485SYan-Hsuan Chuang 	const struct txpwr_lmt_cfg_pair *p = tbl->data;
734*e3037485SYan-Hsuan Chuang 	const struct txpwr_lmt_cfg_pair *end = p + tbl->size / 6;
735*e3037485SYan-Hsuan Chuang 
736*e3037485SYan-Hsuan Chuang 	BUILD_BUG_ON(sizeof(struct txpwr_lmt_cfg_pair) != sizeof(u8) * 6);
737*e3037485SYan-Hsuan Chuang 
738*e3037485SYan-Hsuan Chuang 	for (; p < end; p++) {
739*e3037485SYan-Hsuan Chuang 		phy_set_tx_power_limit(rtwdev, p->regd, p->band,
740*e3037485SYan-Hsuan Chuang 				       p->bw, p->rs,
741*e3037485SYan-Hsuan Chuang 				       p->ch, p->txpwr_lmt);
742*e3037485SYan-Hsuan Chuang 	}
743*e3037485SYan-Hsuan Chuang }
744*e3037485SYan-Hsuan Chuang 
745*e3037485SYan-Hsuan Chuang void rtw_phy_cfg_mac(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
746*e3037485SYan-Hsuan Chuang 		     u32 addr, u32 data)
747*e3037485SYan-Hsuan Chuang {
748*e3037485SYan-Hsuan Chuang 	rtw_write8(rtwdev, addr, data);
749*e3037485SYan-Hsuan Chuang }
750*e3037485SYan-Hsuan Chuang 
751*e3037485SYan-Hsuan Chuang void rtw_phy_cfg_agc(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
752*e3037485SYan-Hsuan Chuang 		     u32 addr, u32 data)
753*e3037485SYan-Hsuan Chuang {
754*e3037485SYan-Hsuan Chuang 	rtw_write32(rtwdev, addr, data);
755*e3037485SYan-Hsuan Chuang }
756*e3037485SYan-Hsuan Chuang 
757*e3037485SYan-Hsuan Chuang void rtw_phy_cfg_bb(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
758*e3037485SYan-Hsuan Chuang 		    u32 addr, u32 data)
759*e3037485SYan-Hsuan Chuang {
760*e3037485SYan-Hsuan Chuang 	if (addr == 0xfe)
761*e3037485SYan-Hsuan Chuang 		msleep(50);
762*e3037485SYan-Hsuan Chuang 	else if (addr == 0xfd)
763*e3037485SYan-Hsuan Chuang 		mdelay(5);
764*e3037485SYan-Hsuan Chuang 	else if (addr == 0xfc)
765*e3037485SYan-Hsuan Chuang 		mdelay(1);
766*e3037485SYan-Hsuan Chuang 	else if (addr == 0xfb)
767*e3037485SYan-Hsuan Chuang 		usleep_range(50, 60);
768*e3037485SYan-Hsuan Chuang 	else if (addr == 0xfa)
769*e3037485SYan-Hsuan Chuang 		udelay(5);
770*e3037485SYan-Hsuan Chuang 	else if (addr == 0xf9)
771*e3037485SYan-Hsuan Chuang 		udelay(1);
772*e3037485SYan-Hsuan Chuang 	else
773*e3037485SYan-Hsuan Chuang 		rtw_write32(rtwdev, addr, data);
774*e3037485SYan-Hsuan Chuang }
775*e3037485SYan-Hsuan Chuang 
776*e3037485SYan-Hsuan Chuang void rtw_phy_cfg_rf(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
777*e3037485SYan-Hsuan Chuang 		    u32 addr, u32 data)
778*e3037485SYan-Hsuan Chuang {
779*e3037485SYan-Hsuan Chuang 	if (addr == 0xffe) {
780*e3037485SYan-Hsuan Chuang 		msleep(50);
781*e3037485SYan-Hsuan Chuang 	} else if (addr == 0xfe) {
782*e3037485SYan-Hsuan Chuang 		usleep_range(100, 110);
783*e3037485SYan-Hsuan Chuang 	} else {
784*e3037485SYan-Hsuan Chuang 		rtw_write_rf(rtwdev, tbl->rf_path, addr, RFREG_MASK, data);
785*e3037485SYan-Hsuan Chuang 		udelay(1);
786*e3037485SYan-Hsuan Chuang 	}
787*e3037485SYan-Hsuan Chuang }
788*e3037485SYan-Hsuan Chuang 
789*e3037485SYan-Hsuan Chuang static void rtw_load_rfk_table(struct rtw_dev *rtwdev)
790*e3037485SYan-Hsuan Chuang {
791*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
792*e3037485SYan-Hsuan Chuang 
793*e3037485SYan-Hsuan Chuang 	if (!chip->rfk_init_tbl)
794*e3037485SYan-Hsuan Chuang 		return;
795*e3037485SYan-Hsuan Chuang 
796*e3037485SYan-Hsuan Chuang 	rtw_load_table(rtwdev, chip->rfk_init_tbl);
797*e3037485SYan-Hsuan Chuang }
798*e3037485SYan-Hsuan Chuang 
799*e3037485SYan-Hsuan Chuang void rtw_phy_load_tables(struct rtw_dev *rtwdev)
800*e3037485SYan-Hsuan Chuang {
801*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
802*e3037485SYan-Hsuan Chuang 	u8 rf_path;
803*e3037485SYan-Hsuan Chuang 
804*e3037485SYan-Hsuan Chuang 	rtw_load_table(rtwdev, chip->mac_tbl);
805*e3037485SYan-Hsuan Chuang 	rtw_load_table(rtwdev, chip->bb_tbl);
806*e3037485SYan-Hsuan Chuang 	rtw_load_table(rtwdev, chip->agc_tbl);
807*e3037485SYan-Hsuan Chuang 	rtw_load_rfk_table(rtwdev);
808*e3037485SYan-Hsuan Chuang 
809*e3037485SYan-Hsuan Chuang 	for (rf_path = 0; rf_path < rtwdev->hal.rf_path_num; rf_path++) {
810*e3037485SYan-Hsuan Chuang 		const struct rtw_table *tbl;
811*e3037485SYan-Hsuan Chuang 
812*e3037485SYan-Hsuan Chuang 		tbl = chip->rf_tbl[rf_path];
813*e3037485SYan-Hsuan Chuang 		rtw_load_table(rtwdev, tbl);
814*e3037485SYan-Hsuan Chuang 	}
815*e3037485SYan-Hsuan Chuang }
816*e3037485SYan-Hsuan Chuang 
817*e3037485SYan-Hsuan Chuang #define bcd_to_dec_pwr_by_rate(val, i) bcd2bin(val >> (i * 8))
818*e3037485SYan-Hsuan Chuang 
819*e3037485SYan-Hsuan Chuang #define RTW_MAX_POWER_INDEX		0x3F
820*e3037485SYan-Hsuan Chuang 
821*e3037485SYan-Hsuan Chuang u8 rtw_cck_rates[] = { DESC_RATE1M, DESC_RATE2M, DESC_RATE5_5M, DESC_RATE11M };
822*e3037485SYan-Hsuan Chuang u8 rtw_ofdm_rates[] = {
823*e3037485SYan-Hsuan Chuang 	DESC_RATE6M,  DESC_RATE9M,  DESC_RATE12M,
824*e3037485SYan-Hsuan Chuang 	DESC_RATE18M, DESC_RATE24M, DESC_RATE36M,
825*e3037485SYan-Hsuan Chuang 	DESC_RATE48M, DESC_RATE54M
826*e3037485SYan-Hsuan Chuang };
827*e3037485SYan-Hsuan Chuang u8 rtw_ht_1s_rates[] = {
828*e3037485SYan-Hsuan Chuang 	DESC_RATEMCS0, DESC_RATEMCS1, DESC_RATEMCS2,
829*e3037485SYan-Hsuan Chuang 	DESC_RATEMCS3, DESC_RATEMCS4, DESC_RATEMCS5,
830*e3037485SYan-Hsuan Chuang 	DESC_RATEMCS6, DESC_RATEMCS7
831*e3037485SYan-Hsuan Chuang };
832*e3037485SYan-Hsuan Chuang u8 rtw_ht_2s_rates[] = {
833*e3037485SYan-Hsuan Chuang 	DESC_RATEMCS8,  DESC_RATEMCS9,  DESC_RATEMCS10,
834*e3037485SYan-Hsuan Chuang 	DESC_RATEMCS11, DESC_RATEMCS12, DESC_RATEMCS13,
835*e3037485SYan-Hsuan Chuang 	DESC_RATEMCS14, DESC_RATEMCS15
836*e3037485SYan-Hsuan Chuang };
837*e3037485SYan-Hsuan Chuang u8 rtw_vht_1s_rates[] = {
838*e3037485SYan-Hsuan Chuang 	DESC_RATEVHT1SS_MCS0, DESC_RATEVHT1SS_MCS1,
839*e3037485SYan-Hsuan Chuang 	DESC_RATEVHT1SS_MCS2, DESC_RATEVHT1SS_MCS3,
840*e3037485SYan-Hsuan Chuang 	DESC_RATEVHT1SS_MCS4, DESC_RATEVHT1SS_MCS5,
841*e3037485SYan-Hsuan Chuang 	DESC_RATEVHT1SS_MCS6, DESC_RATEVHT1SS_MCS7,
842*e3037485SYan-Hsuan Chuang 	DESC_RATEVHT1SS_MCS8, DESC_RATEVHT1SS_MCS9
843*e3037485SYan-Hsuan Chuang };
844*e3037485SYan-Hsuan Chuang u8 rtw_vht_2s_rates[] = {
845*e3037485SYan-Hsuan Chuang 	DESC_RATEVHT2SS_MCS0, DESC_RATEVHT2SS_MCS1,
846*e3037485SYan-Hsuan Chuang 	DESC_RATEVHT2SS_MCS2, DESC_RATEVHT2SS_MCS3,
847*e3037485SYan-Hsuan Chuang 	DESC_RATEVHT2SS_MCS4, DESC_RATEVHT2SS_MCS5,
848*e3037485SYan-Hsuan Chuang 	DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7,
849*e3037485SYan-Hsuan Chuang 	DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9
850*e3037485SYan-Hsuan Chuang };
851*e3037485SYan-Hsuan Chuang u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates);
852*e3037485SYan-Hsuan Chuang u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates);
853*e3037485SYan-Hsuan Chuang u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates);
854*e3037485SYan-Hsuan Chuang u8 rtw_ht_2s_size = ARRAY_SIZE(rtw_ht_2s_rates);
855*e3037485SYan-Hsuan Chuang u8 rtw_vht_1s_size = ARRAY_SIZE(rtw_vht_1s_rates);
856*e3037485SYan-Hsuan Chuang u8 rtw_vht_2s_size = ARRAY_SIZE(rtw_vht_2s_rates);
857*e3037485SYan-Hsuan Chuang u8 *rtw_rate_section[RTW_RATE_SECTION_MAX] = {
858*e3037485SYan-Hsuan Chuang 	rtw_cck_rates, rtw_ofdm_rates,
859*e3037485SYan-Hsuan Chuang 	rtw_ht_1s_rates, rtw_ht_2s_rates,
860*e3037485SYan-Hsuan Chuang 	rtw_vht_1s_rates, rtw_vht_2s_rates
861*e3037485SYan-Hsuan Chuang };
862*e3037485SYan-Hsuan Chuang u8 rtw_rate_size[RTW_RATE_SECTION_MAX] = {
863*e3037485SYan-Hsuan Chuang 	ARRAY_SIZE(rtw_cck_rates),
864*e3037485SYan-Hsuan Chuang 	ARRAY_SIZE(rtw_ofdm_rates),
865*e3037485SYan-Hsuan Chuang 	ARRAY_SIZE(rtw_ht_1s_rates),
866*e3037485SYan-Hsuan Chuang 	ARRAY_SIZE(rtw_ht_2s_rates),
867*e3037485SYan-Hsuan Chuang 	ARRAY_SIZE(rtw_vht_1s_rates),
868*e3037485SYan-Hsuan Chuang 	ARRAY_SIZE(rtw_vht_2s_rates)
869*e3037485SYan-Hsuan Chuang };
870*e3037485SYan-Hsuan Chuang 
871*e3037485SYan-Hsuan Chuang static const u8 rtw_channel_idx_5g[RTW_MAX_CHANNEL_NUM_5G] = {
872*e3037485SYan-Hsuan Chuang 	36,  38,  40,  42,  44,  46,  48, /* Band 1 */
873*e3037485SYan-Hsuan Chuang 	52,  54,  56,  58,  60,  62,  64, /* Band 2 */
874*e3037485SYan-Hsuan Chuang 	100, 102, 104, 106, 108, 110, 112, /* Band 3 */
875*e3037485SYan-Hsuan Chuang 	116, 118, 120, 122, 124, 126, 128, /* Band 3 */
876*e3037485SYan-Hsuan Chuang 	132, 134, 136, 138, 140, 142, 144, /* Band 3 */
877*e3037485SYan-Hsuan Chuang 	149, 151, 153, 155, 157, 159, 161, /* Band 4 */
878*e3037485SYan-Hsuan Chuang 	165, 167, 169, 171, 173, 175, 177}; /* Band 4 */
879*e3037485SYan-Hsuan Chuang 
880*e3037485SYan-Hsuan Chuang static int rtw_channel_to_idx(u8 band, u8 channel)
881*e3037485SYan-Hsuan Chuang {
882*e3037485SYan-Hsuan Chuang 	int ch_idx;
883*e3037485SYan-Hsuan Chuang 	u8 n_channel;
884*e3037485SYan-Hsuan Chuang 
885*e3037485SYan-Hsuan Chuang 	if (band == PHY_BAND_2G) {
886*e3037485SYan-Hsuan Chuang 		ch_idx = channel - 1;
887*e3037485SYan-Hsuan Chuang 		n_channel = RTW_MAX_CHANNEL_NUM_2G;
888*e3037485SYan-Hsuan Chuang 	} else if (band == PHY_BAND_5G) {
889*e3037485SYan-Hsuan Chuang 		n_channel = RTW_MAX_CHANNEL_NUM_5G;
890*e3037485SYan-Hsuan Chuang 		for (ch_idx = 0; ch_idx < n_channel; ch_idx++)
891*e3037485SYan-Hsuan Chuang 			if (rtw_channel_idx_5g[ch_idx] == channel)
892*e3037485SYan-Hsuan Chuang 				break;
893*e3037485SYan-Hsuan Chuang 	} else {
894*e3037485SYan-Hsuan Chuang 		return -1;
895*e3037485SYan-Hsuan Chuang 	}
896*e3037485SYan-Hsuan Chuang 
897*e3037485SYan-Hsuan Chuang 	if (ch_idx >= n_channel)
898*e3037485SYan-Hsuan Chuang 		return -1;
899*e3037485SYan-Hsuan Chuang 
900*e3037485SYan-Hsuan Chuang 	return ch_idx;
901*e3037485SYan-Hsuan Chuang }
902*e3037485SYan-Hsuan Chuang 
903*e3037485SYan-Hsuan Chuang static u8 rtw_get_channel_group(u8 channel)
904*e3037485SYan-Hsuan Chuang {
905*e3037485SYan-Hsuan Chuang 	switch (channel) {
906*e3037485SYan-Hsuan Chuang 	default:
907*e3037485SYan-Hsuan Chuang 		WARN_ON(1);
908*e3037485SYan-Hsuan Chuang 	case 1:
909*e3037485SYan-Hsuan Chuang 	case 2:
910*e3037485SYan-Hsuan Chuang 	case 36:
911*e3037485SYan-Hsuan Chuang 	case 38:
912*e3037485SYan-Hsuan Chuang 	case 40:
913*e3037485SYan-Hsuan Chuang 	case 42:
914*e3037485SYan-Hsuan Chuang 		return 0;
915*e3037485SYan-Hsuan Chuang 	case 3:
916*e3037485SYan-Hsuan Chuang 	case 4:
917*e3037485SYan-Hsuan Chuang 	case 5:
918*e3037485SYan-Hsuan Chuang 	case 44:
919*e3037485SYan-Hsuan Chuang 	case 46:
920*e3037485SYan-Hsuan Chuang 	case 48:
921*e3037485SYan-Hsuan Chuang 	case 50:
922*e3037485SYan-Hsuan Chuang 		return 1;
923*e3037485SYan-Hsuan Chuang 	case 6:
924*e3037485SYan-Hsuan Chuang 	case 7:
925*e3037485SYan-Hsuan Chuang 	case 8:
926*e3037485SYan-Hsuan Chuang 	case 52:
927*e3037485SYan-Hsuan Chuang 	case 54:
928*e3037485SYan-Hsuan Chuang 	case 56:
929*e3037485SYan-Hsuan Chuang 	case 58:
930*e3037485SYan-Hsuan Chuang 		return 2;
931*e3037485SYan-Hsuan Chuang 	case 9:
932*e3037485SYan-Hsuan Chuang 	case 10:
933*e3037485SYan-Hsuan Chuang 	case 11:
934*e3037485SYan-Hsuan Chuang 	case 60:
935*e3037485SYan-Hsuan Chuang 	case 62:
936*e3037485SYan-Hsuan Chuang 	case 64:
937*e3037485SYan-Hsuan Chuang 		return 3;
938*e3037485SYan-Hsuan Chuang 	case 12:
939*e3037485SYan-Hsuan Chuang 	case 13:
940*e3037485SYan-Hsuan Chuang 	case 100:
941*e3037485SYan-Hsuan Chuang 	case 102:
942*e3037485SYan-Hsuan Chuang 	case 104:
943*e3037485SYan-Hsuan Chuang 	case 106:
944*e3037485SYan-Hsuan Chuang 		return 4;
945*e3037485SYan-Hsuan Chuang 	case 14:
946*e3037485SYan-Hsuan Chuang 	case 108:
947*e3037485SYan-Hsuan Chuang 	case 110:
948*e3037485SYan-Hsuan Chuang 	case 112:
949*e3037485SYan-Hsuan Chuang 	case 114:
950*e3037485SYan-Hsuan Chuang 		return 5;
951*e3037485SYan-Hsuan Chuang 	case 116:
952*e3037485SYan-Hsuan Chuang 	case 118:
953*e3037485SYan-Hsuan Chuang 	case 120:
954*e3037485SYan-Hsuan Chuang 	case 122:
955*e3037485SYan-Hsuan Chuang 		return 6;
956*e3037485SYan-Hsuan Chuang 	case 124:
957*e3037485SYan-Hsuan Chuang 	case 126:
958*e3037485SYan-Hsuan Chuang 	case 128:
959*e3037485SYan-Hsuan Chuang 	case 130:
960*e3037485SYan-Hsuan Chuang 		return 7;
961*e3037485SYan-Hsuan Chuang 	case 132:
962*e3037485SYan-Hsuan Chuang 	case 134:
963*e3037485SYan-Hsuan Chuang 	case 136:
964*e3037485SYan-Hsuan Chuang 	case 138:
965*e3037485SYan-Hsuan Chuang 		return 8;
966*e3037485SYan-Hsuan Chuang 	case 140:
967*e3037485SYan-Hsuan Chuang 	case 142:
968*e3037485SYan-Hsuan Chuang 	case 144:
969*e3037485SYan-Hsuan Chuang 		return 9;
970*e3037485SYan-Hsuan Chuang 	case 149:
971*e3037485SYan-Hsuan Chuang 	case 151:
972*e3037485SYan-Hsuan Chuang 	case 153:
973*e3037485SYan-Hsuan Chuang 	case 155:
974*e3037485SYan-Hsuan Chuang 		return 10;
975*e3037485SYan-Hsuan Chuang 	case 157:
976*e3037485SYan-Hsuan Chuang 	case 159:
977*e3037485SYan-Hsuan Chuang 	case 161:
978*e3037485SYan-Hsuan Chuang 		return 11;
979*e3037485SYan-Hsuan Chuang 	case 165:
980*e3037485SYan-Hsuan Chuang 	case 167:
981*e3037485SYan-Hsuan Chuang 	case 169:
982*e3037485SYan-Hsuan Chuang 	case 171:
983*e3037485SYan-Hsuan Chuang 		return 12;
984*e3037485SYan-Hsuan Chuang 	case 173:
985*e3037485SYan-Hsuan Chuang 	case 175:
986*e3037485SYan-Hsuan Chuang 	case 177:
987*e3037485SYan-Hsuan Chuang 		return 13;
988*e3037485SYan-Hsuan Chuang 	}
989*e3037485SYan-Hsuan Chuang }
990*e3037485SYan-Hsuan Chuang 
991*e3037485SYan-Hsuan Chuang static u8 phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
992*e3037485SYan-Hsuan Chuang 				    struct rtw_2g_txpwr_idx *pwr_idx_2g,
993*e3037485SYan-Hsuan Chuang 				    enum rtw_bandwidth bandwidth,
994*e3037485SYan-Hsuan Chuang 				    u8 rate, u8 group)
995*e3037485SYan-Hsuan Chuang {
996*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
997*e3037485SYan-Hsuan Chuang 	u8 tx_power;
998*e3037485SYan-Hsuan Chuang 	bool mcs_rate;
999*e3037485SYan-Hsuan Chuang 	bool above_2ss;
1000*e3037485SYan-Hsuan Chuang 	u8 factor = chip->txgi_factor;
1001*e3037485SYan-Hsuan Chuang 
1002*e3037485SYan-Hsuan Chuang 	if (rate <= DESC_RATE11M)
1003*e3037485SYan-Hsuan Chuang 		tx_power = pwr_idx_2g->cck_base[group];
1004*e3037485SYan-Hsuan Chuang 	else
1005*e3037485SYan-Hsuan Chuang 		tx_power = pwr_idx_2g->bw40_base[group];
1006*e3037485SYan-Hsuan Chuang 
1007*e3037485SYan-Hsuan Chuang 	if (rate >= DESC_RATE6M && rate <= DESC_RATE54M)
1008*e3037485SYan-Hsuan Chuang 		tx_power += pwr_idx_2g->ht_1s_diff.ofdm * factor;
1009*e3037485SYan-Hsuan Chuang 
1010*e3037485SYan-Hsuan Chuang 	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) ||
1011*e3037485SYan-Hsuan Chuang 		   (rate >= DESC_RATEVHT1SS_MCS0 &&
1012*e3037485SYan-Hsuan Chuang 		    rate <= DESC_RATEVHT2SS_MCS9);
1013*e3037485SYan-Hsuan Chuang 	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
1014*e3037485SYan-Hsuan Chuang 		    (rate >= DESC_RATEVHT2SS_MCS0);
1015*e3037485SYan-Hsuan Chuang 
1016*e3037485SYan-Hsuan Chuang 	if (!mcs_rate)
1017*e3037485SYan-Hsuan Chuang 		return tx_power;
1018*e3037485SYan-Hsuan Chuang 
1019*e3037485SYan-Hsuan Chuang 	switch (bandwidth) {
1020*e3037485SYan-Hsuan Chuang 	default:
1021*e3037485SYan-Hsuan Chuang 		WARN_ON(1);
1022*e3037485SYan-Hsuan Chuang 	case RTW_CHANNEL_WIDTH_20:
1023*e3037485SYan-Hsuan Chuang 		tx_power += pwr_idx_2g->ht_1s_diff.bw20 * factor;
1024*e3037485SYan-Hsuan Chuang 		if (above_2ss)
1025*e3037485SYan-Hsuan Chuang 			tx_power += pwr_idx_2g->ht_2s_diff.bw20 * factor;
1026*e3037485SYan-Hsuan Chuang 		break;
1027*e3037485SYan-Hsuan Chuang 	case RTW_CHANNEL_WIDTH_40:
1028*e3037485SYan-Hsuan Chuang 		/* bw40 is the base power */
1029*e3037485SYan-Hsuan Chuang 		if (above_2ss)
1030*e3037485SYan-Hsuan Chuang 			tx_power += pwr_idx_2g->ht_2s_diff.bw40 * factor;
1031*e3037485SYan-Hsuan Chuang 		break;
1032*e3037485SYan-Hsuan Chuang 	}
1033*e3037485SYan-Hsuan Chuang 
1034*e3037485SYan-Hsuan Chuang 	return tx_power;
1035*e3037485SYan-Hsuan Chuang }
1036*e3037485SYan-Hsuan Chuang 
1037*e3037485SYan-Hsuan Chuang static u8 phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
1038*e3037485SYan-Hsuan Chuang 				    struct rtw_5g_txpwr_idx *pwr_idx_5g,
1039*e3037485SYan-Hsuan Chuang 				    enum rtw_bandwidth bandwidth,
1040*e3037485SYan-Hsuan Chuang 				    u8 rate, u8 group)
1041*e3037485SYan-Hsuan Chuang {
1042*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
1043*e3037485SYan-Hsuan Chuang 	u8 tx_power;
1044*e3037485SYan-Hsuan Chuang 	u8 upper, lower;
1045*e3037485SYan-Hsuan Chuang 	bool mcs_rate;
1046*e3037485SYan-Hsuan Chuang 	bool above_2ss;
1047*e3037485SYan-Hsuan Chuang 	u8 factor = chip->txgi_factor;
1048*e3037485SYan-Hsuan Chuang 
1049*e3037485SYan-Hsuan Chuang 	tx_power = pwr_idx_5g->bw40_base[group];
1050*e3037485SYan-Hsuan Chuang 
1051*e3037485SYan-Hsuan Chuang 	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) ||
1052*e3037485SYan-Hsuan Chuang 		   (rate >= DESC_RATEVHT1SS_MCS0 &&
1053*e3037485SYan-Hsuan Chuang 		    rate <= DESC_RATEVHT2SS_MCS9);
1054*e3037485SYan-Hsuan Chuang 	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
1055*e3037485SYan-Hsuan Chuang 		    (rate >= DESC_RATEVHT2SS_MCS0);
1056*e3037485SYan-Hsuan Chuang 
1057*e3037485SYan-Hsuan Chuang 	if (!mcs_rate) {
1058*e3037485SYan-Hsuan Chuang 		tx_power += pwr_idx_5g->ht_1s_diff.ofdm * factor;
1059*e3037485SYan-Hsuan Chuang 		return tx_power;
1060*e3037485SYan-Hsuan Chuang 	}
1061*e3037485SYan-Hsuan Chuang 
1062*e3037485SYan-Hsuan Chuang 	switch (bandwidth) {
1063*e3037485SYan-Hsuan Chuang 	default:
1064*e3037485SYan-Hsuan Chuang 		WARN_ON(1);
1065*e3037485SYan-Hsuan Chuang 	case RTW_CHANNEL_WIDTH_20:
1066*e3037485SYan-Hsuan Chuang 		tx_power += pwr_idx_5g->ht_1s_diff.bw20 * factor;
1067*e3037485SYan-Hsuan Chuang 		if (above_2ss)
1068*e3037485SYan-Hsuan Chuang 			tx_power += pwr_idx_5g->ht_2s_diff.bw20 * factor;
1069*e3037485SYan-Hsuan Chuang 		break;
1070*e3037485SYan-Hsuan Chuang 	case RTW_CHANNEL_WIDTH_40:
1071*e3037485SYan-Hsuan Chuang 		/* bw40 is the base power */
1072*e3037485SYan-Hsuan Chuang 		if (above_2ss)
1073*e3037485SYan-Hsuan Chuang 			tx_power += pwr_idx_5g->ht_2s_diff.bw40 * factor;
1074*e3037485SYan-Hsuan Chuang 		break;
1075*e3037485SYan-Hsuan Chuang 	case RTW_CHANNEL_WIDTH_80:
1076*e3037485SYan-Hsuan Chuang 		/* the base idx of bw80 is the average of bw40+/bw40- */
1077*e3037485SYan-Hsuan Chuang 		lower = pwr_idx_5g->bw40_base[group];
1078*e3037485SYan-Hsuan Chuang 		upper = pwr_idx_5g->bw40_base[group + 1];
1079*e3037485SYan-Hsuan Chuang 
1080*e3037485SYan-Hsuan Chuang 		tx_power = (lower + upper) / 2;
1081*e3037485SYan-Hsuan Chuang 		tx_power += pwr_idx_5g->vht_1s_diff.bw80 * factor;
1082*e3037485SYan-Hsuan Chuang 		if (above_2ss)
1083*e3037485SYan-Hsuan Chuang 			tx_power += pwr_idx_5g->vht_2s_diff.bw80 * factor;
1084*e3037485SYan-Hsuan Chuang 		break;
1085*e3037485SYan-Hsuan Chuang 	}
1086*e3037485SYan-Hsuan Chuang 
1087*e3037485SYan-Hsuan Chuang 	return tx_power;
1088*e3037485SYan-Hsuan Chuang }
1089*e3037485SYan-Hsuan Chuang 
1090*e3037485SYan-Hsuan Chuang /* set tx power level by path for each rates, note that the order of the rates
1091*e3037485SYan-Hsuan Chuang  * are *very* important, bacause 8822B/8821C combines every four bytes of tx
1092*e3037485SYan-Hsuan Chuang  * power index into a four-byte power index register, and calls set_tx_agc to
1093*e3037485SYan-Hsuan Chuang  * write these values into hardware
1094*e3037485SYan-Hsuan Chuang  */
1095*e3037485SYan-Hsuan Chuang static
1096*e3037485SYan-Hsuan Chuang void phy_set_tx_power_level_by_path(struct rtw_dev *rtwdev, u8 ch, u8 path)
1097*e3037485SYan-Hsuan Chuang {
1098*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
1099*e3037485SYan-Hsuan Chuang 	u8 rs;
1100*e3037485SYan-Hsuan Chuang 
1101*e3037485SYan-Hsuan Chuang 	/* do not need cck rates if we are not in 2.4G */
1102*e3037485SYan-Hsuan Chuang 	if (hal->current_band_type == RTW_BAND_2G)
1103*e3037485SYan-Hsuan Chuang 		rs = RTW_RATE_SECTION_CCK;
1104*e3037485SYan-Hsuan Chuang 	else
1105*e3037485SYan-Hsuan Chuang 		rs = RTW_RATE_SECTION_OFDM;
1106*e3037485SYan-Hsuan Chuang 
1107*e3037485SYan-Hsuan Chuang 	for (; rs < RTW_RATE_SECTION_MAX; rs++)
1108*e3037485SYan-Hsuan Chuang 		phy_set_tx_power_index_by_rs(rtwdev, ch, path, rs);
1109*e3037485SYan-Hsuan Chuang }
1110*e3037485SYan-Hsuan Chuang 
1111*e3037485SYan-Hsuan Chuang void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel)
1112*e3037485SYan-Hsuan Chuang {
1113*e3037485SYan-Hsuan Chuang 	struct rtw_chip_info *chip = rtwdev->chip;
1114*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
1115*e3037485SYan-Hsuan Chuang 	u8 path;
1116*e3037485SYan-Hsuan Chuang 
1117*e3037485SYan-Hsuan Chuang 	mutex_lock(&hal->tx_power_mutex);
1118*e3037485SYan-Hsuan Chuang 
1119*e3037485SYan-Hsuan Chuang 	for (path = 0; path < hal->rf_path_num; path++)
1120*e3037485SYan-Hsuan Chuang 		phy_set_tx_power_level_by_path(rtwdev, channel, path);
1121*e3037485SYan-Hsuan Chuang 
1122*e3037485SYan-Hsuan Chuang 	chip->ops->set_tx_power_index(rtwdev);
1123*e3037485SYan-Hsuan Chuang 	mutex_unlock(&hal->tx_power_mutex);
1124*e3037485SYan-Hsuan Chuang }
1125*e3037485SYan-Hsuan Chuang 
1126*e3037485SYan-Hsuan Chuang s8 phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band,
1127*e3037485SYan-Hsuan Chuang 			  enum rtw_bandwidth bandwidth, u8 rf_path,
1128*e3037485SYan-Hsuan Chuang 			  u8 rate, u8 channel, u8 regd);
1129*e3037485SYan-Hsuan Chuang 
1130*e3037485SYan-Hsuan Chuang static
1131*e3037485SYan-Hsuan Chuang u8 phy_get_tx_power_index(void *adapter, u8 rf_path, u8 rate,
1132*e3037485SYan-Hsuan Chuang 			  enum rtw_bandwidth bandwidth, u8 channel, u8 regd)
1133*e3037485SYan-Hsuan Chuang {
1134*e3037485SYan-Hsuan Chuang 	struct rtw_dev *rtwdev = adapter;
1135*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
1136*e3037485SYan-Hsuan Chuang 	struct rtw_txpwr_idx *pwr_idx;
1137*e3037485SYan-Hsuan Chuang 	u8 tx_power;
1138*e3037485SYan-Hsuan Chuang 	u8 group;
1139*e3037485SYan-Hsuan Chuang 	u8 band;
1140*e3037485SYan-Hsuan Chuang 	s8 offset, limit;
1141*e3037485SYan-Hsuan Chuang 
1142*e3037485SYan-Hsuan Chuang 	pwr_idx = &rtwdev->efuse.txpwr_idx_table[rf_path];
1143*e3037485SYan-Hsuan Chuang 	group = rtw_get_channel_group(channel);
1144*e3037485SYan-Hsuan Chuang 
1145*e3037485SYan-Hsuan Chuang 	/* base power index for 2.4G/5G */
1146*e3037485SYan-Hsuan Chuang 	if (channel <= 14) {
1147*e3037485SYan-Hsuan Chuang 		band = PHY_BAND_2G;
1148*e3037485SYan-Hsuan Chuang 		tx_power = phy_get_2g_tx_power_index(rtwdev,
1149*e3037485SYan-Hsuan Chuang 						     &pwr_idx->pwr_idx_2g,
1150*e3037485SYan-Hsuan Chuang 						     bandwidth, rate, group);
1151*e3037485SYan-Hsuan Chuang 		offset = hal->tx_pwr_by_rate_offset_2g[rf_path][rate];
1152*e3037485SYan-Hsuan Chuang 	} else {
1153*e3037485SYan-Hsuan Chuang 		band = PHY_BAND_5G;
1154*e3037485SYan-Hsuan Chuang 		tx_power = phy_get_5g_tx_power_index(rtwdev,
1155*e3037485SYan-Hsuan Chuang 						     &pwr_idx->pwr_idx_5g,
1156*e3037485SYan-Hsuan Chuang 						     bandwidth, rate, group);
1157*e3037485SYan-Hsuan Chuang 		offset = hal->tx_pwr_by_rate_offset_5g[rf_path][rate];
1158*e3037485SYan-Hsuan Chuang 	}
1159*e3037485SYan-Hsuan Chuang 
1160*e3037485SYan-Hsuan Chuang 	limit = phy_get_tx_power_limit(rtwdev, band, bandwidth, rf_path,
1161*e3037485SYan-Hsuan Chuang 				       rate, channel, regd);
1162*e3037485SYan-Hsuan Chuang 
1163*e3037485SYan-Hsuan Chuang 	if (offset > limit)
1164*e3037485SYan-Hsuan Chuang 		offset = limit;
1165*e3037485SYan-Hsuan Chuang 
1166*e3037485SYan-Hsuan Chuang 	tx_power += offset;
1167*e3037485SYan-Hsuan Chuang 
1168*e3037485SYan-Hsuan Chuang 	if (tx_power > rtwdev->chip->max_power_index)
1169*e3037485SYan-Hsuan Chuang 		tx_power = rtwdev->chip->max_power_index;
1170*e3037485SYan-Hsuan Chuang 
1171*e3037485SYan-Hsuan Chuang 	return tx_power;
1172*e3037485SYan-Hsuan Chuang }
1173*e3037485SYan-Hsuan Chuang 
1174*e3037485SYan-Hsuan Chuang void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs)
1175*e3037485SYan-Hsuan Chuang {
1176*e3037485SYan-Hsuan Chuang 	struct rtw_dev *rtwdev = adapter;
1177*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
1178*e3037485SYan-Hsuan Chuang 	u8 regd = rtwdev->regd.txpwr_regd;
1179*e3037485SYan-Hsuan Chuang 	u8 *rates;
1180*e3037485SYan-Hsuan Chuang 	u8 size;
1181*e3037485SYan-Hsuan Chuang 	u8 rate;
1182*e3037485SYan-Hsuan Chuang 	u8 pwr_idx;
1183*e3037485SYan-Hsuan Chuang 	u8 bw;
1184*e3037485SYan-Hsuan Chuang 	int i;
1185*e3037485SYan-Hsuan Chuang 
1186*e3037485SYan-Hsuan Chuang 	if (rs >= RTW_RATE_SECTION_MAX)
1187*e3037485SYan-Hsuan Chuang 		return;
1188*e3037485SYan-Hsuan Chuang 
1189*e3037485SYan-Hsuan Chuang 	rates = rtw_rate_section[rs];
1190*e3037485SYan-Hsuan Chuang 	size = rtw_rate_size[rs];
1191*e3037485SYan-Hsuan Chuang 	bw = hal->current_band_width;
1192*e3037485SYan-Hsuan Chuang 	for (i = 0; i < size; i++) {
1193*e3037485SYan-Hsuan Chuang 		rate = rates[i];
1194*e3037485SYan-Hsuan Chuang 		pwr_idx = phy_get_tx_power_index(adapter, path, rate, bw, ch,
1195*e3037485SYan-Hsuan Chuang 						 regd);
1196*e3037485SYan-Hsuan Chuang 		hal->tx_pwr_tbl[path][rate] = pwr_idx;
1197*e3037485SYan-Hsuan Chuang 	}
1198*e3037485SYan-Hsuan Chuang }
1199*e3037485SYan-Hsuan Chuang 
1200*e3037485SYan-Hsuan Chuang static u8 tbl_to_dec_pwr_by_rate(struct rtw_dev *rtwdev, u32 hex, u8 i)
1201*e3037485SYan-Hsuan Chuang {
1202*e3037485SYan-Hsuan Chuang 	if (rtwdev->chip->is_pwr_by_rate_dec)
1203*e3037485SYan-Hsuan Chuang 		return bcd_to_dec_pwr_by_rate(hex, i);
1204*e3037485SYan-Hsuan Chuang 	else
1205*e3037485SYan-Hsuan Chuang 		return (hex >> (i * 8)) & 0xFF;
1206*e3037485SYan-Hsuan Chuang }
1207*e3037485SYan-Hsuan Chuang 
1208*e3037485SYan-Hsuan Chuang static void phy_get_rate_values_of_txpwr_by_rate(struct rtw_dev *rtwdev,
1209*e3037485SYan-Hsuan Chuang 						 u32 addr, u32 mask,
1210*e3037485SYan-Hsuan Chuang 						 u32 val, u8 *rate,
1211*e3037485SYan-Hsuan Chuang 						 u8 *pwr_by_rate, u8 *rate_num)
1212*e3037485SYan-Hsuan Chuang {
1213*e3037485SYan-Hsuan Chuang 	int i;
1214*e3037485SYan-Hsuan Chuang 
1215*e3037485SYan-Hsuan Chuang 	switch (addr) {
1216*e3037485SYan-Hsuan Chuang 	case 0xE00:
1217*e3037485SYan-Hsuan Chuang 	case 0x830:
1218*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATE6M;
1219*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATE9M;
1220*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATE12M;
1221*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATE18M;
1222*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1223*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1224*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1225*e3037485SYan-Hsuan Chuang 		break;
1226*e3037485SYan-Hsuan Chuang 	case 0xE04:
1227*e3037485SYan-Hsuan Chuang 	case 0x834:
1228*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATE24M;
1229*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATE36M;
1230*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATE48M;
1231*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATE54M;
1232*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1233*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1234*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1235*e3037485SYan-Hsuan Chuang 		break;
1236*e3037485SYan-Hsuan Chuang 	case 0xE08:
1237*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATE1M;
1238*e3037485SYan-Hsuan Chuang 		pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 1);
1239*e3037485SYan-Hsuan Chuang 		*rate_num = 1;
1240*e3037485SYan-Hsuan Chuang 		break;
1241*e3037485SYan-Hsuan Chuang 	case 0x86C:
1242*e3037485SYan-Hsuan Chuang 		if (mask == 0xffffff00) {
1243*e3037485SYan-Hsuan Chuang 			rate[0] = DESC_RATE2M;
1244*e3037485SYan-Hsuan Chuang 			rate[1] = DESC_RATE5_5M;
1245*e3037485SYan-Hsuan Chuang 			rate[2] = DESC_RATE11M;
1246*e3037485SYan-Hsuan Chuang 			for (i = 1; i < 4; ++i)
1247*e3037485SYan-Hsuan Chuang 				pwr_by_rate[i - 1] =
1248*e3037485SYan-Hsuan Chuang 					tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1249*e3037485SYan-Hsuan Chuang 			*rate_num = 3;
1250*e3037485SYan-Hsuan Chuang 		} else if (mask == 0x000000ff) {
1251*e3037485SYan-Hsuan Chuang 			rate[0] = DESC_RATE11M;
1252*e3037485SYan-Hsuan Chuang 			pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 0);
1253*e3037485SYan-Hsuan Chuang 			*rate_num = 1;
1254*e3037485SYan-Hsuan Chuang 		}
1255*e3037485SYan-Hsuan Chuang 		break;
1256*e3037485SYan-Hsuan Chuang 	case 0xE10:
1257*e3037485SYan-Hsuan Chuang 	case 0x83C:
1258*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEMCS0;
1259*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEMCS1;
1260*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEMCS2;
1261*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEMCS3;
1262*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1263*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1264*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1265*e3037485SYan-Hsuan Chuang 		break;
1266*e3037485SYan-Hsuan Chuang 	case 0xE14:
1267*e3037485SYan-Hsuan Chuang 	case 0x848:
1268*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEMCS4;
1269*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEMCS5;
1270*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEMCS6;
1271*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEMCS7;
1272*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1273*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1274*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1275*e3037485SYan-Hsuan Chuang 		break;
1276*e3037485SYan-Hsuan Chuang 	case 0xE18:
1277*e3037485SYan-Hsuan Chuang 	case 0x84C:
1278*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEMCS8;
1279*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEMCS9;
1280*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEMCS10;
1281*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEMCS11;
1282*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1283*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1284*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1285*e3037485SYan-Hsuan Chuang 		break;
1286*e3037485SYan-Hsuan Chuang 	case 0xE1C:
1287*e3037485SYan-Hsuan Chuang 	case 0x868:
1288*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEMCS12;
1289*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEMCS13;
1290*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEMCS14;
1291*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEMCS15;
1292*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1293*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1294*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1295*e3037485SYan-Hsuan Chuang 
1296*e3037485SYan-Hsuan Chuang 		break;
1297*e3037485SYan-Hsuan Chuang 	case 0x838:
1298*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATE1M;
1299*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATE2M;
1300*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATE5_5M;
1301*e3037485SYan-Hsuan Chuang 		for (i = 1; i < 4; ++i)
1302*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i - 1] = tbl_to_dec_pwr_by_rate(rtwdev,
1303*e3037485SYan-Hsuan Chuang 								    val, i);
1304*e3037485SYan-Hsuan Chuang 		*rate_num = 3;
1305*e3037485SYan-Hsuan Chuang 		break;
1306*e3037485SYan-Hsuan Chuang 	case 0xC20:
1307*e3037485SYan-Hsuan Chuang 	case 0xE20:
1308*e3037485SYan-Hsuan Chuang 	case 0x1820:
1309*e3037485SYan-Hsuan Chuang 	case 0x1A20:
1310*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATE1M;
1311*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATE2M;
1312*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATE5_5M;
1313*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATE11M;
1314*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1315*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1316*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1317*e3037485SYan-Hsuan Chuang 		break;
1318*e3037485SYan-Hsuan Chuang 	case 0xC24:
1319*e3037485SYan-Hsuan Chuang 	case 0xE24:
1320*e3037485SYan-Hsuan Chuang 	case 0x1824:
1321*e3037485SYan-Hsuan Chuang 	case 0x1A24:
1322*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATE6M;
1323*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATE9M;
1324*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATE12M;
1325*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATE18M;
1326*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1327*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1328*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1329*e3037485SYan-Hsuan Chuang 		break;
1330*e3037485SYan-Hsuan Chuang 	case 0xC28:
1331*e3037485SYan-Hsuan Chuang 	case 0xE28:
1332*e3037485SYan-Hsuan Chuang 	case 0x1828:
1333*e3037485SYan-Hsuan Chuang 	case 0x1A28:
1334*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATE24M;
1335*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATE36M;
1336*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATE48M;
1337*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATE54M;
1338*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1339*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1340*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1341*e3037485SYan-Hsuan Chuang 		break;
1342*e3037485SYan-Hsuan Chuang 	case 0xC2C:
1343*e3037485SYan-Hsuan Chuang 	case 0xE2C:
1344*e3037485SYan-Hsuan Chuang 	case 0x182C:
1345*e3037485SYan-Hsuan Chuang 	case 0x1A2C:
1346*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEMCS0;
1347*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEMCS1;
1348*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEMCS2;
1349*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEMCS3;
1350*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1351*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1352*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1353*e3037485SYan-Hsuan Chuang 		break;
1354*e3037485SYan-Hsuan Chuang 	case 0xC30:
1355*e3037485SYan-Hsuan Chuang 	case 0xE30:
1356*e3037485SYan-Hsuan Chuang 	case 0x1830:
1357*e3037485SYan-Hsuan Chuang 	case 0x1A30:
1358*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEMCS4;
1359*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEMCS5;
1360*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEMCS6;
1361*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEMCS7;
1362*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1363*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1364*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1365*e3037485SYan-Hsuan Chuang 		break;
1366*e3037485SYan-Hsuan Chuang 	case 0xC34:
1367*e3037485SYan-Hsuan Chuang 	case 0xE34:
1368*e3037485SYan-Hsuan Chuang 	case 0x1834:
1369*e3037485SYan-Hsuan Chuang 	case 0x1A34:
1370*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEMCS8;
1371*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEMCS9;
1372*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEMCS10;
1373*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEMCS11;
1374*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1375*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1376*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1377*e3037485SYan-Hsuan Chuang 		break;
1378*e3037485SYan-Hsuan Chuang 	case 0xC38:
1379*e3037485SYan-Hsuan Chuang 	case 0xE38:
1380*e3037485SYan-Hsuan Chuang 	case 0x1838:
1381*e3037485SYan-Hsuan Chuang 	case 0x1A38:
1382*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEMCS12;
1383*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEMCS13;
1384*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEMCS14;
1385*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEMCS15;
1386*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1387*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1388*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1389*e3037485SYan-Hsuan Chuang 		break;
1390*e3037485SYan-Hsuan Chuang 	case 0xC3C:
1391*e3037485SYan-Hsuan Chuang 	case 0xE3C:
1392*e3037485SYan-Hsuan Chuang 	case 0x183C:
1393*e3037485SYan-Hsuan Chuang 	case 0x1A3C:
1394*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEVHT1SS_MCS0;
1395*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEVHT1SS_MCS1;
1396*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEVHT1SS_MCS2;
1397*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEVHT1SS_MCS3;
1398*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1399*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1400*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1401*e3037485SYan-Hsuan Chuang 		break;
1402*e3037485SYan-Hsuan Chuang 	case 0xC40:
1403*e3037485SYan-Hsuan Chuang 	case 0xE40:
1404*e3037485SYan-Hsuan Chuang 	case 0x1840:
1405*e3037485SYan-Hsuan Chuang 	case 0x1A40:
1406*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEVHT1SS_MCS4;
1407*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEVHT1SS_MCS5;
1408*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEVHT1SS_MCS6;
1409*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEVHT1SS_MCS7;
1410*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1411*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1412*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1413*e3037485SYan-Hsuan Chuang 		break;
1414*e3037485SYan-Hsuan Chuang 	case 0xC44:
1415*e3037485SYan-Hsuan Chuang 	case 0xE44:
1416*e3037485SYan-Hsuan Chuang 	case 0x1844:
1417*e3037485SYan-Hsuan Chuang 	case 0x1A44:
1418*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEVHT1SS_MCS8;
1419*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEVHT1SS_MCS9;
1420*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEVHT2SS_MCS0;
1421*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEVHT2SS_MCS1;
1422*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1423*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1424*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1425*e3037485SYan-Hsuan Chuang 		break;
1426*e3037485SYan-Hsuan Chuang 	case 0xC48:
1427*e3037485SYan-Hsuan Chuang 	case 0xE48:
1428*e3037485SYan-Hsuan Chuang 	case 0x1848:
1429*e3037485SYan-Hsuan Chuang 	case 0x1A48:
1430*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEVHT2SS_MCS2;
1431*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEVHT2SS_MCS3;
1432*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEVHT2SS_MCS4;
1433*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEVHT2SS_MCS5;
1434*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1435*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1436*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1437*e3037485SYan-Hsuan Chuang 		break;
1438*e3037485SYan-Hsuan Chuang 	case 0xC4C:
1439*e3037485SYan-Hsuan Chuang 	case 0xE4C:
1440*e3037485SYan-Hsuan Chuang 	case 0x184C:
1441*e3037485SYan-Hsuan Chuang 	case 0x1A4C:
1442*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEVHT2SS_MCS6;
1443*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEVHT2SS_MCS7;
1444*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEVHT2SS_MCS8;
1445*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEVHT2SS_MCS9;
1446*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1447*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1448*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1449*e3037485SYan-Hsuan Chuang 		break;
1450*e3037485SYan-Hsuan Chuang 	case 0xCD8:
1451*e3037485SYan-Hsuan Chuang 	case 0xED8:
1452*e3037485SYan-Hsuan Chuang 	case 0x18D8:
1453*e3037485SYan-Hsuan Chuang 	case 0x1AD8:
1454*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEMCS16;
1455*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEMCS17;
1456*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEMCS18;
1457*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEMCS19;
1458*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1459*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1460*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1461*e3037485SYan-Hsuan Chuang 		break;
1462*e3037485SYan-Hsuan Chuang 	case 0xCDC:
1463*e3037485SYan-Hsuan Chuang 	case 0xEDC:
1464*e3037485SYan-Hsuan Chuang 	case 0x18DC:
1465*e3037485SYan-Hsuan Chuang 	case 0x1ADC:
1466*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEMCS20;
1467*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEMCS21;
1468*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEMCS22;
1469*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEMCS23;
1470*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1471*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1472*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1473*e3037485SYan-Hsuan Chuang 		break;
1474*e3037485SYan-Hsuan Chuang 	case 0xCE0:
1475*e3037485SYan-Hsuan Chuang 	case 0xEE0:
1476*e3037485SYan-Hsuan Chuang 	case 0x18E0:
1477*e3037485SYan-Hsuan Chuang 	case 0x1AE0:
1478*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEVHT3SS_MCS0;
1479*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEVHT3SS_MCS1;
1480*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEVHT3SS_MCS2;
1481*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEVHT3SS_MCS3;
1482*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1483*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1484*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1485*e3037485SYan-Hsuan Chuang 		break;
1486*e3037485SYan-Hsuan Chuang 	case 0xCE4:
1487*e3037485SYan-Hsuan Chuang 	case 0xEE4:
1488*e3037485SYan-Hsuan Chuang 	case 0x18E4:
1489*e3037485SYan-Hsuan Chuang 	case 0x1AE4:
1490*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEVHT3SS_MCS4;
1491*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEVHT3SS_MCS5;
1492*e3037485SYan-Hsuan Chuang 		rate[2] = DESC_RATEVHT3SS_MCS6;
1493*e3037485SYan-Hsuan Chuang 		rate[3] = DESC_RATEVHT3SS_MCS7;
1494*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 4; ++i)
1495*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1496*e3037485SYan-Hsuan Chuang 		*rate_num = 4;
1497*e3037485SYan-Hsuan Chuang 		break;
1498*e3037485SYan-Hsuan Chuang 	case 0xCE8:
1499*e3037485SYan-Hsuan Chuang 	case 0xEE8:
1500*e3037485SYan-Hsuan Chuang 	case 0x18E8:
1501*e3037485SYan-Hsuan Chuang 	case 0x1AE8:
1502*e3037485SYan-Hsuan Chuang 		rate[0] = DESC_RATEVHT3SS_MCS8;
1503*e3037485SYan-Hsuan Chuang 		rate[1] = DESC_RATEVHT3SS_MCS9;
1504*e3037485SYan-Hsuan Chuang 		for (i = 0; i < 2; ++i)
1505*e3037485SYan-Hsuan Chuang 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
1506*e3037485SYan-Hsuan Chuang 		*rate_num = 2;
1507*e3037485SYan-Hsuan Chuang 		break;
1508*e3037485SYan-Hsuan Chuang 	default:
1509*e3037485SYan-Hsuan Chuang 		rtw_warn(rtwdev, "invalid tx power index addr 0x%08x\n", addr);
1510*e3037485SYan-Hsuan Chuang 		break;
1511*e3037485SYan-Hsuan Chuang 	}
1512*e3037485SYan-Hsuan Chuang }
1513*e3037485SYan-Hsuan Chuang 
1514*e3037485SYan-Hsuan Chuang void phy_store_tx_power_by_rate(void *adapter, u32 band, u32 rfpath, u32 txnum,
1515*e3037485SYan-Hsuan Chuang 				u32 regaddr, u32 bitmask, u32 data)
1516*e3037485SYan-Hsuan Chuang {
1517*e3037485SYan-Hsuan Chuang 	struct rtw_dev *rtwdev = adapter;
1518*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
1519*e3037485SYan-Hsuan Chuang 	u8 rate_num = 0;
1520*e3037485SYan-Hsuan Chuang 	u8 rate;
1521*e3037485SYan-Hsuan Chuang 	u8 rates[RTW_RF_PATH_MAX] = {0};
1522*e3037485SYan-Hsuan Chuang 	s8 offset;
1523*e3037485SYan-Hsuan Chuang 	s8 pwr_by_rate[RTW_RF_PATH_MAX] = {0};
1524*e3037485SYan-Hsuan Chuang 	int i;
1525*e3037485SYan-Hsuan Chuang 
1526*e3037485SYan-Hsuan Chuang 	phy_get_rate_values_of_txpwr_by_rate(rtwdev, regaddr, bitmask, data,
1527*e3037485SYan-Hsuan Chuang 					     rates, pwr_by_rate, &rate_num);
1528*e3037485SYan-Hsuan Chuang 
1529*e3037485SYan-Hsuan Chuang 	if (WARN_ON(rfpath >= RTW_RF_PATH_MAX ||
1530*e3037485SYan-Hsuan Chuang 		    (band != PHY_BAND_2G && band != PHY_BAND_5G) ||
1531*e3037485SYan-Hsuan Chuang 		    rate_num > RTW_RF_PATH_MAX))
1532*e3037485SYan-Hsuan Chuang 		return;
1533*e3037485SYan-Hsuan Chuang 
1534*e3037485SYan-Hsuan Chuang 	for (i = 0; i < rate_num; i++) {
1535*e3037485SYan-Hsuan Chuang 		offset = pwr_by_rate[i];
1536*e3037485SYan-Hsuan Chuang 		rate = rates[i];
1537*e3037485SYan-Hsuan Chuang 		if (band == PHY_BAND_2G)
1538*e3037485SYan-Hsuan Chuang 			hal->tx_pwr_by_rate_offset_2g[rfpath][rate] = offset;
1539*e3037485SYan-Hsuan Chuang 		else if (band == PHY_BAND_5G)
1540*e3037485SYan-Hsuan Chuang 			hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset;
1541*e3037485SYan-Hsuan Chuang 		else
1542*e3037485SYan-Hsuan Chuang 			continue;
1543*e3037485SYan-Hsuan Chuang 	}
1544*e3037485SYan-Hsuan Chuang }
1545*e3037485SYan-Hsuan Chuang 
1546*e3037485SYan-Hsuan Chuang static
1547*e3037485SYan-Hsuan Chuang void phy_tx_power_by_rate_config_by_path(struct rtw_hal *hal, u8 path,
1548*e3037485SYan-Hsuan Chuang 					 u8 rs, u8 size, u8 *rates)
1549*e3037485SYan-Hsuan Chuang {
1550*e3037485SYan-Hsuan Chuang 	u8 rate;
1551*e3037485SYan-Hsuan Chuang 	u8 base_idx, rate_idx;
1552*e3037485SYan-Hsuan Chuang 	s8 base_2g, base_5g;
1553*e3037485SYan-Hsuan Chuang 
1554*e3037485SYan-Hsuan Chuang 	if (rs >= RTW_RATE_SECTION_VHT_1S)
1555*e3037485SYan-Hsuan Chuang 		base_idx = rates[size - 3];
1556*e3037485SYan-Hsuan Chuang 	else
1557*e3037485SYan-Hsuan Chuang 		base_idx = rates[size - 1];
1558*e3037485SYan-Hsuan Chuang 	base_2g = hal->tx_pwr_by_rate_offset_2g[path][base_idx];
1559*e3037485SYan-Hsuan Chuang 	base_5g = hal->tx_pwr_by_rate_offset_5g[path][base_idx];
1560*e3037485SYan-Hsuan Chuang 	hal->tx_pwr_by_rate_base_2g[path][rs] = base_2g;
1561*e3037485SYan-Hsuan Chuang 	hal->tx_pwr_by_rate_base_5g[path][rs] = base_5g;
1562*e3037485SYan-Hsuan Chuang 	for (rate = 0; rate < size; rate++) {
1563*e3037485SYan-Hsuan Chuang 		rate_idx = rates[rate];
1564*e3037485SYan-Hsuan Chuang 		hal->tx_pwr_by_rate_offset_2g[path][rate_idx] -= base_2g;
1565*e3037485SYan-Hsuan Chuang 		hal->tx_pwr_by_rate_offset_5g[path][rate_idx] -= base_5g;
1566*e3037485SYan-Hsuan Chuang 	}
1567*e3037485SYan-Hsuan Chuang }
1568*e3037485SYan-Hsuan Chuang 
1569*e3037485SYan-Hsuan Chuang void rtw_phy_tx_power_by_rate_config(struct rtw_hal *hal)
1570*e3037485SYan-Hsuan Chuang {
1571*e3037485SYan-Hsuan Chuang 	u8 path;
1572*e3037485SYan-Hsuan Chuang 
1573*e3037485SYan-Hsuan Chuang 	for (path = 0; path < RTW_RF_PATH_MAX; path++) {
1574*e3037485SYan-Hsuan Chuang 		phy_tx_power_by_rate_config_by_path(hal, path,
1575*e3037485SYan-Hsuan Chuang 				RTW_RATE_SECTION_CCK,
1576*e3037485SYan-Hsuan Chuang 				rtw_cck_size, rtw_cck_rates);
1577*e3037485SYan-Hsuan Chuang 		phy_tx_power_by_rate_config_by_path(hal, path,
1578*e3037485SYan-Hsuan Chuang 				RTW_RATE_SECTION_OFDM,
1579*e3037485SYan-Hsuan Chuang 				rtw_ofdm_size, rtw_ofdm_rates);
1580*e3037485SYan-Hsuan Chuang 		phy_tx_power_by_rate_config_by_path(hal, path,
1581*e3037485SYan-Hsuan Chuang 				RTW_RATE_SECTION_HT_1S,
1582*e3037485SYan-Hsuan Chuang 				rtw_ht_1s_size, rtw_ht_1s_rates);
1583*e3037485SYan-Hsuan Chuang 		phy_tx_power_by_rate_config_by_path(hal, path,
1584*e3037485SYan-Hsuan Chuang 				RTW_RATE_SECTION_HT_2S,
1585*e3037485SYan-Hsuan Chuang 				rtw_ht_2s_size, rtw_ht_2s_rates);
1586*e3037485SYan-Hsuan Chuang 		phy_tx_power_by_rate_config_by_path(hal, path,
1587*e3037485SYan-Hsuan Chuang 				RTW_RATE_SECTION_VHT_1S,
1588*e3037485SYan-Hsuan Chuang 				rtw_vht_1s_size, rtw_vht_1s_rates);
1589*e3037485SYan-Hsuan Chuang 		phy_tx_power_by_rate_config_by_path(hal, path,
1590*e3037485SYan-Hsuan Chuang 				RTW_RATE_SECTION_VHT_2S,
1591*e3037485SYan-Hsuan Chuang 				rtw_vht_2s_size, rtw_vht_2s_rates);
1592*e3037485SYan-Hsuan Chuang 	}
1593*e3037485SYan-Hsuan Chuang }
1594*e3037485SYan-Hsuan Chuang 
1595*e3037485SYan-Hsuan Chuang static void
1596*e3037485SYan-Hsuan Chuang phy_tx_power_limit_config(struct rtw_hal *hal, u8 regd, u8 bw, u8 rs)
1597*e3037485SYan-Hsuan Chuang {
1598*e3037485SYan-Hsuan Chuang 	s8 base, orig;
1599*e3037485SYan-Hsuan Chuang 	u8 ch;
1600*e3037485SYan-Hsuan Chuang 
1601*e3037485SYan-Hsuan Chuang 	for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_2G; ch++) {
1602*e3037485SYan-Hsuan Chuang 		base = hal->tx_pwr_by_rate_base_2g[0][rs];
1603*e3037485SYan-Hsuan Chuang 		orig = hal->tx_pwr_limit_2g[regd][bw][rs][ch];
1604*e3037485SYan-Hsuan Chuang 		hal->tx_pwr_limit_2g[regd][bw][rs][ch] -= base;
1605*e3037485SYan-Hsuan Chuang 	}
1606*e3037485SYan-Hsuan Chuang 
1607*e3037485SYan-Hsuan Chuang 	for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_5G; ch++) {
1608*e3037485SYan-Hsuan Chuang 		base = hal->tx_pwr_by_rate_base_5g[0][rs];
1609*e3037485SYan-Hsuan Chuang 		hal->tx_pwr_limit_5g[regd][bw][rs][ch] -= base;
1610*e3037485SYan-Hsuan Chuang 	}
1611*e3037485SYan-Hsuan Chuang }
1612*e3037485SYan-Hsuan Chuang 
1613*e3037485SYan-Hsuan Chuang void rtw_phy_tx_power_limit_config(struct rtw_hal *hal)
1614*e3037485SYan-Hsuan Chuang {
1615*e3037485SYan-Hsuan Chuang 	u8 regd, bw, rs;
1616*e3037485SYan-Hsuan Chuang 
1617*e3037485SYan-Hsuan Chuang 	for (regd = 0; regd < RTW_REGD_MAX; regd++)
1618*e3037485SYan-Hsuan Chuang 		for (bw = 0; bw < RTW_CHANNEL_WIDTH_MAX; bw++)
1619*e3037485SYan-Hsuan Chuang 			for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++)
1620*e3037485SYan-Hsuan Chuang 				phy_tx_power_limit_config(hal, regd, bw, rs);
1621*e3037485SYan-Hsuan Chuang }
1622*e3037485SYan-Hsuan Chuang 
1623*e3037485SYan-Hsuan Chuang static s8 get_tx_power_limit(struct rtw_hal *hal, u8 bw, u8 rs, u8 ch, u8 regd)
1624*e3037485SYan-Hsuan Chuang {
1625*e3037485SYan-Hsuan Chuang 	if (regd > RTW_REGD_WW)
1626*e3037485SYan-Hsuan Chuang 		return RTW_MAX_POWER_INDEX;
1627*e3037485SYan-Hsuan Chuang 
1628*e3037485SYan-Hsuan Chuang 	return hal->tx_pwr_limit_2g[regd][bw][rs][ch];
1629*e3037485SYan-Hsuan Chuang }
1630*e3037485SYan-Hsuan Chuang 
1631*e3037485SYan-Hsuan Chuang s8 phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band,
1632*e3037485SYan-Hsuan Chuang 			  enum rtw_bandwidth bw, u8 rf_path,
1633*e3037485SYan-Hsuan Chuang 			  u8 rate, u8 channel, u8 regd)
1634*e3037485SYan-Hsuan Chuang {
1635*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
1636*e3037485SYan-Hsuan Chuang 	s8 power_limit;
1637*e3037485SYan-Hsuan Chuang 	u8 rs;
1638*e3037485SYan-Hsuan Chuang 	int ch_idx;
1639*e3037485SYan-Hsuan Chuang 
1640*e3037485SYan-Hsuan Chuang 	if (rate >= DESC_RATE1M && rate <= DESC_RATE11M)
1641*e3037485SYan-Hsuan Chuang 		rs = RTW_RATE_SECTION_CCK;
1642*e3037485SYan-Hsuan Chuang 	else if (rate >= DESC_RATE6M && rate <= DESC_RATE54M)
1643*e3037485SYan-Hsuan Chuang 		rs = RTW_RATE_SECTION_OFDM;
1644*e3037485SYan-Hsuan Chuang 	else if (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS7)
1645*e3037485SYan-Hsuan Chuang 		rs = RTW_RATE_SECTION_HT_1S;
1646*e3037485SYan-Hsuan Chuang 	else if (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15)
1647*e3037485SYan-Hsuan Chuang 		rs = RTW_RATE_SECTION_HT_2S;
1648*e3037485SYan-Hsuan Chuang 	else if (rate >= DESC_RATEVHT1SS_MCS0 && rate <= DESC_RATEVHT1SS_MCS9)
1649*e3037485SYan-Hsuan Chuang 		rs = RTW_RATE_SECTION_VHT_1S;
1650*e3037485SYan-Hsuan Chuang 	else if (rate >= DESC_RATEVHT2SS_MCS0 && rate <= DESC_RATEVHT2SS_MCS9)
1651*e3037485SYan-Hsuan Chuang 		rs = RTW_RATE_SECTION_VHT_2S;
1652*e3037485SYan-Hsuan Chuang 	else
1653*e3037485SYan-Hsuan Chuang 		goto err;
1654*e3037485SYan-Hsuan Chuang 
1655*e3037485SYan-Hsuan Chuang 	ch_idx = rtw_channel_to_idx(band, channel);
1656*e3037485SYan-Hsuan Chuang 	if (ch_idx < 0)
1657*e3037485SYan-Hsuan Chuang 		goto err;
1658*e3037485SYan-Hsuan Chuang 
1659*e3037485SYan-Hsuan Chuang 	power_limit = get_tx_power_limit(hal, bw, rs, ch_idx, regd);
1660*e3037485SYan-Hsuan Chuang 
1661*e3037485SYan-Hsuan Chuang 	return power_limit;
1662*e3037485SYan-Hsuan Chuang 
1663*e3037485SYan-Hsuan Chuang err:
1664*e3037485SYan-Hsuan Chuang 	WARN(1, "invalid arguments, band=%d, bw=%d, path=%d, rate=%d, ch=%d\n",
1665*e3037485SYan-Hsuan Chuang 	     band, bw, rf_path, rate, channel);
1666*e3037485SYan-Hsuan Chuang 	return RTW_MAX_POWER_INDEX;
1667*e3037485SYan-Hsuan Chuang }
1668*e3037485SYan-Hsuan Chuang 
1669*e3037485SYan-Hsuan Chuang void phy_set_tx_power_limit(struct rtw_dev *rtwdev, u8 regd, u8 band,
1670*e3037485SYan-Hsuan Chuang 			    u8 bw, u8 rs, u8 ch, s8 pwr_limit)
1671*e3037485SYan-Hsuan Chuang {
1672*e3037485SYan-Hsuan Chuang 	struct rtw_hal *hal = &rtwdev->hal;
1673*e3037485SYan-Hsuan Chuang 	int ch_idx;
1674*e3037485SYan-Hsuan Chuang 
1675*e3037485SYan-Hsuan Chuang 	pwr_limit = clamp_t(s8, pwr_limit,
1676*e3037485SYan-Hsuan Chuang 			    -RTW_MAX_POWER_INDEX, RTW_MAX_POWER_INDEX);
1677*e3037485SYan-Hsuan Chuang 	ch_idx = rtw_channel_to_idx(band, ch);
1678*e3037485SYan-Hsuan Chuang 
1679*e3037485SYan-Hsuan Chuang 	if (regd >= RTW_REGD_MAX || bw >= RTW_CHANNEL_WIDTH_MAX ||
1680*e3037485SYan-Hsuan Chuang 	    rs >= RTW_RATE_SECTION_MAX || ch_idx < 0) {
1681*e3037485SYan-Hsuan Chuang 		WARN(1,
1682*e3037485SYan-Hsuan Chuang 		     "wrong txpwr_lmt regd=%u, band=%u bw=%u, rs=%u, ch_idx=%u, pwr_limit=%d\n",
1683*e3037485SYan-Hsuan Chuang 		     regd, band, bw, rs, ch_idx, pwr_limit);
1684*e3037485SYan-Hsuan Chuang 		return;
1685*e3037485SYan-Hsuan Chuang 	}
1686*e3037485SYan-Hsuan Chuang 
1687*e3037485SYan-Hsuan Chuang 	if (band == PHY_BAND_2G)
1688*e3037485SYan-Hsuan Chuang 		hal->tx_pwr_limit_2g[regd][bw][rs][ch_idx] = pwr_limit;
1689*e3037485SYan-Hsuan Chuang 	else if (band == PHY_BAND_5G)
1690*e3037485SYan-Hsuan Chuang 		hal->tx_pwr_limit_5g[regd][bw][rs][ch_idx] = pwr_limit;
1691*e3037485SYan-Hsuan Chuang }
1692*e3037485SYan-Hsuan Chuang 
1693*e3037485SYan-Hsuan Chuang static
1694*e3037485SYan-Hsuan Chuang void rtw_hw_tx_power_limit_init(struct rtw_hal *hal, u8 regd, u8 bw, u8 rs)
1695*e3037485SYan-Hsuan Chuang {
1696*e3037485SYan-Hsuan Chuang 	u8 ch;
1697*e3037485SYan-Hsuan Chuang 
1698*e3037485SYan-Hsuan Chuang 	/* 2.4G channels */
1699*e3037485SYan-Hsuan Chuang 	for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_2G; ch++)
1700*e3037485SYan-Hsuan Chuang 		hal->tx_pwr_limit_2g[regd][bw][rs][ch] = RTW_MAX_POWER_INDEX;
1701*e3037485SYan-Hsuan Chuang 
1702*e3037485SYan-Hsuan Chuang 	/* 5G channels */
1703*e3037485SYan-Hsuan Chuang 	for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_5G; ch++)
1704*e3037485SYan-Hsuan Chuang 		hal->tx_pwr_limit_5g[regd][bw][rs][ch] = RTW_MAX_POWER_INDEX;
1705*e3037485SYan-Hsuan Chuang }
1706*e3037485SYan-Hsuan Chuang 
1707*e3037485SYan-Hsuan Chuang void rtw_hw_init_tx_power(struct rtw_hal *hal)
1708*e3037485SYan-Hsuan Chuang {
1709*e3037485SYan-Hsuan Chuang 	u8 regd, path, rate, rs, bw;
1710*e3037485SYan-Hsuan Chuang 
1711*e3037485SYan-Hsuan Chuang 	/* init tx power by rate offset */
1712*e3037485SYan-Hsuan Chuang 	for (path = 0; path < RTW_RF_PATH_MAX; path++) {
1713*e3037485SYan-Hsuan Chuang 		for (rate = 0; rate < DESC_RATE_MAX; rate++) {
1714*e3037485SYan-Hsuan Chuang 			hal->tx_pwr_by_rate_offset_2g[path][rate] = 0;
1715*e3037485SYan-Hsuan Chuang 			hal->tx_pwr_by_rate_offset_5g[path][rate] = 0;
1716*e3037485SYan-Hsuan Chuang 		}
1717*e3037485SYan-Hsuan Chuang 	}
1718*e3037485SYan-Hsuan Chuang 
1719*e3037485SYan-Hsuan Chuang 	/* init tx power limit */
1720*e3037485SYan-Hsuan Chuang 	for (regd = 0; regd < RTW_REGD_MAX; regd++)
1721*e3037485SYan-Hsuan Chuang 		for (bw = 0; bw < RTW_CHANNEL_WIDTH_MAX; bw++)
1722*e3037485SYan-Hsuan Chuang 			for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++)
1723*e3037485SYan-Hsuan Chuang 				rtw_hw_tx_power_limit_init(hal, regd, bw, rs);
1724*e3037485SYan-Hsuan Chuang }
1725