diff mbox series

[01/11] rtw88: resolve order of tx power setting routines

Message ID 1559116487-5244-2-git-send-email-yhchuang@realtek.com (mailing list archive)
State Accepted
Commit fa6dfe6bff246ddd5be3cfe81637f137acd6c294
Delegated to: Kalle Valo
Headers show
Series rtw88: power index setting routine updates and fixes | expand

Commit Message

Tony Chuang May 29, 2019, 7:54 a.m. UTC
From: Yan-Hsuan Chuang <yhchuang@realtek.com>

Some functions that should be static are unnecessarily exposed, remove
their declaration in header file phy.h.

After resolving their declaration order, they can be declared as static.
So this commit changes nothing except the order and marking them static.

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/phy.c | 1287 +++++++++++++++---------------
 drivers/net/wireless/realtek/rtw88/phy.h |    7 +-
 2 files changed, 642 insertions(+), 652 deletions(-)

Comments

Larry Finger May 29, 2019, 3:16 p.m. UTC | #1
On 5/29/19 2:54 AM, yhchuang@realtek.com wrote:
> From: Yan-Hsuan Chuang <yhchuang@realtek.com>
> 
> Some functions that should be static are unnecessarily exposed, remove
> their declaration in header file phy.h.
> 
> After resolving their declaration order, they can be declared as static.
> So this commit changes nothing except the order and marking them static.
> 
> Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>

This patch does not apply. Using quilt to see what is wrong, there are 6 changes 
that have already been applied.

Larry
Tony Chuang May 30, 2019, 2:29 a.m. UTC | #2
> -----Original Message-----
> From: Larry Finger [mailto:larry.finger@gmail.com] On Behalf Of Larry Finger
> Sent: Wednesday, May 29, 2019 11:17 PM
> To: Tony Chuang; kvalo@codeaurora.org
> Cc: linux-wireless@vger.kernel.org
> Subject: Re: [PATCH 01/11] rtw88: resolve order of tx power setting routines
> 
> On 5/29/19 2:54 AM, yhchuang@realtek.com wrote:
> > From: Yan-Hsuan Chuang <yhchuang@realtek.com>
> >
> > Some functions that should be static are unnecessarily exposed, remove
> > their declaration in header file phy.h.
> >
> > After resolving their declaration order, they can be declared as static.
> > So this commit changes nothing except the order and marking them static.
> >
> > Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
> 
> This patch does not apply. Using quilt to see what is wrong, there are 6
> changes
> that have already been applied.
> 
> Larry
> 


These patches are based on

https://kernel.googlesource.com/pub/scm/linux/kernel/git/kvalo/wireless-drivers
branch master

commit 6aca09771db4277a78853d6ac680d8d5f0d915e3
Author: YueHaibing <yuehaibing@huawei.com>
Date:   Sat May 4 18:32:24 2019 +0800

    rtw88: Make some symbols static


It should apply, did I miss something?


Yan-Hsuan
Larry Finger May 30, 2019, 2:57 a.m. UTC | #3
On 5/29/19 9:29 PM, Tony Chuang wrote:
> 
> 
>> -----Original Message-----
>> From: Larry Finger [mailto:larry.finger@gmail.com] On Behalf Of Larry Finger
>> Sent: Wednesday, May 29, 2019 11:17 PM
>> To: Tony Chuang; kvalo@codeaurora.org
>> Cc: linux-wireless@vger.kernel.org
>> Subject: Re: [PATCH 01/11] rtw88: resolve order of tx power setting routines
>>
>> On 5/29/19 2:54 AM, yhchuang@realtek.com wrote:
>>> From: Yan-Hsuan Chuang <yhchuang@realtek.com>
>>>
>>> Some functions that should be static are unnecessarily exposed, remove
>>> their declaration in header file phy.h.
>>>
>>> After resolving their declaration order, they can be declared as static.
>>> So this commit changes nothing except the order and marking them static.
>>>
>>> Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
>>
>> This patch does not apply. Using quilt to see what is wrong, there are 6
>> changes
>> that have already been applied.
>>
>> Larry
>>
> 
> 
> These patches are based on
> 
> https://kernel.googlesource.com/pub/scm/linux/kernel/git/kvalo/wireless-drivers
> branch master
> 
> commit 6aca09771db4277a78853d6ac680d8d5f0d915e3
> Author: YueHaibing <yuehaibing@huawei.com>
> Date:   Sat May 4 18:32:24 2019 +0800
> 
>      rtw88: Make some symbols static
> 
> 
> It should apply, did I miss something?

I was trying to apply the patch to wireless-drivers-next. That may be my 
problem. The other 10 applied OK.

Larry
Kalle Valo May 30, 2019, 4:59 a.m. UTC | #4
Tony Chuang <yhchuang@realtek.com> writes:

>> -----Original Message-----
>> From: Larry Finger [mailto:larry.finger@gmail.com] On Behalf Of Larry Finger
>> Sent: Wednesday, May 29, 2019 11:17 PM
>> To: Tony Chuang; kvalo@codeaurora.org
>> Cc: linux-wireless@vger.kernel.org
>> Subject: Re: [PATCH 01/11] rtw88: resolve order of tx power setting routines
>> 
>> On 5/29/19 2:54 AM, yhchuang@realtek.com wrote:
>> > From: Yan-Hsuan Chuang <yhchuang@realtek.com>
>> >
>> > Some functions that should be static are unnecessarily exposed, remove
>> > their declaration in header file phy.h.
>> >
>> > After resolving their declaration order, they can be declared as static.
>> > So this commit changes nothing except the order and marking them static.
>> >
>> > Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
>> 
>> This patch does not apply. Using quilt to see what is wrong, there are 6
>> changes
>> that have already been applied.
>> 
>> Larry
>> 
>
>
> These patches are based on
>
> https://kernel.googlesource.com/pub/scm/linux/kernel/git/kvalo/wireless-drivers
> branch master
>
> commit 6aca09771db4277a78853d6ac680d8d5f0d915e3
> Author: YueHaibing <yuehaibing@huawei.com>
> Date:   Sat May 4 18:32:24 2019 +0800
>
>     rtw88: Make some symbols static
>
>
> It should apply, did I miss something?

I keep the bar high and take to wireless-drivers only patches which fix
important, user visible problems. Everything else goes to
wireless-drivers-next. So you should use wireless-drivers-next as the
baseline for all regular patches.
Tony Chuang May 30, 2019, 5:05 a.m. UTC | #5
> -----Original Message-----
> From: Kalle Valo [mailto:kvalo@codeaurora.org]
> Sent: Thursday, May 30, 2019 1:00 PM
> To: Tony Chuang
> Cc: Larry Finger; linux-wireless@vger.kernel.org
> Subject: Re: [PATCH 01/11] rtw88: resolve order of tx power setting routines
> 
> Tony Chuang <yhchuang@realtek.com> writes:
> 
> >> -----Original Message-----
> >> From: Larry Finger [mailto:larry.finger@gmail.com] On Behalf Of Larry
> Finger
> >> Sent: Wednesday, May 29, 2019 11:17 PM
> >> To: Tony Chuang; kvalo@codeaurora.org
> >> Cc: linux-wireless@vger.kernel.org
> >> Subject: Re: [PATCH 01/11] rtw88: resolve order of tx power setting
> routines
> >>
> >> On 5/29/19 2:54 AM, yhchuang@realtek.com wrote:
> >> > From: Yan-Hsuan Chuang <yhchuang@realtek.com>
> >> >
> >> > Some functions that should be static are unnecessarily exposed, remove
> >> > their declaration in header file phy.h.
> >> >
> >> > After resolving their declaration order, they can be declared as static.
> >> > So this commit changes nothing except the order and marking them
> static.
> >> >
> >> > Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
> >>
> >> This patch does not apply. Using quilt to see what is wrong, there are 6
> >> changes
> >> that have already been applied.
> >>
> >> Larry
> >>
> >
> >
> > These patches are based on
> >
> >
> https://kernel.googlesource.com/pub/scm/linux/kernel/git/kvalo/wireless-dr
> ivers
> > branch master
> >
> > commit 6aca09771db4277a78853d6ac680d8d5f0d915e3
> > Author: YueHaibing <yuehaibing@huawei.com>
> > Date:   Sat May 4 18:32:24 2019 +0800
> >
> >     rtw88: Make some symbols static
> >
> >
> > It should apply, did I miss something?
> 
> I keep the bar high and take to wireless-drivers only patches which fix
> important, user visible problems. Everything else goes to
> wireless-drivers-next. So you should use wireless-drivers-next as the
> baseline for all regular patches.

