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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);

static const struct ath11k_bus_params ath11k_ahb_bus_params = {
	.mhi_support = false,
	.m3_fw_support = false,
};

/* Target firmware's Copy Engine configuration. */
+1 −0
Original line number Diff line number Diff line
@@ -582,6 +582,7 @@ struct ath11k_board_data {

struct ath11k_bus_params {
	bool mhi_support;
	bool m3_fw_support;
};

/* IPQ8074 HW channel counters frequency value in hertz */
+1 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@
#define ATH11K_DEFAULT_BOARD_FILE	"board.bin"
#define ATH11K_DEFAULT_CAL_FILE		"caldata.bin"
#define ATH11K_AMSS_FILE		"amss.bin"
#define ATH11K_M3_FILE			"m3.bin"

enum ath11k_hw_rate_cck {
	ATH11K_HW_RATE_CCK_LP_11M = 0,
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);

static const struct ath11k_bus_params ath11k_pci_bus_params = {
	.mhi_support = true,
	.m3_fw_support = true,
};

static const struct ath11k_msi_config msi_config = {
+75 −7
Original line number Diff line number Diff line
@@ -1516,11 +1516,17 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab)
	req.bdf_support_valid = 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 = 0;

		req.m3_cache_support_valid = 0;
		req.m3_cache_support = 0;
	}

	req.cal_done_valid = 1;
	req.cal_done = ab->qmi.cal_done;
@@ -1908,8 +1914,57 @@ static int ath11k_qmi_load_bdf(struct ath11k_base *ab)
	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)
{
	struct m3_mem_region *m3_mem = &ab->qmi.m3_mem;
	struct qmi_wlanfw_m3_info_req_msg_v01 req;
	struct qmi_wlanfw_m3_info_resp_msg_v01 resp;
	struct qmi_txn txn = {};
@@ -1917,8 +1972,20 @@ static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab)

	memset(&req, 0, sizeof(req));
	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.size = 0;
	}

	ret = qmi_txn_init(&ab->qmi.handle, &txn,
			   qmi_wlanfw_m3_info_resp_msg_v01_ei, &resp);
@@ -2424,5 +2491,6 @@ void ath11k_qmi_deinit_service(struct ath11k_base *ab)
	qmi_handle_release(&ab->qmi.handle);
	cancel_work_sync(&ab->qmi.event_work);
	destroy_workqueue(ab->qmi.event_wq);
	ath11k_qmi_m3_free(ab);
}
Loading