]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: rtw89: phy: initialize AFE by firmware element table
authorPing-Ke Shih <pkshih@realtek.com>
Mon, 15 Sep 2025 06:53:14 +0000 (14:53 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Thu, 18 Sep 2025 01:13:57 +0000 (09:13 +0800)
A power-on sequence table is introduced to initialize AFE (Analogue Front
End) connecting to RF components. Build the sequence in firmware file,
and use a parser to execute the sequences including write/poll/delay
actions.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250915065314.38846-1-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/fw.h
drivers/net/wireless/realtek/rtw89/phy.c
drivers/net/wireless/realtek/rtw89/phy.h

index b116f8d718ac8715c2b7de78b190eefee4e79e24..e445fcd0218711c974f00726b78ebd61ace45106 100644 (file)
@@ -5417,6 +5417,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
 {
        int ret;
 
+       rtw89_phy_init_bb_afe(rtwdev);
+
        ret = rtw89_mac_init(rtwdev);
        if (ret) {
                rtw89_err(rtwdev, "mac init fail, ret:%d\n", ret);
index 2841ea84bbc0af2d2a0ca8d8c507a31c14b994e2..708132363da39a02bba1f25a1d95204325fb4486 100644 (file)
@@ -4690,6 +4690,7 @@ struct rtw89_fw_elm_info {
        struct rtw89_fw_txpwr_track_cfg *txpwr_trk;
        struct rtw89_phy_rfk_log_fmt *rfk_log_fmt;
        const struct rtw89_regd_data *regd;
+       const struct rtw89_fw_element_hdr *afe;
 };
 
 enum rtw89_fw_mss_dev_type {
index 5f330b625659e60b55d134ba2271346e00ff1b36..0ef3ee44e2f06ea6f61b775569846cc8ff52ecdf 100644 (file)
@@ -1285,6 +1285,18 @@ int rtw89_recognize_regd_from_elm(struct rtw89_dev *rtwdev,
        return 0;
 }
 
+static
+int rtw89_build_afe_pwr_seq_from_elm(struct rtw89_dev *rtwdev,
+                                    const struct rtw89_fw_element_hdr *elm,
+                                    const union rtw89_fw_element_arg arg)
+{
+       struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+
+       elm_info->afe = elm;
+
+       return 0;
+}
+
 static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
        [RTW89_FW_ELEMENT_ID_BBMCU0] = {__rtw89_fw_recognize_from_elm,
                                        { .fw_type = RTW89_FW_BBMCU0 }, NULL},
@@ -1370,6 +1382,9 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
        [RTW89_FW_ELEMENT_ID_REGD] = {
                rtw89_recognize_regd_from_elm, {}, "REGD",
        },
+       [RTW89_FW_ELEMENT_ID_AFE_PWR_SEQ] = {
+               rtw89_build_afe_pwr_seq_from_elm, {}, "AFE",
+       },
 };
 
 int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
index fad9d87d3e561cf9f3547b3b8fe378ee8174c087..98b187305481b35bf8c928c451d757f202a4a8b9 100644 (file)
@@ -3984,6 +3984,7 @@ enum rtw89_fw_element_id {
        RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_2GHZ = 24,
        RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_5GHZ = 25,
        RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_6GHZ = 26,
+       RTW89_FW_ELEMENT_ID_AFE_PWR_SEQ = 27,
 
        RTW89_FW_ELEMENT_ID_NUM,
 };
@@ -4089,6 +4090,30 @@ struct rtw89_fw_txpwr_track_cfg {
         BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_N) | \
         BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_P))
 
+enum rtw89_fw_afe_action {
+       RTW89_FW_AFE_ACTION_WRITE = 0,
+       RTW89_FW_AFE_ACTION_DELAY = 1,
+       RTW89_FW_AFE_ACTION_POLL = 2,
+};
+
+enum rtw89_fw_afe_cat {
+       RTW89_FW_AFE_CAT_BB = 0,
+       RTW89_FW_AFE_CAT_BB1 = 1,
+       RTW89_FW_AFE_CAT_MAC = 2,
+       RTW89_FW_AFE_CAT_MAC1 = 3,
+       RTW89_FW_AFE_CAT_AFEDIG = 4,
+       RTW89_FW_AFE_CAT_AFEDIG1 = 5,
+};
+
+enum rtw89_fw_afe_class {
+       RTW89_FW_AFE_CLASS_P0 = 0,
+       RTW89_FW_AFE_CLASS_P1 = 1,
+       RTW89_FW_AFE_CLASS_P2 = 2,
+       RTW89_FW_AFE_CLASS_P3 = 3,
+       RTW89_FW_AFE_CLASS_P4 = 4,
+       RTW89_FW_AFE_CLASS_CMN = 5,
+};
+
 struct rtw89_fw_element_hdr {
        __le32 id; /* enum rtw89_fw_element_id */
        __le32 size; /* exclude header size */
@@ -4126,6 +4151,17 @@ struct rtw89_fw_element_hdr {
                        u8 rsvd1[3];
                        __le16 offset[];
                } __packed rfk_log_fmt;
+               struct {
+                       u8 rsvd[8];
+                       struct rtw89_phy_afe_info {
+                               __le32 action; /* enum rtw89_fw_afe_action */
+                               __le32 cat; /* enum rtw89_fw_afe_cat */
+                               __le32 class; /* enum rtw89_fw_afe_class */
+                               __le32 addr;
+                               __le32 mask;
+                               __le32 val;
+                       } __packed infos[];
+               } __packed afe;
                struct __rtw89_fw_txpwr_element txpwr;
                struct __rtw89_fw_regd_element regd;
        } __packed u;
index 0e9cb0558eb3b5df605e6a2f6877078fbb80812f..45823c9e944847ec1017963870ab23391c4f0c54 100644 (file)
@@ -1702,6 +1702,91 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev)
        rtw89_phy_bb_reset(rtwdev);
 }
 
