public inbox for linux-wireless@vger.kernel.org
 help / color / mirror / Atom feed
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


  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