--- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -631,6 +631,23 @@ void ath11k_ahb_power_down(struct ath11k rproc_shutdown(ab->tgt_rproc); } +int ath11k_ahb_fwreset_from_cold_boot(struct ath11k_base *ab) +{ + if (enable_cold_boot_cal == 0 || ab->qmi.cal_done) + return 0; + + ath11k_dbg(ab, ATH11K_DBG_AHB, "wait for cold boot done\n"); + while (ab->qmi.cal_done == 0) + msleep(ATH11K_FW_READY_DELAY); + + /* reset the firmware */ + ath11k_ahb_power_down(ab); + ath11k_ahb_power_up(ab); + ath11k_dbg(ab, ATH11K_DBG_AHB, "exit wait for cold boot done\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; @@ -945,6 +962,8 @@ static int ath11k_ahb_probe(struct platf goto err_ce_free; } + ath11k_ahb_fwreset_from_cold_boot(ab); + return 0; err_ce_free: --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -99,6 +99,9 @@ enum ath11k_firmware_mode { /* factory tests etc */ ATH11K_FIRMWARE_MODE_FTM, + + /* Cold boot calibration */ + ATH11K_FIRMWARE_MODE_COLD_BOOT = 7, }; #define ATH11K_IRQ_NUM_MAX 52 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -9,6 +9,11 @@ #include #include +/* set the default max assoc sta to max supported by driver */ +unsigned int enable_cold_boot_cal = 1; +module_param(enable_cold_boot_cal, uint, 0644); +MODULE_PARM_DESC(enable_cold_boot_cal, "cold boot calibration enable:1 disable:0"); + static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, @@ -1677,6 +1682,7 @@ out: static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) { int i, idx; + u32 caldb_location[2] = {0, 0}; for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) { switch (ab->qmi.target_mem[i].type) { @@ -1692,9 +1698,20 @@ static int ath11k_qmi_alloc_target_mem_c 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 = 0; + + if (of_property_read_u32_array(ab->dev->of_node, "qcom,caldb-addr", + &caldb_location[0], + ARRAY_SIZE(caldb_location))) { + ath11k_warn(ab, "qmi no bdf_addr in device_tree\n"); + } + + if (enable_cold_boot_cal) { + ab->qmi.target_mem[idx].paddr = caldb_location[ab->qmi.target_mem_mode]; + ab->qmi.target_mem[idx].vaddr = caldb_location[ab->qmi.target_mem_mode]; + } else { + ab->qmi.target_mem[idx].paddr = 0; + ab->qmi.target_mem[idx].vaddr = 0; + } 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++; @@ -2117,6 +2134,32 @@ int ath11k_qmi_firmware_start(struct ath return 0; } +int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab) +{ + int ret; + int coldboot_wait_limit = 0; + + 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_info(ab, "Coldboot calibration wait started\n"); + while (ab->qmi.cal_done == 0) { + if (++coldboot_wait_limit >= ATH11K_COLD_BOOT_MAX_WAIT_LIMIT) { + ath11k_warn(ab, "Coldboot Calibration timeout %d secs", + coldboot_wait_limit / 10); + return -EINVAL; + } + mdelay(ATH11K_FW_READY_DELAY); + } + + ath11k_info(ab, "Coldboot calibration wait ended\n"); + + return 0; +} + static int ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi, enum ath11k_qmi_event_type type, @@ -2253,11 +2296,16 @@ static void ath11k_qmi_msg_fw_ready_cb(s 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; + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cold boot calibration done\n"); } static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = { @@ -2368,11 +2416,14 @@ static void ath11k_qmi_driver_event_work queue_work(ab->workqueue, &ab->restart_work); break; } - - ath11k_core_qmi_firmware_ready(ab); - ab->qmi.cal_done = 1; - set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags); - + if (enable_cold_boot_cal && ab->qmi.cal_done == 0) { + 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: break; --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -34,6 +34,11 @@ #define ATH11K_FIRMWARE_MODE_OFF 4 #define ATH11K_QMI_TARGET_MEM_MODE_DEFAULT 0 +#define ATH11K_FW_READY_DELAY 100 /* 100 msec */ +#define ATH11K_COLD_BOOT_MAX_WAIT_LIMIT 400 + +extern unsigned int enable_cold_boot_cal; + struct ath11k_base; enum ath11k_qmi_file_type {