From: Ping-Ke Shih <pkshih@realtek.com>
To: <linux-wireless@vger.kernel.org>
Subject: [PATCH rtw-next 4/7] wifi: rtw89: 8922d: read and configure RF by calibration data from efuse physical map
Date: Mon, 23 Mar 2026 11:25:53 +0800 [thread overview]
Message-ID: <20260323032556.19825-5-pkshih@realtek.com> (raw)
In-Reply-To: <20260323032556.19825-1-pkshih@realtek.com>
The calibration data is from physical map, including 1) thermal trim to
align output thermal value across chips, and 2) PA bias to transmit
expected power by controller.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/core.h | 2 +
drivers/net/wireless/realtek/rtw89/reg.h | 2 +
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 205 ++++++++++++++++++
3 files changed, 209 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index d0ae3e15253b..cde46ed21d32 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -5595,9 +5595,11 @@ struct rtw89_tssi_info {
struct rtw89_power_trim_info {
bool pg_thermal_trim;
bool pg_pa_bias_trim;
+ bool pg_vco_trim;
u8 thermal_trim[RF_PATH_MAX];
u8 pa_bias_trim[RF_PATH_MAX];
u8 pad_bias_trim[RF_PATH_MAX];
+ u8 vco_trim[RF_PATH_MAX];
};
enum rtw89_regd_func {
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index b6fd7b434de9..179006c8e499 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -8517,6 +8517,7 @@
#define RR_LUTWD0_LB GENMASK(5, 0)
#define RR_TM 0x42
#define RR_TM_TRI BIT(19)
+#define RR_TM_TRM GENMASK(17, 11)
#define RR_TM_VAL_V1 GENMASK(7, 0)
#define RR_TM_VAL GENMASK(6, 1)
#define RR_TM2 0x43
@@ -8649,6 +8650,7 @@
#define RR_LDO 0xb1
#define RR_LDO_SEL GENMASK(8, 6)
#define RR_VCO 0xb2
+#define RR_VCO_VAL GENMASK(18, 14)
#define RR_VCO_SEL GENMASK(9, 8)
#define RR_VCI 0xb3
#define RR_VCI_ON BIT(7)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 0ae34a4f8d79..cbe8e067ae55 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -630,6 +630,211 @@ static int rtw8922d_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map,
}
}
+static void rtw8922d_phycap_parsing_vco_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 vco_trim_addr[RF_PATH_NUM_8922D] = {0x175E, 0x175F};
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ const u32 vco_check_addr = 0x1700;
+ u8 val;
+
+ val = phycap_map[vco_check_addr - addr];
+ if (val & BIT(1))
+ return;
+
+ info->pg_vco_trim = true;
+
+ info->vco_trim[0] = u8_get_bits(phycap_map[vco_trim_addr[0] - addr], GENMASK(4, 0));
+ info->vco_trim[1] = u8_get_bits(phycap_map[vco_trim_addr[1] - addr], GENMASK(4, 0));
+}
+
+static void rtw8922d_vco_trim(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+
+ if (!info->pg_vco_trim)
+ return;
+
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_VCO, RR_VCO_VAL, info->vco_trim[0]);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_VCO, RR_VCO_VAL, info->vco_trim[1]);
+}
+
+#define THM_TRIM_POSITIVE_MASK BIT(6)
+#define THM_TRIM_MAGNITUDE_MASK GENMASK(5, 0)
+#define THM_TRIM_MAX (15)
+#define THM_TRIM_MIN (-15)
+
+static void rtw8922d_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 thm_trim_addr[RF_PATH_NUM_8922D] = {0x1706, 0x1732};
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ bool pg = true;
+ u8 pg_th;
+ s8 val;
+ u8 i;
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ pg_th = phycap_map[thm_trim_addr[i] - addr];
+ if (pg_th == 0xff) {
+ memset(info->thermal_trim, 0, sizeof(info->thermal_trim));
+ pg = false;
+ goto out;
+ }
+
+ val = u8_get_bits(pg_th, THM_TRIM_MAGNITUDE_MASK);
+
+ if (!(pg_th & THM_TRIM_POSITIVE_MASK))
+ val *= -1;
+
+ if (val <= THM_TRIM_MIN || val >= THM_TRIM_MAX) {
+ val = 0;
+ info->thermal_trim[i] = 0;
+ } else {
+ info->thermal_trim[i] = pg_th;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[THERMAL][TRIM] path=%d thermal_trim=0x%x (%d)\n",
+ i, pg_th, val);
+ }
+
+out:
+ info->pg_thermal_trim = pg;
+}
+
+static void rtw8922d_thermal_trim(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u8 thermal;
+ int i;
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ thermal = info->pg_thermal_trim ? info->thermal_trim[i] : 0;
+ rtw89_write_rf(rtwdev, i, RR_TM, RR_TM_TRM, thermal & 0x7f);
+ }
+}
+
+static void rtw8922d_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 pabias_trim_addr[RF_PATH_NUM_8922D] = {0x1707, 0x1733};
+ static const u32 check_pa_pad_trim_addr = 0x1700;
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ bool pg = true;
+ u8 val;
+ u8 i;
+
+ val = phycap_map[check_pa_pad_trim_addr - addr];
+ if (val == 0xff) {
+ pg = false;
+ goto out;
+ }
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr];
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n",
+ i, info->pa_bias_trim[i]);
+ }
+
+out:
+ info->pg_pa_bias_trim = pg;
+}
+
+static void rtw8922d_pa_bias_trim(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u8 pabias_2g, pabias_5g;
+ u8 i;
+
+ if (!info->pg_pa_bias_trim) {
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PA_BIAS][TRIM] no PG, do nothing\n");
+
+ return;
+ }
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ pabias_2g = FIELD_GET(GENMASK(3, 0), info->pa_bias_trim[i]);
+ pabias_5g = FIELD_GET(GENMASK(7, 4), info->pa_bias_trim[i]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PA_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n",
+ i, pabias_2g, pabias_5g);
+
+ rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXG_V1, pabias_2g);
+ rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXA_V1, pabias_5g);
+ }
+}
+
+static void rtw8922d_phycap_parsing_pad_bias_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 pad_bias_trim_addr[RF_PATH_NUM_8922D] = {0x1708, 0x1734};
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ u8 i;
+
+ if (!info->pg_pa_bias_trim)
+ return;
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ info->pad_bias_trim[i] = phycap_map[pad_bias_trim_addr[i] - addr];
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PAD_BIAS][TRIM] path=%d pad_bias_trim=0x%x\n",
+ i, info->pad_bias_trim[i]);
+ }
+}
+
+static void rtw8922d_pad_bias_trim(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u8 pad_bias_2g, pad_bias_5g;
+ u8 i;
+
+ if (!info->pg_pa_bias_trim) {
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PAD_BIAS][TRIM] no PG, do nothing\n");
+ return;
+ }
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ pad_bias_2g = u8_get_bits(info->pad_bias_trim[i], GENMASK(3, 0));
+ pad_bias_5g = u8_get_bits(info->pad_bias_trim[i], GENMASK(7, 4));
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PAD_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n",
+ i, pad_bias_2g, pad_bias_5g);
+
+ rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASD_TXG_V1, pad_bias_2g);
+ rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASD_TXA_V1, pad_bias_5g);
+ }
+}
+
+static int rtw8922d_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map)
+{
+ rtw8922d_phycap_parsing_vco_trim(rtwdev, phycap_map);
+ rtw8922d_phycap_parsing_thermal_trim(rtwdev, phycap_map);
+ rtw8922d_phycap_parsing_pa_bias_trim(rtwdev, phycap_map);
+ rtw8922d_phycap_parsing_pad_bias_trim(rtwdev, phycap_map);
+
+ return 0;
+}
+
+static void rtw8922d_power_trim(struct rtw89_dev *rtwdev)
+{
+ rtw8922d_vco_trim(rtwdev);
+ rtw8922d_thermal_trim(rtwdev);
+ rtw8922d_pa_bias_trim(rtwdev);
+ rtw8922d_pad_bias_trim(rtwdev);
+}
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
--
2.25.1
next prev parent reply other threads:[~2026-03-23 3:26 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-23 3:25 [PATCH rtw-next 0/7] wifi: rtw89: 8922d: add RTL8922D common routine part 1 Ping-Ke Shih
2026-03-23 3:25 ` [PATCH rtw-next 1/7] wifi: rtw89: 8922d: add definition of quota, registers and efuse block Ping-Ke Shih
2026-03-23 3:25 ` [PATCH rtw-next 2/7] wifi: rtw89: 8922d: add power on/off functions Ping-Ke Shih
2026-03-23 3:25 ` [PATCH rtw-next 3/7] wifi: rtw89: 8922d: define efuse map and read necessary fields Ping-Ke Shih
2026-03-23 3:25 ` Ping-Ke Shih [this message]
2026-03-23 3:25 ` [PATCH rtw-next 5/7] wifi: rtw89: 8922d: add set channel of MAC part Ping-Ke Shih
2026-03-23 3:25 ` [PATCH rtw-next 6/7] wifi: rtw89: 8922d: add set channel of BB part Ping-Ke Shih
2026-03-23 10:53 ` Bitterblue Smith
2026-03-24 0:49 ` Ping-Ke Shih
2026-03-23 3:25 ` [PATCH rtw-next 7/7] wifi: rtw89: 8922d: add set channel of RF part Ping-Ke Shih
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260323032556.19825-5-pkshih@realtek.com \
--to=pkshih@realtek.com \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox