wifi: rtw89: add thermal protect by digital voltage reduction

The temperature is rising when WiFi does high throughput, and reduce
voltage is a way to ease temperature.

The existing method to do thermal protect is to reduce TX duty, which
can affect throughput obviously. Before doing reduce TX duty (with -20
thermal value offset), driver does voltage reduction first, which doesn't
affect throughput but lower power consumption.

The voltage gram of register is 0.01 voltage, and the suggested maximum
reduction is 6 grams, which driver defines 6 as maximum voltage level.
When thermal value is over threshold, driver will try to adjust level and
corresponding register value. It should be adjust grams one by one with
additional 50 ms delay to ensure hardware work properly.

A note that the voltage must reset to normal value before entering power
save mode, otherwise WiFi card might get lost. Since it takes 50 ms delay
for each gram to adjust voltage, we stop to enter power save if protect
level is not zero.

By the way, adjust thermal threshold to 0xB4 as desired.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20260707091056.42771-10-pkshih@realtek.com
This commit is contained in:
Ping-Ke Shih
2026-07-07 17:10:50 +08:00
parent 4e199cd666
commit 47ad03f1ec
8 changed files with 107 additions and 1 deletions

View File

@@ -5236,9 +5236,18 @@ static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev)
static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev,
enum rtw89_tfc_interval interval)
{
struct rtw89_hal *hal = &rtwdev->hal;
struct ieee80211_vif *vif;
struct rtw89_vif *rtwvif;
/*
* If vcore level is set, temperature is high and voltage is low. As
* entering power save must reset voltage to default, avoid power save
* until vcore decreases to zero resulting from temperature becomes low.
*/
if (hal->thermal_prot_vlv)
return;
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
if (rtwvif->tdls_peer)
continue;

View File

@@ -5523,10 +5523,13 @@ enum rtw89_dm_type {
RTW89_DM_HW_SCAN,
RTW89_DM_INACTIVE_PS,
RTW89_DM_DIG_PD,
RTW89_DM_VCORE,
};
#define RTW89_THERMAL_PROT_LV_MAX 5
#define RTW89_THERMAL_PROT_STEP 5 /* -5% for each level */
#define RTW89_THERMAL_PROT_VLV_MAX 6
#define RTW89_THERMAL_PROT_VLV_TH_OFFSET 20
struct rtw89_hal {
u32 rx_fltr;
@@ -5567,6 +5570,7 @@ struct rtw89_hal {
u8 thermal_prot_vmax;
u8 thermal_prot_vmin;
u8 thermal_prot_vlv; /* 0 ~ RTW89_THERMAL_PROT_VLV_MAX (6) */
u8 fixed_dig_pd_th; /* v = (X(dBm) + 102)/2 */
s8 fixed_dig_cck_pd_th; /* dBm */

View File

@@ -4778,6 +4778,7 @@ static const struct rtw89_disabled_dm_info {
DM_INFO(HW_SCAN),
DM_INFO(INACTIVE_PS),
DM_INFO(DIG_PD),
DM_INFO(VCORE),
};
static ssize_t

View File

@@ -1602,6 +1602,8 @@ int rtw89_mac_pwr_on(struct rtw89_dev *rtwdev)
void rtw89_mac_pwr_off(struct rtw89_dev *rtwdev)
{
rtw89_mac_set_vcore_reset(rtwdev);
rtw89_mac_power_switch(rtwdev, false);
}
@@ -7477,6 +7479,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
.cfg_ppdu_status = rtw89_mac_cfg_ppdu_status_ax,
.cfg_phy_rpt = NULL,
.set_edcca_mode = NULL,
.set_vcore_cfg = NULL,
.dle_mix_cfg = dle_mix_cfg_ax,
.chk_dle_rdy = chk_dle_rdy_ax,

View File

@@ -1100,6 +1100,7 @@ struct rtw89_mac_gen_def {
int (*cfg_ppdu_status)(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable);
void (*cfg_phy_rpt)(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable);
void (*set_edcca_mode)(struct rtw89_dev *rtwdev, u8 mac_idx, bool normal);
void (*set_vcore_cfg)(struct rtw89_dev *rtwdev, u8 vlv);
int (*dle_mix_cfg)(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg);
int (*chk_dle_rdy)(struct rtw89_dev *rtwdev, bool wde_or_ple);
@@ -1459,6 +1460,29 @@ void rtw89_mac_set_edcca_mode(struct rtw89_dev *rtwdev, u8 mac_idx, bool normal)
mac->set_edcca_mode(rtwdev, mac_idx, normal);
}
static inline
void rtw89_mac_set_vcore_cfg(struct rtw89_dev *rtwdev, u8 vlv)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
if (!mac->set_vcore_cfg)
return;
mac->set_vcore_cfg(rtwdev, vlv);
}
static inline
void rtw89_mac_set_vcore_reset(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
if (hal->thermal_prot_vlv == 0)
return;
hal->thermal_prot_vlv = 0;
rtw89_mac_set_vcore_cfg(rtwdev, 0);
}
static inline
void rtw89_mac_set_edcca_mode_bands(struct rtw89_dev *rtwdev, bool normal)
{

View File

@@ -2676,6 +2676,43 @@ void rtw89_mac_set_edcca_mode_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool norm
}
}
static
void rtw89_mac_set_vcore_cfg_be(struct rtw89_dev *rtwdev, u8 vlv)
{
struct rtw89_hal *hal = &rtwdev->hal;
u32 val32;
u8 target;
u8 vpwm;
int i;
if (rtwdev->chip->chip_id != RTL8922D)
return;
target = clamp(hal->thermal_prot_vmax - vlv,
hal->thermal_prot_vmin, hal->thermal_prot_vmax);
val32 = rtw89_read32(rtwdev, R_BE_SPS_DIG_ON_CTRL0);
vpwm = u32_get_bits(val32, B_BE_PWMTUNE_MASK);
val32 &= ~B_BE_PWMTUNE_MASK;
if (vpwm == target)
return;
for (i = 0; i < RTW89_THERMAL_PROT_VLV_MAX; i++) {
if (vpwm > target)
vpwm--;
else
vpwm++;
rtw89_write32(rtwdev, R_BE_SPS_DIG_ON_CTRL0, val32 | vpwm);
if (vpwm == target)
break;
mdelay(50);
}
}
static
int rtw89_mac_cfg_ppdu_status_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable)
{
@@ -3287,6 +3324,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = {
.cfg_ppdu_status = rtw89_mac_cfg_ppdu_status_be,
.cfg_phy_rpt = rtw89_mac_cfg_phy_rpt_be,
.set_edcca_mode = rtw89_mac_set_edcca_mode_be,
.set_vcore_cfg = rtw89_mac_set_vcore_cfg_be,
.dle_mix_cfg = dle_mix_cfg_be,
.chk_dle_rdy = chk_dle_rdy_be,

View File

@@ -5718,6 +5718,32 @@ static void rtw89_phy_antdiv_init(struct rtw89_dev *rtwdev)
rtw89_phy_antdiv_reg_init(rtwdev);
}
static void rtw89_phy_thermal_protect_vcore(struct rtw89_dev *rtwdev)
{
struct rtw89_phy_stat *phystat = &rtwdev->phystat;
struct rtw89_hal *hal = &rtwdev->hal;
bool vcore_enabled = !!hal->thermal_prot_vmax;
u8 th_max = phystat->last_thermal_max;
u8 vlv = hal->thermal_prot_vlv;
u8 prot_th;
if (!vcore_enabled || (hal->disabled_dm_bitmap & BIT(RTW89_DM_VCORE)))
return;
prot_th = hal->thermal_prot_th - RTW89_THERMAL_PROT_VLV_TH_OFFSET;
if (th_max > prot_th && vlv < RTW89_THERMAL_PROT_VLV_MAX)
vlv++;
else if (th_max < prot_th - 2 && vlv > 0)
vlv--;
else
return;
rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "thermal protection vlv=%d\n", vlv);
hal->thermal_prot_vlv = vlv;
rtw89_mac_set_vcore_cfg(rtwdev, vlv);
}
static void rtw89_phy_thermal_protect(struct rtw89_dev *rtwdev)
{
struct rtw89_phy_stat *phystat = &rtwdev->phystat;
@@ -6186,6 +6212,7 @@ void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
struct rtw89_bb_ctx *bb;
rtw89_phy_stat_thermal_update(rtwdev);
rtw89_phy_thermal_protect_vcore(rtwdev);
rtw89_phy_thermal_protect(rtwdev);
rtw89_phy_stat_rssi_update(rtwdev);
rtw89_phy_stat_update(rtwdev);

View File

@@ -3451,7 +3451,7 @@ const struct rtw89_chip_info rtw8922d_chip_info = {
.wde_qempty_acq_grpnum = 8,
.wde_qempty_mgq_grpsel = 8,
.rf_base_addr = {0x3e000, 0x3f000},
.thermal_th = {0xac, 0xad},
.thermal_th = {0xac, 0xb4},
.pwr_on_seq = NULL,
.pwr_off_seq = NULL,
.bb_table = NULL,