Commit 56970454 authored by Govind Singh's avatar Govind Singh Committed by Kalle Valo

ath11k: add support for m3 firmware

PCI devices like QCA6390 have a separate firmware image for the m3
micro-controller. Add support to load the firmware using m3.bin file.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2
Signed-off-by: default avatarGovind Singh <govinds@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1597389030-13887-2-git-send-email-kvalo@codeaurora.org
parent 1ff8ed78
...@@ -27,6 +27,7 @@ MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match); ...@@ -27,6 +27,7 @@ MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
static const struct ath11k_bus_params ath11k_ahb_bus_params = { static const struct ath11k_bus_params ath11k_ahb_bus_params = {
.mhi_support = false, .mhi_support = false,
.m3_fw_support = false,
}; };
/* Target firmware's Copy Engine configuration. */ /* Target firmware's Copy Engine configuration. */
......
...@@ -582,6 +582,7 @@ struct ath11k_board_data { ...@@ -582,6 +582,7 @@ struct ath11k_board_data {
struct ath11k_bus_params { struct ath11k_bus_params {
bool mhi_support; bool mhi_support;
bool m3_fw_support;
}; };
/* IPQ8074 HW channel counters frequency value in hertz */ /* IPQ8074 HW channel counters frequency value in hertz */
......
...@@ -73,6 +73,7 @@ ...@@ -73,6 +73,7 @@
#define ATH11K_DEFAULT_BOARD_FILE "board.bin" #define ATH11K_DEFAULT_BOARD_FILE "board.bin"
#define ATH11K_DEFAULT_CAL_FILE "caldata.bin" #define ATH11K_DEFAULT_CAL_FILE "caldata.bin"
#define ATH11K_AMSS_FILE "amss.bin" #define ATH11K_AMSS_FILE "amss.bin"
#define ATH11K_M3_FILE "m3.bin"
enum ath11k_hw_rate_cck { enum ath11k_hw_rate_cck {
ATH11K_HW_RATE_CCK_LP_11M = 0, ATH11K_HW_RATE_CCK_LP_11M = 0,
......
...@@ -29,6 +29,7 @@ MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); ...@@ -29,6 +29,7 @@ MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
static const struct ath11k_bus_params ath11k_pci_bus_params = { static const struct ath11k_bus_params ath11k_pci_bus_params = {
.mhi_support = true, .mhi_support = true,
.m3_fw_support = true,
}; };
static const struct ath11k_msi_config msi_config = { static const struct ath11k_msi_config msi_config = {
......
...@@ -1516,11 +1516,17 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab) ...@@ -1516,11 +1516,17 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab)
req.bdf_support_valid = 1; req.bdf_support_valid = 1;
req.bdf_support = 1; req.bdf_support = 1;
if (ab->bus_params.m3_fw_support) {
req.m3_support_valid = 1;
req.m3_support = 1;
req.m3_cache_support_valid = 1;
req.m3_cache_support = 1;
} else {
req.m3_support_valid = 0; req.m3_support_valid = 0;
req.m3_support = 0; req.m3_support = 0;
req.m3_cache_support_valid = 0; req.m3_cache_support_valid = 0;
req.m3_cache_support = 0; req.m3_cache_support = 0;
}
req.cal_done_valid = 1; req.cal_done_valid = 1;
req.cal_done = ab->qmi.cal_done; req.cal_done = ab->qmi.cal_done;
...@@ -1908,8 +1914,57 @@ static int ath11k_qmi_load_bdf(struct ath11k_base *ab) ...@@ -1908,8 +1914,57 @@ static int ath11k_qmi_load_bdf(struct ath11k_base *ab)
return ret; return ret;
} }
static int ath11k_qmi_m3_load(struct ath11k_base *ab)
{
struct m3_mem_region *m3_mem = &ab->qmi.m3_mem;
const struct firmware *fw;
char path[100];
int ret;
if (m3_mem->vaddr || m3_mem->size)
return 0;
fw = ath11k_core_firmware_request(ab, ATH11K_M3_FILE);
if (IS_ERR(fw)) {
ret = PTR_ERR(fw);
ath11k_core_create_firmware_path(ab, ATH11K_M3_FILE,
path, sizeof(path));
ath11k_err(ab, "failed to load %s: %d\n", path, ret);
return ret;
}
m3_mem->vaddr = dma_alloc_coherent(ab->dev,
fw->size, &m3_mem->paddr,
GFP_KERNEL);
if (!m3_mem->vaddr) {
ath11k_err(ab, "failed to allocate memory for M3 with size %zu\n",
fw->size);
release_firmware(fw);
return -ENOMEM;
}
memcpy(m3_mem->vaddr, fw->data, fw->size);
m3_mem->size = fw->size;
release_firmware(fw);
return 0;
}
static void ath11k_qmi_m3_free(struct ath11k_base *ab)
{
struct m3_mem_region *m3_mem = &ab->qmi.m3_mem;
if (!ab->bus_params.m3_fw_support || !m3_mem->vaddr)
return;
dma_free_coherent(ab->dev, m3_mem->size,
m3_mem->vaddr, m3_mem->paddr);
m3_mem->vaddr = NULL;
}
static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab)
{ {
struct m3_mem_region *m3_mem = &ab->qmi.m3_mem;
struct qmi_wlanfw_m3_info_req_msg_v01 req; struct qmi_wlanfw_m3_info_req_msg_v01 req;
struct qmi_wlanfw_m3_info_resp_msg_v01 resp; struct qmi_wlanfw_m3_info_resp_msg_v01 resp;
struct qmi_txn txn = {}; struct qmi_txn txn = {};
...@@ -1917,8 +1972,20 @@ static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) ...@@ -1917,8 +1972,20 @@ static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab)
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
memset(&resp, 0, sizeof(resp)); memset(&resp, 0, sizeof(resp));
if (ab->bus_params.m3_fw_support) {
ret = ath11k_qmi_m3_load(ab);
if (ret) {
ath11k_err(ab, "failed to load m3 firmware: %d", ret);
return ret;
}
req.addr = m3_mem->paddr;
req.size = m3_mem->size;
} else {
req.addr = 0; req.addr = 0;
req.size = 0; req.size = 0;
}
ret = qmi_txn_init(&ab->qmi.handle, &txn, ret = qmi_txn_init(&ab->qmi.handle, &txn,
qmi_wlanfw_m3_info_resp_msg_v01_ei, &resp); qmi_wlanfw_m3_info_resp_msg_v01_ei, &resp);
...@@ -2424,5 +2491,6 @@ void ath11k_qmi_deinit_service(struct ath11k_base *ab) ...@@ -2424,5 +2491,6 @@ void ath11k_qmi_deinit_service(struct ath11k_base *ab)
qmi_handle_release(&ab->qmi.handle); qmi_handle_release(&ab->qmi.handle);
cancel_work_sync(&ab->qmi.event_work); cancel_work_sync(&ab->qmi.event_work);
destroy_workqueue(ab->qmi.event_wq); destroy_workqueue(ab->qmi.event_wq);
ath11k_qmi_m3_free(ab);
} }
...@@ -96,6 +96,12 @@ struct target_info { ...@@ -96,6 +96,12 @@ struct target_info {
char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1]; char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1];
}; };
struct m3_mem_region {
u32 size;
dma_addr_t paddr;
void *vaddr;
};
struct ath11k_qmi { struct ath11k_qmi {
struct ath11k_base *ab; struct ath11k_base *ab;
struct qmi_handle handle; struct qmi_handle handle;
...@@ -110,6 +116,7 @@ struct ath11k_qmi { ...@@ -110,6 +116,7 @@ struct ath11k_qmi {
u32 target_mem_mode; u32 target_mem_mode;
u8 cal_done; u8 cal_done;
struct target_info target; struct target_info target;
struct m3_mem_region m3_mem;
}; };
#define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 189 #define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 189
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment