diff mbox series

[6/7] wifi: rtw88: Extend TX power stuff for 3-4 spatial streams

Message ID b5b39106-406c-40fb-a3db-6f755467d6a7@gmail.com (mailing list archive)
State New
Delegated to: Ping-Ke Shih
Headers show
Series wifi: rtw88: Prepare to support RTL8814AU (part 1/2) | expand

Commit Message

Bitterblue Smith Jan. 26, 2025, 11:01 p.m. UTC
Although the RTL8814AU only has 3 spatial streams, maybe some other chip
has 4.

Correct the TX power index and TX power limit calculations for 3SS and
4SS HT/VHT rates.

With this the RTL8814AU can set the TX power correctly.

Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
---
I just realised this patch depends on another pending patch:
https://lore.kernel.org/linux-wireless/8a60f581-0ab5-4d98-a97d-dd83b605008f@gmail.com/

Originally this patch was going to be in part 2, but then I rearranged
them. Too late to turn back now...
---
 drivers/net/wireless/realtek/rtw88/main.h     |   4 +
 drivers/net/wireless/realtek/rtw88/phy.c      | 149 ++++++++++++------
 drivers/net/wireless/realtek/rtw88/phy.h      |   4 +
 drivers/net/wireless/realtek/rtw88/rtw8821c.c |   2 +-
 drivers/net/wireless/realtek/rtw88/rtw8822b.c |   2 +-
 drivers/net/wireless/realtek/rtw88/rtw8822c.c |   2 +-
 drivers/net/wireless/realtek/rtw88/rtw88xxa.c |   2 +-
 7 files changed, 114 insertions(+), 51 deletions(-)

Comments

Ping-Ke Shih Jan. 27, 2025, 7:06 a.m. UTC | #1
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:

> Although the RTL8814AU only has 3 spatial streams, maybe some other chip
> has 4.
> 
> Correct the TX power index and TX power limit calculations for 3SS and
> 4SS HT/VHT rates.
> 
> With this the RTL8814AU can set the TX power correctly.
> 
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
> ---
> I just realised this patch depends on another pending patch:
> https://lore.kernel.org/linux-wireless/8a60f581-0ab5-4d98-a97d-dd83b605008f@gmail.com/
> 
> Originally this patch was going to be in part 2, but then I rearranged
> them. Too late to turn back now...

Next time, if you want rearrange two or more patchset, just ask me to
drop all patches and re-send with increasing version number. 

