mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
wifi: ath12k: support downloading auxiliary ucode image for QCC2072
QCC2072 requires another firmware image named aux_ucode.bin, add support to download it. Add a new hardware parameter download_aux_ucode to make sure other chips are not affected. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com> Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com> Link: https://patch.msgid.link/20260112-ath12k-support-qcc2072-v2-10-fc8ce1e43969@oss.qualcomm.com Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
parent
68cc3ac881
commit
b065ccf419
|
|
@ -1082,6 +1082,8 @@ struct ath12k_base {
|
|||
size_t amss_dualmac_len;
|
||||
const u8 *m3_data;
|
||||
size_t m3_len;
|
||||
const u8 *aux_uc_data;
|
||||
size_t aux_uc_len;
|
||||
|
||||
DECLARE_BITMAP(fw_features, ATH12K_FW_FEATURE_COUNT);
|
||||
bool fw_features_valid;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
|
|
@ -121,6 +121,14 @@ static int ath12k_fw_request_firmware_api_n(struct ath12k_base *ab,
|
|||
ab->fw.m3_data = data;
|
||||
ab->fw.m3_len = ie_len;
|
||||
break;
|
||||
case ATH12K_FW_IE_AUX_UC_IMAGE:
|
||||
ath12k_dbg(ab, ATH12K_DBG_BOOT,
|
||||
"found aux_uc image ie (%zd B)\n",
|
||||
ie_len);
|
||||
|
||||
ab->fw.aux_uc_data = data;
|
||||
ab->fw.aux_uc_len = ie_len;
|
||||
break;
|
||||
case ATH12K_FW_IE_AMSS_DUALMAC_IMAGE:
|
||||
ath12k_dbg(ab, ATH12K_DBG_BOOT,
|
||||
"found dualmac fw image ie (%zd B)\n",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#ifndef ATH12K_FW_H
|
||||
|
|
@ -15,6 +15,7 @@ enum ath12k_fw_ie_type {
|
|||
ATH12K_FW_IE_AMSS_IMAGE = 2,
|
||||
ATH12K_FW_IE_M3_IMAGE = 3,
|
||||
ATH12K_FW_IE_AMSS_DUALMAC_IMAGE = 4,
|
||||
ATH12K_FW_IE_AUX_UC_IMAGE = 5,
|
||||
};
|
||||
|
||||
enum ath12k_fw_features {
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
#define ATH12K_DEFAULT_CAL_FILE "caldata.bin"
|
||||
#define ATH12K_AMSS_FILE "amss.bin"
|
||||
#define ATH12K_M3_FILE "m3.bin"
|
||||
#define ATH12K_AUX_UC_FILE "aux_ucode.bin"
|
||||
#define ATH12K_REGDB_FILE_NAME "regdb.bin"
|
||||
|
||||
#define ATH12K_PCIE_MAX_PAYLOAD_SIZE 128
|
||||
|
|
@ -142,6 +143,7 @@ struct ath12k_hw_params {
|
|||
size_t board_size;
|
||||
size_t cal_offset;
|
||||
enum ath12k_m3_fw_loaders m3_loader;
|
||||
bool download_aux_ucode:1;
|
||||
} fw;
|
||||
|
||||
u8 max_radios;
|
||||
|
|
|
|||
|
|
@ -1623,6 +1623,47 @@ static const struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct qmi_elem_info qmi_wlanfw_aux_uc_info_req_msg_v01_ei[] = {
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_8_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u64),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x01,
|
||||
.offset = offsetof(struct qmi_wlanfw_aux_uc_info_req_msg_v01, addr),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_4_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u32),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x02,
|
||||
.offset = offsetof(struct qmi_wlanfw_aux_uc_info_req_msg_v01, size),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct qmi_elem_info qmi_wlanfw_aux_uc_info_resp_msg_v01_ei[] = {
|
||||
{
|
||||
.data_type = QMI_STRUCT,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(struct qmi_response_type_v01),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x02,
|
||||
.offset = offsetof(struct qmi_wlanfw_aux_uc_info_resp_msg_v01, resp),
|
||||
.ei_array = qmi_response_type_v01_ei,
|
||||
},
|
||||
{
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = {
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_4_BYTE,
|
||||
|
|
@ -3237,6 +3278,131 @@ int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void ath12k_qmi_aux_uc_free(struct ath12k_base *ab)
|
||||
{
|
||||
struct m3_mem_region *aux_uc_mem = &ab->qmi.aux_uc_mem;
|
||||
|
||||
if (!aux_uc_mem->vaddr)
|
||||
return;
|
||||
|
||||
dma_free_coherent(ab->dev, aux_uc_mem->total_size,
|
||||
aux_uc_mem->vaddr, aux_uc_mem->paddr);
|
||||
aux_uc_mem->vaddr = NULL;
|
||||
aux_uc_mem->total_size = 0;
|
||||
aux_uc_mem->size = 0;
|
||||
}
|
||||
|
||||
static int ath12k_qmi_aux_uc_load(struct ath12k_base *ab)
|
||||
{
|
||||
struct m3_mem_region *aux_uc_mem = &ab->qmi.aux_uc_mem;
|
||||
const struct firmware *fw = NULL;
|
||||
const void *aux_uc_data;
|
||||
char path[100];
|
||||
size_t aux_uc_len;
|
||||
int ret;
|
||||
|
||||
if (ab->fw.aux_uc_data && ab->fw.aux_uc_len > 0) {
|
||||
/* firmware-N.bin had a aux_uc firmware file so use that */
|
||||
aux_uc_data = ab->fw.aux_uc_data;
|
||||
aux_uc_len = ab->fw.aux_uc_len;
|
||||
} else {
|
||||
/*
|
||||
* No aux_uc file in firmware-N.bin so try to request old
|
||||
* separate aux_ucode.bin.
|
||||
*/
|
||||
fw = ath12k_core_firmware_request(ab, ATH12K_AUX_UC_FILE);
|
||||
if (IS_ERR(fw)) {
|
||||
ret = PTR_ERR(fw);
|
||||
ath12k_core_create_firmware_path(ab, ATH12K_AUX_UC_FILE,
|
||||
path, sizeof(path));
|
||||
ath12k_err(ab, "failed to load %s: %d\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
aux_uc_data = fw->data;
|
||||
aux_uc_len = fw->size;
|
||||
}
|
||||
|
||||
/* In recovery/resume cases, AUX_UC buffer is not freed, try to reuse that */
|
||||
if (aux_uc_mem->vaddr) {
|
||||
if (aux_uc_mem->total_size >= aux_uc_len)
|
||||
goto copy;
|
||||
|
||||
/* Old buffer is too small, free and reallocate */
|
||||
ath12k_qmi_aux_uc_free(ab);
|
||||
}
|
||||
|
||||
aux_uc_mem->vaddr = dma_alloc_coherent(ab->dev, aux_uc_len,
|
||||
&aux_uc_mem->paddr, GFP_KERNEL);
|
||||
if (!aux_uc_mem->vaddr) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
aux_uc_mem->total_size = aux_uc_len;
|
||||
|
||||
copy:
|
||||
memcpy(aux_uc_mem->vaddr, aux_uc_data, aux_uc_len);
|
||||
aux_uc_mem->size = aux_uc_len;
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline_for_stack
|
||||
int ath12k_qmi_wlanfw_aux_uc_info_send(struct ath12k_base *ab)
|
||||
{
|
||||
struct m3_mem_region *aux_uc_mem = &ab->qmi.aux_uc_mem;
|
||||
struct qmi_wlanfw_aux_uc_info_req_msg_v01 req = {};
|
||||
struct qmi_wlanfw_aux_uc_info_resp_msg_v01 resp = {};
|
||||
struct qmi_txn txn;
|
||||
int ret = 0;
|
||||
|
||||
ret = ath12k_qmi_aux_uc_load(ab);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to load aux_uc firmware: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
req.addr = aux_uc_mem->paddr;
|
||||
req.size = aux_uc_mem->size;
|
||||
|
||||
ret = qmi_txn_init(&ab->qmi.handle, &txn,
|
||||
qmi_wlanfw_aux_uc_info_resp_msg_v01_ei, &resp);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
|
||||
QMI_WLANFW_AUX_UC_INFO_REQ_V01,
|
||||
QMI_WLANFW_AUX_UC_INFO_REQ_MSG_V01_MAX_MSG_LEN,
|
||||
qmi_wlanfw_aux_uc_info_req_msg_v01_ei, &req);
|
||||
if (ret < 0) {
|
||||
qmi_txn_cancel(&txn);
|
||||
ath12k_warn(ab, "qmi failed to send AUX_UC information request, err = %d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS));
|
||||
if (ret < 0) {
|
||||
ath12k_warn(ab, "qmi failed AUX_UC information request %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath12k_warn(ab, "qmi AUX_UC info request failed, result: %d, err: %d\n",
|
||||
resp.resp.result, resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab,
|
||||
u32 mode)
|
||||
{
|
||||
|
|
@ -3601,6 +3767,7 @@ static noinline_for_stack
|
|||
int ath12k_qmi_event_load_bdf(struct ath12k_qmi *qmi)
|
||||
{
|
||||
struct ath12k_base *ab = qmi->ab;
|
||||
const struct ath12k_hw_params *hw_params = ab->hw_params;
|
||||
int ret;
|
||||
|
||||
ret = ath12k_qmi_request_target_cap(ab);
|
||||
|
|
@ -3621,7 +3788,7 @@ int ath12k_qmi_event_load_bdf(struct ath12k_qmi *qmi)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (ab->hw_params->download_calib) {
|
||||
if (hw_params->download_calib) {
|
||||
ret = ath12k_qmi_load_bdf_qmi(ab, ATH12K_QMI_BDF_TYPE_CALIBRATION);
|
||||
if (ret < 0)
|
||||
ath12k_warn(ab, "qmi failed to load calibrated data :%d\n", ret);
|
||||
|
|
@ -3633,6 +3800,14 @@ int ath12k_qmi_event_load_bdf(struct ath12k_qmi *qmi)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (hw_params->fw.download_aux_ucode) {
|
||||
ret = ath12k_qmi_wlanfw_aux_uc_info_send(ab);
|
||||
if (ret < 0) {
|
||||
ath12k_warn(ab, "qmi failed to send aux_uc info req: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -3906,6 +4081,7 @@ void ath12k_qmi_deinit_service(struct ath12k_base *ab)
|
|||
qmi_handle_release(&ab->qmi.handle);
|
||||
cancel_work_sync(&ab->qmi.event_work);
|
||||
destroy_workqueue(ab->qmi.event_wq);
|
||||
ath12k_qmi_aux_uc_free(ab);
|
||||
ath12k_qmi_m3_free(ab);
|
||||
ath12k_qmi_free_target_mem_chunk(ab);
|
||||
ab->qmi.ab = NULL;
|
||||
|
|
@ -3914,5 +4090,6 @@ void ath12k_qmi_deinit_service(struct ath12k_base *ab)
|
|||
void ath12k_qmi_free_resource(struct ath12k_base *ab)
|
||||
{
|
||||
ath12k_qmi_free_target_mem_chunk(ab);
|
||||
ath12k_qmi_aux_uc_free(ab);
|
||||
ath12k_qmi_m3_free(ab);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ struct ath12k_qmi {
|
|||
u8 num_radios;
|
||||
struct target_info target;
|
||||
struct m3_mem_region m3_mem;
|
||||
struct m3_mem_region aux_uc_mem;
|
||||
unsigned int service_ins_id;
|
||||
struct dev_mem_info dev_mem[ATH12K_QMI_WLFW_MAX_DEV_MEM_NUM_V01];
|
||||
};
|
||||
|
|
@ -203,6 +204,7 @@ enum ath12k_qmi_cnss_feature {
|
|||
CNSS_FEATURE_MIN_ENUM_VAL_V01 = INT_MIN,
|
||||
CNSS_QDSS_CFG_MISS_V01 = 3,
|
||||
CNSS_PCIE_PERST_NO_PULL_V01 = 4,
|
||||
CNSS_AUX_UC_SUPPORT_V01 = 6,
|
||||
CNSS_MAX_FEATURE_V01 = 64,
|
||||
CNSS_FEATURE_MAX_ENUM_VAL_V01 = INT_MAX,
|
||||
};
|
||||
|
|
@ -541,6 +543,19 @@ struct qmi_wlanfw_m3_info_resp_msg_v01 {
|
|||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define QMI_WLANFW_AUX_UC_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
|
||||
#define QMI_WLANFW_AUX_UC_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
#define QMI_WLANFW_AUX_UC_INFO_REQ_V01 0x005A
|
||||
|
||||
struct qmi_wlanfw_aux_uc_info_req_msg_v01 {
|
||||
u64 addr;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct qmi_wlanfw_aux_uc_info_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN 11
|
||||
#define QMI_WLANFW_WLAN_MODE_RESP_MSG_V01_MAX_LEN 7
|
||||
#define QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN 803
|
||||
|
|
|
|||
|
|
@ -339,6 +339,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
.board_size = 256 * 1024,
|
||||
.cal_offset = 128 * 1024,
|
||||
.m3_loader = ath12k_m3_fw_loader_driver,
|
||||
.download_aux_ucode = false,
|
||||
},
|
||||
.max_radios = 1,
|
||||
.single_pdev_only = false,
|
||||
|
|
@ -421,6 +422,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
.board_size = 256 * 1024,
|
||||
.cal_offset = 256 * 1024,
|
||||
.m3_loader = ath12k_m3_fw_loader_driver,
|
||||
.download_aux_ucode = false,
|
||||
},
|
||||
|
||||
.max_radios = 1,
|
||||
|
|
@ -505,6 +507,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
.board_size = 256 * 1024,
|
||||
.cal_offset = 128 * 1024,
|
||||
.m3_loader = ath12k_m3_fw_loader_driver,
|
||||
.download_aux_ucode = false,
|
||||
},
|
||||
.max_radios = 2,
|
||||
.single_pdev_only = false,
|
||||
|
|
@ -586,6 +589,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
.board_size = 256 * 1024,
|
||||
.cal_offset = 128 * 1024,
|
||||
.m3_loader = ath12k_m3_fw_loader_remoteproc,
|
||||
.download_aux_ucode = false,
|
||||
},
|
||||
.max_radios = 1,
|
||||
.single_pdev_only = false,
|
||||
|
|
@ -661,6 +665,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
.board_size = 256 * 1024,
|
||||
.cal_offset = 256 * 1024,
|
||||
.m3_loader = ath12k_m3_fw_loader_driver,
|
||||
.download_aux_ucode = true,
|
||||
},
|
||||
|
||||
.max_radios = 1,
|
||||
|
|
@ -707,7 +712,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
.wmi_init = ath12k_wifi7_wmi_init_wcn7850,
|
||||
|
||||
.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
|
||||
BIT(CNSS_PCIE_PERST_NO_PULL_V01),
|
||||
BIT(CNSS_PCIE_PERST_NO_PULL_V01) |
|
||||
BIT(CNSS_AUX_UC_SUPPORT_V01),
|
||||
|
||||
.rfkill_pin = 0,
|
||||
.rfkill_cfg = 0,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user