18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Bluetooth supports for Qualcomm Atheros chips 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2015 The Linux Foundation. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/firmware.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 118c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "btqca.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define VERSION "0.1" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ciint qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version, 188c2ecf20Sopenharmony_ci enum qca_btsoc_type soc_type) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci struct sk_buff *skb; 218c2ecf20Sopenharmony_ci struct edl_event_hdr *edl; 228c2ecf20Sopenharmony_ci struct qca_btsoc_version *ver; 238c2ecf20Sopenharmony_ci char cmd; 248c2ecf20Sopenharmony_ci int err = 0; 258c2ecf20Sopenharmony_ci u8 event_type = HCI_EV_VENDOR; 268c2ecf20Sopenharmony_ci u8 rlen = sizeof(*edl) + sizeof(*ver); 278c2ecf20Sopenharmony_ci u8 rtype = EDL_APP_VER_RES_EVT; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci bt_dev_dbg(hdev, "QCA Version Request"); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci /* Unlike other SoC's sending version command response as payload to 328c2ecf20Sopenharmony_ci * VSE event. WCN3991 sends version command response as a payload to 338c2ecf20Sopenharmony_ci * command complete event. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci if (soc_type >= QCA_WCN3991) { 368c2ecf20Sopenharmony_ci event_type = 0; 378c2ecf20Sopenharmony_ci rlen += 1; 388c2ecf20Sopenharmony_ci rtype = EDL_PATCH_VER_REQ_CMD; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci cmd = EDL_PATCH_VER_REQ_CMD; 428c2ecf20Sopenharmony_ci skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN, 438c2ecf20Sopenharmony_ci &cmd, event_type, HCI_INIT_TIMEOUT); 448c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 458c2ecf20Sopenharmony_ci err = PTR_ERR(skb); 468c2ecf20Sopenharmony_ci bt_dev_err(hdev, "Reading QCA version information failed (%d)", 478c2ecf20Sopenharmony_ci err); 488c2ecf20Sopenharmony_ci return err; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (skb->len != rlen) { 528c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Version size mismatch len %d", skb->len); 538c2ecf20Sopenharmony_ci err = -EILSEQ; 548c2ecf20Sopenharmony_ci goto out; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci edl = (struct edl_event_hdr *)(skb->data); 588c2ecf20Sopenharmony_ci if (!edl) { 598c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA TLV with no header"); 608c2ecf20Sopenharmony_ci err = -EILSEQ; 618c2ecf20Sopenharmony_ci goto out; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (edl->cresp != EDL_CMD_REQ_RES_EVT || 658c2ecf20Sopenharmony_ci edl->rtype != rtype) { 668c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp, 678c2ecf20Sopenharmony_ci edl->rtype); 688c2ecf20Sopenharmony_ci err = -EIO; 698c2ecf20Sopenharmony_ci goto out; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (soc_type >= QCA_WCN3991) 738c2ecf20Sopenharmony_ci memmove(&edl->data, &edl->data[1], sizeof(*ver)); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci ver = (struct qca_btsoc_version *)(edl->data); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci bt_dev_info(hdev, "QCA Product ID :0x%08x", 788c2ecf20Sopenharmony_ci le32_to_cpu(ver->product_id)); 798c2ecf20Sopenharmony_ci bt_dev_info(hdev, "QCA SOC Version :0x%08x", 808c2ecf20Sopenharmony_ci le32_to_cpu(ver->soc_id)); 818c2ecf20Sopenharmony_ci bt_dev_info(hdev, "QCA ROM Version :0x%08x", 828c2ecf20Sopenharmony_ci le16_to_cpu(ver->rom_ver)); 838c2ecf20Sopenharmony_ci bt_dev_info(hdev, "QCA Patch Version:0x%08x", 848c2ecf20Sopenharmony_ci le16_to_cpu(ver->patch_ver)); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* QCA chipset version can be decided by patch and SoC 878c2ecf20Sopenharmony_ci * version, combination with upper 2 bytes from SoC 888c2ecf20Sopenharmony_ci * and lower 2 bytes from patch will be used. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci *soc_version = (le32_to_cpu(ver->soc_id) << 16) | 918c2ecf20Sopenharmony_ci (le16_to_cpu(ver->rom_ver) & 0x0000ffff); 928c2ecf20Sopenharmony_ci if (*soc_version == 0) 938c2ecf20Sopenharmony_ci err = -EILSEQ; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ciout: 968c2ecf20Sopenharmony_ci kfree_skb(skb); 978c2ecf20Sopenharmony_ci if (err) 988c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Failed to get version (%d)", err); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return err; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qca_read_soc_version); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int qca_send_reset(struct hci_dev *hdev) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct sk_buff *skb; 1078c2ecf20Sopenharmony_ci int err; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci bt_dev_dbg(hdev, "QCA HCI_RESET"); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); 1128c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 1138c2ecf20Sopenharmony_ci err = PTR_ERR(skb); 1148c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Reset failed (%d)", err); 1158c2ecf20Sopenharmony_ci return err; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci kfree_skb(skb); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciint qca_send_pre_shutdown_cmd(struct hci_dev *hdev) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct sk_buff *skb; 1268c2ecf20Sopenharmony_ci int err; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci bt_dev_dbg(hdev, "QCA pre shutdown cmd"); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci skb = __hci_cmd_sync_ev(hdev, QCA_PRE_SHUTDOWN_CMD, 0, 1318c2ecf20Sopenharmony_ci NULL, HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 1348c2ecf20Sopenharmony_ci err = PTR_ERR(skb); 1358c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA preshutdown_cmd failed (%d)", err); 1368c2ecf20Sopenharmony_ci return err; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci kfree_skb(skb); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void qca_tlv_check_data(struct qca_fw_config *config, 1468c2ecf20Sopenharmony_ci u8 *fw_data, enum qca_btsoc_type soc_type) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci const u8 *data; 1498c2ecf20Sopenharmony_ci u32 type_len; 1508c2ecf20Sopenharmony_ci u16 tag_id, tag_len; 1518c2ecf20Sopenharmony_ci int idx, length; 1528c2ecf20Sopenharmony_ci struct tlv_type_hdr *tlv; 1538c2ecf20Sopenharmony_ci struct tlv_type_patch *tlv_patch; 1548c2ecf20Sopenharmony_ci struct tlv_type_nvm *tlv_nvm; 1558c2ecf20Sopenharmony_ci uint8_t nvm_baud_rate = config->user_baud_rate; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci tlv = (struct tlv_type_hdr *)fw_data; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci type_len = le32_to_cpu(tlv->type_len); 1608c2ecf20Sopenharmony_ci length = (type_len >> 8) & 0x00ffffff; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff); 1638c2ecf20Sopenharmony_ci BT_DBG("Length\t\t : %d bytes", length); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci config->dnld_mode = QCA_SKIP_EVT_NONE; 1668c2ecf20Sopenharmony_ci config->dnld_type = QCA_SKIP_EVT_NONE; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci switch (config->type) { 1698c2ecf20Sopenharmony_ci case TLV_TYPE_PATCH: 1708c2ecf20Sopenharmony_ci tlv_patch = (struct tlv_type_patch *)tlv->data; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* For Rome version 1.1 to 3.1, all segment commands 1738c2ecf20Sopenharmony_ci * are acked by a vendor specific event (VSE). 1748c2ecf20Sopenharmony_ci * For Rome >= 3.2, the download mode field indicates 1758c2ecf20Sopenharmony_ci * if VSE is skipped by the controller. 1768c2ecf20Sopenharmony_ci * In case VSE is skipped, only the last segment is acked. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci config->dnld_mode = tlv_patch->download_mode; 1798c2ecf20Sopenharmony_ci config->dnld_type = config->dnld_mode; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci BT_DBG("Total Length : %d bytes", 1828c2ecf20Sopenharmony_ci le32_to_cpu(tlv_patch->total_size)); 1838c2ecf20Sopenharmony_ci BT_DBG("Patch Data Length : %d bytes", 1848c2ecf20Sopenharmony_ci le32_to_cpu(tlv_patch->data_length)); 1858c2ecf20Sopenharmony_ci BT_DBG("Signing Format Version : 0x%x", 1868c2ecf20Sopenharmony_ci tlv_patch->format_version); 1878c2ecf20Sopenharmony_ci BT_DBG("Signature Algorithm : 0x%x", 1888c2ecf20Sopenharmony_ci tlv_patch->signature); 1898c2ecf20Sopenharmony_ci BT_DBG("Download mode : 0x%x", 1908c2ecf20Sopenharmony_ci tlv_patch->download_mode); 1918c2ecf20Sopenharmony_ci BT_DBG("Reserved : 0x%x", 1928c2ecf20Sopenharmony_ci tlv_patch->reserved1); 1938c2ecf20Sopenharmony_ci BT_DBG("Product ID : 0x%04x", 1948c2ecf20Sopenharmony_ci le16_to_cpu(tlv_patch->product_id)); 1958c2ecf20Sopenharmony_ci BT_DBG("Rom Build Version : 0x%04x", 1968c2ecf20Sopenharmony_ci le16_to_cpu(tlv_patch->rom_build)); 1978c2ecf20Sopenharmony_ci BT_DBG("Patch Version : 0x%04x", 1988c2ecf20Sopenharmony_ci le16_to_cpu(tlv_patch->patch_version)); 1998c2ecf20Sopenharmony_ci BT_DBG("Reserved : 0x%x", 2008c2ecf20Sopenharmony_ci le16_to_cpu(tlv_patch->reserved2)); 2018c2ecf20Sopenharmony_ci BT_DBG("Patch Entry Address : 0x%x", 2028c2ecf20Sopenharmony_ci le32_to_cpu(tlv_patch->entry)); 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci case TLV_TYPE_NVM: 2068c2ecf20Sopenharmony_ci idx = 0; 2078c2ecf20Sopenharmony_ci data = tlv->data; 2088c2ecf20Sopenharmony_ci while (idx < length) { 2098c2ecf20Sopenharmony_ci tlv_nvm = (struct tlv_type_nvm *)(data + idx); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci tag_id = le16_to_cpu(tlv_nvm->tag_id); 2128c2ecf20Sopenharmony_ci tag_len = le16_to_cpu(tlv_nvm->tag_len); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* Update NVM tags as needed */ 2158c2ecf20Sopenharmony_ci switch (tag_id) { 2168c2ecf20Sopenharmony_ci case EDL_TAG_ID_HCI: 2178c2ecf20Sopenharmony_ci /* HCI transport layer parameters 2188c2ecf20Sopenharmony_ci * enabling software inband sleep 2198c2ecf20Sopenharmony_ci * onto controller side. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci tlv_nvm->data[0] |= 0x80; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* UART Baud Rate */ 2248c2ecf20Sopenharmony_ci if (soc_type >= QCA_WCN3991) 2258c2ecf20Sopenharmony_ci tlv_nvm->data[1] = nvm_baud_rate; 2268c2ecf20Sopenharmony_ci else 2278c2ecf20Sopenharmony_ci tlv_nvm->data[2] = nvm_baud_rate; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci case EDL_TAG_ID_DEEP_SLEEP: 2328c2ecf20Sopenharmony_ci /* Sleep enable mask 2338c2ecf20Sopenharmony_ci * enabling deep sleep feature on controller. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci tlv_nvm->data[0] |= 0x01; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci default: 2458c2ecf20Sopenharmony_ci BT_ERR("Unknown TLV type %d", config->type); 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size, 2518c2ecf20Sopenharmony_ci const u8 *data, enum qca_tlv_dnld_mode mode, 2528c2ecf20Sopenharmony_ci enum qca_btsoc_type soc_type) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct sk_buff *skb; 2558c2ecf20Sopenharmony_ci struct edl_event_hdr *edl; 2568c2ecf20Sopenharmony_ci struct tlv_seg_resp *tlv_resp; 2578c2ecf20Sopenharmony_ci u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2]; 2588c2ecf20Sopenharmony_ci int err = 0; 2598c2ecf20Sopenharmony_ci u8 event_type = HCI_EV_VENDOR; 2608c2ecf20Sopenharmony_ci u8 rlen = (sizeof(*edl) + sizeof(*tlv_resp)); 2618c2ecf20Sopenharmony_ci u8 rtype = EDL_TVL_DNLD_RES_EVT; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci cmd[0] = EDL_PATCH_TLV_REQ_CMD; 2648c2ecf20Sopenharmony_ci cmd[1] = seg_size; 2658c2ecf20Sopenharmony_ci memcpy(cmd + 2, data, seg_size); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (mode == QCA_SKIP_EVT_VSE_CC || mode == QCA_SKIP_EVT_VSE) 2688c2ecf20Sopenharmony_ci return __hci_cmd_send(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, 2698c2ecf20Sopenharmony_ci cmd); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Unlike other SoC's sending version command response as payload to 2728c2ecf20Sopenharmony_ci * VSE event. WCN3991 sends version command response as a payload to 2738c2ecf20Sopenharmony_ci * command complete event. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci if (soc_type >= QCA_WCN3991) { 2768c2ecf20Sopenharmony_ci event_type = 0; 2778c2ecf20Sopenharmony_ci rlen = sizeof(*edl); 2788c2ecf20Sopenharmony_ci rtype = EDL_PATCH_TLV_REQ_CMD; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd, 2828c2ecf20Sopenharmony_ci event_type, HCI_INIT_TIMEOUT); 2838c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 2848c2ecf20Sopenharmony_ci err = PTR_ERR(skb); 2858c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Failed to send TLV segment (%d)", err); 2868c2ecf20Sopenharmony_ci return err; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (skb->len != rlen) { 2908c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA TLV response size mismatch"); 2918c2ecf20Sopenharmony_ci err = -EILSEQ; 2928c2ecf20Sopenharmony_ci goto out; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci edl = (struct edl_event_hdr *)(skb->data); 2968c2ecf20Sopenharmony_ci if (!edl) { 2978c2ecf20Sopenharmony_ci bt_dev_err(hdev, "TLV with no header"); 2988c2ecf20Sopenharmony_ci err = -EILSEQ; 2998c2ecf20Sopenharmony_ci goto out; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != rtype) { 3038c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x", 3048c2ecf20Sopenharmony_ci edl->cresp, edl->rtype); 3058c2ecf20Sopenharmony_ci err = -EIO; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (soc_type >= QCA_WCN3991) 3098c2ecf20Sopenharmony_ci goto out; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci tlv_resp = (struct tlv_seg_resp *)(edl->data); 3128c2ecf20Sopenharmony_ci if (tlv_resp->result) { 3138c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x (0x%x)", 3148c2ecf20Sopenharmony_ci edl->cresp, edl->rtype, tlv_resp->result); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ciout: 3188c2ecf20Sopenharmony_ci kfree_skb(skb); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return err; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int qca_inject_cmd_complete_event(struct hci_dev *hdev) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct hci_event_hdr *hdr; 3268c2ecf20Sopenharmony_ci struct hci_ev_cmd_complete *evt; 3278c2ecf20Sopenharmony_ci struct sk_buff *skb; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL); 3308c2ecf20Sopenharmony_ci if (!skb) 3318c2ecf20Sopenharmony_ci return -ENOMEM; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci hdr = skb_put(skb, sizeof(*hdr)); 3348c2ecf20Sopenharmony_ci hdr->evt = HCI_EV_CMD_COMPLETE; 3358c2ecf20Sopenharmony_ci hdr->plen = sizeof(*evt) + 1; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci evt = skb_put(skb, sizeof(*evt)); 3388c2ecf20Sopenharmony_ci evt->ncmd = 1; 3398c2ecf20Sopenharmony_ci evt->opcode = cpu_to_le16(QCA_HCI_CC_OPCODE); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci skb_put_u8(skb, QCA_HCI_CC_SUCCESS); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) = HCI_EVENT_PKT; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return hci_recv_frame(hdev, skb); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int qca_download_firmware(struct hci_dev *hdev, 3498c2ecf20Sopenharmony_ci struct qca_fw_config *config, 3508c2ecf20Sopenharmony_ci enum qca_btsoc_type soc_type) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci const struct firmware *fw; 3538c2ecf20Sopenharmony_ci u8 *data; 3548c2ecf20Sopenharmony_ci const u8 *segment; 3558c2ecf20Sopenharmony_ci int ret, size, remain, i = 0; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci bt_dev_info(hdev, "QCA Downloading %s", config->fwname); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci ret = request_firmware(&fw, config->fwname, &hdev->dev); 3608c2ecf20Sopenharmony_ci if (ret) { 3618c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Failed to request file: %s (%d)", 3628c2ecf20Sopenharmony_ci config->fwname, ret); 3638c2ecf20Sopenharmony_ci return ret; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci size = fw->size; 3678c2ecf20Sopenharmony_ci data = vmalloc(fw->size); 3688c2ecf20Sopenharmony_ci if (!data) { 3698c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Failed to allocate memory for file: %s", 3708c2ecf20Sopenharmony_ci config->fwname); 3718c2ecf20Sopenharmony_ci release_firmware(fw); 3728c2ecf20Sopenharmony_ci return -ENOMEM; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci memcpy(data, fw->data, size); 3768c2ecf20Sopenharmony_ci release_firmware(fw); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci qca_tlv_check_data(config, data, soc_type); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci segment = data; 3818c2ecf20Sopenharmony_ci remain = size; 3828c2ecf20Sopenharmony_ci while (remain > 0) { 3838c2ecf20Sopenharmony_ci int segsize = min(MAX_SIZE_PER_TLV_SEGMENT, remain); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci bt_dev_dbg(hdev, "Send segment %d, size %d", i++, segsize); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci remain -= segsize; 3888c2ecf20Sopenharmony_ci /* The last segment is always acked regardless download mode */ 3898c2ecf20Sopenharmony_ci if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT) 3908c2ecf20Sopenharmony_ci config->dnld_mode = QCA_SKIP_EVT_NONE; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci ret = qca_tlv_send_segment(hdev, segsize, segment, 3938c2ecf20Sopenharmony_ci config->dnld_mode, soc_type); 3948c2ecf20Sopenharmony_ci if (ret) 3958c2ecf20Sopenharmony_ci goto out; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci segment += segsize; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* Latest qualcomm chipsets are not sending a command complete event 4018c2ecf20Sopenharmony_ci * for every fw packet sent. They only respond with a vendor specific 4028c2ecf20Sopenharmony_ci * event for the last packet. This optimization in the chip will 4038c2ecf20Sopenharmony_ci * decrease the BT in initialization time. Here we will inject a command 4048c2ecf20Sopenharmony_ci * complete event to avoid a command timeout error message. 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_ci if (config->dnld_type == QCA_SKIP_EVT_VSE_CC || 4078c2ecf20Sopenharmony_ci config->dnld_type == QCA_SKIP_EVT_VSE) 4088c2ecf20Sopenharmony_ci ret = qca_inject_cmd_complete_event(hdev); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ciout: 4118c2ecf20Sopenharmony_ci vfree(data); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return ret; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int qca_disable_soc_logging(struct hci_dev *hdev) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct sk_buff *skb; 4198c2ecf20Sopenharmony_ci u8 cmd[2]; 4208c2ecf20Sopenharmony_ci int err; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci cmd[0] = QCA_DISABLE_LOGGING_SUB_OP; 4238c2ecf20Sopenharmony_ci cmd[1] = 0x00; 4248c2ecf20Sopenharmony_ci skb = __hci_cmd_sync_ev(hdev, QCA_DISABLE_LOGGING, sizeof(cmd), cmd, 4258c2ecf20Sopenharmony_ci HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT); 4268c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 4278c2ecf20Sopenharmony_ci err = PTR_ERR(skb); 4288c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Failed to disable soc logging(%d)", err); 4298c2ecf20Sopenharmony_ci return err; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci kfree_skb(skb); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ciint qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct sk_buff *skb; 4408c2ecf20Sopenharmony_ci u8 cmd[9]; 4418c2ecf20Sopenharmony_ci int err; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD; 4448c2ecf20Sopenharmony_ci cmd[1] = 0x02; /* TAG ID */ 4458c2ecf20Sopenharmony_ci cmd[2] = sizeof(bdaddr_t); /* size */ 4468c2ecf20Sopenharmony_ci memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t)); 4478c2ecf20Sopenharmony_ci skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd, 4488c2ecf20Sopenharmony_ci HCI_EV_VENDOR, HCI_INIT_TIMEOUT); 4498c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 4508c2ecf20Sopenharmony_ci err = PTR_ERR(skb); 4518c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Change address command failed (%d)", err); 4528c2ecf20Sopenharmony_ci return err; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci kfree_skb(skb); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qca_set_bdaddr_rome); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ciint qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, 4628c2ecf20Sopenharmony_ci enum qca_btsoc_type soc_type, u32 soc_ver, 4638c2ecf20Sopenharmony_ci const char *firmware_name) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct qca_fw_config config; 4668c2ecf20Sopenharmony_ci int err; 4678c2ecf20Sopenharmony_ci u8 rom_ver = 0; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci bt_dev_dbg(hdev, "QCA setup on UART"); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci config.user_baud_rate = baudrate; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* Download rampatch file */ 4748c2ecf20Sopenharmony_ci config.type = TLV_TYPE_PATCH; 4758c2ecf20Sopenharmony_ci if (qca_is_wcn399x(soc_type)) { 4768c2ecf20Sopenharmony_ci /* Firmware files to download are based on ROM version. 4778c2ecf20Sopenharmony_ci * ROM version is derived from last two bytes of soc_ver. 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | 4808c2ecf20Sopenharmony_ci (soc_ver & 0x0000000f); 4818c2ecf20Sopenharmony_ci snprintf(config.fwname, sizeof(config.fwname), 4828c2ecf20Sopenharmony_ci "qca/crbtfw%02x.tlv", rom_ver); 4838c2ecf20Sopenharmony_ci } else if (soc_type == QCA_QCA6390) { 4848c2ecf20Sopenharmony_ci rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | 4858c2ecf20Sopenharmony_ci (soc_ver & 0x0000000f); 4868c2ecf20Sopenharmony_ci snprintf(config.fwname, sizeof(config.fwname), 4878c2ecf20Sopenharmony_ci "qca/htbtfw%02x.tlv", rom_ver); 4888c2ecf20Sopenharmony_ci } else { 4898c2ecf20Sopenharmony_ci snprintf(config.fwname, sizeof(config.fwname), 4908c2ecf20Sopenharmony_ci "qca/rampatch_%08x.bin", soc_ver); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci err = qca_download_firmware(hdev, &config, soc_type); 4948c2ecf20Sopenharmony_ci if (err < 0) { 4958c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Failed to download patch (%d)", err); 4968c2ecf20Sopenharmony_ci return err; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* Give the controller some time to get ready to receive the NVM */ 5008c2ecf20Sopenharmony_ci msleep(10); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Download NVM configuration */ 5038c2ecf20Sopenharmony_ci config.type = TLV_TYPE_NVM; 5048c2ecf20Sopenharmony_ci if (firmware_name) 5058c2ecf20Sopenharmony_ci snprintf(config.fwname, sizeof(config.fwname), 5068c2ecf20Sopenharmony_ci "qca/%s", firmware_name); 5078c2ecf20Sopenharmony_ci else if (qca_is_wcn399x(soc_type)) 5088c2ecf20Sopenharmony_ci snprintf(config.fwname, sizeof(config.fwname), 5098c2ecf20Sopenharmony_ci "qca/crnv%02x.bin", rom_ver); 5108c2ecf20Sopenharmony_ci else if (soc_type == QCA_QCA6390) 5118c2ecf20Sopenharmony_ci snprintf(config.fwname, sizeof(config.fwname), 5128c2ecf20Sopenharmony_ci "qca/htnv%02x.bin", rom_ver); 5138c2ecf20Sopenharmony_ci else 5148c2ecf20Sopenharmony_ci snprintf(config.fwname, sizeof(config.fwname), 5158c2ecf20Sopenharmony_ci "qca/nvm_%08x.bin", soc_ver); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci err = qca_download_firmware(hdev, &config, soc_type); 5188c2ecf20Sopenharmony_ci if (err < 0) { 5198c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err); 5208c2ecf20Sopenharmony_ci return err; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (soc_type >= QCA_WCN3991) { 5248c2ecf20Sopenharmony_ci err = qca_disable_soc_logging(hdev); 5258c2ecf20Sopenharmony_ci if (err < 0) 5268c2ecf20Sopenharmony_ci return err; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* Perform HCI reset */ 5308c2ecf20Sopenharmony_ci err = qca_send_reset(hdev); 5318c2ecf20Sopenharmony_ci if (err < 0) { 5328c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Failed to run HCI_RESET (%d)", err); 5338c2ecf20Sopenharmony_ci return err; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci bt_dev_info(hdev, "QCA setup on UART is completed"); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci return 0; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qca_uart_setup); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ciint qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct sk_buff *skb; 5458c2ecf20Sopenharmony_ci int err; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6, bdaddr, 5488c2ecf20Sopenharmony_ci HCI_EV_VENDOR, HCI_INIT_TIMEOUT); 5498c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 5508c2ecf20Sopenharmony_ci err = PTR_ERR(skb); 5518c2ecf20Sopenharmony_ci bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err); 5528c2ecf20Sopenharmony_ci return err; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci kfree_skb(skb); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qca_set_bdaddr); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>"); 5638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION); 5648c2ecf20Sopenharmony_ciMODULE_VERSION(VERSION); 5658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 566