Hi, Kalle

But this series has dependency with " rtw88: Make some symbols static"
Or you can handle it

> 
> --
> Kalle Valo
> 

Yan-Hsuan
Kalle Valo May 30, 2019, 5:11 a.m. UTC | #6
Tony Chuang <yhchuang@realtek.com> writes:

>> > These patches are based on
>> >
>> >
>> https://kernel.googlesource.com/pub/scm/linux/kernel/git/kvalo/wireless-dr
>> ivers
>> > branch master
>> >
>> > commit 6aca09771db4277a78853d6ac680d8d5f0d915e3
>> > Author: YueHaibing <yuehaibing@huawei.com>
>> > Date:   Sat May 4 18:32:24 2019 +0800
>> >
>> >     rtw88: Make some symbols static
>> >
>> >
>> > It should apply, did I miss something?
>> 
>> I keep the bar high and take to wireless-drivers only patches which fix
>> important, user visible problems. Everything else goes to
>> wireless-drivers-next. So you should use wireless-drivers-next as the
>> baseline for all regular patches.
>
> But this series has dependency with " rtw88: Make some symbols static"

This is exactly why I keep the bar high for patches going to
wireless-drivers :) These depencies and conflicts are just too time
consuming otherwise.

> Or you can handle it

Unfortunately not, as I made a mistake when fast-forwarding
wireless-drivers and I cannot merge wireless-drivers into
wireles-drivers-next right now. So you just need to wait for the
depencies to trickle down to w-d-next, that will take few weeks.
Tony Chuang May 30, 2019, 5:15 a.m. UTC | #7
> -----Original Message-----
> From: Kalle Valo [mailto:kvalo@codeaurora.org]
> Sent: Thursday, May 30, 2019 1:11 PM
> To: Tony Chuang
> Cc: Larry Finger; linux-wireless@vger.kernel.org
> Subject: Re: [PATCH 01/11] rtw88: resolve order of tx power setting routines
> 
> Tony Chuang <yhchuang@realtek.com> writes:
> 
> >> > These patches are based on
> >> >
> >> >
> >>
> https://kernel.googlesource.com/pub/scm/linux/kernel/git/kvalo/wireless-dr
> >> ivers
> >> > branch master
> >> >
> >> > commit 6aca09771db4277a78853d6ac680d8d5f0d915e3
> >> > Author: YueHaibing <yuehaibing@huawei.com>
> >> > Date:   Sat May 4 18:32:24 2019 +0800
> >> >
> >> >     rtw88: Make some symbols static
> >> >
> >> >
> >> > It should apply, did I miss something?
> >>
> >> I keep the bar high and take to wireless-drivers only patches which fix
> >> important, user visible problems. Everything else goes to
> >> wireless-drivers-next. So you should use wireless-drivers-next as the
> >> baseline for all regular patches.
> >
> > But this series has dependency with " rtw88: Make some symbols static"
> 
> This is exactly why I keep the bar high for patches going to
> wireless-drivers :) These depencies and conflicts are just too time
> consuming otherwise.
> 
> > Or you can handle it
> 
> Unfortunately not, as I made a mistake when fast-forwarding
> wireless-drivers and I cannot merge wireless-drivers into
> wireles-drivers-next right now. So you just need to wait for the
> depencies to trickle down to w-d-next, that will take few weeks.

It means that I just need to wait for the patches in w-d to go to w-d-next?
So I don't need to resend them, just wait and you can merge this.

Yan-Hsuan
Kalle Valo June 27, 2019, 5:27 p.m. UTC | #8
<yhchuang@realtek.com> wrote:

> From: Yan-Hsuan Chuang <yhchuang@realtek.com>
> 
> Some functions that should be static are unnecessarily exposed, remove
> their declaration in header file phy.h.
> 
> After resolving their declaration order, they can be declared as static.
> So this commit changes nothing except the order and marking them static.
> 
> Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>

10 patches applied to wireless-drivers-next.git, thanks.

fa6dfe6bff24 rtw88: resolve order of tx power setting routines
226746fd1201 rtw88: do not use (void *) as argument
43712199e05b rtw88: unify prefixes for tx power setting routine
522801493e7b rtw88: remove unused variable
764038160aea rtw88: fix incorrect tx power limit at 5G
adf3c676d1d2 rtw88: choose the lowest as world-wide power limit
93f68a865f11 rtw88: correct power limit selection
191c4257ba19 rtw88: update tx power limit table to RF v20
0d350f0a91f2 rtw88: remove all RTW_MAX_POWER_INDEX macro
b741422218ef rtw88: refine flow to get tx power index
diff mbox series

Patch

diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index 404d894..ed104ea 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -65,6 +65,56 @@  static const u32 db_invert_table[12][8] = {
 	 1995262315,	2511886432U,	3162277660U,	3981071706U}
 };
 
+u8 rtw_cck_rates[] = { DESC_RATE1M, DESC_RATE2M, DESC_RATE5_5M, DESC_RATE11M };
+u8 rtw_ofdm_rates[] = {
+	DESC_RATE6M,  DESC_RATE9M,  DESC_RATE12M,
+	DESC_RATE18M, DESC_RATE24M, DESC_RATE36M,
+	DESC_RATE48M, DESC_RATE54M
+};
+u8 rtw_ht_1s_rates[] = {
+	DESC_RATEMCS0, DESC_RATEMCS1, DESC_RATEMCS2,
+	DESC_RATEMCS3, DESC_RATEMCS4, DESC_RATEMCS5,
+	DESC_RATEMCS6, DESC_RATEMCS7
+};
+u8 rtw_ht_2s_rates[] = {
+	DESC_RATEMCS8,  DESC_RATEMCS9,  DESC_RATEMCS10,
+	DESC_RATEMCS11, DESC_RATEMCS12, DESC_RATEMCS13,
+	DESC_RATEMCS14, DESC_RATEMCS15
+};
+u8 rtw_vht_1s_rates[] = {
+	DESC_RATEVHT1SS_MCS0, DESC_RATEVHT1SS_MCS1,
+	DESC_RATEVHT1SS_MCS2, DESC_RATEVHT1SS_MCS3,
+	DESC_RATEVHT1SS_MCS4, DESC_RATEVHT1SS_MCS5,
+	DESC_RATEVHT1SS_MCS6, DESC_RATEVHT1SS_MCS7,
+	DESC_RATEVHT1SS_MCS8, DESC_RATEVHT1SS_MCS9
+};
+u8 rtw_vht_2s_rates[] = {
+	DESC_RATEVHT2SS_MCS0, DESC_RATEVHT2SS_MCS1,
+	DESC_RATEVHT2SS_MCS2, DESC_RATEVHT2SS_MCS3,
+	DESC_RATEVHT2SS_MCS4, DESC_RATEVHT2SS_MCS5,
+	DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7,
+	DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9
+};
+u8 *rtw_rate_section[RTW_RATE_SECTION_MAX] = {
+	rtw_cck_rates, rtw_ofdm_rates,
+	rtw_ht_1s_rates, rtw_ht_2s_rates,
+	rtw_vht_1s_rates, rtw_vht_2s_rates
+};
+u8 rtw_rate_size[RTW_RATE_SECTION_MAX] = {
+	ARRAY_SIZE(rtw_cck_rates),
+	ARRAY_SIZE(rtw_ofdm_rates),
+	ARRAY_SIZE(rtw_ht_1s_rates),
+	ARRAY_SIZE(rtw_ht_2s_rates),
+	ARRAY_SIZE(rtw_vht_1s_rates),
+	ARRAY_SIZE(rtw_vht_2s_rates)
+};
+static const u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates);
+static const u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates);
+static const u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates);
+static const u8 rtw_ht_2s_size = ARRAY_SIZE(rtw_ht_2s_rates);
+static const u8 rtw_vht_1s_size = ARRAY_SIZE(rtw_vht_1s_rates);
+static const u8 rtw_vht_2s_size = ARRAY_SIZE(rtw_vht_2s_rates);
+
 enum rtw_phy_band_type {
 	PHY_BAND_2G	= 0,
 	PHY_BAND_5G	= 1,
@@ -714,563 +764,73 @@  void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
 	}
 }
 
