xref: /openbmc/linux/drivers/bluetooth/btqca.c (revision d37cf9b63113f13d742713881ce691fc615d8b3b)
145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
283e81961SBen Young Tae Kim /*
383e81961SBen Young Tae Kim  *  Bluetooth supports for Qualcomm Atheros chips
483e81961SBen Young Tae Kim  *
583e81961SBen Young Tae Kim  *  Copyright (c) 2015 The Linux Foundation. All rights reserved.
683e81961SBen Young Tae Kim  */
783e81961SBen Young Tae Kim #include <linux/module.h>
883e81961SBen Young Tae Kim #include <linux/firmware.h>
9b6459415SJakub Kicinski #include <linux/vmalloc.h>
1083e81961SBen Young Tae Kim 
1183e81961SBen Young Tae Kim #include <net/bluetooth/bluetooth.h>
1283e81961SBen Young Tae Kim #include <net/bluetooth/hci_core.h>
1383e81961SBen Young Tae Kim 
1483e81961SBen Young Tae Kim #include "btqca.h"
1583e81961SBen Young Tae Kim 
1683e81961SBen Young Tae Kim #define VERSION "0.1"
1783e81961SBen Young Tae Kim 
qca_read_soc_version(struct hci_dev * hdev,struct qca_btsoc_version * ver,enum qca_btsoc_type soc_type)18059924fdSVenkata Lakshmi Narayana Gubba int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
197d250a06SBalakrishna Godavarthi 			 enum qca_btsoc_type soc_type)
2083e81961SBen Young Tae Kim {
2183e81961SBen Young Tae Kim 	struct sk_buff *skb;
2283e81961SBen Young Tae Kim 	struct edl_event_hdr *edl;
2383e81961SBen Young Tae Kim 	char cmd;
2483e81961SBen Young Tae Kim 	int err = 0;
257d250a06SBalakrishna Godavarthi 	u8 event_type = HCI_EV_VENDOR;
267d250a06SBalakrishna Godavarthi 	u8 rlen = sizeof(*edl) + sizeof(*ver);
277d250a06SBalakrishna Godavarthi 	u8 rtype = EDL_APP_VER_RES_EVT;
2883e81961SBen Young Tae Kim 
29ba493d4fSBalakrishna Godavarthi 	bt_dev_dbg(hdev, "QCA Version Request");
3083e81961SBen Young Tae Kim 
317d250a06SBalakrishna Godavarthi 	/* Unlike other SoC's sending version command response as payload to
327d250a06SBalakrishna Godavarthi 	 * VSE event. WCN3991 sends version command response as a payload to
337d250a06SBalakrishna Godavarthi 	 * command complete event.
347d250a06SBalakrishna Godavarthi 	 */
35e5d6468fSRocky Liao 	if (soc_type >= QCA_WCN3991) {
367d250a06SBalakrishna Godavarthi 		event_type = 0;
377d250a06SBalakrishna Godavarthi 		rlen += 1;
387d250a06SBalakrishna Godavarthi 		rtype = EDL_PATCH_VER_REQ_CMD;
397d250a06SBalakrishna Godavarthi 	}
407d250a06SBalakrishna Godavarthi 
4183e81961SBen Young Tae Kim 	cmd = EDL_PATCH_VER_REQ_CMD;
4283e81961SBen Young Tae Kim 	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
437d250a06SBalakrishna Godavarthi 				&cmd, event_type, HCI_INIT_TIMEOUT);
4483e81961SBen Young Tae Kim 	if (IS_ERR(skb)) {
4583e81961SBen Young Tae Kim 		err = PTR_ERR(skb);
46ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "Reading QCA version information failed (%d)",
4783e81961SBen Young Tae Kim 			   err);
4883e81961SBen Young Tae Kim 		return err;
4983e81961SBen Young Tae Kim 	}
5083e81961SBen Young Tae Kim 
517d250a06SBalakrishna Godavarthi 	if (skb->len != rlen) {
52ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Version size mismatch len %d", skb->len);
5383e81961SBen Young Tae Kim 		err = -EILSEQ;
5483e81961SBen Young Tae Kim 		goto out;
5583e81961SBen Young Tae Kim 	}
5683e81961SBen Young Tae Kim 
5783e81961SBen Young Tae Kim 	edl = (struct edl_event_hdr *)(skb->data);
580676cab4SColin Ian King 	if (!edl) {
59ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA TLV with no header");
6083e81961SBen Young Tae Kim 		err = -EILSEQ;
6183e81961SBen Young Tae Kim 		goto out;
6283e81961SBen Young Tae Kim 	}
6383e81961SBen Young Tae Kim 
6483e81961SBen Young Tae Kim 	if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
657d250a06SBalakrishna Godavarthi 	    edl->rtype != rtype) {
66ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp,
67ba493d4fSBalakrishna Godavarthi 			   edl->rtype);
6883e81961SBen Young Tae Kim 		err = -EIO;
6983e81961SBen Young Tae Kim 		goto out;
7083e81961SBen Young Tae Kim 	}
7183e81961SBen Young Tae Kim 
72e5d6468fSRocky Liao 	if (soc_type >= QCA_WCN3991)
73059924fdSVenkata Lakshmi Narayana Gubba 		memcpy(ver, edl->data + 1, sizeof(*ver));
74059924fdSVenkata Lakshmi Narayana Gubba 	else
75059924fdSVenkata Lakshmi Narayana Gubba 		memcpy(ver, &edl->data, sizeof(*ver));
7683e81961SBen Young Tae Kim 
774942857bSZijun Hu 	bt_dev_info(hdev, "QCA Product ID   :0x%08x",
784942857bSZijun Hu 		    le32_to_cpu(ver->product_id));
794942857bSZijun Hu 	bt_dev_info(hdev, "QCA SOC Version  :0x%08x",
804942857bSZijun Hu 		    le32_to_cpu(ver->soc_id));
814942857bSZijun Hu 	bt_dev_info(hdev, "QCA ROM Version  :0x%08x",
824942857bSZijun Hu 		    le16_to_cpu(ver->rom_ver));
834942857bSZijun Hu 	bt_dev_info(hdev, "QCA Patch Version:0x%08x",
844942857bSZijun Hu 		    le16_to_cpu(ver->patch_ver));
8583e81961SBen Young Tae Kim 
86059924fdSVenkata Lakshmi Narayana Gubba 	if (ver->soc_id == 0 || ver->rom_ver == 0)
87aadebac4SBalakrishna Godavarthi 		err = -EILSEQ;
8883e81961SBen Young Tae Kim 
8983e81961SBen Young Tae Kim out:
9083e81961SBen Young Tae Kim 	kfree_skb(skb);
91aadebac4SBalakrishna Godavarthi 	if (err)
92aadebac4SBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Failed to get version (%d)", err);
9383e81961SBen Young Tae Kim 
9483e81961SBen Young Tae Kim 	return err;
9583e81961SBen Young Tae Kim }
96ba493d4fSBalakrishna Godavarthi EXPORT_SYMBOL_GPL(qca_read_soc_version);
9783e81961SBen Young Tae Kim 
qca_read_fw_build_info(struct hci_dev * hdev)98c0187b0bSVenkata Lakshmi Narayana Gubba static int qca_read_fw_build_info(struct hci_dev *hdev)
99c0187b0bSVenkata Lakshmi Narayana Gubba {
100c0187b0bSVenkata Lakshmi Narayana Gubba 	struct sk_buff *skb;
101c0187b0bSVenkata Lakshmi Narayana Gubba 	struct edl_event_hdr *edl;
1026b63e0efSJohan Hovold 	char *build_label;
1036b63e0efSJohan Hovold 	char cmd;
104c0187b0bSVenkata Lakshmi Narayana Gubba 	int build_lbl_len, err = 0;
105c0187b0bSVenkata Lakshmi Narayana Gubba 
106c0187b0bSVenkata Lakshmi Narayana Gubba 	bt_dev_dbg(hdev, "QCA read fw build info");
107c0187b0bSVenkata Lakshmi Narayana Gubba 
108c0187b0bSVenkata Lakshmi Narayana Gubba 	cmd = EDL_GET_BUILD_INFO_CMD;
109c0187b0bSVenkata Lakshmi Narayana Gubba 	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
110c0187b0bSVenkata Lakshmi Narayana Gubba 				&cmd, 0, HCI_INIT_TIMEOUT);
111c0187b0bSVenkata Lakshmi Narayana Gubba 	if (IS_ERR(skb)) {
112c0187b0bSVenkata Lakshmi Narayana Gubba 		err = PTR_ERR(skb);
113c0187b0bSVenkata Lakshmi Narayana Gubba 		bt_dev_err(hdev, "Reading QCA fw build info failed (%d)",
114c0187b0bSVenkata Lakshmi Narayana Gubba 			   err);
115c0187b0bSVenkata Lakshmi Narayana Gubba 		return err;
116c0187b0bSVenkata Lakshmi Narayana Gubba 	}
117c0187b0bSVenkata Lakshmi Narayana Gubba 
1186b63e0efSJohan Hovold 	if (skb->len < sizeof(*edl)) {
1196b63e0efSJohan Hovold 		err = -EILSEQ;
1206b63e0efSJohan Hovold 		goto out;
1216b63e0efSJohan Hovold 	}
1226b63e0efSJohan Hovold 
123c0187b0bSVenkata Lakshmi Narayana Gubba 	edl = (struct edl_event_hdr *)(skb->data);
124c0187b0bSVenkata Lakshmi Narayana Gubba 	if (!edl) {
125c0187b0bSVenkata Lakshmi Narayana Gubba 		bt_dev_err(hdev, "QCA read fw build info with no header");
126c0187b0bSVenkata Lakshmi Narayana Gubba 		err = -EILSEQ;
127c0187b0bSVenkata Lakshmi Narayana Gubba 		goto out;
128c0187b0bSVenkata Lakshmi Narayana Gubba 	}
129c0187b0bSVenkata Lakshmi Narayana Gubba 
130c0187b0bSVenkata Lakshmi Narayana Gubba 	if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
131c0187b0bSVenkata Lakshmi Narayana Gubba 	    edl->rtype != EDL_GET_BUILD_INFO_CMD) {
132c0187b0bSVenkata Lakshmi Narayana Gubba 		bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp,
133c0187b0bSVenkata Lakshmi Narayana Gubba 			   edl->rtype);
134c0187b0bSVenkata Lakshmi Narayana Gubba 		err = -EIO;
135c0187b0bSVenkata Lakshmi Narayana Gubba 		goto out;
136c0187b0bSVenkata Lakshmi Narayana Gubba 	}
137c0187b0bSVenkata Lakshmi Narayana Gubba 
1386b63e0efSJohan Hovold 	if (skb->len < sizeof(*edl) + 1) {
1396b63e0efSJohan Hovold 		err = -EILSEQ;
1406b63e0efSJohan Hovold 		goto out;
141c0187b0bSVenkata Lakshmi Narayana Gubba 	}
142c0187b0bSVenkata Lakshmi Narayana Gubba 
1436b63e0efSJohan Hovold 	build_lbl_len = edl->data[0];
1446b63e0efSJohan Hovold 
1456b63e0efSJohan Hovold 	if (skb->len < sizeof(*edl) + 1 + build_lbl_len) {
1466b63e0efSJohan Hovold 		err = -EILSEQ;
1476b63e0efSJohan Hovold 		goto out;
1486b63e0efSJohan Hovold 	}
1496b63e0efSJohan Hovold 
1506b63e0efSJohan Hovold 	build_label = kstrndup(&edl->data[1], build_lbl_len, GFP_KERNEL);
151dfde465dSDan Carpenter 	if (!build_label) {
152dfde465dSDan Carpenter 		err = -ENOMEM;
1536b63e0efSJohan Hovold 		goto out;
154dfde465dSDan Carpenter 	}
1556b63e0efSJohan Hovold 
156c0187b0bSVenkata Lakshmi Narayana Gubba 	hci_set_fw_info(hdev, "%s", build_label);
157c0187b0bSVenkata Lakshmi Narayana Gubba 
1586b63e0efSJohan Hovold 	kfree(build_label);
159c0187b0bSVenkata Lakshmi Narayana Gubba out:
160c0187b0bSVenkata Lakshmi Narayana Gubba 	kfree_skb(skb);
161c0187b0bSVenkata Lakshmi Narayana Gubba 	return err;
162c0187b0bSVenkata Lakshmi Narayana Gubba }
163c0187b0bSVenkata Lakshmi Narayana Gubba 
qca_send_patch_config_cmd(struct hci_dev * hdev)1644fac8a7aSSai Teja Aluvala static int qca_send_patch_config_cmd(struct hci_dev *hdev)
1654fac8a7aSSai Teja Aluvala {
1664fac8a7aSSai Teja Aluvala 	const u8 cmd[] = { EDL_PATCH_CONFIG_CMD, 0x01, 0, 0, 0 };
1674fac8a7aSSai Teja Aluvala 	struct sk_buff *skb;
1684fac8a7aSSai Teja Aluvala 	struct edl_event_hdr *edl;
1694fac8a7aSSai Teja Aluvala 	int err;
1704fac8a7aSSai Teja Aluvala 
1714fac8a7aSSai Teja Aluvala 	bt_dev_dbg(hdev, "QCA Patch config");
1724fac8a7aSSai Teja Aluvala 
1734fac8a7aSSai Teja Aluvala 	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, sizeof(cmd),
174fb3e827bSZijun Hu 				cmd, 0, HCI_INIT_TIMEOUT);
1754fac8a7aSSai Teja Aluvala 	if (IS_ERR(skb)) {
1764fac8a7aSSai Teja Aluvala 		err = PTR_ERR(skb);
1774fac8a7aSSai Teja Aluvala 		bt_dev_err(hdev, "Sending QCA Patch config failed (%d)", err);
1784fac8a7aSSai Teja Aluvala 		return err;
1794fac8a7aSSai Teja Aluvala 	}
1804fac8a7aSSai Teja Aluvala 
1814fac8a7aSSai Teja Aluvala 	if (skb->len != 2) {
1824fac8a7aSSai Teja Aluvala 		bt_dev_err(hdev, "QCA Patch config cmd size mismatch len %d", skb->len);
1834fac8a7aSSai Teja Aluvala 		err = -EILSEQ;
1844fac8a7aSSai Teja Aluvala 		goto out;
1854fac8a7aSSai Teja Aluvala 	}
1864fac8a7aSSai Teja Aluvala 
1874fac8a7aSSai Teja Aluvala 	edl = (struct edl_event_hdr *)(skb->data);
1884fac8a7aSSai Teja Aluvala 	if (!edl) {
1894fac8a7aSSai Teja Aluvala 		bt_dev_err(hdev, "QCA Patch config with no header");
1904fac8a7aSSai Teja Aluvala 		err = -EILSEQ;
1914fac8a7aSSai Teja Aluvala 		goto out;
1924fac8a7aSSai Teja Aluvala 	}
1934fac8a7aSSai Teja Aluvala 
1944fac8a7aSSai Teja Aluvala 	if (edl->cresp != EDL_PATCH_CONFIG_RES_EVT || edl->rtype != EDL_PATCH_CONFIG_CMD) {
1954fac8a7aSSai Teja Aluvala 		bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp,
1964fac8a7aSSai Teja Aluvala 			   edl->rtype);
1974fac8a7aSSai Teja Aluvala 		err = -EIO;
1984fac8a7aSSai Teja Aluvala 		goto out;
1994fac8a7aSSai Teja Aluvala 	}
2004fac8a7aSSai Teja Aluvala 
2014fac8a7aSSai Teja Aluvala 	err = 0;
2024fac8a7aSSai Teja Aluvala 
2034fac8a7aSSai Teja Aluvala out:
2044fac8a7aSSai Teja Aluvala 	kfree_skb(skb);
2054fac8a7aSSai Teja Aluvala 	return err;
2064fac8a7aSSai Teja Aluvala }
2074fac8a7aSSai Teja Aluvala 
qca_send_reset(struct hci_dev * hdev)208ba493d4fSBalakrishna Godavarthi static int qca_send_reset(struct hci_dev *hdev)
20983e81961SBen Young Tae Kim {
21083e81961SBen Young Tae Kim 	struct sk_buff *skb;
21183e81961SBen Young Tae Kim 	int err;
21283e81961SBen Young Tae Kim 
213ba493d4fSBalakrishna Godavarthi 	bt_dev_dbg(hdev, "QCA HCI_RESET");
21483e81961SBen Young Tae Kim 
21583e81961SBen Young Tae Kim 	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
21683e81961SBen Young Tae Kim 	if (IS_ERR(skb)) {
21783e81961SBen Young Tae Kim 		err = PTR_ERR(skb);
218ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Reset failed (%d)", err);
21983e81961SBen Young Tae Kim 		return err;
22083e81961SBen Young Tae Kim 	}
22183e81961SBen Young Tae Kim 
22283e81961SBen Young Tae Kim 	kfree_skb(skb);
22383e81961SBen Young Tae Kim 
22483e81961SBen Young Tae Kim 	return 0;
22583e81961SBen Young Tae Kim }
22683e81961SBen Young Tae Kim 
qca_read_fw_board_id(struct hci_dev * hdev,u16 * bid)227a381ee26STim Jiang static int qca_read_fw_board_id(struct hci_dev *hdev, u16 *bid)
228a381ee26STim Jiang {
229a381ee26STim Jiang 	u8 cmd;
230a381ee26STim Jiang 	struct sk_buff *skb;
231a381ee26STim Jiang 	struct edl_event_hdr *edl;
232a381ee26STim Jiang 	int err = 0;
233a381ee26STim Jiang 
234a381ee26STim Jiang 	cmd = EDL_GET_BID_REQ_CMD;
235a381ee26STim Jiang 	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
236a381ee26STim Jiang 				&cmd, 0, HCI_INIT_TIMEOUT);
237a381ee26STim Jiang 	if (IS_ERR(skb)) {
238a381ee26STim Jiang 		err = PTR_ERR(skb);
239a381ee26STim Jiang 		bt_dev_err(hdev, "Reading QCA board ID failed (%d)", err);
240a381ee26STim Jiang 		return err;
241a381ee26STim Jiang 	}
242a381ee26STim Jiang 
243a381ee26STim Jiang 	edl = skb_pull_data(skb, sizeof(*edl));
244a381ee26STim Jiang 	if (!edl) {
245a381ee26STim Jiang 		bt_dev_err(hdev, "QCA read board ID with no header");
246a381ee26STim Jiang 		err = -EILSEQ;
247a381ee26STim Jiang 		goto out;
248a381ee26STim Jiang 	}
249a381ee26STim Jiang 
250a381ee26STim Jiang 	if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
251a381ee26STim Jiang 	    edl->rtype != EDL_GET_BID_REQ_CMD) {
252a381ee26STim Jiang 		bt_dev_err(hdev, "QCA Wrong packet: %d %d", edl->cresp, edl->rtype);
253a381ee26STim Jiang 		err = -EIO;
254a381ee26STim Jiang 		goto out;
255a381ee26STim Jiang 	}
256a381ee26STim Jiang 
257ba307abeSJohan Hovold 	if (skb->len < 3) {
258ba307abeSJohan Hovold 		err = -EILSEQ;
259ba307abeSJohan Hovold 		goto out;
260ba307abeSJohan Hovold 	}
261ba307abeSJohan Hovold 
262a381ee26STim Jiang 	*bid = (edl->data[1] << 8) + edl->data[2];
263a381ee26STim Jiang 	bt_dev_dbg(hdev, "%s: bid = %x", __func__, *bid);
264a381ee26STim Jiang 
265a381ee26STim Jiang out:
266a381ee26STim Jiang 	kfree_skb(skb);
267a381ee26STim Jiang 	return err;
268a381ee26STim Jiang }
269a381ee26STim Jiang 
qca_send_pre_shutdown_cmd(struct hci_dev * hdev)270a2780889SHarish Bandi int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
271a2780889SHarish Bandi {
272a2780889SHarish Bandi 	struct sk_buff *skb;
273a2780889SHarish Bandi 	int err;
274a2780889SHarish Bandi 
275a2780889SHarish Bandi 	bt_dev_dbg(hdev, "QCA pre shutdown cmd");
276a2780889SHarish Bandi 
277010376abSHarish Bandi 	skb = __hci_cmd_sync_ev(hdev, QCA_PRE_SHUTDOWN_CMD, 0,
278010376abSHarish Bandi 				NULL, HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
279010376abSHarish Bandi 
280a2780889SHarish Bandi 	if (IS_ERR(skb)) {
281a2780889SHarish Bandi 		err = PTR_ERR(skb);
282a2780889SHarish Bandi 		bt_dev_err(hdev, "QCA preshutdown_cmd failed (%d)", err);
283a2780889SHarish Bandi 		return err;
284a2780889SHarish Bandi 	}
285a2780889SHarish Bandi 
286a2780889SHarish Bandi 	kfree_skb(skb);
287a2780889SHarish Bandi 
288a2780889SHarish Bandi 	return 0;
289a2780889SHarish Bandi }
290a2780889SHarish Bandi EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd);
291a2780889SHarish Bandi 
qca_filename_has_extension(const char * filename)292ae2d111cSCheng Jiang static bool qca_filename_has_extension(const char *filename)
293ae2d111cSCheng Jiang {
294ae2d111cSCheng Jiang 	const char *suffix = strrchr(filename, '.');
295ae2d111cSCheng Jiang 
296ae2d111cSCheng Jiang 	/* File extensions require a dot, but not as the first or last character */
297ae2d111cSCheng Jiang 	if (!suffix || suffix == filename || *(suffix + 1) == '\0')
298ae2d111cSCheng Jiang 		return 0;
299ae2d111cSCheng Jiang 
300ae2d111cSCheng Jiang 	/* Avoid matching directories with names that look like files with extensions */
301ae2d111cSCheng Jiang 	return !strchr(suffix, '/');
302ae2d111cSCheng Jiang }
303ae2d111cSCheng Jiang 
qca_get_alt_nvm_file(char * filename,size_t max_size)304ae2d111cSCheng Jiang static bool qca_get_alt_nvm_file(char *filename, size_t max_size)
305ae2d111cSCheng Jiang {
306ae2d111cSCheng Jiang 	char fwname[64];
307ae2d111cSCheng Jiang 	const char *suffix;
308ae2d111cSCheng Jiang 
309ae2d111cSCheng Jiang 	/* nvm file name has an extension, replace with .bin */
310ae2d111cSCheng Jiang 	if (qca_filename_has_extension(filename)) {
311ae2d111cSCheng Jiang 		suffix = strrchr(filename, '.');
312ae2d111cSCheng Jiang 		strscpy(fwname, filename, suffix - filename + 1);
313ae2d111cSCheng Jiang 		snprintf(fwname + (suffix - filename),
314ae2d111cSCheng Jiang 		       sizeof(fwname) - (suffix - filename), ".bin");
315ae2d111cSCheng Jiang 		/* If nvm file is already the default one, return false to skip the retry. */
316ae2d111cSCheng Jiang 		if (strcmp(fwname, filename) == 0)
317ae2d111cSCheng Jiang 			return false;
318ae2d111cSCheng Jiang 
319ae2d111cSCheng Jiang 		snprintf(filename, max_size, "%s", fwname);
320ae2d111cSCheng Jiang 		return true;
321ae2d111cSCheng Jiang 	}
322ae2d111cSCheng Jiang 	return false;
323ae2d111cSCheng Jiang }
324ae2d111cSCheng Jiang 
qca_tlv_check_data(struct hci_dev * hdev,struct qca_fw_config * config,u8 * fw_data,size_t fw_size,enum qca_btsoc_type soc_type)325427281f9SJohan Hovold static int qca_tlv_check_data(struct hci_dev *hdev,
326ecf6b2d9SVenkata Lakshmi Narayana Gubba 			       struct qca_fw_config *config,
327427281f9SJohan Hovold 			       u8 *fw_data, size_t fw_size,
328427281f9SJohan Hovold 			       enum qca_btsoc_type soc_type)
32983e81961SBen Young Tae Kim {
33083e81961SBen Young Tae Kim 	const u8 *data;
33183e81961SBen Young Tae Kim 	u32 type_len;
33283e81961SBen Young Tae Kim 	u16 tag_id, tag_len;
33383e81961SBen Young Tae Kim 	int idx, length;
33483e81961SBen Young Tae Kim 	struct tlv_type_hdr *tlv;
33583e81961SBen Young Tae Kim 	struct tlv_type_patch *tlv_patch;
33683e81961SBen Young Tae Kim 	struct tlv_type_nvm *tlv_nvm;
337b6388254SRocky Liao 	uint8_t nvm_baud_rate = config->user_baud_rate;
338c3a38d10SJohan Hovold 	u8 type;
33983e81961SBen Young Tae Kim 
340e303d124SBalakrishna Godavarthi 	config->dnld_mode = QCA_SKIP_EVT_NONE;
341e303d124SBalakrishna Godavarthi 	config->dnld_type = QCA_SKIP_EVT_NONE;
3426e03126aSLoic Poulain 
34383e81961SBen Young Tae Kim 	switch (config->type) {
344ecf6b2d9SVenkata Lakshmi Narayana Gubba 	case ELF_TYPE_PATCH:
345427281f9SJohan Hovold 		if (fw_size < 7)
346427281f9SJohan Hovold 			return -EINVAL;
347427281f9SJohan Hovold 
348ecf6b2d9SVenkata Lakshmi Narayana Gubba 		config->dnld_mode = QCA_SKIP_EVT_VSE_CC;
349ecf6b2d9SVenkata Lakshmi Narayana Gubba 		config->dnld_type = QCA_SKIP_EVT_VSE_CC;
350ecf6b2d9SVenkata Lakshmi Narayana Gubba 
351ecf6b2d9SVenkata Lakshmi Narayana Gubba 		bt_dev_dbg(hdev, "File Class        : 0x%x", fw_data[4]);
352ecf6b2d9SVenkata Lakshmi Narayana Gubba 		bt_dev_dbg(hdev, "Data Encoding     : 0x%x", fw_data[5]);
353ecf6b2d9SVenkata Lakshmi Narayana Gubba 		bt_dev_dbg(hdev, "File version      : 0x%x", fw_data[6]);
354ecf6b2d9SVenkata Lakshmi Narayana Gubba 		break;
35583e81961SBen Young Tae Kim 	case TLV_TYPE_PATCH:
356427281f9SJohan Hovold 		if (fw_size < sizeof(struct tlv_type_hdr) + sizeof(struct tlv_type_patch))
357427281f9SJohan Hovold 			return -EINVAL;
358427281f9SJohan Hovold 
359ecf6b2d9SVenkata Lakshmi Narayana Gubba 		tlv = (struct tlv_type_hdr *)fw_data;
360ecf6b2d9SVenkata Lakshmi Narayana Gubba 		type_len = le32_to_cpu(tlv->type_len);
36183e81961SBen Young Tae Kim 		tlv_patch = (struct tlv_type_patch *)tlv->data;
3626e03126aSLoic Poulain 
3636e03126aSLoic Poulain 		/* For Rome version 1.1 to 3.1, all segment commands
3646e03126aSLoic Poulain 		 * are acked by a vendor specific event (VSE).
3656e03126aSLoic Poulain 		 * For Rome >= 3.2, the download mode field indicates
3666e03126aSLoic Poulain 		 * if VSE is skipped by the controller.
3676e03126aSLoic Poulain 		 * In case VSE is skipped, only the last segment is acked.
3686e03126aSLoic Poulain 		 */
3696e03126aSLoic Poulain 		config->dnld_mode = tlv_patch->download_mode;
37032646db8SBalakrishna Godavarthi 		config->dnld_type = config->dnld_mode;
3716e03126aSLoic Poulain 
372ecf6b2d9SVenkata Lakshmi Narayana Gubba 		BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
3736e03126aSLoic Poulain 		BT_DBG("Total Length           : %d bytes",
37483e81961SBen Young Tae Kim 		       le32_to_cpu(tlv_patch->total_size));
3756e03126aSLoic Poulain 		BT_DBG("Patch Data Length      : %d bytes",
37683e81961SBen Young Tae Kim 		       le32_to_cpu(tlv_patch->data_length));
37783e81961SBen Young Tae Kim 		BT_DBG("Signing Format Version : 0x%x",
37883e81961SBen Young Tae Kim 		       tlv_patch->format_version);
3796e03126aSLoic Poulain 		BT_DBG("Signature Algorithm    : 0x%x",
38083e81961SBen Young Tae Kim 		       tlv_patch->signature);
3816e03126aSLoic Poulain 		BT_DBG("Download mode          : 0x%x",
3826e03126aSLoic Poulain 		       tlv_patch->download_mode);
3836e03126aSLoic Poulain 		BT_DBG("Reserved               : 0x%x",
3846e03126aSLoic Poulain 		       tlv_patch->reserved1);
3856e03126aSLoic Poulain 		BT_DBG("Product ID             : 0x%04x",
38683e81961SBen Young Tae Kim 		       le16_to_cpu(tlv_patch->product_id));
3876e03126aSLoic Poulain 		BT_DBG("Rom Build Version      : 0x%04x",
38883e81961SBen Young Tae Kim 		       le16_to_cpu(tlv_patch->rom_build));
3896e03126aSLoic Poulain 		BT_DBG("Patch Version          : 0x%04x",
39083e81961SBen Young Tae Kim 		       le16_to_cpu(tlv_patch->patch_version));
3916e03126aSLoic Poulain 		BT_DBG("Reserved               : 0x%x",
39283e81961SBen Young Tae Kim 		       le16_to_cpu(tlv_patch->reserved2));
3936e03126aSLoic Poulain 		BT_DBG("Patch Entry Address    : 0x%x",
39483e81961SBen Young Tae Kim 		       le32_to_cpu(tlv_patch->entry));
39583e81961SBen Young Tae Kim 		break;
39683e81961SBen Young Tae Kim 
39783e81961SBen Young Tae Kim 	case TLV_TYPE_NVM:
398427281f9SJohan Hovold 		if (fw_size < sizeof(struct tlv_type_hdr))
399427281f9SJohan Hovold 			return -EINVAL;
400427281f9SJohan Hovold 
401ecf6b2d9SVenkata Lakshmi Narayana Gubba 		tlv = (struct tlv_type_hdr *)fw_data;
402ecf6b2d9SVenkata Lakshmi Narayana Gubba 
403ecf6b2d9SVenkata Lakshmi Narayana Gubba 		type_len = le32_to_cpu(tlv->type_len);
404c3a38d10SJohan Hovold 		length = type_len >> 8;
405c3a38d10SJohan Hovold 		type = type_len & 0xff;
406ecf6b2d9SVenkata Lakshmi Narayana Gubba 
407c3a38d10SJohan Hovold 		/* Some NVM files have more than one set of tags, only parse
408c3a38d10SJohan Hovold 		 * the first set when it has type 2 for now. When there is
409c3a38d10SJohan Hovold 		 * more than one set there is an enclosing header of type 4.
410c3a38d10SJohan Hovold 		 */
411c3a38d10SJohan Hovold 		if (type == 4) {
412c3a38d10SJohan Hovold 			if (fw_size < 2 * sizeof(struct tlv_type_hdr))
413c3a38d10SJohan Hovold 				return -EINVAL;
414c3a38d10SJohan Hovold 
415c3a38d10SJohan Hovold 			tlv++;
416c3a38d10SJohan Hovold 
417c3a38d10SJohan Hovold 			type_len = le32_to_cpu(tlv->type_len);
418c3a38d10SJohan Hovold 			length = type_len >> 8;
419c3a38d10SJohan Hovold 			type = type_len & 0xff;
420c3a38d10SJohan Hovold 		}
421c3a38d10SJohan Hovold 
422c3a38d10SJohan Hovold 		BT_DBG("TLV Type\t\t : 0x%x", type);
423ecf6b2d9SVenkata Lakshmi Narayana Gubba 		BT_DBG("Length\t\t : %d bytes", length);
424ecf6b2d9SVenkata Lakshmi Narayana Gubba 
425c3a38d10SJohan Hovold 		if (type != 2)
426c3a38d10SJohan Hovold 			break;
427c3a38d10SJohan Hovold 
428427281f9SJohan Hovold 		if (fw_size < length + (tlv->data - fw_data))
429427281f9SJohan Hovold 			return -EINVAL;
430427281f9SJohan Hovold 
43183e81961SBen Young Tae Kim 		idx = 0;
43283e81961SBen Young Tae Kim 		data = tlv->data;
433427281f9SJohan Hovold 		while (idx < length - sizeof(struct tlv_type_nvm)) {
43483e81961SBen Young Tae Kim 			tlv_nvm = (struct tlv_type_nvm *)(data + idx);
43583e81961SBen Young Tae Kim 
43683e81961SBen Young Tae Kim 			tag_id = le16_to_cpu(tlv_nvm->tag_id);
43783e81961SBen Young Tae Kim 			tag_len = le16_to_cpu(tlv_nvm->tag_len);
43883e81961SBen Young Tae Kim 
439427281f9SJohan Hovold 			if (length < idx + sizeof(struct tlv_type_nvm) + tag_len)
440427281f9SJohan Hovold 				return -EINVAL;
441427281f9SJohan Hovold 
44283e81961SBen Young Tae Kim 			/* Update NVM tags as needed */
44383e81961SBen Young Tae Kim 			switch (tag_id) {
4449d23305fSJohan Hovold 			case EDL_TAG_ID_BD_ADDR:
4459d23305fSJohan Hovold 				if (tag_len != sizeof(bdaddr_t))
4469d23305fSJohan Hovold 					return -EINVAL;
4479d23305fSJohan Hovold 
4489d23305fSJohan Hovold 				memcpy(&config->bdaddr, tlv_nvm->data, sizeof(bdaddr_t));
4499d23305fSJohan Hovold 
4509d23305fSJohan Hovold 				break;
4519d23305fSJohan Hovold 
45283e81961SBen Young Tae Kim 			case EDL_TAG_ID_HCI:
453427281f9SJohan Hovold 				if (tag_len < 3)
454427281f9SJohan Hovold 					return -EINVAL;
455427281f9SJohan Hovold 
45683e81961SBen Young Tae Kim 				/* HCI transport layer parameters
45783e81961SBen Young Tae Kim 				 * enabling software inband sleep
45883e81961SBen Young Tae Kim 				 * onto controller side.
45983e81961SBen Young Tae Kim 				 */
46083e81961SBen Young Tae Kim 				tlv_nvm->data[0] |= 0x80;
46183e81961SBen Young Tae Kim 
46283e81961SBen Young Tae Kim 				/* UART Baud Rate */
463e5d6468fSRocky Liao 				if (soc_type >= QCA_WCN3991)
464b6388254SRocky Liao 					tlv_nvm->data[1] = nvm_baud_rate;
465b6388254SRocky Liao 				else
466b6388254SRocky Liao 					tlv_nvm->data[2] = nvm_baud_rate;
46783e81961SBen Young Tae Kim 
46883e81961SBen Young Tae Kim 				break;
46983e81961SBen Young Tae Kim 
47083e81961SBen Young Tae Kim 			case EDL_TAG_ID_DEEP_SLEEP:
471427281f9SJohan Hovold 				if (tag_len < 1)
472427281f9SJohan Hovold 					return -EINVAL;
473427281f9SJohan Hovold 
47483e81961SBen Young Tae Kim 				/* Sleep enable mask
47583e81961SBen Young Tae Kim 				 * enabling deep sleep feature on controller.
47683e81961SBen Young Tae Kim 				 */
47783e81961SBen Young Tae Kim 				tlv_nvm->data[0] |= 0x01;
47883e81961SBen Young Tae Kim 
47983e81961SBen Young Tae Kim 				break;
48083e81961SBen Young Tae Kim 			}
48183e81961SBen Young Tae Kim 
482427281f9SJohan Hovold 			idx += sizeof(struct tlv_type_nvm) + tag_len;
48383e81961SBen Young Tae Kim 		}
48483e81961SBen Young Tae Kim 		break;
48583e81961SBen Young Tae Kim 
48683e81961SBen Young Tae Kim 	default:
48783e81961SBen Young Tae Kim 		BT_ERR("Unknown TLV type %d", config->type);
488427281f9SJohan Hovold 		return -EINVAL;
48983e81961SBen Young Tae Kim 	}
490427281f9SJohan Hovold 
491427281f9SJohan Hovold 	return 0;
49283e81961SBen Young Tae Kim }
49383e81961SBen Young Tae Kim 
qca_tlv_send_segment(struct hci_dev * hdev,int seg_size,const u8 * data,enum qca_tlv_dnld_mode mode,enum qca_btsoc_type soc_type)494ba493d4fSBalakrishna Godavarthi static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size,
4957d250a06SBalakrishna Godavarthi 				const u8 *data, enum qca_tlv_dnld_mode mode,
4967d250a06SBalakrishna Godavarthi 				enum qca_btsoc_type soc_type)
49783e81961SBen Young Tae Kim {
49883e81961SBen Young Tae Kim 	struct sk_buff *skb;
49983e81961SBen Young Tae Kim 	struct edl_event_hdr *edl;
50083e81961SBen Young Tae Kim 	struct tlv_seg_resp *tlv_resp;
50183e81961SBen Young Tae Kim 	u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2];
50283e81961SBen Young Tae Kim 	int err = 0;
5037d250a06SBalakrishna Godavarthi 	u8 event_type = HCI_EV_VENDOR;
5047d250a06SBalakrishna Godavarthi 	u8 rlen = (sizeof(*edl) + sizeof(*tlv_resp));
5057d250a06SBalakrishna Godavarthi 	u8 rtype = EDL_TVL_DNLD_RES_EVT;
50683e81961SBen Young Tae Kim 
50783e81961SBen Young Tae Kim 	cmd[0] = EDL_PATCH_TLV_REQ_CMD;
50883e81961SBen Young Tae Kim 	cmd[1] = seg_size;
50983e81961SBen Young Tae Kim 	memcpy(cmd + 2, data, seg_size);
51083e81961SBen Young Tae Kim 
511e303d124SBalakrishna Godavarthi 	if (mode == QCA_SKIP_EVT_VSE_CC || mode == QCA_SKIP_EVT_VSE)
5126e03126aSLoic Poulain 		return __hci_cmd_send(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2,
5136e03126aSLoic Poulain 				      cmd);
5146e03126aSLoic Poulain 
5157d250a06SBalakrishna Godavarthi 	/* Unlike other SoC's sending version command response as payload to
5167d250a06SBalakrishna Godavarthi 	 * VSE event. WCN3991 sends version command response as a payload to
5177d250a06SBalakrishna Godavarthi 	 * command complete event.
5187d250a06SBalakrishna Godavarthi 	 */
519e5d6468fSRocky Liao 	if (soc_type >= QCA_WCN3991) {
5207d250a06SBalakrishna Godavarthi 		event_type = 0;
5217d250a06SBalakrishna Godavarthi 		rlen = sizeof(*edl);
5227d250a06SBalakrishna Godavarthi 		rtype = EDL_PATCH_TLV_REQ_CMD;
5237d250a06SBalakrishna Godavarthi 	}
5247d250a06SBalakrishna Godavarthi 
52583e81961SBen Young Tae Kim 	skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd,
5267d250a06SBalakrishna Godavarthi 				event_type, HCI_INIT_TIMEOUT);
52783e81961SBen Young Tae Kim 	if (IS_ERR(skb)) {
52883e81961SBen Young Tae Kim 		err = PTR_ERR(skb);
529ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Failed to send TLV segment (%d)", err);
53083e81961SBen Young Tae Kim 		return err;
53183e81961SBen Young Tae Kim 	}
53283e81961SBen Young Tae Kim 
5337d250a06SBalakrishna Godavarthi 	if (skb->len != rlen) {
534ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA TLV response size mismatch");
53583e81961SBen Young Tae Kim 		err = -EILSEQ;
53683e81961SBen Young Tae Kim 		goto out;
53783e81961SBen Young Tae Kim 	}
53883e81961SBen Young Tae Kim 
53983e81961SBen Young Tae Kim 	edl = (struct edl_event_hdr *)(skb->data);
5400676cab4SColin Ian King 	if (!edl) {
541ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "TLV with no header");
54283e81961SBen Young Tae Kim 		err = -EILSEQ;
54383e81961SBen Young Tae Kim 		goto out;
54483e81961SBen Young Tae Kim 	}
54583e81961SBen Young Tae Kim 
5467d250a06SBalakrishna Godavarthi 	if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != rtype) {
5477d250a06SBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x",
5487d250a06SBalakrishna Godavarthi 			   edl->cresp, edl->rtype);
5497d250a06SBalakrishna Godavarthi 		err = -EIO;
5507d250a06SBalakrishna Godavarthi 	}
55183e81961SBen Young Tae Kim 
552e5d6468fSRocky Liao 	if (soc_type >= QCA_WCN3991)
5537d250a06SBalakrishna Godavarthi 		goto out;
5547d250a06SBalakrishna Godavarthi 
5557d250a06SBalakrishna Godavarthi 	tlv_resp = (struct tlv_seg_resp *)(edl->data);
5567d250a06SBalakrishna Godavarthi 	if (tlv_resp->result) {
557ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x (0x%x)",
558ba493d4fSBalakrishna Godavarthi 			   edl->cresp, edl->rtype, tlv_resp->result);
55983e81961SBen Young Tae Kim 	}
56083e81961SBen Young Tae Kim 
56183e81961SBen Young Tae Kim out:
56283e81961SBen Young Tae Kim 	kfree_skb(skb);
56383e81961SBen Young Tae Kim 
56483e81961SBen Young Tae Kim 	return err;
56583e81961SBen Young Tae Kim }
56683e81961SBen Young Tae Kim 
qca_inject_cmd_complete_event(struct hci_dev * hdev)56732646db8SBalakrishna Godavarthi static int qca_inject_cmd_complete_event(struct hci_dev *hdev)
56832646db8SBalakrishna Godavarthi {
56932646db8SBalakrishna Godavarthi 	struct hci_event_hdr *hdr;
57032646db8SBalakrishna Godavarthi 	struct hci_ev_cmd_complete *evt;
57132646db8SBalakrishna Godavarthi 	struct sk_buff *skb;
57232646db8SBalakrishna Godavarthi 
57332646db8SBalakrishna Godavarthi 	skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL);
57432646db8SBalakrishna Godavarthi 	if (!skb)
57532646db8SBalakrishna Godavarthi 		return -ENOMEM;
57632646db8SBalakrishna Godavarthi 
57732646db8SBalakrishna Godavarthi 	hdr = skb_put(skb, sizeof(*hdr));
57832646db8SBalakrishna Godavarthi 	hdr->evt = HCI_EV_CMD_COMPLETE;
57932646db8SBalakrishna Godavarthi 	hdr->plen = sizeof(*evt) + 1;
58032646db8SBalakrishna Godavarthi 
58132646db8SBalakrishna Godavarthi 	evt = skb_put(skb, sizeof(*evt));
58232646db8SBalakrishna Godavarthi 	evt->ncmd = 1;
5832fde6afbSMatthias Kaehlcke 	evt->opcode = cpu_to_le16(QCA_HCI_CC_OPCODE);
58432646db8SBalakrishna Godavarthi 
58532646db8SBalakrishna Godavarthi 	skb_put_u8(skb, QCA_HCI_CC_SUCCESS);
58632646db8SBalakrishna Godavarthi 
58732646db8SBalakrishna Godavarthi 	hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
58832646db8SBalakrishna Godavarthi 
58932646db8SBalakrishna Godavarthi 	return hci_recv_frame(hdev, skb);
59032646db8SBalakrishna Godavarthi }
59132646db8SBalakrishna Godavarthi 
qca_download_firmware(struct hci_dev * hdev,struct qca_fw_config * config,enum qca_btsoc_type soc_type,u8 rom_ver)592ba493d4fSBalakrishna Godavarthi static int qca_download_firmware(struct hci_dev *hdev,
5937d250a06SBalakrishna Godavarthi 				 struct qca_fw_config *config,
594ecf6b2d9SVenkata Lakshmi Narayana Gubba 				 enum qca_btsoc_type soc_type,
595ecf6b2d9SVenkata Lakshmi Narayana Gubba 				 u8 rom_ver)
59683e81961SBen Young Tae Kim {
59783e81961SBen Young Tae Kim 	const struct firmware *fw;
598b43ca511SConnor Abbott 	u8 *data;
5996e03126aSLoic Poulain 	const u8 *segment;
600b43ca511SConnor Abbott 	int ret, size, remain, i = 0;
60183e81961SBen Young Tae Kim 
602ba493d4fSBalakrishna Godavarthi 	bt_dev_info(hdev, "QCA Downloading %s", config->fwname);
60383e81961SBen Young Tae Kim 
60483e81961SBen Young Tae Kim 	ret = request_firmware(&fw, config->fwname, &hdev->dev);
60583e81961SBen Young Tae Kim 	if (ret) {
606ecf6b2d9SVenkata Lakshmi Narayana Gubba 		/* For WCN6750, if mbn file is not present then check for
607ecf6b2d9SVenkata Lakshmi Narayana Gubba 		 * tlv file.
608ecf6b2d9SVenkata Lakshmi Narayana Gubba 		 */
609ecf6b2d9SVenkata Lakshmi Narayana Gubba 		if (soc_type == QCA_WCN6750 && config->type == ELF_TYPE_PATCH) {
610ecf6b2d9SVenkata Lakshmi Narayana Gubba 			bt_dev_dbg(hdev, "QCA Failed to request file: %s (%d)",
611ecf6b2d9SVenkata Lakshmi Narayana Gubba 				   config->fwname, ret);
612ecf6b2d9SVenkata Lakshmi Narayana Gubba 			config->type = TLV_TYPE_PATCH;
613ecf6b2d9SVenkata Lakshmi Narayana Gubba 			snprintf(config->fwname, sizeof(config->fwname),
614ecf6b2d9SVenkata Lakshmi Narayana Gubba 				 "qca/msbtfw%02x.tlv", rom_ver);
615ecf6b2d9SVenkata Lakshmi Narayana Gubba 			bt_dev_info(hdev, "QCA Downloading %s", config->fwname);
616ecf6b2d9SVenkata Lakshmi Narayana Gubba 			ret = request_firmware(&fw, config->fwname, &hdev->dev);
617ecf6b2d9SVenkata Lakshmi Narayana Gubba 			if (ret) {
618ba493d4fSBalakrishna Godavarthi 				bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
61983e81961SBen Young Tae Kim 					   config->fwname, ret);
62083e81961SBen Young Tae Kim 				return ret;
62183e81961SBen Young Tae Kim 			}
622ae2d111cSCheng Jiang 		}
623ae2d111cSCheng Jiang 		/* If the board-specific file is missing, try loading the default
624ae2d111cSCheng Jiang 		 * one, unless that was attempted already.
625ae2d111cSCheng Jiang 		 */
626ae2d111cSCheng Jiang 		else if (config->type == TLV_TYPE_NVM &&
627ae2d111cSCheng Jiang 			 qca_get_alt_nvm_file(config->fwname, sizeof(config->fwname))) {
628ae2d111cSCheng Jiang 			bt_dev_info(hdev, "QCA Downloading %s", config->fwname);
629ae2d111cSCheng Jiang 			ret = request_firmware(&fw, config->fwname, &hdev->dev);
630ae2d111cSCheng Jiang 			if (ret) {
631ae2d111cSCheng Jiang 				bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
632ae2d111cSCheng Jiang 					   config->fwname, ret);
633ae2d111cSCheng Jiang 				return ret;
634ae2d111cSCheng Jiang 			}
635ecf6b2d9SVenkata Lakshmi Narayana Gubba 		} else {
636ecf6b2d9SVenkata Lakshmi Narayana Gubba 			bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
637ecf6b2d9SVenkata Lakshmi Narayana Gubba 				   config->fwname, ret);
638ecf6b2d9SVenkata Lakshmi Narayana Gubba 			return ret;
639ecf6b2d9SVenkata Lakshmi Narayana Gubba 		}
640ecf6b2d9SVenkata Lakshmi Narayana Gubba 	}
64183e81961SBen Young Tae Kim 
642b43ca511SConnor Abbott 	size = fw->size;
643b43ca511SConnor Abbott 	data = vmalloc(fw->size);
644b43ca511SConnor Abbott 	if (!data) {
645b43ca511SConnor Abbott 		bt_dev_err(hdev, "QCA Failed to allocate memory for file: %s",
646b43ca511SConnor Abbott 			   config->fwname);
647b43ca511SConnor Abbott 		release_firmware(fw);
648b43ca511SConnor Abbott 		return -ENOMEM;
649b43ca511SConnor Abbott 	}
65083e81961SBen Young Tae Kim 
651b43ca511SConnor Abbott 	memcpy(data, fw->data, size);
652b43ca511SConnor Abbott 	release_firmware(fw);
653b43ca511SConnor Abbott 
654427281f9SJohan Hovold 	ret = qca_tlv_check_data(hdev, config, data, size, soc_type);
655427281f9SJohan Hovold 	if (ret)
6567bcba557SJohan Hovold 		goto out;
657b43ca511SConnor Abbott 
658b43ca511SConnor Abbott 	segment = data;
659b43ca511SConnor Abbott 	remain = size;
6606e03126aSLoic Poulain 	while (remain > 0) {
6616e03126aSLoic Poulain 		int segsize = min(MAX_SIZE_PER_TLV_SEGMENT, remain);
6626e03126aSLoic Poulain 
6636e03126aSLoic Poulain 		bt_dev_dbg(hdev, "Send segment %d, size %d", i++, segsize);
6646e03126aSLoic Poulain 
6656e03126aSLoic Poulain 		remain -= segsize;
6666e03126aSLoic Poulain 		/* The last segment is always acked regardless download mode */
6676e03126aSLoic Poulain 		if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT)
668e303d124SBalakrishna Godavarthi 			config->dnld_mode = QCA_SKIP_EVT_NONE;
6696e03126aSLoic Poulain 
670ba493d4fSBalakrishna Godavarthi 		ret = qca_tlv_send_segment(hdev, segsize, segment,
6717d250a06SBalakrishna Godavarthi 					   config->dnld_mode, soc_type);
6726e03126aSLoic Poulain 		if (ret)
67332646db8SBalakrishna Godavarthi 			goto out;
6746e03126aSLoic Poulain 
6756e03126aSLoic Poulain 		segment += segsize;
67683e81961SBen Young Tae Kim 	}
67783e81961SBen Young Tae Kim 
67832646db8SBalakrishna Godavarthi 	/* Latest qualcomm chipsets are not sending a command complete event
67932646db8SBalakrishna Godavarthi 	 * for every fw packet sent. They only respond with a vendor specific
68032646db8SBalakrishna Godavarthi 	 * event for the last packet. This optimization in the chip will
68132646db8SBalakrishna Godavarthi 	 * decrease the BT in initialization time. Here we will inject a command
68232646db8SBalakrishna Godavarthi 	 * complete event to avoid a command timeout error message.
68332646db8SBalakrishna Godavarthi 	 */
684e303d124SBalakrishna Godavarthi 	if (config->dnld_type == QCA_SKIP_EVT_VSE_CC ||
685e303d124SBalakrishna Godavarthi 	    config->dnld_type == QCA_SKIP_EVT_VSE)
686c7c5ae29SClaire Chang 		ret = qca_inject_cmd_complete_event(hdev);
68732646db8SBalakrishna Godavarthi 
68832646db8SBalakrishna Godavarthi out:
689b43ca511SConnor Abbott 	vfree(data);
69083e81961SBen Young Tae Kim 
69183e81961SBen Young Tae Kim 	return ret;
69283e81961SBen Young Tae Kim }
69383e81961SBen Young Tae Kim 
qca_disable_soc_logging(struct hci_dev * hdev)694590deccfSBalakrishna Godavarthi static int qca_disable_soc_logging(struct hci_dev *hdev)
695590deccfSBalakrishna Godavarthi {
696590deccfSBalakrishna Godavarthi 	struct sk_buff *skb;
697590deccfSBalakrishna Godavarthi 	u8 cmd[2];
698590deccfSBalakrishna Godavarthi 	int err;
699590deccfSBalakrishna Godavarthi 
700590deccfSBalakrishna Godavarthi 	cmd[0] = QCA_DISABLE_LOGGING_SUB_OP;
701590deccfSBalakrishna Godavarthi 	cmd[1] = 0x00;
702590deccfSBalakrishna Godavarthi 	skb = __hci_cmd_sync_ev(hdev, QCA_DISABLE_LOGGING, sizeof(cmd), cmd,
703590deccfSBalakrishna Godavarthi 				HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
704590deccfSBalakrishna Godavarthi 	if (IS_ERR(skb)) {
705590deccfSBalakrishna Godavarthi 		err = PTR_ERR(skb);
706590deccfSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Failed to disable soc logging(%d)", err);
707590deccfSBalakrishna Godavarthi 		return err;
708590deccfSBalakrishna Godavarthi 	}
709590deccfSBalakrishna Godavarthi 
710590deccfSBalakrishna Godavarthi 	kfree_skb(skb);
711590deccfSBalakrishna Godavarthi 
712590deccfSBalakrishna Godavarthi 	return 0;
713590deccfSBalakrishna Godavarthi }
714590deccfSBalakrishna Godavarthi 
qca_set_bdaddr_rome(struct hci_dev * hdev,const bdaddr_t * bdaddr)71583e81961SBen Young Tae Kim int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
71683e81961SBen Young Tae Kim {
71783e81961SBen Young Tae Kim 	struct sk_buff *skb;
71883e81961SBen Young Tae Kim 	u8 cmd[9];
71983e81961SBen Young Tae Kim 	int err;
72083e81961SBen Young Tae Kim 
72183e81961SBen Young Tae Kim 	cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD;
72283e81961SBen Young Tae Kim 	cmd[1] = 0x02; 			/* TAG ID */
72383e81961SBen Young Tae Kim 	cmd[2] = sizeof(bdaddr_t);	/* size */
72483e81961SBen Young Tae Kim 	memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t));
72583e81961SBen Young Tae Kim 	skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd,
726e4cc5a18SMarcel Holtmann 				HCI_EV_VENDOR, HCI_INIT_TIMEOUT);
72783e81961SBen Young Tae Kim 	if (IS_ERR(skb)) {
72883e81961SBen Young Tae Kim 		err = PTR_ERR(skb);
729ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Change address command failed (%d)", err);
73083e81961SBen Young Tae Kim 		return err;
73183e81961SBen Young Tae Kim 	}
73283e81961SBen Young Tae Kim 
73383e81961SBen Young Tae Kim 	kfree_skb(skb);
73483e81961SBen Young Tae Kim 
73583e81961SBen Young Tae Kim 	return 0;
73683e81961SBen Young Tae Kim }
73783e81961SBen Young Tae Kim EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
73883e81961SBen Young Tae Kim 
qca_check_bdaddr(struct hci_dev * hdev,const struct qca_fw_config * config)7399d23305fSJohan Hovold static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *config)
7403019a9d3SJohan Hovold {
7413019a9d3SJohan Hovold 	struct hci_rp_read_bd_addr *bda;
7423019a9d3SJohan Hovold 	struct sk_buff *skb;
7433019a9d3SJohan Hovold 	int err;
7443019a9d3SJohan Hovold 
7453019a9d3SJohan Hovold 	if (bacmp(&hdev->public_addr, BDADDR_ANY))
7463019a9d3SJohan Hovold 		return 0;
7473019a9d3SJohan Hovold 
7483019a9d3SJohan Hovold 	skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,
7493019a9d3SJohan Hovold 			     HCI_INIT_TIMEOUT);
7503019a9d3SJohan Hovold 	if (IS_ERR(skb)) {
7513019a9d3SJohan Hovold 		err = PTR_ERR(skb);
7523019a9d3SJohan Hovold 		bt_dev_err(hdev, "Failed to read device address (%d)", err);
7533019a9d3SJohan Hovold 		return err;
7543019a9d3SJohan Hovold 	}
7553019a9d3SJohan Hovold 
7563019a9d3SJohan Hovold 	if (skb->len != sizeof(*bda)) {
7573019a9d3SJohan Hovold 		bt_dev_err(hdev, "Device address length mismatch");
7583019a9d3SJohan Hovold 		kfree_skb(skb);
7593019a9d3SJohan Hovold 		return -EIO;
7603019a9d3SJohan Hovold 	}
7613019a9d3SJohan Hovold 
7623019a9d3SJohan Hovold 	bda = (struct hci_rp_read_bd_addr *)skb->data;
7639d23305fSJohan Hovold 	if (!bacmp(&bda->bdaddr, &config->bdaddr))
7643019a9d3SJohan Hovold 		set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
7653019a9d3SJohan Hovold 
7663019a9d3SJohan Hovold 	kfree_skb(skb);
7673019a9d3SJohan Hovold 
7683019a9d3SJohan Hovold 	return 0;
7693019a9d3SJohan Hovold }
7703019a9d3SJohan Hovold 
qca_get_nvm_name_by_board(char * fwname,size_t max_size,const char * stem,enum qca_btsoc_type soc_type,struct qca_btsoc_version ver,u8 rom_ver,u16 bid)771ae2d111cSCheng Jiang static void qca_get_nvm_name_by_board(char *fwname, size_t max_size,
772ae2d111cSCheng Jiang 		const char *stem, enum qca_btsoc_type soc_type,
773a381ee26STim Jiang 		struct qca_btsoc_version ver, u8 rom_ver, u16 bid)
774a381ee26STim Jiang {
775a381ee26STim Jiang 	const char *variant;
776ae2d111cSCheng Jiang 	const char *prefix;
777a381ee26STim Jiang 
778ae2d111cSCheng Jiang 	/* Set the default value to variant and prefix */
779ae2d111cSCheng Jiang 	variant = "";
780ae2d111cSCheng Jiang 	prefix = "b";
781ae2d111cSCheng Jiang 
782ae2d111cSCheng Jiang 	if (soc_type == QCA_QCA2066)
783ae2d111cSCheng Jiang 		prefix = "";
784ae2d111cSCheng Jiang 
785ae2d111cSCheng Jiang 	if (soc_type == QCA_WCN6855 || soc_type == QCA_QCA2066) {
786ae2d111cSCheng Jiang 		/* If the chip is manufactured by GlobalFoundries */
787a381ee26STim Jiang 		if ((le32_to_cpu(ver.soc_id) & QCA_HSP_GF_SOC_MASK) == QCA_HSP_GF_SOC_ID)
788a381ee26STim Jiang 			variant = "g";
789a381ee26STim Jiang 	}
790a381ee26STim Jiang 
791ae2d111cSCheng Jiang 	if (rom_ver != 0) {
792ae2d111cSCheng Jiang 		if (bid == 0x0 || bid == 0xffff)
793ae2d111cSCheng Jiang 			snprintf(fwname, max_size, "qca/%s%02x%s.bin", stem, rom_ver, variant);
794e68d2b88SZijun Hu 		else
795ae2d111cSCheng Jiang 			snprintf(fwname, max_size, "qca/%s%02x%s.%s%02x", stem, rom_ver,
796ae2d111cSCheng Jiang 						variant, prefix, bid);
797ae2d111cSCheng Jiang 	} else {
798ae2d111cSCheng Jiang 		if (bid == 0x0 || bid == 0xffff)
799ae2d111cSCheng Jiang 			snprintf(fwname, max_size, "qca/%s%s.bin", stem, variant);
800ae2d111cSCheng Jiang 		else
801ae2d111cSCheng Jiang 			snprintf(fwname, max_size, "qca/%s%s.%s%02x", stem, variant, prefix, bid);
802ae2d111cSCheng Jiang 	}
803e68d2b88SZijun Hu }
804e68d2b88SZijun Hu 
qca_uart_setup(struct hci_dev * hdev,uint8_t baudrate,enum qca_btsoc_type soc_type,struct qca_btsoc_version ver,const char * firmware_name)805aadebac4SBalakrishna Godavarthi int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
806059924fdSVenkata Lakshmi Narayana Gubba 		   enum qca_btsoc_type soc_type, struct qca_btsoc_version ver,
80799c905c6SRocky Liao 		   const char *firmware_name)
80883e81961SBen Young Tae Kim {
8099d23305fSJohan Hovold 	struct qca_fw_config config = {};
81083e81961SBen Young Tae Kim 	int err;
811523760b7SHarish Bandi 	u8 rom_ver = 0;
812059924fdSVenkata Lakshmi Narayana Gubba 	u32 soc_ver;
813a381ee26STim Jiang 	u16 boardid = 0;
81483e81961SBen Young Tae Kim 
815ba493d4fSBalakrishna Godavarthi 	bt_dev_dbg(hdev, "QCA setup on UART");
81683e81961SBen Young Tae Kim 
817059924fdSVenkata Lakshmi Narayana Gubba 	soc_ver = get_soc_ver(ver.soc_id, ver.rom_ver);
818059924fdSVenkata Lakshmi Narayana Gubba 
819059924fdSVenkata Lakshmi Narayana Gubba 	bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
820059924fdSVenkata Lakshmi Narayana Gubba 
82183e81961SBen Young Tae Kim 	config.user_baud_rate = baudrate;
82283e81961SBen Young Tae Kim 
8234219d468SBalakrishna Godavarthi 	/* Firmware files to download are based on ROM version.
8244219d468SBalakrishna Godavarthi 	 * ROM version is derived from last two bytes of soc_ver.
8254219d468SBalakrishna Godavarthi 	 */
826f904feefSLuca Weiss 	if (soc_type == QCA_WCN3988)
827f904feefSLuca Weiss 		rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f);
828f904feefSLuca Weiss 	else
82999fba8e3SVenkata Lakshmi Narayana Gubba 		rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
83099fba8e3SVenkata Lakshmi Narayana Gubba 
8314fac8a7aSSai Teja Aluvala 	if (soc_type == QCA_WCN6750)
8324fac8a7aSSai Teja Aluvala 		qca_send_patch_config_cmd(hdev);
8334fac8a7aSSai Teja Aluvala 
83499fba8e3SVenkata Lakshmi Narayana Gubba 	/* Download rampatch file */
83599fba8e3SVenkata Lakshmi Narayana Gubba 	config.type = TLV_TYPE_PATCH;
836691d54d0SNeil Armstrong 	switch (soc_type) {
837691d54d0SNeil Armstrong 	case QCA_WCN3990:
838691d54d0SNeil Armstrong 	case QCA_WCN3991:
839691d54d0SNeil Armstrong 	case QCA_WCN3998:
8404219d468SBalakrishna Godavarthi 		snprintf(config.fwname, sizeof(config.fwname),
8414219d468SBalakrishna Godavarthi 			 "qca/crbtfw%02x.tlv", rom_ver);
842691d54d0SNeil Armstrong 		break;
843691d54d0SNeil Armstrong 	case QCA_WCN3988:
844691d54d0SNeil Armstrong 		snprintf(config.fwname, sizeof(config.fwname),
845691d54d0SNeil Armstrong 			 "qca/apbtfw%02x.tlv", rom_ver);
846691d54d0SNeil Armstrong 		break;
847a381ee26STim Jiang 	case QCA_QCA2066:
848a381ee26STim Jiang 		snprintf(config.fwname, sizeof(config.fwname),
849a381ee26STim Jiang 			 "qca/hpbtfw%02x.tlv", rom_ver);
850a381ee26STim Jiang 		break;
851691d54d0SNeil Armstrong 	case QCA_QCA6390:
852e5d6468fSRocky Liao 		snprintf(config.fwname, sizeof(config.fwname),
853e5d6468fSRocky Liao 			 "qca/htbtfw%02x.tlv", rom_ver);
854691d54d0SNeil Armstrong 		break;
855691d54d0SNeil Armstrong 	case QCA_WCN6750:
856ecf6b2d9SVenkata Lakshmi Narayana Gubba 		/* Choose mbn file by default.If mbn file is not found
857ecf6b2d9SVenkata Lakshmi Narayana Gubba 		 * then choose tlv file
858ecf6b2d9SVenkata Lakshmi Narayana Gubba 		 */
859ecf6b2d9SVenkata Lakshmi Narayana Gubba 		config.type = ELF_TYPE_PATCH;
860d8f97da1SVenkata Lakshmi Narayana Gubba 		snprintf(config.fwname, sizeof(config.fwname),
861ecf6b2d9SVenkata Lakshmi Narayana Gubba 			 "qca/msbtfw%02x.mbn", rom_ver);
862691d54d0SNeil Armstrong 		break;
863691d54d0SNeil Armstrong 	case QCA_WCN6855:
864095327feSSteev Klimaszewski 		snprintf(config.fwname, sizeof(config.fwname),
865095327feSSteev Klimaszewski 			 "qca/hpbtfw%02x.tlv", rom_ver);
866691d54d0SNeil Armstrong 		break;
867e0c1278aSNeil Armstrong 	case QCA_WCN7850:
868e0c1278aSNeil Armstrong 		snprintf(config.fwname, sizeof(config.fwname),
869e0c1278aSNeil Armstrong 			 "qca/hmtbtfw%02x.tlv", rom_ver);
870e0c1278aSNeil Armstrong 		break;
871691d54d0SNeil Armstrong 	default:
8724219d468SBalakrishna Godavarthi 		snprintf(config.fwname, sizeof(config.fwname),
8734219d468SBalakrishna Godavarthi 			 "qca/rampatch_%08x.bin", soc_ver);
8744219d468SBalakrishna Godavarthi 	}
8754219d468SBalakrishna Godavarthi 
876ecf6b2d9SVenkata Lakshmi Narayana Gubba 	err = qca_download_firmware(hdev, &config, soc_type, rom_ver);
87783e81961SBen Young Tae Kim 	if (err < 0) {
878ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Failed to download patch (%d)", err);
87983e81961SBen Young Tae Kim 		return err;
88083e81961SBen Young Tae Kim 	}
88183e81961SBen Young Tae Kim 
8828059ba0bSMatthias Kaehlcke 	/* Give the controller some time to get ready to receive the NVM */
8838059ba0bSMatthias Kaehlcke 	msleep(10);
8848059ba0bSMatthias Kaehlcke 
885e68d2b88SZijun Hu 	if (soc_type == QCA_QCA2066 || soc_type == QCA_WCN7850)
886a381ee26STim Jiang 		qca_read_fw_board_id(hdev, &boardid);
887a381ee26STim Jiang 
88883e81961SBen Young Tae Kim 	/* Download NVM configuration */
88983e81961SBen Young Tae Kim 	config.type = TLV_TYPE_NVM;
890691d54d0SNeil Armstrong 	if (firmware_name) {
891ae2d111cSCheng Jiang 		/* The firmware name has an extension, use it directly */
892ae2d111cSCheng Jiang 		if (qca_filename_has_extension(firmware_name)) {
893ae2d111cSCheng Jiang 			snprintf(config.fwname, sizeof(config.fwname), "qca/%s", firmware_name);
894ae2d111cSCheng Jiang 		} else {
895ae2d111cSCheng Jiang 			qca_read_fw_board_id(hdev, &boardid);
896ae2d111cSCheng Jiang 			qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
897ae2d111cSCheng Jiang 				 firmware_name, soc_type, ver, 0, boardid);
898ae2d111cSCheng Jiang 		}
899691d54d0SNeil Armstrong 	} else {
900691d54d0SNeil Armstrong 		switch (soc_type) {
901691d54d0SNeil Armstrong 		case QCA_WCN3990:
902691d54d0SNeil Armstrong 		case QCA_WCN3991:
903691d54d0SNeil Armstrong 		case QCA_WCN3998:
9048153b738SMin-Hua Chen 			if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) {
905059924fdSVenkata Lakshmi Narayana Gubba 				snprintf(config.fwname, sizeof(config.fwname),
906059924fdSVenkata Lakshmi Narayana Gubba 					 "qca/crnv%02xu.bin", rom_ver);
907059924fdSVenkata Lakshmi Narayana Gubba 			} else {
9084219d468SBalakrishna Godavarthi 				snprintf(config.fwname, sizeof(config.fwname),
9094219d468SBalakrishna Godavarthi 					 "qca/crnv%02x.bin", rom_ver);
910059924fdSVenkata Lakshmi Narayana Gubba 			}
911691d54d0SNeil Armstrong 			break;
912691d54d0SNeil Armstrong 		case QCA_WCN3988:
913691d54d0SNeil Armstrong 			snprintf(config.fwname, sizeof(config.fwname),
914691d54d0SNeil Armstrong 				 "qca/apnv%02x.bin", rom_ver);
915691d54d0SNeil Armstrong 			break;
916a381ee26STim Jiang 		case QCA_QCA2066:
917ae2d111cSCheng Jiang 			qca_get_nvm_name_by_board(config.fwname,
918ae2d111cSCheng Jiang 				sizeof(config.fwname), "hpnv", soc_type, ver,
919ae2d111cSCheng Jiang 				rom_ver, boardid);
920a381ee26STim Jiang 			break;
921691d54d0SNeil Armstrong 		case QCA_QCA6390:
922e5d6468fSRocky Liao 			snprintf(config.fwname, sizeof(config.fwname),
923e5d6468fSRocky Liao 				 "qca/htnv%02x.bin", rom_ver);
924691d54d0SNeil Armstrong 			break;
925691d54d0SNeil Armstrong 		case QCA_WCN6750:
926d8f97da1SVenkata Lakshmi Narayana Gubba 			snprintf(config.fwname, sizeof(config.fwname),
927d8f97da1SVenkata Lakshmi Narayana Gubba 				 "qca/msnv%02x.bin", rom_ver);
928691d54d0SNeil Armstrong 			break;
929691d54d0SNeil Armstrong 		case QCA_WCN6855:
930*ab8b6bf2SZijun Hu 			qca_read_fw_board_id(hdev, &boardid);
931*ab8b6bf2SZijun Hu 			qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
932*ab8b6bf2SZijun Hu 						  "hpnv", soc_type, ver, rom_ver, boardid);
933691d54d0SNeil Armstrong 			break;
934e0c1278aSNeil Armstrong 		case QCA_WCN7850:
935ae2d111cSCheng Jiang 			qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
936ae2d111cSCheng Jiang 				 "hmtnv", soc_type, ver, rom_ver, boardid);
937e0c1278aSNeil Armstrong 			break;
938691d54d0SNeil Armstrong 		default:
9394219d468SBalakrishna Godavarthi 			snprintf(config.fwname, sizeof(config.fwname),
9404219d468SBalakrishna Godavarthi 				 "qca/nvm_%08x.bin", soc_ver);
941691d54d0SNeil Armstrong 		}
942691d54d0SNeil Armstrong 	}
9434219d468SBalakrishna Godavarthi 
944ecf6b2d9SVenkata Lakshmi Narayana Gubba 	err = qca_download_firmware(hdev, &config, soc_type, rom_ver);
94583e81961SBen Young Tae Kim 	if (err < 0) {
946ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err);
94783e81961SBen Young Tae Kim 		return err;
94883e81961SBen Young Tae Kim 	}
94983e81961SBen Young Tae Kim 
950691d54d0SNeil Armstrong 	switch (soc_type) {
951691d54d0SNeil Armstrong 	case QCA_WCN3991:
952a381ee26STim Jiang 	case QCA_QCA2066:
953691d54d0SNeil Armstrong 	case QCA_QCA6390:
954691d54d0SNeil Armstrong 	case QCA_WCN6750:
955691d54d0SNeil Armstrong 	case QCA_WCN6855:
956e0c1278aSNeil Armstrong 	case QCA_WCN7850:
957590deccfSBalakrishna Godavarthi 		err = qca_disable_soc_logging(hdev);
958590deccfSBalakrishna Godavarthi 		if (err < 0)
959590deccfSBalakrishna Godavarthi 			return err;
960691d54d0SNeil Armstrong 		break;
961691d54d0SNeil Armstrong 	default:
962691d54d0SNeil Armstrong 		break;
963590deccfSBalakrishna Godavarthi 	}
964590deccfSBalakrishna Godavarthi 
965d8f97da1SVenkata Lakshmi Narayana Gubba 	/* WCN399x and WCN6750 supports the Microsoft vendor extension with 0xFD70 as the
966eaf19b0cSMiao-chen Chou 	 * VsMsftOpCode.
967eaf19b0cSMiao-chen Chou 	 */
968eaf19b0cSMiao-chen Chou 	switch (soc_type) {
969691d54d0SNeil Armstrong 	case QCA_WCN3988:
970eaf19b0cSMiao-chen Chou 	case QCA_WCN3990:
971eaf19b0cSMiao-chen Chou 	case QCA_WCN3991:
972eaf19b0cSMiao-chen Chou 	case QCA_WCN3998:
973d8f97da1SVenkata Lakshmi Narayana Gubba 	case QCA_WCN6750:
974eaf19b0cSMiao-chen Chou 		hci_set_msft_opcode(hdev, 0xFD70);
975eaf19b0cSMiao-chen Chou 		break;
976eaf19b0cSMiao-chen Chou 	default:
977eaf19b0cSMiao-chen Chou 		break;
978eaf19b0cSMiao-chen Chou 	}
979eaf19b0cSMiao-chen Chou 
98083e81961SBen Young Tae Kim 	/* Perform HCI reset */
981ba493d4fSBalakrishna Godavarthi 	err = qca_send_reset(hdev);
98283e81961SBen Young Tae Kim 	if (err < 0) {
983ba493d4fSBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Failed to run HCI_RESET (%d)", err);
98483e81961SBen Young Tae Kim 		return err;
98583e81961SBen Young Tae Kim 	}
98683e81961SBen Young Tae Kim 
987095327feSSteev Klimaszewski 	switch (soc_type) {
988095327feSSteev Klimaszewski 	case QCA_WCN3991:
989095327feSSteev Klimaszewski 	case QCA_WCN6750:
990095327feSSteev Klimaszewski 	case QCA_WCN6855:
991e0c1278aSNeil Armstrong 	case QCA_WCN7850:
992c0187b0bSVenkata Lakshmi Narayana Gubba 		/* get fw build info */
993c0187b0bSVenkata Lakshmi Narayana Gubba 		err = qca_read_fw_build_info(hdev);
994c0187b0bSVenkata Lakshmi Narayana Gubba 		if (err < 0)
995c0187b0bSVenkata Lakshmi Narayana Gubba 			return err;
996095327feSSteev Klimaszewski 		break;
997095327feSSteev Klimaszewski 	default:
998095327feSSteev Klimaszewski 		break;
999c0187b0bSVenkata Lakshmi Narayana Gubba 	}
1000c0187b0bSVenkata Lakshmi Narayana Gubba 
10019d23305fSJohan Hovold 	err = qca_check_bdaddr(hdev, &config);
10023019a9d3SJohan Hovold 	if (err)
10033019a9d3SJohan Hovold 		return err;
10043019a9d3SJohan Hovold 
1005ba493d4fSBalakrishna Godavarthi 	bt_dev_info(hdev, "QCA setup on UART is completed");
100683e81961SBen Young Tae Kim 
100783e81961SBen Young Tae Kim 	return 0;
100883e81961SBen Young Tae Kim }
1009ba493d4fSBalakrishna Godavarthi EXPORT_SYMBOL_GPL(qca_uart_setup);
101083e81961SBen Young Tae Kim 
qca_set_bdaddr(struct hci_dev * hdev,const bdaddr_t * bdaddr)10115c0a1001SBalakrishna Godavarthi int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
10125c0a1001SBalakrishna Godavarthi {
10131622e563SJohan Hovold 	bdaddr_t bdaddr_swapped;
10145c0a1001SBalakrishna Godavarthi 	struct sk_buff *skb;
10155c0a1001SBalakrishna Godavarthi 	int err;
10165c0a1001SBalakrishna Godavarthi 
10171622e563SJohan Hovold 	baswap(&bdaddr_swapped, bdaddr);
10181622e563SJohan Hovold 
10191622e563SJohan Hovold 	skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6,
10201622e563SJohan Hovold 				&bdaddr_swapped, HCI_EV_VENDOR,
10211622e563SJohan Hovold 				HCI_INIT_TIMEOUT);
10225c0a1001SBalakrishna Godavarthi 	if (IS_ERR(skb)) {
10235c0a1001SBalakrishna Godavarthi 		err = PTR_ERR(skb);
10245c0a1001SBalakrishna Godavarthi 		bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err);
10255c0a1001SBalakrishna Godavarthi 		return err;
10265c0a1001SBalakrishna Godavarthi 	}
10275c0a1001SBalakrishna Godavarthi 
10285c0a1001SBalakrishna Godavarthi 	kfree_skb(skb);
10295c0a1001SBalakrishna Godavarthi 
10305c0a1001SBalakrishna Godavarthi 	return 0;
10315c0a1001SBalakrishna Godavarthi }
10325c0a1001SBalakrishna Godavarthi EXPORT_SYMBOL_GPL(qca_set_bdaddr);
10335c0a1001SBalakrishna Godavarthi 
1034523760b7SHarish Bandi 
103583e81961SBen Young Tae Kim MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>");
103683e81961SBen Young Tae Kim MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION);
103783e81961SBen Young Tae Kim MODULE_VERSION(VERSION);
103883e81961SBen Young Tae Kim MODULE_LICENSE("GPL");
1039