const char *fw_name_old;
 };
 
+enum bootloader_param_change {
+       not_changed,
+       cmd_sent,
+       changed
+};
+
 struct btnxpuart_dev {
        struct hci_dev *hdev;
        struct serdev_device *serdev;
        u32 fw_v1_sent_bytes;
        u32 fw_dnld_v3_offset;
        u32 fw_v3_offset_correction;
+       u32 fw_v3_prev_sent;
        u32 fw_v1_expected_len;
        u32 boot_reg_offset;
        wait_queue_head_t fw_dnld_done_wait_q;
        u32 new_baudrate;
        u32 current_baudrate;
        u32 fw_init_baudrate;
-       bool timeout_changed;
-       bool baudrate_changed;
+       enum bootloader_param_change timeout_changed;
+       enum bootloader_param_change baudrate_changed;
        bool helper_downloaded;
 
        struct ps_data psdata;
        nxpdev->boot_reg_offset = 0;
        nxpdev->fw_dnld_v3_offset = 0;
        nxpdev->fw_v3_offset_correction = 0;
-       nxpdev->baudrate_changed = false;
-       nxpdev->timeout_changed = false;
+       nxpdev->baudrate_changed = not_changed;
+       nxpdev->timeout_changed = not_changed;
        nxpdev->helper_downloaded = false;
 
        serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE);
        len = __le16_to_cpu(req->len);
 
        if (!nxp_data->helper_fw_name) {
-               if (!nxpdev->timeout_changed) {
-                       nxpdev->timeout_changed = nxp_fw_change_timeout(hdev,
-                                                                       len);
+               if (nxpdev->timeout_changed != changed) {
+                       nxp_fw_change_timeout(hdev, len);
+                       nxpdev->timeout_changed = changed;
                        goto free_skb;
                }
-               if (!nxpdev->baudrate_changed) {
-                       nxpdev->baudrate_changed = nxp_fw_change_baudrate(hdev,
-                                                                         len);
-                       if (nxpdev->baudrate_changed) {
+               if (nxpdev->baudrate_changed != changed) {
+                       if (nxp_fw_change_baudrate(hdev, len)) {
+                               nxpdev->baudrate_changed = changed;
                                serdev_device_set_baudrate(nxpdev->serdev,
                                                           HCI_NXP_SEC_BAUDRATE);
                                serdev_device_set_flow_control(nxpdev->serdev, true);
 {
        struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
        struct v3_data_req *req;
-       __u16 len;
+       __u16 len = 0;
+       __u16 err = 0;
        __u32 offset;
 
        if (!process_boot_signature(nxpdev))
        if (!req || !nxpdev->fw)
                goto free_skb;
 
-       if (!req->error) {
+       err = __le16_to_cpu(req->error);
+
+       if (!err) {
                nxp_send_ack(NXP_ACK_V3, hdev);
+               if (nxpdev->timeout_changed == cmd_sent)
+                       nxpdev->timeout_changed = changed;
+               if (nxpdev->baudrate_changed == cmd_sent)
+                       nxpdev->baudrate_changed = changed;
        } else {
                nxp_handle_fw_download_error(hdev, req);
+               if (nxpdev->timeout_changed == cmd_sent &&
+                   err == NXP_CRC_RX_ERROR) {
+                       nxpdev->fw_v3_offset_correction -= nxpdev->fw_v3_prev_sent;
+                       nxpdev->timeout_changed = not_changed;
+               }
+               if (nxpdev->baudrate_changed == cmd_sent &&
+                   err == NXP_CRC_RX_ERROR) {
+                       nxpdev->fw_v3_offset_correction -= nxpdev->fw_v3_prev_sent;
+                       nxpdev->baudrate_changed = not_changed;
+               }
                goto free_skb;
        }
 
        len = __le16_to_cpu(req->len);
 
-       if (!nxpdev->timeout_changed) {
-               nxpdev->timeout_changed = nxp_fw_change_timeout(hdev, len);
+       if (nxpdev->timeout_changed != changed) {
+               nxp_fw_change_timeout(hdev, len);
+               nxpdev->timeout_changed = cmd_sent;
                goto free_skb;
        }
 
-       if (!nxpdev->baudrate_changed) {
-               nxpdev->baudrate_changed = nxp_fw_change_baudrate(hdev, len);
-               if (nxpdev->baudrate_changed) {
+       if (nxpdev->baudrate_changed != changed) {
+               if (nxp_fw_change_baudrate(hdev, len)) {
+                       nxpdev->baudrate_changed = cmd_sent;
                        serdev_device_set_baudrate(nxpdev->serdev,
                                                   HCI_NXP_SEC_BAUDRATE);
                        serdev_device_set_flow_control(nxpdev->serdev, true);
                                nxpdev->fw_dnld_v3_offset, len);
 
 free_skb:
+       nxpdev->fw_v3_prev_sent = len;
        kfree_skb(skb);
        return 0;
 }