return PACKET_MAX;
 }
 
+static void
+rtw89_core_tx_wake(struct rtw89_dev *rtwdev,
+                  struct rtw89_core_tx_request *tx_req)
+{
+       if (!rtwdev->fw.tx_wake)
+               return;
+
+       if (!test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
+               return;
+
+       if (tx_req->tx_type != RTW89_CORE_TX_TYPE_MGMT)
+               return;
+
+       rtw89_mac_notify_wake(rtwdev);
+}
+
 static void
 rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev,
                               struct rtw89_core_tx_request *tx_req)
        rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true);
        rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true);
        rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
+       rtw89_core_tx_wake(rtwdev, &tx_req);
+
        ret = rtw89_hci_tx_write(rtwdev, &tx_req);
        if (ret) {
                rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
        INIT_DELAYED_WORK(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work);
        rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0);
        spin_lock_init(&rtwdev->ba_lock);
+       spin_lock_init(&rtwdev->rpwm_lock);
        mutex_init(&rtwdev->mutex);
        mutex_init(&rtwdev->rf_mutex);
        rtwdev->total_sta_assoc = 0;
 
        bool fw_log_enable;
        bool old_ht_ra_format;
        bool scan_offload;
+       bool tx_wake;
 };
 
 struct rtw89_cam_info {
        /* txqs to setup ba session */
        struct list_head ba_list;
        struct work_struct ba_work;
+       /* used to protect rpwm */
+       spinlock_t rpwm_lock;
 
        struct rtw89_cam_info cam_info;
 
 
        if (chip->chip_id == RTL8852A &&
            RTW89_FW_SUIT_VER_CODE(fw_suit) >= RTW89_FW_VER_CODE(0, 13, 35, 0))
                rtwdev->fw.scan_offload = true;
+
+       if (chip->chip_id == RTL8852A &&
+           RTW89_FW_SUIT_VER_CODE(fw_suit) >= RTW89_FW_VER_CODE(0, 13, 35, 0))
+               rtwdev->fw.tx_wake = true;
 }
 
 int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
 
 }
 
 static void rtw89_mac_send_rpwm(struct rtw89_dev *rtwdev,
-                               enum rtw89_rpwm_req_pwr_state req_pwr_state)
+                               enum rtw89_rpwm_req_pwr_state req_pwr_state,
+                               bool notify_wake)
 {
        u16 request;
 
+       spin_lock_bh(&rtwdev->rpwm_lock);
+
        request = rtw89_read16(rtwdev, R_AX_RPWM);
        request ^= request | PS_RPWM_TOGGLE;
-
-       rtwdev->mac.rpwm_seq_num = (rtwdev->mac.rpwm_seq_num + 1) &
-                                  RPWM_SEQ_NUM_MAX;
-       request |= FIELD_PREP(PS_RPWM_SEQ_NUM, rtwdev->mac.rpwm_seq_num);
-
        request |= req_pwr_state;
 
-       if (req_pwr_state < RTW89_MAC_RPWM_REQ_PWR_STATE_CLK_GATED)
-               request |= PS_RPWM_ACK;
+       if (notify_wake) {
+               request |= PS_RPWM_NOTIFY_WAKE;
+       } else {
+               rtwdev->mac.rpwm_seq_num = (rtwdev->mac.rpwm_seq_num + 1) &
+                                           RPWM_SEQ_NUM_MAX;
+               request |= FIELD_PREP(PS_RPWM_SEQ_NUM,
+                                     rtwdev->mac.rpwm_seq_num);
 
+               if (req_pwr_state < RTW89_MAC_RPWM_REQ_PWR_STATE_CLK_GATED)
+                       request |= PS_RPWM_ACK;
+       }
        rtw89_write16(rtwdev, rtwdev->hci.rpwm_addr, request);
+
+       spin_unlock_bh(&rtwdev->rpwm_lock);
 }
 
 static int rtw89_mac_check_cpwm_state(struct rtw89_dev *rtwdev,
        else
                state = RTW89_MAC_RPWM_REQ_PWR_STATE_ACTIVE;
 
-       rtw89_mac_send_rpwm(rtwdev, state);
+       rtw89_mac_send_rpwm(rtwdev, state, false);
        ret = read_poll_timeout_atomic(rtw89_mac_check_cpwm_state, ret, !ret,
                                       1000, 15000, false, rtwdev, state);
        if (ret)
                          enter ? "entering" : "leaving");
 }
 
+void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev)
+{
+       enum rtw89_rpwm_req_pwr_state state;
+
+       state = rtw89_mac_get_req_pwr_state(rtwdev);
+       rtw89_mac_send_rpwm(rtwdev, state, true);
+}
+
 static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on)
 {
 #define PWR_ACT 1
 
                            enum rtw89_phy_idx phy_idx,
                            u32 reg_base, u32 *cr);
 void rtw89_mac_power_mode_change(struct rtw89_dev *rtwdev, bool enter);
+void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev);
 void rtw89_mac_bf_assoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta);
 void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
 
 #define PS_RPWM_TOGGLE BIT(15)
 #define PS_RPWM_ACK BIT(14)
 #define PS_RPWM_SEQ_NUM GENMASK(13, 12)
+#define PS_RPWM_NOTIFY_WAKE BIT(8)
 #define PS_RPWM_STATE 0x7
 #define RPWM_SEQ_NUM_MAX 3
 #define PS_CPWM_SEQ_NUM GENMASK(13, 12)