rproc_shutdown(ab_ahb->tgt_rproc);
 }
 
+static int ath11k_ahb_fwreset_from_cold_boot(struct ath11k_base *ab)
+{
+       int timeout;
+
+       if (ath11k_cold_boot_cal == 0 || ab->qmi.cal_done ||
+           ab->hw_params.cold_boot_calib == 0)
+               return 0;
+
+       ath11k_dbg(ab, ATH11K_DBG_AHB, "wait for cold boot done\n");
+       timeout = wait_event_timeout(ab->qmi.cold_boot_waitq,
+                                    (ab->qmi.cal_done  == 1),
+                                    ATH11K_COLD_BOOT_FW_RESET_DELAY);
+       if (timeout <= 0) {
+               ath11k_cold_boot_cal = 0;
+               ath11k_warn(ab, "Coldboot Calibration failed timed out\n");
+       }
+
+       /* reset the firmware */
+       ath11k_ahb_power_down(ab);
+       ath11k_ahb_power_up(ab);
+
+       ath11k_dbg(ab, ATH11K_DBG_AHB, "exited from cold boot mode\n");
+       return 0;
+}
+
 static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
 {
        struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
                goto err_ce_free;
        }
 
+       ath11k_ahb_fwreset_from_cold_boot(ab);
+
        return 0;
 
 err_ce_free:
 
                .supports_monitor = true,
                .supports_shadow_regs = false,
                .idle_ps = false,
+               .cold_boot_calib = true,
        },
        {
                .hw_rev = ATH11K_HW_IPQ6018_HW10,
                .supports_monitor = true,
                .supports_shadow_regs = false,
                .idle_ps = false,
+               .cold_boot_calib = true,
        },
        {
                .name = "qca6390 hw2.0",
                .supports_monitor = false,
                .supports_shadow_regs = true,
                .idle_ps = true,
+               .cold_boot_calib = false,
        },
 };
 
        INIT_LIST_HEAD(&ab->peers);
        init_waitqueue_head(&ab->peer_mapping_wq);
        init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
+       init_waitqueue_head(&ab->qmi.cold_boot_waitq);
        INIT_WORK(&ab->restart_work, ath11k_core_restart);
        timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
        ab->dev = dev;
 
 #define SLEEP_CLOCK_SELECT_INTERNAL_BIT        0x02
 #define HOST_CSTATE_BIT                        0x04
 
+bool ath11k_cold_boot_cal = 1;
+EXPORT_SYMBOL(ath11k_cold_boot_cal);
+module_param_named(cold_boot_cal, ath11k_cold_boot_cal, bool, 0644);
+MODULE_PARM_DESC(cold_boot_cal,
+                "Decrease the channel switch time but increase the driver load time (Default: true)");
+
 static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = {
        {
                .data_type      = QMI_OPT_FLAG,
                                ath11k_warn(ab, "qmi mem size is low to load caldata\n");
                                return -EINVAL;
                        }
-                       /* TODO ath11k does not support cold boot calibration */
-                       ab->qmi.target_mem[idx].paddr = 0;
-                       ab->qmi.target_mem[idx].vaddr = NULL;
+
+                       if (ath11k_cold_boot_cal && ab->hw_params.cold_boot_calib) {
+                               ab->qmi.target_mem[idx].paddr =
+                                                    ATH11K_QMI_CALDB_ADDRESS;
+                               ab->qmi.target_mem[idx].vaddr =
+                                                    (void *)ATH11K_QMI_CALDB_ADDRESS;
+                       } else {
+                               ab->qmi.target_mem[idx].paddr = 0;
+                               ab->qmi.target_mem[idx].vaddr = NULL;
+                       }
                        ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
                        ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
                        idx++;
        return 0;
 }
 
+static int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab)
+{
+       int timeout;
+       int ret;
+
+       ret = ath11k_qmi_wlanfw_mode_send(ab, ATH11K_FIRMWARE_MODE_COLD_BOOT);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send wlan fw mode:%d\n", ret);
+               return ret;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "Coldboot calibration wait started\n");
+
+       timeout = wait_event_timeout(ab->qmi.cold_boot_waitq,
+                                    (ab->qmi.cal_done  == 1),
+                                    ATH11K_COLD_BOOT_FW_RESET_DELAY);
+       if (timeout <= 0) {
+               ath11k_warn(ab, "Coldboot Calibration failed - wait ended\n");
+               return 0;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "Coldboot calibration done\n");
+
+       return 0;
+}
+
 static int
 ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi,
                             enum ath11k_qmi_event_type type,
        ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_FW_READY, NULL);
 }
 
-static void ath11k_qmi_msg_cold_boot_cal_done_cb(struct qmi_handle *qmi,
+static void ath11k_qmi_msg_cold_boot_cal_done_cb(struct qmi_handle *qmi_hdl,
                                                 struct sockaddr_qrtr *sq,
                                                 struct qmi_txn *txn,
                                                 const void *decoded)
 {
+       struct ath11k_qmi *qmi = container_of(qmi_hdl,
+                                             struct ath11k_qmi, handle);
+       struct ath11k_base *ab = qmi->ab;
+
+       ab->qmi.cal_done = 1;
+       wake_up(&ab->qmi.cold_boot_waitq);
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cold boot calibration done\n");
 }
 
 static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = {
                                break;
                        }
 
-                       ath11k_core_qmi_firmware_ready(ab);
-                       ab->qmi.cal_done = 1;
-                       set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
+                       if (ath11k_cold_boot_cal && ab->qmi.cal_done == 0 &&
+                           ab->hw_params.cold_boot_calib) {
+                               ath11k_qmi_process_coldboot_calibration(ab);
+                       } else {
+                               clear_bit(ATH11K_FLAG_CRASH_FLUSH,
+                                         &ab->dev_flags);
+                               clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
+                               ath11k_core_qmi_firmware_ready(ab);
+                               set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
+                       }
 
                        break;
                case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE:
 
 #define ATH11K_HOST_VERSION_STRING             "WIN"
 #define ATH11K_QMI_WLANFW_TIMEOUT_MS           5000
 #define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE      64
+#define ATH11K_QMI_CALDB_ADDRESS               0x4BA00000
 #define ATH11K_QMI_BDF_MAX_SIZE                        (256 * 1024)
 #define ATH11K_QMI_CALDATA_OFFSET              (128 * 1024)
 #define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128
 #define QMI_WLANFW_MAX_DATA_SIZE_V01           6144
 #define ATH11K_FIRMWARE_MODE_OFF               4
 #define ATH11K_QMI_TARGET_MEM_MODE_DEFAULT     0
+#define ATH11K_COLD_BOOT_FW_RESET_DELAY                (40 * HZ)
 
 struct ath11k_base;
 
        struct target_info target;
        struct m3_mem_region m3_mem;
        unsigned int service_ins_id;
+       wait_queue_head_t cold_boot_waitq;
 };
 
 #define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN                189