]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: rtw89: 8922d: read and configure RF by calibration data from efuse physical map
authorPing-Ke Shih <pkshih@realtek.com>
Tue, 24 Mar 2026 06:20:46 +0000 (14:20 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Mon, 30 Mar 2026 02:07:05 +0000 (10:07 +0800)
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>
Link: https://patch.msgid.link/20260324062049.52266-5-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/reg.h
drivers/net/wireless/realtek/rtw89/rtw8922d.c

index d0ae3e15253b425469a6ad90cc1c0cf4141dbfd2..cde46ed21d328b55f0f50283867dc973482d466e 100644 (file)
@@ -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 {
index b6fd7b434de97b96fafb958a51b41fc787ea28a6..179006c8e4996986049276cd85da46a1f1ffd7f8 100644 (file)
 #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
 #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)
index 0ae34a4f8d79bd6b66b5b5013ad4376623d4543f..cbe8e067ae55d98472f69e2261568412b17da7dd 100644 (file)
@@ -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");