-void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
-{
-	const struct phy_pg_cfg_pair *p = tbl->data;
-	const struct phy_pg_cfg_pair *end = p + tbl->size / 6;
-
-	BUILD_BUG_ON(sizeof(struct phy_pg_cfg_pair) != sizeof(u32) * 6);
-
-	for (; p < end; p++) {
-		if (p->addr == 0xfe || p->addr == 0xffe) {
-			msleep(50);
-			continue;
-		}
-		phy_store_tx_power_by_rate(rtwdev, p->band, p->rf_path,
-					   p->tx_num, p->addr, p->bitmask,
-					   p->data);
-	}
-}
-
-void rtw_parse_tbl_txpwr_lmt(struct rtw_dev *rtwdev,
-			     const struct rtw_table *tbl)
-{
-	const struct txpwr_lmt_cfg_pair *p = tbl->data;
-	const struct txpwr_lmt_cfg_pair *end = p + tbl->size / 6;
-
-	BUILD_BUG_ON(sizeof(struct txpwr_lmt_cfg_pair) != sizeof(u8) * 6);
-
-	for (; p < end; p++) {
-		phy_set_tx_power_limit(rtwdev, p->regd, p->band,
-				       p->bw, p->rs,
-				       p->ch, p->txpwr_lmt);
-	}
-}
-
-void rtw_phy_cfg_mac(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
-		     u32 addr, u32 data)
-{
-	rtw_write8(rtwdev, addr, data);
-}
-
-void rtw_phy_cfg_agc(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
-		     u32 addr, u32 data)
-{
-	rtw_write32(rtwdev, addr, data);
-}
-
-void rtw_phy_cfg_bb(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
-		    u32 addr, u32 data)
-{
-	if (addr == 0xfe)
-		msleep(50);
-	else if (addr == 0xfd)
-		mdelay(5);
-	else if (addr == 0xfc)
-		mdelay(1);
-	else if (addr == 0xfb)
-		usleep_range(50, 60);
-	else if (addr == 0xfa)
-		udelay(5);
-	else if (addr == 0xf9)
-		udelay(1);
-	else
-		rtw_write32(rtwdev, addr, data);
-}
-
-void rtw_phy_cfg_rf(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
-		    u32 addr, u32 data)
-{
-	if (addr == 0xffe) {
-		msleep(50);
-	} else if (addr == 0xfe) {
-		usleep_range(100, 110);
-	} else {
-		rtw_write_rf(rtwdev, tbl->rf_path, addr, RFREG_MASK, data);
-		udelay(1);
-	}
-}
-
-static void rtw_load_rfk_table(struct rtw_dev *rtwdev)
-{
-	struct rtw_chip_info *chip = rtwdev->chip;
-
-	if (!chip->rfk_init_tbl)
-		return;
-
-	rtw_load_table(rtwdev, chip->rfk_init_tbl);
-}
-
-void rtw_phy_load_tables(struct rtw_dev *rtwdev)
-{
-	struct rtw_chip_info *chip = rtwdev->chip;
-	u8 rf_path;
-
-	rtw_load_table(rtwdev, chip->mac_tbl);
-	rtw_load_table(rtwdev, chip->bb_tbl);
-	rtw_load_table(rtwdev, chip->agc_tbl);
-	rtw_load_rfk_table(rtwdev);
-
-	for (rf_path = 0; rf_path < rtwdev->hal.rf_path_num; rf_path++) {
-		const struct rtw_table *tbl;
-
-		tbl = chip->rf_tbl[rf_path];
-		rtw_load_table(rtwdev, tbl);
-	}
-}
-
 #define bcd_to_dec_pwr_by_rate(val, i) bcd2bin(val >> (i * 8))
 
-#define RTW_MAX_POWER_INDEX		0x3F
-
-u8 rtw_cck_rates[] = { DESC_RATE1M, DESC_RATE2M, DESC_RATE5_5M, DESC_RATE11M };
-u8 rtw_ofdm_rates[] = {
-	DESC_RATE6M,  DESC_RATE9M,  DESC_RATE12M,
-	DESC_RATE18M, DESC_RATE24M, DESC_RATE36M,
-	DESC_RATE48M, DESC_RATE54M
-};
-u8 rtw_ht_1s_rates[] = {
-	DESC_RATEMCS0, DESC_RATEMCS1, DESC_RATEMCS2,
-	DESC_RATEMCS3, DESC_RATEMCS4, DESC_RATEMCS5,
-	DESC_RATEMCS6, DESC_RATEMCS7
-};
-u8 rtw_ht_2s_rates[] = {
-	DESC_RATEMCS8,  DESC_RATEMCS9,  DESC_RATEMCS10,
-	DESC_RATEMCS11, DESC_RATEMCS12, DESC_RATEMCS13,
-	DESC_RATEMCS14, DESC_RATEMCS15
-};
-u8 rtw_vht_1s_rates[] = {
-	DESC_RATEVHT1SS_MCS0, DESC_RATEVHT1SS_MCS1,
-	DESC_RATEVHT1SS_MCS2, DESC_RATEVHT1SS_MCS3,
-	DESC_RATEVHT1SS_MCS4, DESC_RATEVHT1SS_MCS5,
-	DESC_RATEVHT1SS_MCS6, DESC_RATEVHT1SS_MCS7,
-	DESC_RATEVHT1SS_MCS8, DESC_RATEVHT1SS_MCS9
-};
-u8 rtw_vht_2s_rates[] = {
-	DESC_RATEVHT2SS_MCS0, DESC_RATEVHT2SS_MCS1,
-	DESC_RATEVHT2SS_MCS2, DESC_RATEVHT2SS_MCS3,
-	DESC_RATEVHT2SS_MCS4, DESC_RATEVHT2SS_MCS5,
-	DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7,
-	DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9
-};
-
-static u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates);
-static u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates);
-static u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates);
-static u8 rtw_ht_2s_size = ARRAY_SIZE(rtw_ht_2s_rates);
-static u8 rtw_vht_1s_size = ARRAY_SIZE(rtw_vht_1s_rates);
-static u8 rtw_vht_2s_size = ARRAY_SIZE(rtw_vht_2s_rates);
-u8 *rtw_rate_section[RTW_RATE_SECTION_MAX] = {
-	rtw_cck_rates, rtw_ofdm_rates,
-	rtw_ht_1s_rates, rtw_ht_2s_rates,
-	rtw_vht_1s_rates, rtw_vht_2s_rates
-};
-u8 rtw_rate_size[RTW_RATE_SECTION_MAX] = {
-	ARRAY_SIZE(rtw_cck_rates),
-	ARRAY_SIZE(rtw_ofdm_rates),
-	ARRAY_SIZE(rtw_ht_1s_rates),
-	ARRAY_SIZE(rtw_ht_2s_rates),
-	ARRAY_SIZE(rtw_vht_1s_rates),
-	ARRAY_SIZE(rtw_vht_2s_rates)
-};
-
-static const u8 rtw_channel_idx_5g[RTW_MAX_CHANNEL_NUM_5G] = {
-	36,  38,  40,  42,  44,  46,  48, /* Band 1 */
-	52,  54,  56,  58,  60,  62,  64, /* Band 2 */
-	100, 102, 104, 106, 108, 110, 112, /* Band 3 */
-	116, 118, 120, 122, 124, 126, 128, /* Band 3 */
-	132, 134, 136, 138, 140, 142, 144, /* Band 3 */
-	149, 151, 153, 155, 157, 159, 161, /* Band 4 */
-	165, 167, 169, 171, 173, 175, 177}; /* Band 4 */
-
-static int rtw_channel_to_idx(u8 band, u8 channel)
+static u8 tbl_to_dec_pwr_by_rate(struct rtw_dev *rtwdev, u32 hex, u8 i)
 {
-	int ch_idx;
-	u8 n_channel;
-
-	if (band == PHY_BAND_2G) {
-		ch_idx = channel - 1;
-		n_channel = RTW_MAX_CHANNEL_NUM_2G;
-	} else if (band == PHY_BAND_5G) {
-		n_channel = RTW_MAX_CHANNEL_NUM_5G;
-		for (ch_idx = 0; ch_idx < n_channel; ch_idx++)
-			if (rtw_channel_idx_5g[ch_idx] == channel)
-				break;
-	} else {
-		return -1;
-	}
-
-	if (ch_idx >= n_channel)
-		return -1;
+	if (rtwdev->chip->is_pwr_by_rate_dec)
+		return bcd_to_dec_pwr_by_rate(hex, i);
 
-	return ch_idx;
+	return (hex >> (i * 8)) & 0xFF;
 }
 