> ---
>  drivers/net/wireless/realtek/rtw88/main.h     |   4 +
>  drivers/net/wireless/realtek/rtw88/phy.c      | 149 ++++++++++++------
>  drivers/net/wireless/realtek/rtw88/phy.h      |   4 +
>  drivers/net/wireless/realtek/rtw88/rtw8821c.c |   2 +-
>  drivers/net/wireless/realtek/rtw88/rtw8822b.c |   2 +-
>  drivers/net/wireless/realtek/rtw88/rtw8822c.c |   2 +-
>  drivers/net/wireless/realtek/rtw88/rtw88xxa.c |   2 +-
>  7 files changed, 114 insertions(+), 51 deletions(-)
> 
> diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
> index ba64d269521a..bbae6d7c1aa9 100644
> --- a/drivers/net/wireless/realtek/rtw88/main.h
> +++ b/drivers/net/wireless/realtek/rtw88/main.h
> @@ -166,6 +166,10 @@ enum rtw_rate_section {
>         RTW_RATE_SECTION_HT_2S,
>         RTW_RATE_SECTION_VHT_1S,
>         RTW_RATE_SECTION_VHT_2S,

Suggest to add a 
          __RTW_RATE_SECTION_2SS_MAX = RTW_RATE_SECTION_VHT_2S,
          or
          __RTW_RATE_SECTION_2SS_NUM = RTW_RATE_SECTION_HT_3S,
          (Be careful the place, enumerator will increase automatically)

(The suffix of existing RTW_RATE_SECTION_MAX is wrong -- _NUM instead of _MAX)

> +       RTW_RATE_SECTION_HT_3S,
> +       RTW_RATE_SECTION_HT_4S,
> +       RTW_RATE_SECTION_VHT_3S,
> +       RTW_RATE_SECTION_VHT_4S,
> 
>         /* keep last */
>         RTW_RATE_SECTION_MAX,
> diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
> index 8ed20c89d216..5ddc9d4988b8 100644
> --- a/drivers/net/wireless/realtek/rtw88/phy.c
> +++ b/drivers/net/wireless/realtek/rtw88/phy.c
> @@ -53,21 +53,25 @@ static const u32 db_invert_table[12][8] = {
>  };
> 
>  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,
> @@ -75,6 +79,7 @@ u8 rtw_vht_1s_rates[] = {
>         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,
> @@ -82,10 +87,41 @@ u8 rtw_vht_2s_rates[] = {
>         DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7,
>         DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9
>  };
> +
> +u8 rtw_ht_3s_rates[] = {
> +       DESC_RATEMCS16, DESC_RATEMCS17, DESC_RATEMCS18,
> +       DESC_RATEMCS19, DESC_RATEMCS20, DESC_RATEMCS21,
> +       DESC_RATEMCS22, DESC_RATEMCS23
> +};
> +
> +u8 rtw_ht_4s_rates[] = {
> +       DESC_RATEMCS24, DESC_RATEMCS25, DESC_RATEMCS26,
> +       DESC_RATEMCS27, DESC_RATEMCS28, DESC_RATEMCS29,
> +       DESC_RATEMCS30, DESC_RATEMCS31
> +};
> +
> +u8 rtw_vht_3s_rates[] = {
> +       DESC_RATEVHT3SS_MCS0, DESC_RATEVHT3SS_MCS1,
> +       DESC_RATEVHT3SS_MCS2, DESC_RATEVHT3SS_MCS3,
> +       DESC_RATEVHT3SS_MCS4, DESC_RATEVHT3SS_MCS5,
> +       DESC_RATEVHT3SS_MCS6, DESC_RATEVHT3SS_MCS7,
> +       DESC_RATEVHT3SS_MCS8, DESC_RATEVHT3SS_MCS9
> +};
> +
> +u8 rtw_vht_4s_rates[] = {
> +       DESC_RATEVHT4SS_MCS0, DESC_RATEVHT4SS_MCS1,
> +       DESC_RATEVHT4SS_MCS2, DESC_RATEVHT4SS_MCS3,
> +       DESC_RATEVHT4SS_MCS4, DESC_RATEVHT4SS_MCS5,
> +       DESC_RATEVHT4SS_MCS6, DESC_RATEVHT4SS_MCS7,
> +       DESC_RATEVHT4SS_MCS8, DESC_RATEVHT4SS_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
> +       rtw_vht_1s_rates, rtw_vht_2s_rates,
> +       rtw_ht_3s_rates, rtw_ht_4s_rates,
> +       rtw_vht_3s_rates, rtw_vht_4s_rates
>  };
>  EXPORT_SYMBOL(rtw_rate_section);
> 
> @@ -95,17 +131,14 @@ u8 rtw_rate_size[RTW_RATE_SECTION_MAX] = {
>         ARRAY_SIZE(rtw_ht_1s_rates),
>         ARRAY_SIZE(rtw_ht_2s_rates),
>         ARRAY_SIZE(rtw_vht_1s_rates),
> -       ARRAY_SIZE(rtw_vht_2s_rates)
> +       ARRAY_SIZE(rtw_vht_2s_rates),
> +       ARRAY_SIZE(rtw_ht_3s_rates),
> +       ARRAY_SIZE(rtw_ht_4s_rates),
> +       ARRAY_SIZE(rtw_vht_3s_rates),
> +       ARRAY_SIZE(rtw_vht_4s_rates)
>  };
>  EXPORT_SYMBOL(rtw_rate_size);
> 
> -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,
> @@ -1635,10 +1668,12 @@ static void
>  rtw_xref_txpwr_lmt_by_rs(struct rtw_dev *rtwdev, u8 regd, u8 bw, u8 ch_idx)
>  {
>         u8 rs_idx, rs_ht, rs_vht;
> -       u8 rs_cmp[2][2] = {{RTW_RATE_SECTION_HT_1S, RTW_RATE_SECTION_VHT_1S},
> -                          {RTW_RATE_SECTION_HT_2S, RTW_RATE_SECTION_VHT_2S} };
> +       u8 rs_cmp[4][2] = {{RTW_RATE_SECTION_HT_1S, RTW_RATE_SECTION_VHT_1S},
> +                          {RTW_RATE_SECTION_HT_2S, RTW_RATE_SECTION_VHT_2S},
> +                          {RTW_RATE_SECTION_HT_3S, RTW_RATE_SECTION_VHT_3S},
> +                          {RTW_RATE_SECTION_HT_4S, RTW_RATE_SECTION_VHT_4S} };

Can be 'static const' by the way. 

> 
> -       for (rs_idx = 0; rs_idx < 2; rs_idx++) {
> +       for (rs_idx = 0; rs_idx < 4; rs_idx++) {
>                 rs_ht = rs_cmp[rs_idx][0];
>                 rs_vht = rs_cmp[rs_idx][1];
> 

[...]

> diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
> index cc152248407c..106a9e38e428 100644
> --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
> @@ -709,7 +709,7 @@ static void rtw8821c_set_tx_power_index(struct rtw_dev *rtwdev)
>         int rs, path;
> 
>         for (path = 0; path < hal->rf_path_num; path++) {
> -               for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) {
> +               for (rs = 0; rs < RTW_RATE_SECTION_HT_3S; rs++) {

As mentioned above,
        rs < __RTW_RATE_SECTION_2SS_NUM
        or
        rs <= __RTW_RATE_SECTION_2SS_MAX

>                         if (rs == RTW_RATE_SECTION_HT_2S ||
>                             rs == RTW_RATE_SECTION_VHT_2S)
>                                 continue;
diff mbox series

Patch

diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index ba64d269521a..bbae6d7c1aa9 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -166,6 +166,10 @@  enum rtw_rate_section {
 	RTW_RATE_SECTION_HT_2S,
 	RTW_RATE_SECTION_VHT_1S,
 	RTW_RATE_SECTION_VHT_2S,
+	RTW_RATE_SECTION_HT_3S,
+	RTW_RATE_SECTION_HT_4S,
+	RTW_RATE_SECTION_VHT_3S,
+	RTW_RATE_SECTION_VHT_4S,
 
 	/* keep last */
 	RTW_RATE_SECTION_MAX,
diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index 8ed20c89d216..5ddc9d4988b8 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -53,21 +53,25 @@  static const u32 db_invert_table[12][8] = {
 };
 
 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,
@@ -75,6 +79,7 @@  u8 rtw_vht_1s_rates[] = {
 	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,
@@ -82,10 +87,41 @@  u8 rtw_vht_2s_rates[] = {
 	DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7,
 	DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9
 };
+
+u8 rtw_ht_3s_rates[] = {
+	DESC_RATEMCS16, DESC_RATEMCS17, DESC_RATEMCS18,
+	DESC_RATEMCS19, DESC_RATEMCS20, DESC_RATEMCS21,
+	DESC_RATEMCS22, DESC_RATEMCS23
+};
+
+u8 rtw_ht_4s_rates[] = {
+	DESC_RATEMCS24, DESC_RATEMCS25, DESC_RATEMCS26,
+	DESC_RATEMCS27, DESC_RATEMCS28, DESC_RATEMCS29,
+	DESC_RATEMCS30, DESC_RATEMCS31
+};
+
+u8 rtw_vht_3s_rates[] = {
+	DESC_RATEVHT3SS_MCS0, DESC_RATEVHT3SS_MCS1,
+	DESC_RATEVHT3SS_MCS2, DESC_RATEVHT3SS_MCS3,
+	DESC_RATEVHT3SS_MCS4, DESC_RATEVHT3SS_MCS5,
+	DESC_RATEVHT3SS_MCS6, DESC_RATEVHT3SS_MCS7,
+	DESC_RATEVHT3SS_MCS8, DESC_RATEVHT3SS_MCS9
+};
+
+u8 rtw_vht_4s_rates[] = {
+	DESC_RATEVHT4SS_MCS0, DESC_RATEVHT4SS_MCS1,
+	DESC_RATEVHT4SS_MCS2, DESC_RATEVHT4SS_MCS3,
+	DESC_RATEVHT4SS_MCS4, DESC_RATEVHT4SS_MCS5,
+	DESC_RATEVHT4SS_MCS6, DESC_RATEVHT4SS_MCS7,
+	DESC_RATEVHT4SS_MCS8, DESC_RATEVHT4SS_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
+	rtw_vht_1s_rates, rtw_vht_2s_rates,
+	rtw_ht_3s_rates, rtw_ht_4s_rates,
+	rtw_vht_3s_rates, rtw_vht_4s_rates
 };
 EXPORT_SYMBOL(rtw_rate_section);
 
@@ -95,17 +131,14 @@  u8 rtw_rate_size[RTW_RATE_SECTION_MAX] = {
 	ARRAY_SIZE(rtw_ht_1s_rates),
 	ARRAY_SIZE(rtw_ht_2s_rates),
 	ARRAY_SIZE(rtw_vht_1s_rates),
-	ARRAY_SIZE(rtw_vht_2s_rates)
+	ARRAY_SIZE(rtw_vht_2s_rates),
+	ARRAY_SIZE(rtw_ht_3s_rates),
+	ARRAY_SIZE(rtw_ht_4s_rates),
+	ARRAY_SIZE(rtw_vht_3s_rates),
+	ARRAY_SIZE(rtw_vht_4s_rates)
 };
 EXPORT_SYMBOL(rtw_rate_size);
 
-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,
@@ -1635,10 +1668,12 @@  static void
 rtw_xref_txpwr_lmt_by_rs(struct rtw_dev *rtwdev, u8 regd, u8 bw, u8 ch_idx)
 {
 	u8 rs_idx, rs_ht, rs_vht;
-	u8 rs_cmp[2][2] = {{RTW_RATE_SECTION_HT_1S, RTW_RATE_SECTION_VHT_1S},
-			   {RTW_RATE_SECTION_HT_2S, RTW_RATE_SECTION_VHT_2S} };
+	u8 rs_cmp[4][2] = {{RTW_RATE_SECTION_HT_1S, RTW_RATE_SECTION_VHT_1S},
+			   {RTW_RATE_SECTION_HT_2S, RTW_RATE_SECTION_VHT_2S},
+			   {RTW_RATE_SECTION_HT_3S, RTW_RATE_SECTION_VHT_3S},
+			   {RTW_RATE_SECTION_HT_4S, RTW_RATE_SECTION_VHT_4S} };
 
-	for (rs_idx = 0; rs_idx < 2; rs_idx++) {
+	for (rs_idx = 0; rs_idx < 4; rs_idx++) {
 		rs_ht = rs_cmp[rs_idx][0];
 		rs_vht = rs_cmp[rs_idx][1];
 
@@ -1959,10 +1994,10 @@  static u8 rtw_phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
 					u8 rate, u8 group)
 {
 	const struct rtw_chip_info *chip = rtwdev->chip;
-	u8 tx_power;
-	bool mcs_rate;
-	bool above_2ss;
+	bool above_2ss, above_3ss, above_4ss;
 	u8 factor = chip->txgi_factor;
+	bool mcs_rate;
+	u8 tx_power;
 
 	if (rate <= DESC_RATE11M)
 		tx_power = pwr_idx_2g->cck_base[group];
@@ -1972,11 +2007,15 @@  static u8 rtw_phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
 	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) ||
+	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS31) ||
 		   (rate >= DESC_RATEVHT1SS_MCS0 &&
-		    rate <= DESC_RATEVHT2SS_MCS9);
-	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
+		    rate <= DESC_RATEVHT4SS_MCS9);
+	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS31) ||
 		    (rate >= DESC_RATEVHT2SS_MCS0);
+	above_3ss = (rate >= DESC_RATEMCS16 && rate <= DESC_RATEMCS31) ||
+		    (rate >= DESC_RATEVHT3SS_MCS0);
+	above_4ss = (rate >= DESC_RATEMCS24 && rate <= DESC_RATEMCS31) ||
+		    (rate >= DESC_RATEVHT4SS_MCS0);
 
 	if (!mcs_rate)
 		return tx_power;
@@ -1989,11 +2028,19 @@  static u8 rtw_phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
 		tx_power += pwr_idx_2g->ht_1s_diff.bw20 * factor;
 		if (above_2ss)
 			tx_power += pwr_idx_2g->ht_2s_diff.bw20 * factor;
+		if (above_3ss)
+			tx_power += pwr_idx_2g->ht_3s_diff.bw20 * factor;
+		if (above_4ss)
+			tx_power += pwr_idx_2g->ht_4s_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;
+		if (above_3ss)
+			tx_power += pwr_idx_2g->ht_3s_diff.bw40 * factor;
+		if (above_4ss)
+			tx_power += pwr_idx_2g->ht_4s_diff.bw40 * factor;
 		break;
 	}
 
@@ -2006,19 +2053,23 @@  static u8 rtw_phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
 					u8 rate, u8 group)
 {
 	const struct rtw_chip_info *chip = rtwdev->chip;
-	u8 tx_power;
+	bool above_2ss, above_3ss, above_4ss;
+	u8 factor = chip->txgi_factor;
 	u8 upper, lower;
 	bool mcs_rate;
-	bool above_2ss;
-	u8 factor = chip->txgi_factor;
+	u8 tx_power;
 
 	tx_power = pwr_idx_5g->bw40_base[group];
 
-	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) ||
+	mcs_rate = (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS31) ||
 		   (rate >= DESC_RATEVHT1SS_MCS0 &&
-		    rate <= DESC_RATEVHT2SS_MCS9);
-	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
+		    rate <= DESC_RATEVHT4SS_MCS9);
+	above_2ss = (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS31) ||
 		    (rate >= DESC_RATEVHT2SS_MCS0);
+	above_3ss = (rate >= DESC_RATEMCS16 && rate <= DESC_RATEMCS31) ||
+		    (rate >= DESC_RATEVHT3SS_MCS0);
+	above_4ss = (rate >= DESC_RATEMCS24 && rate <= DESC_RATEMCS31) ||
+		    (rate >= DESC_RATEVHT4SS_MCS0);
 
 	if (!mcs_rate) {
 		tx_power += pwr_idx_5g->ht_1s_diff.ofdm * factor;
@@ -2033,11 +2084,19 @@  static u8 rtw_phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
 		tx_power += pwr_idx_5g->ht_1s_diff.bw20 * factor;
 		if (above_2ss)
 			tx_power += pwr_idx_5g->ht_2s_diff.bw20 * factor;
+		if (above_3ss)
+			tx_power += pwr_idx_5g->ht_3s_diff.bw20 * factor;
+		if (above_4ss)
+			tx_power += pwr_idx_5g->ht_4s_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;
+		if (above_3ss)
+			tx_power += pwr_idx_5g->ht_3s_diff.bw40 * factor;
+		if (above_4ss)
+			tx_power += pwr_idx_5g->ht_4s_diff.bw40 * factor;
 		break;
 	case RTW_CHANNEL_WIDTH_80:
 		/* the base idx of bw80 is the average of bw40+/bw40- */
@@ -2048,6 +2107,10 @@  static u8 rtw_phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
 		tx_power += pwr_idx_5g->vht_1s_diff.bw80 * factor;
 		if (above_2ss)
 			tx_power += pwr_idx_5g->vht_2s_diff.bw80 * factor;
+		if (above_3ss)
+			tx_power += pwr_idx_5g->vht_3s_diff.bw80 * factor;
+		if (above_4ss)
+			tx_power += pwr_idx_5g->vht_4s_diff.bw80 * factor;
 		break;
 	}
 
@@ -2065,10 +2128,18 @@  static u8 rtw_phy_rate_to_rate_section(u8 rate)
 		return RTW_RATE_SECTION_HT_1S;
 	else if (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15)
 		return RTW_RATE_SECTION_HT_2S;
+	else if (rate >= DESC_RATEMCS16 && rate <= DESC_RATEMCS23)
+		return RTW_RATE_SECTION_HT_3S;
+	else if (rate >= DESC_RATEMCS24 && rate <= DESC_RATEMCS31)
+		return RTW_RATE_SECTION_HT_4S;
 	else if (rate >= DESC_RATEVHT1SS_MCS0 && rate <= DESC_RATEVHT1SS_MCS9)
 		return RTW_RATE_SECTION_VHT_1S;
 	else if (rate >= DESC_RATEVHT2SS_MCS0 && rate <= DESC_RATEVHT2SS_MCS9)
 		return RTW_RATE_SECTION_VHT_2S;
+	else if (rate >= DESC_RATEVHT3SS_MCS0 && rate <= DESC_RATEVHT3SS_MCS9)
+		return RTW_RATE_SECTION_VHT_3S;
+	else if (rate >= DESC_RATEVHT4SS_MCS0 && rate <= DESC_RATEVHT4SS_MCS9)
+		return RTW_RATE_SECTION_VHT_4S;
 	else
 		return RTW_RATE_SECTION_MAX;
 }
@@ -2096,7 +2167,7 @@  static s8 rtw_phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band,
 		bw = RTW_CHANNEL_WIDTH_20;
 
 	/* only 20/40M BW with ht */
-	if (rs == RTW_RATE_SECTION_HT_1S || rs == RTW_RATE_SECTION_HT_2S)
+	if (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS31)
 		bw = min_t(u8, bw, RTW_CHANNEL_WIDTH_40);
 
 	/* select min power limit among [20M BW ~ current BW] */
@@ -2280,7 +2351,7 @@  rtw_phy_tx_power_by_rate_config_by_path(struct rtw_hal *hal, u8 path,
 	u8 base_idx, rate_idx;
 	s8 base_2g, base_5g;
 
-	if (rs >= RTW_RATE_SECTION_VHT_1S)
+	if (size == 10) /* VHT rates */
 		base_idx = rates[size - 3];
 	else
 		base_idx = rates[size - 1];
@@ -2297,28 +2368,12 @@  rtw_phy_tx_power_by_rate_config_by_path(struct rtw_hal *hal, u8 path,
 
 void rtw_phy_tx_power_by_rate_config(struct rtw_hal *hal)
 {
-	u8 path;
+	u8 path, rs;
 
-	for (path = 0; path < RTW_RF_PATH_MAX; path++) {
-		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
-				RTW_RATE_SECTION_CCK,
-				rtw_cck_size, rtw_cck_rates);
-		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
-				RTW_RATE_SECTION_OFDM,
-				rtw_ofdm_size, rtw_ofdm_rates);
-		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
-				RTW_RATE_SECTION_HT_1S,
-				rtw_ht_1s_size, rtw_ht_1s_rates);
-		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
-				RTW_RATE_SECTION_HT_2S,
-				rtw_ht_2s_size, rtw_ht_2s_rates);
-		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
-				RTW_RATE_SECTION_VHT_1S,
-				rtw_vht_1s_size, rtw_vht_1s_rates);
-		rtw_phy_tx_power_by_rate_config_by_path(hal, path,
-				RTW_RATE_SECTION_VHT_2S,
-				rtw_vht_2s_size, rtw_vht_2s_rates);
-	}
+	for (path = 0; path < RTW_RF_PATH_MAX; path++)
+		for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++)
+			rtw_phy_tx_power_by_rate_config_by_path(hal, path, rs,
+				rtw_rate_size[rs], rtw_rate_section[rs]);
 }
 
 static void
diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h
index ccfcbd3ced03..707576d04262 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.h
+++ b/drivers/net/wireless/realtek/rtw88/phy.h
@@ -13,6 +13,10 @@  extern u8 rtw_ht_1s_rates[];
 extern u8 rtw_ht_2s_rates[];
 extern u8 rtw_vht_1s_rates[];
 extern u8 rtw_vht_2s_rates[];
+extern u8 rtw_ht_3s_rates[];
+extern u8 rtw_ht_4s_rates[];
+extern u8 rtw_vht_3s_rates[];
+extern u8 rtw_vht_4s_rates[];
 extern u8 *rtw_rate_section[];
 extern u8 rtw_rate_size[];
 
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
index cc152248407c..106a9e38e428 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
@@ -709,7 +709,7 @@  static void rtw8821c_set_tx_power_index(struct rtw_dev *rtwdev)
 	int rs, path;
 
 	for (path = 0; path < hal->rf_path_num; path++) {
-		for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) {
+		for (rs = 0; rs < RTW_RATE_SECTION_HT_3S; rs++) {
 			if (rs == RTW_RATE_SECTION_HT_2S ||
 			    rs == RTW_RATE_SECTION_VHT_2S)
 				continue;
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
index 23a29019752d..5472fbf2b498 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
@@ -964,7 +964,7 @@  static void rtw8822b_set_tx_power_index(struct rtw_dev *rtwdev)
 	int rs, path;
 
 	for (path = 0; path < hal->rf_path_num; path++) {
-		for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++)
+		for (rs = 0; rs < RTW_RATE_SECTION_HT_3S; rs++)
 			rtw8822b_set_tx_power_index_by_rate(rtwdev, path, rs,
 							    &phy_pwr_idx);
 	}
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index ec362a817f5f..aea9a20eab59 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -2746,7 +2746,7 @@  static void rtw8822c_set_tx_power_index(struct rtw_dev *rtwdev)
 	s8 diff_idx[4];
 
 	rtw8822c_set_write_tx_power_ref(rtwdev, pwr_ref_cck, pwr_ref_ofdm);
-	for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) {
+	for (rs = 0; rs < RTW_RATE_SECTION_HT_3S; rs++) {
 		for (j = 0; j < rtw_rate_size[rs]; j++) {
 			rate = rtw_rate_section[rs][j];
 			pwr_a = hal->tx_pwr_tbl[RF_PATH_A][rate];
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
index 71e61b9c0bec..08bbd84733d1 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
@@ -1637,7 +1637,7 @@  void rtw88xxa_set_tx_power_index(struct rtw_dev *rtwdev)
 	int rs, path;
 
 	for (path = 0; path < hal->rf_path_num; path++) {
-		for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) {
+		for (rs = 0; rs < RTW_RATE_SECTION_HT_3S; rs++) {
 			if (hal->rf_path_num == 1 &&
 			    (rs == RTW_RATE_SECTION_HT_2S ||
 			     rs == RTW_RATE_SECTION_VHT_2S))