{
        struct rtw89_fw_hdr_section_info *section_info;
        const u8 *fw_end = fw + len;
+       const u8 *fwdynhdr;
        const u8 *bin;
+       u32 base_hdr_len;
        u32 i;
 
        if (!info)
                return -EINVAL;
 
        info->section_num = GET_FW_HDR_SEC_NUM(fw);
-       info->hdr_len = RTW89_FW_HDR_SIZE +
-                       info->section_num * RTW89_FW_SECTION_HDR_SIZE;
+       base_hdr_len = RTW89_FW_HDR_SIZE +
+                      info->section_num * RTW89_FW_SECTION_HDR_SIZE;
+       info->dynamic_hdr_en = GET_FW_HDR_DYN_HDR(fw);
+
+       if (info->dynamic_hdr_en) {
+               info->hdr_len = GET_FW_HDR_LEN(fw);
+               info->dynamic_hdr_len = info->hdr_len - base_hdr_len;
+               fwdynhdr = fw + base_hdr_len;
+               if (GET_FW_DYNHDR_LEN(fwdynhdr) != info->dynamic_hdr_len) {
+                       rtw89_err(rtwdev, "[ERR]invalid fw dynamic header len\n");
+                       return -EINVAL;
+               }
+       } else {
+               info->hdr_len = base_hdr_len;
+               info->dynamic_hdr_len = 0;
+       }
 
        bin = fw + info->hdr_len;
 
                goto fwdl_err;
        }
 
-       ret = rtw89_fw_download_hdr(rtwdev, fw, info.hdr_len);
+       ret = rtw89_fw_download_hdr(rtwdev, fw, info.hdr_len - info.dynamic_hdr_len);
        if (ret) {
                ret = -EBUSY;
                goto fwdl_err;
 
 struct rtw89_fw_bin_info {
        u8 section_num;
        u32 hdr_len;
+       bool dynamic_hdr_en;
+       u32 dynamic_hdr_len;
        struct rtw89_fw_hdr_section_info section_info[FWDL_SECTION_MAX_NUM];
 };
 
        le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 16))
 #define GET_FW_HDR_SUBINDEX(fwhdr)     \
        le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(31, 24))
+#define GET_FW_HDR_LEN(fwhdr)  \
+       le32_get_bits(*((const __le32 *)(fwhdr) + 3), GENMASK(23, 16))
 #define GET_FW_HDR_MONTH(fwhdr)                \
        le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(7, 0))
 #define GET_FW_HDR_DATE(fwhdr)         \
        le32_get_bits(*((const __le32 *)(fwhdr) + 5), GENMASK(31, 0))
 #define GET_FW_HDR_SEC_NUM(fwhdr)      \
        le32_get_bits(*((const __le32 *)(fwhdr) + 6), GENMASK(15, 8))
+#define GET_FW_HDR_DYN_HDR(fwhdr)      \
+       le32_get_bits(*((const __le32 *)(fwhdr) + 7), BIT(16))
 #define GET_FW_HDR_CMD_VERSERION(fwhdr)        \
        le32_get_bits(*((const __le32 *)(fwhdr) + 7), GENMASK(31, 24))
+
+#define GET_FW_DYNHDR_LEN(fwdynhdr)    \
+       le32_get_bits(*((const __le32 *)(fwdynhdr)), GENMASK(31, 0))
+#define GET_FW_DYNHDR_COUNT(fwdynhdr)  \
+       le32_get_bits(*((const __le32 *)(fwdynhdr) + 1), GENMASK(31, 0))
+
 static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val)
 {
        le32p_replace_bits((__le32 *)fwhdr + 7, val, GENMASK(15, 0));