-static u8 rtw_get_channel_group(u8 channel)
+static void phy_get_rate_values_of_txpwr_by_rate(struct rtw_dev *rtwdev,
+						 u32 addr, u32 mask,
+						 u32 val, u8 *rate,
+						 u8 *pwr_by_rate, u8 *rate_num)
 {
-	switch (channel) {
-	default:
-		WARN_ON(1);
-		/* fall through */
-	case 1:
-	case 2:
-	case 36:
-	case 38:
-	case 40:
-	case 42:
-		return 0;
-	case 3:
-	case 4:
-	case 5:
-	case 44:
-	case 46:
-	case 48:
-	case 50:
-		return 1;
-	case 6:
-	case 7:
-	case 8:
-	case 52:
-	case 54:
-	case 56:
-	case 58:
-		return 2;
-	case 9:
-	case 10:
-	case 11:
-	case 60:
-	case 62:
-	case 64:
-		return 3;
-	case 12:
-	case 13:
-	case 100:
-	case 102:
-	case 104:
-	case 106:
-		return 4;
-	case 14:
-	case 108:
-	case 110:
-	case 112:
-	case 114:
-		return 5;
-	case 116:
-	case 118:
-	case 120:
-	case 122:
-		return 6;
-	case 124:
-	case 126:
-	case 128:
-	case 130:
-		return 7;
-	case 132:
-	case 134:
-	case 136:
-	case 138:
-		return 8;
-	case 140:
-	case 142:
-	case 144:
-		return 9;
-	case 149:
-	case 151:
-	case 153:
-	case 155:
-		return 10;
-	case 157:
-	case 159:
-	case 161:
-		return 11;
-	case 165:
-	case 167:
-	case 169:
-	case 171:
-		return 12;
-	case 173:
-	case 175:
-	case 177:
-		return 13;
-	}
-}
-
-static u8 phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
-				    struct rtw_2g_txpwr_idx *pwr_idx_2g,
-				    enum rtw_bandwidth bandwidth,
-				    u8 rate, u8 group)
-{
-	struct rtw_chip_info *chip = rtwdev->chip;
-	u8 tx_power;
-	bool mcs_rate;
-	bool above_2ss;
-	u8 factor = chip->txgi_factor;
-
-	if (rate <= DESC_RATE11M)
-		tx_power = pwr_idx_2g->cck_base[group];
-	else
-		tx_power = pwr_idx_2g->bw40_base[group];
-
-	if (rate >= DESC_RATE6M && rate <= DESC_RATE54M)
-		tx_power += pwr_idx_2g->ht_1s_diff.ofdm * factor;
-
-	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) ||
-		   (rate >= DESC_RATEVHT1SS_MCS0 &&
-		    rate <= DESC_RATEVHT2SS_MCS9);
-	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
-		    (rate >= DESC_RATEVHT2SS_MCS0);
-
-	if (!mcs_rate)
-		return tx_power;
+	int i;
 
-	switch (bandwidth) {
-	default:
-		WARN_ON(1);
-		/* fall through */
-	case RTW_CHANNEL_WIDTH_20:
-		tx_power += pwr_idx_2g->ht_1s_diff.bw20 * factor;
-		if (above_2ss)
-			tx_power += pwr_idx_2g->ht_2s_diff.bw20 * factor;
+	switch (addr) {
+	case 0xE00:
+	case 0x830:
+		rate[0] = DESC_RATE6M;
+		rate[1] = DESC_RATE9M;
+		rate[2] = DESC_RATE12M;
+		rate[3] = DESC_RATE18M;
+		for (i = 0; i < 4; ++i)
+			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+		*rate_num = 4;
 		break;
-	case RTW_CHANNEL_WIDTH_40:
-		/* bw40 is the base power */
-		if (above_2ss)
-			tx_power += pwr_idx_2g->ht_2s_diff.bw40 * factor;
+	case 0xE04:
+	case 0x834:
+		rate[0] = DESC_RATE24M;
+		rate[1] = DESC_RATE36M;
+		rate[2] = DESC_RATE48M;
+		rate[3] = DESC_RATE54M;
+		for (i = 0; i < 4; ++i)
+			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+		*rate_num = 4;
 		break;
-	}
-
-	return tx_power;
-}
-
-static u8 phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
-				    struct rtw_5g_txpwr_idx *pwr_idx_5g,
-				    enum rtw_bandwidth bandwidth,
-				    u8 rate, u8 group)
-{
-	struct rtw_chip_info *chip = rtwdev->chip;
-	u8 tx_power;
-	u8 upper, lower;
-	bool mcs_rate;
-	bool above_2ss;
-	u8 factor = chip->txgi_factor;
-
-	tx_power = pwr_idx_5g->bw40_base[group];
-
-	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) ||
-		   (rate >= DESC_RATEVHT1SS_MCS0 &&
-		    rate <= DESC_RATEVHT2SS_MCS9);
-	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
-		    (rate >= DESC_RATEVHT2SS_MCS0);
-
-	if (!mcs_rate) {
-		tx_power += pwr_idx_5g->ht_1s_diff.ofdm * factor;
-		return tx_power;
-	}
-
-	switch (bandwidth) {
-	default:
-		WARN_ON(1);
-		/* fall through */
-	case RTW_CHANNEL_WIDTH_20:
-		tx_power += pwr_idx_5g->ht_1s_diff.bw20 * factor;
-		if (above_2ss)
-			tx_power += pwr_idx_5g->ht_2s_diff.bw20 * factor;
+	case 0xE08:
+		rate[0] = DESC_RATE1M;
+		pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 1);
+		*rate_num = 1;
 		break;
-	case RTW_CHANNEL_WIDTH_40:
-		/* bw40 is the base power */
-		if (above_2ss)
-			tx_power += pwr_idx_5g->ht_2s_diff.bw40 * factor;
+	case 0x86C:
+		if (mask == 0xffffff00) {
+			rate[0] = DESC_RATE2M;
+			rate[1] = DESC_RATE5_5M;
+			rate[2] = DESC_RATE11M;
+			for (i = 1; i < 4; ++i)
+				pwr_by_rate[i - 1] =
+					tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+			*rate_num = 3;
+		} else if (mask == 0x000000ff) {
+			rate[0] = DESC_RATE11M;
+			pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 0);
+			*rate_num = 1;
+		}
 		break;