+void rtw89_phy_init_bb_afe(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+       const struct rtw89_fw_element_hdr *afe_elm = elm_info->afe;
+       const struct rtw89_phy_afe_info *info;
+       u32 action, cat, class;
+       u32 addr, mask, val;
+       u32 poll, rpt;
+       u32 n, i;
+
+       if (!afe_elm)
+               return;
+
+       n = le32_to_cpu(afe_elm->size) / sizeof(*info);
+
+       for (i = 0; i < n; i++) {
+               info = &afe_elm->u.afe.infos[i];
+
+               class = le32_to_cpu(info->class);
+               switch (class) {
+               case RTW89_FW_AFE_CLASS_P0:
+               case RTW89_FW_AFE_CLASS_P1:
+               case RTW89_FW_AFE_CLASS_CMN:
+                       /* Currently support two paths */
+                       break;
+               case RTW89_FW_AFE_CLASS_P2:
+               case RTW89_FW_AFE_CLASS_P3:
+               case RTW89_FW_AFE_CLASS_P4:
+               default:
+                       rtw89_warn(rtwdev, "unexpected AFE class %u\n", class);
+                       continue;
+               }
+
+               addr = le32_to_cpu(info->addr);
+               mask = le32_to_cpu(info->mask);
+               val = le32_to_cpu(info->val);
+               cat = le32_to_cpu(info->cat);
+               action = le32_to_cpu(info->action);
+
+               switch (action) {
+               case RTW89_FW_AFE_ACTION_WRITE:
+                       switch (cat) {
+                       case RTW89_FW_AFE_CAT_MAC:
+                       case RTW89_FW_AFE_CAT_MAC1:
+                               rtw89_write32_mask(rtwdev, addr, mask, val);
+                               break;
+                       case RTW89_FW_AFE_CAT_AFEDIG:
+                       case RTW89_FW_AFE_CAT_AFEDIG1:
+                               rtw89_write32_mask(rtwdev, addr, mask, val);
+                               break;
+                       case RTW89_FW_AFE_CAT_BB:
+                               rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_0);
+                               break;
+                       case RTW89_FW_AFE_CAT_BB1:
+                               rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_1);
+                               break;
+                       default:
+                               rtw89_warn(rtwdev,
+                                          "unexpected AFE writing action %u\n", action);
+                               break;
+                       }
+                       break;
+               case RTW89_FW_AFE_ACTION_POLL:
+                       for (poll = 0; poll <= 10; poll++) {
+                               /*
+                                * For CAT_BB, AFE reads register with mcu_offset 0,
+                                * so both CAT_MAC and CAT_BB use the same method.
+                                */
+                               rpt = rtw89_read32_mask(rtwdev, addr, mask);
+                               if (rpt == val)
+                                       goto poll_done;
+
+                               fsleep(1);
+                       }
+                       rtw89_warn(rtwdev, "failed to poll AFE cat=%u addr=0x%x mask=0x%x\n",
+                                  cat, addr, mask);
+poll_done:
+                       break;
+               case RTW89_FW_AFE_ACTION_DELAY:
+                       fsleep(addr);
+                       break;
+               }
+       }
+}
+
 static u32 rtw89_phy_nctl_poll(struct rtw89_dev *rtwdev)
 {
        rtw89_phy_write32(rtwdev, 0x8080, 0x4);
index 1184b3c16d6f99aab167fae34893b7d9c6767c3e..674397c4b9a9f6befce64bd7f821f4f54f6689d2 100644 (file)
@@ -829,6 +829,7 @@ bool rtw89_phy_write_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
 bool rtw89_phy_write_rf_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
                           u32 addr, u32 mask, u32 data);
 void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev);
+void rtw89_phy_init_bb_afe(struct rtw89_dev *rtwdev);
 void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio);
 void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev,
                                const struct rtw89_reg2_def *reg,