-	case RTW_CHANNEL_WIDTH_80:
-		/* the base idx of bw80 is the average of bw40+/bw40- */
-		lower = pwr_idx_5g->bw40_base[group];
-		upper = pwr_idx_5g->bw40_base[group + 1];
-
-		tx_power = (lower + upper) / 2;
-		tx_power += pwr_idx_5g->vht_1s_diff.bw80 * factor;
-		if (above_2ss)
-			tx_power += pwr_idx_5g->vht_2s_diff.bw80 * factor;
-		break;
-	}
-
-	return tx_power;
-}
-
-/* set tx power level by path for each rates, note that the order of the rates
- * are *very* important, bacause 8822B/8821C combines every four bytes of tx
- * power index into a four-byte power index register, and calls set_tx_agc to
- * write these values into hardware
- */
-static
-void phy_set_tx_power_level_by_path(struct rtw_dev *rtwdev, u8 ch, u8 path)
-{
-	struct rtw_hal *hal = &rtwdev->hal;
-	u8 rs;
-
-	/* do not need cck rates if we are not in 2.4G */
-	if (hal->current_band_type == RTW_BAND_2G)
-		rs = RTW_RATE_SECTION_CCK;
-	else
-		rs = RTW_RATE_SECTION_OFDM;
-
-	for (; rs < RTW_RATE_SECTION_MAX; rs++)
-		phy_set_tx_power_index_by_rs(rtwdev, ch, path, rs);
-}
-
-void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel)
-{
-	struct rtw_chip_info *chip = rtwdev->chip;
-	struct rtw_hal *hal = &rtwdev->hal;
-	u8 path;
-
-	mutex_lock(&hal->tx_power_mutex);
-
-	for (path = 0; path < hal->rf_path_num; path++)
-		phy_set_tx_power_level_by_path(rtwdev, channel, path);
-
-	chip->ops->set_tx_power_index(rtwdev);
-	mutex_unlock(&hal->tx_power_mutex);
-}
-
-s8 phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band,
-			  enum rtw_bandwidth bandwidth, u8 rf_path,
-			  u8 rate, u8 channel, u8 regd);
-
-static
-u8 phy_get_tx_power_index(void *adapter, u8 rf_path, u8 rate,
-			  enum rtw_bandwidth bandwidth, u8 channel, u8 regd)
-{
-	struct rtw_dev *rtwdev = adapter;
-	struct rtw_hal *hal = &rtwdev->hal;
-	struct rtw_txpwr_idx *pwr_idx;
-	u8 tx_power;
-	u8 group;
-	u8 band;
-	s8 offset, limit;
-
-	pwr_idx = &rtwdev->efuse.txpwr_idx_table[rf_path];
-	group = rtw_get_channel_group(channel);
-
-	/* base power index for 2.4G/5G */
-	if (channel <= 14) {
-		band = PHY_BAND_2G;
-		tx_power = phy_get_2g_tx_power_index(rtwdev,
-						     &pwr_idx->pwr_idx_2g,
-						     bandwidth, rate, group);
-		offset = hal->tx_pwr_by_rate_offset_2g[rf_path][rate];
-	} else {
-		band = PHY_BAND_5G;
-		tx_power = phy_get_5g_tx_power_index(rtwdev,
-						     &pwr_idx->pwr_idx_5g,
-						     bandwidth, rate, group);
-		offset = hal->tx_pwr_by_rate_offset_5g[rf_path][rate];
-	}
-
-	limit = phy_get_tx_power_limit(rtwdev, band, bandwidth, rf_path,
-				       rate, channel, regd);
-
-	if (offset > limit)
-		offset = limit;
-
-	tx_power += offset;
-
-	if (tx_power > rtwdev->chip->max_power_index)
-		tx_power = rtwdev->chip->max_power_index;
-
-	return tx_power;
-}
-
-void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs)
-{
-	struct rtw_dev *rtwdev = adapter;
-	struct rtw_hal *hal = &rtwdev->hal;
-	u8 regd = rtwdev->regd.txpwr_regd;
-	u8 *rates;
-	u8 size;
-	u8 rate;
-	u8 pwr_idx;
-	u8 bw;
-	int i;
-
-	if (rs >= RTW_RATE_SECTION_MAX)
-		return;
-
-	rates = rtw_rate_section[rs];
-	size = rtw_rate_size[rs];
-	bw = hal->current_band_width;
-	for (i = 0; i < size; i++) {
-		rate = rates[i];
-		pwr_idx = phy_get_tx_power_index(adapter, path, rate, bw, ch,
-						 regd);
-		hal->tx_pwr_tbl[path][rate] = pwr_idx;
-	}
-}
-
-static u8 tbl_to_dec_pwr_by_rate(struct rtw_dev *rtwdev, u32 hex, u8 i)
-{
-	if (rtwdev->chip->is_pwr_by_rate_dec)
-		return bcd_to_dec_pwr_by_rate(hex, i);
-	else
-		return (hex >> (i * 8)) & 0xFF;
-}
-
-static void phy_get_rate_values_of_txpwr_by_rate(struct rtw_dev *rtwdev,
-						 u32 addr, u32 mask,
-						 u32 val, u8 *rate,
-						 u8 *pwr_by_rate, u8 *rate_num)
-{
-	int i;
-
-	switch (addr) {
-	case 0xE00:
-	case 0x830:
-		rate[0] = DESC_RATE6M;
-		rate[1] = DESC_RATE9M;
-		rate[2] = DESC_RATE12M;
-		rate[3] = DESC_RATE18M;
-		for (i = 0; i < 4; ++i)
-			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
-		*rate_num = 4;
-		break;
-	case 0xE04:
-	case 0x834:
-		rate[0] = DESC_RATE24M;
-		rate[1] = DESC_RATE36M;
-		rate[2] = DESC_RATE48M;
-		rate[3] = DESC_RATE54M;
-		for (i = 0; i < 4; ++i)
-			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
-		*rate_num = 4;
-		break;
-	case 0xE08:
-		rate[0] = DESC_RATE1M;
-		pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 1);
-		*rate_num = 1;
-		break;
-	case 0x86C:
-		if (mask == 0xffffff00) {
-			rate[0] = DESC_RATE2M;
-			rate[1] = DESC_RATE5_5M;
-			rate[2] = DESC_RATE11M;
-			for (i = 1; i < 4; ++i)
-				pwr_by_rate[i - 1] =
-					tbl_to_dec_pwr_by_rate(rtwdev, val, i);
-			*rate_num = 3;
-		} else if (mask == 0x000000ff) {
-			rate[0] = DESC_RATE11M;
-			pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 0);
-			*rate_num = 1;
-		}
-		break;
-	case 0xE10:
-	case 0x83C:
-		rate[0] = DESC_RATEMCS0;
-		rate[1] = DESC_RATEMCS1;
-		rate[2] = DESC_RATEMCS2;
-		rate[3] = DESC_RATEMCS3;
-		for (i = 0; i < 4; ++i)
-			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
-		*rate_num = 4;
+	case 0xE10:
+	case 0x83C:
+		rate[0] = DESC_RATEMCS0;
+		rate[1] = DESC_RATEMCS1;
+		rate[2] = DESC_RATEMCS2;
+		rate[3] = DESC_RATEMCS3;
+		for (i = 0; i < 4; ++i)
+			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+		*rate_num = 4;
 		break;
 	case 0xE14:
 	case 0x848:
@@ -1301,7 +861,6 @@  static void phy_get_rate_values_of_txpwr_by_rate(struct rtw_dev *rtwdev,
 		for (i = 0; i < 4; ++i)
 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
 		*rate_num = 4;
-
 		break;
 	case 0x838:
 		rate[0] = DESC_RATE1M;
@@ -1504,54 +1063,558 @@  static void phy_get_rate_values_of_txpwr_by_rate(struct rtw_dev *rtwdev,
 			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
 		*rate_num = 4;
 		break;
-	case 0xCE8:
-	case 0xEE8:
-	case 0x18E8:
-	case 0x1AE8:
-		rate[0] = DESC_RATEVHT3SS_MCS8;
-		rate[1] = DESC_RATEVHT3SS_MCS9;
-		for (i = 0; i < 2; ++i)
-			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
-		*rate_num = 2;
+	case 0xCE8:
+	case 0xEE8:
+	case 0x18E8:
+	case 0x1AE8:
+		rate[0] = DESC_RATEVHT3SS_MCS8;
+		rate[1] = DESC_RATEVHT3SS_MCS9;
+		for (i = 0; i < 2; ++i)
+			pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+		*rate_num = 2;
+		break;
+	default:
+		rtw_warn(rtwdev, "invalid tx power index addr 0x%08x\n", addr);
+		break;
+	}
+}
+
+static void phy_store_tx_power_by_rate(void *adapter,
+				       u32 band, u32 rfpath, u32 txnum,
+				       u32 regaddr, u32 bitmask, u32 data)
+{
+	struct rtw_dev *rtwdev = adapter;
+	struct rtw_hal *hal = &rtwdev->hal;
+	u8 rate_num = 0;
+	u8 rate;
+	u8 rates[RTW_RF_PATH_MAX] = {0};
+	s8 offset;
+	s8 pwr_by_rate[RTW_RF_PATH_MAX] = {0};
+	int i;
+
+	phy_get_rate_values_of_txpwr_by_rate(rtwdev, regaddr, bitmask, data,
+					     rates, pwr_by_rate, &rate_num);
+
+	if (WARN_ON(rfpath >= RTW_RF_PATH_MAX ||
+		    (band != PHY_BAND_2G && band != PHY_BAND_5G) ||
+		    rate_num > RTW_RF_PATH_MAX))
+		return;
+
+	for (i = 0; i < rate_num; i++) {
+		offset = pwr_by_rate[i];
+		rate = rates[i];
+		if (band == PHY_BAND_2G)
+			hal->tx_pwr_by_rate_offset_2g[rfpath][rate] = offset;
+		else if (band == PHY_BAND_5G)
+			hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset;
+		else
+			continue;
+	}
+}
+
+void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
+{
+	const struct phy_pg_cfg_pair *p = tbl->data;
+	const struct phy_pg_cfg_pair *end = p + tbl->size / 6;
+
+	BUILD_BUG_ON(sizeof(struct phy_pg_cfg_pair) != sizeof(u32) * 6);
+
+	for (; p < end; p++) {
+		if (p->addr == 0xfe || p->addr == 0xffe) {
+			msleep(50);
+			continue;
+		}
+		phy_store_tx_power_by_rate(rtwdev, p->band, p->rf_path,
+					   p->tx_num, p->addr, p->bitmask,
+					   p->data);
+	}
+}
+
+static const u8 rtw_channel_idx_5g[RTW_MAX_CHANNEL_NUM_5G] = {
+	36,  38,  40,  42,  44,  46,  48, /* Band 1 */
+	52,  54,  56,  58,  60,  62,  64, /* Band 2 */
+	100, 102, 104, 106, 108, 110, 112, /* Band 3 */
+	116, 118, 120, 122, 124, 126, 128, /* Band 3 */
+	132, 134, 136, 138, 140, 142, 144, /* Band 3 */
+	149, 151, 153, 155, 157, 159, 161, /* Band 4 */
+	165, 167, 169, 171, 173, 175, 177}; /* Band 4 */
+
+static int rtw_channel_to_idx(u8 band, u8 channel)
+{
+	int ch_idx;
+	u8 n_channel;
+
+	if (band == PHY_BAND_2G) {
+		ch_idx = channel - 1;
+		n_channel = RTW_MAX_CHANNEL_NUM_2G;
+	} else if (band == PHY_BAND_5G) {
+		n_channel = RTW_MAX_CHANNEL_NUM_5G;
+		for (ch_idx = 0; ch_idx < n_channel; ch_idx++)
+			if (rtw_channel_idx_5g[ch_idx] == channel)
+				break;
+	} else {
+		return -1;
+	}
+
+	if (ch_idx >= n_channel)
+		return -1;
+
+	return ch_idx;
+}
+
+static void phy_set_tx_power_limit(struct rtw_dev *rtwdev, u8 regd, u8 band,
+				   u8 bw, u8 rs, u8 ch, s8 pwr_limit)
+{
+	struct rtw_hal *hal = &rtwdev->hal;
+	int ch_idx;
+
+	pwr_limit = clamp_t(s8, pwr_limit,
+			    -RTW_MAX_POWER_INDEX, RTW_MAX_POWER_INDEX);
+	ch_idx = rtw_channel_to_idx(band, ch);
+
+	if (regd >= RTW_REGD_MAX || bw >= RTW_CHANNEL_WIDTH_MAX ||
+	    rs >= RTW_RATE_SECTION_MAX || ch_idx < 0) {
+		WARN(1,
+		     "wrong txpwr_lmt regd=%u, band=%u bw=%u, rs=%u, ch_idx=%u, pwr_limit=%d\n",
+		     regd, band, bw, rs, ch_idx, pwr_limit);
+		return;
+	}
+
+	if (band == PHY_BAND_2G)
+		hal->tx_pwr_limit_2g[regd][bw][rs][ch_idx] = pwr_limit;
+	else if (band == PHY_BAND_5G)
+		hal->tx_pwr_limit_5g[regd][bw][rs][ch_idx] = pwr_limit;
+}
+
+void rtw_parse_tbl_txpwr_lmt(struct rtw_dev *rtwdev,
+			     const struct rtw_table *tbl)
+{
+	const struct txpwr_lmt_cfg_pair *p = tbl->data;
+	const struct txpwr_lmt_cfg_pair *end = p + tbl->size / 6;
+
+	BUILD_BUG_ON(sizeof(struct txpwr_lmt_cfg_pair) != sizeof(u8) * 6);
+
+	for (; p < end; p++) {
+		phy_set_tx_power_limit(rtwdev, p->regd, p->band,
+				       p->bw, p->rs,
+				       p->ch, p->txpwr_lmt);
+	}
+}
+
+void rtw_phy_cfg_mac(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
+		     u32 addr, u32 data)
+{
+	rtw_write8(rtwdev, addr, data);
+}
+
+void rtw_phy_cfg_agc(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
+		     u32 addr, u32 data)
+{
+	rtw_write32(rtwdev, addr, data);
+}
+
+void rtw_phy_cfg_bb(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
+		    u32 addr, u32 data)
+{
+	if (addr == 0xfe)
+		msleep(50);
+	else if (addr == 0xfd)
+		mdelay(5);
+	else if (addr == 0xfc)
+		mdelay(1);
+	else if (addr == 0xfb)
+		usleep_range(50, 60);
+	else if (addr == 0xfa)
+		udelay(5);
+	else if (addr == 0xf9)
+		udelay(1);
+	else
+		rtw_write32(rtwdev, addr, data);
+}
+
+void rtw_phy_cfg_rf(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
+		    u32 addr, u32 data)
+{
+	if (addr == 0xffe) {
+		msleep(50);
+	} else if (addr == 0xfe) {
+		usleep_range(100, 110);
+	} else {
+		rtw_write_rf(rtwdev, tbl->rf_path, addr, RFREG_MASK, data);
+		udelay(1);
+	}
+}
+
+static void rtw_load_rfk_table(struct rtw_dev *rtwdev)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+
+	if (!chip->rfk_init_tbl)
+		return;
+
+	rtw_load_table(rtwdev, chip->rfk_init_tbl);
+}
+
+void rtw_phy_load_tables(struct rtw_dev *rtwdev)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+	u8 rf_path;
+
+	rtw_load_table(rtwdev, chip->mac_tbl);
+	rtw_load_table(rtwdev, chip->bb_tbl);
+	rtw_load_table(rtwdev, chip->agc_tbl);
+	rtw_load_rfk_table(rtwdev);
+
+	for (rf_path = 0; rf_path < rtwdev->hal.rf_path_num; rf_path++) {
+		const struct rtw_table *tbl;
+
+		tbl = chip->rf_tbl[rf_path];
+		rtw_load_table(rtwdev, tbl);
+	}
+}
+
+static u8 rtw_get_channel_group(u8 channel)
+{
+	switch (channel) {
+	default:
+		WARN_ON(1);
+		/* fall through */
+	case 1:
+	case 2:
+	case 36:
+	case 38:
+	case 40:
+	case 42:
+		return 0;
+	case 3:
+	case 4:
+	case 5:
+	case 44:
+	case 46:
+	case 48:
+	case 50:
+		return 1;
+	case 6:
+	case 7:
+	case 8:
+	case 52:
+	case 54:
+	case 56:
+	case 58:
+		return 2;
+	case 9:
+	case 10:
+	case 11:
+	case 60:
+	case 62:
+	case 64:
+		return 3;
+	case 12:
+	case 13:
+	case 100:
+	case 102:
+	case 104:
+	case 106:
+		return 4;
+	case 14:
+	case 108:
+	case 110:
+	case 112:
+	case 114:
+		return 5;
+	case 116:
+	case 118:
+	case 120:
+	case 122:
+		return 6;
+	case 124:
+	case 126:
+	case 128:
+	case 130:
+		return 7;
+	case 132:
+	case 134:
+	case 136:
+	case 138:
+		return 8;
+	case 140:
+	case 142:
+	case 144:
+		return 9;
+	case 149:
+	case 151:
+	case 153:
+	case 155:
+		return 10;
+	case 157:
+	case 159:
+	case 161:
+		return 11;
+	case 165:
+	case 167:
+	case 169:
+	case 171:
+		return 12;
+	case 173:
+	case 175:
+	case 177:
+		return 13;
+	}
+}
+
+static u8 phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
+				    struct rtw_2g_txpwr_idx *pwr_idx_2g,
+				    enum rtw_bandwidth bandwidth,
+				    u8 rate, u8 group)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+	u8 tx_power;
+	bool mcs_rate;
+	bool above_2ss;
+	u8 factor = chip->txgi_factor;
+
+	if (rate <= DESC_RATE11M)
+		tx_power = pwr_idx_2g->cck_base[group];
+	else
+		tx_power = pwr_idx_2g->bw40_base[group];
+
+	if (rate >= DESC_RATE6M && rate <= DESC_RATE54M)
+		tx_power += pwr_idx_2g->ht_1s_diff.ofdm * factor;
+
+	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) ||
+		   (rate >= DESC_RATEVHT1SS_MCS0 &&
+		    rate <= DESC_RATEVHT2SS_MCS9);
+	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
+		    (rate >= DESC_RATEVHT2SS_MCS0);
+
+	if (!mcs_rate)
+		return tx_power;
+
+	switch (bandwidth) {
+	default:
+		WARN_ON(1);
+		/* fall through */
+	case RTW_CHANNEL_WIDTH_20:
+		tx_power += pwr_idx_2g->ht_1s_diff.bw20 * factor;
+		if (above_2ss)
+			tx_power += pwr_idx_2g->ht_2s_diff.bw20 * factor;
+		break;
+	case RTW_CHANNEL_WIDTH_40:
+		/* bw40 is the base power */
+		if (above_2ss)
+			tx_power += pwr_idx_2g->ht_2s_diff.bw40 * factor;
+		break;
+	}
+
+	return tx_power;
+}
+
+static u8 phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
+				    struct rtw_5g_txpwr_idx *pwr_idx_5g,
+				    enum rtw_bandwidth bandwidth,
+				    u8 rate, u8 group)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+	u8 tx_power;
+	u8 upper, lower;
+	bool mcs_rate;
+	bool above_2ss;
+	u8 factor = chip->txgi_factor;
+
+	tx_power = pwr_idx_5g->bw40_base[group];
+
+	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) ||
+		   (rate >= DESC_RATEVHT1SS_MCS0 &&
+		    rate <= DESC_RATEVHT2SS_MCS9);
+	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
+		    (rate >= DESC_RATEVHT2SS_MCS0);
+
+	if (!mcs_rate) {
+		tx_power += pwr_idx_5g->ht_1s_diff.ofdm * factor;
+		return tx_power;
+	}
+
+	switch (bandwidth) {
+	default:
+		WARN_ON(1);
+		/* fall through */
+	case RTW_CHANNEL_WIDTH_20:
+		tx_power += pwr_idx_5g->ht_1s_diff.bw20 * factor;
+		if (above_2ss)
+			tx_power += pwr_idx_5g->ht_2s_diff.bw20 * factor;
+		break;
+	case RTW_CHANNEL_WIDTH_40:
+		/* bw40 is the base power */
+		if (above_2ss)
+			tx_power += pwr_idx_5g->ht_2s_diff.bw40 * factor;
 		break;
-	default:
-		rtw_warn(rtwdev, "invalid tx power index addr 0x%08x\n", addr);
+	case RTW_CHANNEL_WIDTH_80:
+		/* the base idx of bw80 is the average of bw40+/bw40- */
+		lower = pwr_idx_5g->bw40_base[group];
+		upper = pwr_idx_5g->bw40_base[group + 1];
+
+		tx_power = (lower + upper) / 2;
+		tx_power += pwr_idx_5g->vht_1s_diff.bw80 * factor;
+		if (above_2ss)
+			tx_power += pwr_idx_5g->vht_2s_diff.bw80 * factor;
 		break;
 	}
+
+	return tx_power;
+}
+
+static s8 get_tx_power_limit(struct rtw_hal *hal, u8 bw, u8 rs, u8 ch, u8 regd)
+{
+	if (regd > RTW_REGD_WW)
+		return RTW_MAX_POWER_INDEX;
+
+	return hal->tx_pwr_limit_2g[regd][bw][rs][ch];
+}
+
+static s8 phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band,
+				 enum rtw_bandwidth bw, u8 rf_path,
+				 u8 rate, u8 channel, u8 regd)
+{
+	struct rtw_hal *hal = &rtwdev->hal;
+	s8 power_limit;
+	u8 rs;
+	int ch_idx;
+
+	if (rate >= DESC_RATE1M && rate <= DESC_RATE11M)
+		rs = RTW_RATE_SECTION_CCK;
+	else if (rate >= DESC_RATE6M && rate <= DESC_RATE54M)
+		rs = RTW_RATE_SECTION_OFDM;
+	else if (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS7)
+		rs = RTW_RATE_SECTION_HT_1S;
+	else if (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15)
+		rs = RTW_RATE_SECTION_HT_2S;
+	else if (rate >= DESC_RATEVHT1SS_MCS0 && rate <= DESC_RATEVHT1SS_MCS9)
+		rs = RTW_RATE_SECTION_VHT_1S;
+	else if (rate >= DESC_RATEVHT2SS_MCS0 && rate <= DESC_RATEVHT2SS_MCS9)
+		rs = RTW_RATE_SECTION_VHT_2S;
+	else
+		goto err;
+
+	ch_idx = rtw_channel_to_idx(band, channel);
+	if (ch_idx < 0)
+		goto err;
+
+	power_limit = get_tx_power_limit(hal, bw, rs, ch_idx, regd);
+
+	return power_limit;
+
+err:
+	WARN(1, "invalid arguments, band=%d, bw=%d, path=%d, rate=%d, ch=%d\n",
+	     band, bw, rf_path, rate, channel);
+	return RTW_MAX_POWER_INDEX;
+}
+
+static
+u8 phy_get_tx_power_index(void *adapter, u8 rf_path, u8 rate,
+			  enum rtw_bandwidth bandwidth, u8 channel, u8 regd)
+{
+	struct rtw_dev *rtwdev = adapter;
+	struct rtw_hal *hal = &rtwdev->hal;
+	struct rtw_txpwr_idx *pwr_idx;
+	u8 tx_power;
+	u8 group;
+	u8 band;
+	s8 offset, limit;
+
+	pwr_idx = &rtwdev->efuse.txpwr_idx_table[rf_path];
+	group = rtw_get_channel_group(channel);
+
+	/* base power index for 2.4G/5G */
+	if (channel <= 14) {
+		band = PHY_BAND_2G;
+		tx_power = phy_get_2g_tx_power_index(rtwdev,
+						     &pwr_idx->pwr_idx_2g,
+						     bandwidth, rate, group);
+		offset = hal->tx_pwr_by_rate_offset_2g[rf_path][rate];
+	} else {
+		band = PHY_BAND_5G;
+		tx_power = phy_get_5g_tx_power_index(rtwdev,
+						     &pwr_idx->pwr_idx_5g,
+						     bandwidth, rate, group);
+		offset = hal->tx_pwr_by_rate_offset_5g[rf_path][rate];
+	}
+
+	limit = phy_get_tx_power_limit(rtwdev, band, bandwidth, rf_path,
+				       rate, channel, regd);
+
+	if (offset > limit)
+		offset = limit;
+
+	tx_power += offset;
+
+	if (tx_power > rtwdev->chip->max_power_index)
+		tx_power = rtwdev->chip->max_power_index;
+
+	return tx_power;
 }
 
-void phy_store_tx_power_by_rate(void *adapter, u32 band, u32 rfpath, u32 txnum,
-				u32 regaddr, u32 bitmask, u32 data)
+static void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs)
 {
 	struct rtw_dev *rtwdev = adapter;
 	struct rtw_hal *hal = &rtwdev->hal;
-	u8 rate_num = 0;
+	u8 regd = rtwdev->regd.txpwr_regd;
+	u8 *rates;
+	u8 size;
 	u8 rate;
-	u8 rates[RTW_RF_PATH_MAX] = {0};
-	s8 offset;
-	s8 pwr_by_rate[RTW_RF_PATH_MAX] = {0};
+	u8 pwr_idx;
+	u8 bw;
 	int i;
 
-	phy_get_rate_values_of_txpwr_by_rate(rtwdev, regaddr, bitmask, data,
-					     rates, pwr_by_rate, &rate_num);
-
-	if (WARN_ON(rfpath >= RTW_RF_PATH_MAX ||
-		    (band != PHY_BAND_2G && band != PHY_BAND_5G) ||
-		    rate_num > RTW_RF_PATH_MAX))
+	if (rs >= RTW_RATE_SECTION_MAX)
 		return;
 
-	for (i = 0; i < rate_num; i++) {
-		offset = pwr_by_rate[i];
+	rates = rtw_rate_section[rs];
+	size = rtw_rate_size[rs];
+	bw = hal->current_band_width;
+	for (i = 0; i < size; i++) {
 		rate = rates[i];
-		if (band == PHY_BAND_2G)
-			hal->tx_pwr_by_rate_offset_2g[rfpath][rate] = offset;
-		else if (band == PHY_BAND_5G)
-			hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset;
-		else
-			continue;
+		pwr_idx = phy_get_tx_power_index(adapter, path, rate, bw, ch,
+						 regd);
+		hal->tx_pwr_tbl[path][rate] = pwr_idx;
 	}
 }
 
+/* set tx power level by path for each rates, note that the order of the rates
+ * are *very* important, bacause 8822B/8821C combines every four bytes of tx
+ * power index into a four-byte power index register, and calls set_tx_agc to
+ * write these values into hardware
+ */
+static
+void phy_set_tx_power_level_by_path(struct rtw_dev *rtwdev, u8 ch, u8 path)
+{
+	struct rtw_hal *hal = &rtwdev->hal;
+	u8 rs;
+
+	/* do not need cck rates if we are not in 2.4G */
+	if (hal->current_band_type == RTW_BAND_2G)
+		rs = RTW_RATE_SECTION_CCK;
+	else
+		rs = RTW_RATE_SECTION_OFDM;
+
+	for (; rs < RTW_RATE_SECTION_MAX; rs++)
+		phy_set_tx_power_index_by_rs(rtwdev, ch, path, rs);
+}
+
+void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+	struct rtw_hal *hal = &rtwdev->hal;
+	u8 path;
+
+	mutex_lock(&hal->tx_power_mutex);
+
+	for (path = 0; path < hal->rf_path_num; path++)
+		phy_set_tx_power_level_by_path(rtwdev, channel, path);
+
+	chip->ops->set_tx_power_index(rtwdev);
+	mutex_unlock(&hal->tx_power_mutex);
+}
+
 static
 void phy_tx_power_by_rate_config_by_path(struct rtw_hal *hal, u8 path,
 					 u8 rs, u8 size, u8 *rates)
@@ -1629,76 +1692,6 @@  void rtw_phy_tx_power_limit_config(struct rtw_hal *hal)
 				phy_tx_power_limit_config(hal, regd, bw, rs);
 }
 
-static s8 get_tx_power_limit(struct rtw_hal *hal, u8 bw, u8 rs, u8 ch, u8 regd)
-{
-	if (regd > RTW_REGD_WW)
-		return RTW_MAX_POWER_INDEX;
-
-	return hal->tx_pwr_limit_2g[regd][bw][rs][ch];
-}
-
-s8 phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band,
-			  enum rtw_bandwidth bw, u8 rf_path,
-			  u8 rate, u8 channel, u8 regd)
-{
-	struct rtw_hal *hal = &rtwdev->hal;
-	s8 power_limit;
-	u8 rs;
-	int ch_idx;
-
-	if (rate >= DESC_RATE1M && rate <= DESC_RATE11M)
-		rs = RTW_RATE_SECTION_CCK;
-	else if (rate >= DESC_RATE6M && rate <= DESC_RATE54M)
-		rs = RTW_RATE_SECTION_OFDM;
-	else if (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS7)
-		rs = RTW_RATE_SECTION_HT_1S;
-	else if (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15)
-		rs = RTW_RATE_SECTION_HT_2S;
-	else if (rate >= DESC_RATEVHT1SS_MCS0 && rate <= DESC_RATEVHT1SS_MCS9)
-		rs = RTW_RATE_SECTION_VHT_1S;
-	else if (rate >= DESC_RATEVHT2SS_MCS0 && rate <= DESC_RATEVHT2SS_MCS9)
-		rs = RTW_RATE_SECTION_VHT_2S;
-	else
-		goto err;
-
-	ch_idx = rtw_channel_to_idx(band, channel);
-	if (ch_idx < 0)
-		goto err;
-
-	power_limit = get_tx_power_limit(hal, bw, rs, ch_idx, regd);
-
-	return power_limit;
-
-err:
-	WARN(1, "invalid arguments, band=%d, bw=%d, path=%d, rate=%d, ch=%d\n",
-	     band, bw, rf_path, rate, channel);
-	return RTW_MAX_POWER_INDEX;
-}
-
-void phy_set_tx_power_limit(struct rtw_dev *rtwdev, u8 regd, u8 band,
-			    u8 bw, u8 rs, u8 ch, s8 pwr_limit)
-{
-	struct rtw_hal *hal = &rtwdev->hal;
-	int ch_idx;
-
-	pwr_limit = clamp_t(s8, pwr_limit,
-			    -RTW_MAX_POWER_INDEX, RTW_MAX_POWER_INDEX);
-	ch_idx = rtw_channel_to_idx(band, ch);
-
-	if (regd >= RTW_REGD_MAX || bw >= RTW_CHANNEL_WIDTH_MAX ||
-	    rs >= RTW_RATE_SECTION_MAX || ch_idx < 0) {
-		WARN(1,
-		     "wrong txpwr_lmt regd=%u, band=%u bw=%u, rs=%u, ch_idx=%u, pwr_limit=%d\n",
-		     regd, band, bw, rs, ch_idx, pwr_limit);
-		return;
-	}
-
-	if (band == PHY_BAND_2G)
-		hal->tx_pwr_limit_2g[regd][bw][rs][ch_idx] = pwr_limit;
-	else if (band == PHY_BAND_5G)
-		hal->tx_pwr_limit_5g[regd][bw][rs][ch_idx] = pwr_limit;
-}
-
 static
 void rtw_hw_tx_power_limit_init(struct rtw_hal *hal, u8 regd, u8 bw, u8 rs)
 {
diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h
index ec03a20..7ad64e7 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.h
+++ b/drivers/net/wireless/realtek/rtw88/phy.h
@@ -7,6 +7,8 @@ 
 
 #include "debug.h"
 
+#define RTW_MAX_POWER_INDEX		0x7F
+
 extern u8 rtw_cck_rates[];
 extern u8 rtw_ofdm_rates[];
 extern u8 rtw_ht_1s_rates[];
@@ -27,11 +29,6 @@  bool rtw_phy_write_rf_reg(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
 			  u32 addr, u32 mask, u32 data);
 bool rtw_phy_write_rf_reg_mix(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
 			      u32 addr, u32 mask, u32 data);
-void phy_store_tx_power_by_rate(void *adapter, u32 band, u32 rfpath, u32 txnum,
-				u32 regaddr, u32 bitmask, u32 data);
-void phy_set_tx_power_limit(struct rtw_dev *rtwdev, u8 regd, u8 band,
-			    u8 bw, u8 rs, u8 ch, s8 pwr_limit);
-void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs);
 void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg);
 void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl);
 void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl);