// SPDX-License-Identifier: ISC/* Copyright (C) 2021 MediaTek Inc. * */#include <linux/module.h>#include <linux/firmware.h>#include <linux/usb.h>#include <linux/iopoll.h>#include <linux/unaligned.h> #include <net/bluetooth/bluetooth.h>#include <net/bluetooth/hci_core.h> #include "btmtk.h" #define VERSION "0.1" /* It is for mt79xx download rom patch*/#define MTK_FW_ROM_PATCH_HEADER_SIZE 32#define MTK_FW_ROM_PATCH_GD_SIZE 64#define MTK_FW_ROM_PATCH_SEC_MAP_SIZE 64#define MTK_SEC_MAP_COMMON_SIZE 12#define MTK_SEC_MAP_NEED_SEND_SIZE 52 /* It is for mt79xx iso data transmission setting */#define MTK_ISO_THRESHOLD 264 struct btmtk_patch_header { u8 datetime[16]; u8 platform[4]; __le16 hwver; __le16 swver; __le32 magicnum;} __packed; struct btmtk_global_desc { __le32 patch_ver; __le32 sub_sys; __le32 feature_opt; __le32 section_num;} __packed; struct btmtk_section_map { __le32 sectype; __le32 secoffset; __le32 secsize; union { __le32 u4SecSpec[13]; struct { __le32 dlAddr; __le32 dlsize; __le32 seckeyidx; __le32 alignlen; __le32 sectype; __le32 dlmodecrctype; __le32 crc; __le32 reserved[6]; } bin_info_spec; };} __packed; static void btmtk_coredump(struct hci_dev *hdev){ int err; err = __hci_cmd_send(hdev, 0xfd5b, 0, NULL); if (err < 0) bt_dev_err(hdev, "Coredump failed (%d)", err);} static void btmtk_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb){ struct btmtk_data *data = hci_get_priv(hdev); char buf[80]; snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n", data->dev_id); skb_put_data(skb, buf, strlen(buf)); snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n", data->cd_info.fw_version); skb_put_data(skb, buf, strlen(buf)); snprintf(buf, sizeof(buf), "Driver: %s\n", data->cd_info.driver_name); skb_put_data(skb, buf, strlen(buf)); snprintf(buf, sizeof(buf), "Vendor: MediaTek\n"); skb_put_data(skb, buf, strlen(buf));} static void btmtk_coredump_notify(struct hci_dev *hdev, int state){ struct btmtk_data *data = hci_get_priv(hdev); switch (state) { case HCI_DEVCOREDUMP_IDLE: data->cd_info.state = HCI_DEVCOREDUMP_IDLE; break; case HCI_DEVCOREDUMP_ACTIVE: data->cd_info.state = HCI_DEVCOREDUMP_ACTIVE; break; case HCI_DEVCOREDUMP_TIMEOUT: case HCI_DEVCOREDUMP_ABORT: case HCI_DEVCOREDUMP_DONE: data->cd_info.state = HCI_DEVCOREDUMP_IDLE; btmtk_reset_sync(hdev); break; }} void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver, u32 fw_flavor){ if (dev_id == 0x6639) snprintf(buf, size, "mediatek/mt7927/BT_RAM_CODE_MT%04x_2_%x_hdr.bin", dev_id & 0xffff, (fw_ver & 0xff) + 1); else if (dev_id == 0x7925) snprintf(buf, size, "mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin", dev_id & 0xffff, dev_id & 0xffff, (fw_ver & 0xff) + 1); else if (dev_id == 0x7961 && fw_flavor) snprintf(buf, size, "mediatek/BT_RAM_CODE_MT%04x_1a_%x_hdr.bin", dev_id & 0xffff, (fw_ver & 0xff) + 1); else snprintf(buf, size, "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin", dev_id & 0xffff, (fw_ver & 0xff) + 1);}EXPORT_SYMBOL_GPL(btmtk_fw_get_filename); int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, wmt_cmd_sync_func_t wmt_cmd_sync, u32 dev_id){ struct btmtk_hci_wmt_params wmt_params; struct btmtk_patch_header *hdr; struct btmtk_global_desc *globaldesc = NULL; struct btmtk_section_map *sectionmap; const struct firmware *fw; const u8 *fw_ptr; const u8 *fw_bin_ptr; int err, dlen, i, status; u8 flag, first_block, retry; u32 section_num, dl_size, section_offset; u8 cmd[64]; err = request_firmware(&fw, fwname, &hdev->dev); if (err < 0) { bt_dev_err(hdev, "Failed to load firmware file (%d)", err); return err; } fw_ptr = fw->data; fw_bin_ptr = fw_ptr; hdr = (struct btmtk_patch_header *)fw_ptr; globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE); section_num = le32_to_cpu(globaldesc->section_num); bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s", le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime); for (i = 0; i < section_num; i++) { first_block = 1; fw_ptr = fw_bin_ptr; sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i); section_offset = le32_to_cpu(sectionmap->secoffset); dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize); /* MT6639: only download sections where dlmode byte0 == 0x01, * matching the Windows driver behavior which skips WiFi/other * sections that would cause the chip to hang. */ if (dev_id == 0x6639 && dl_size > 0 && (le32_to_cpu(sectionmap->bin_info_spec.dlmodecrctype) & 0xff) != 0x01) continue; if (dl_size > 0) { retry = 20; while (retry > 0) { cmd[0] = 0; /* 0 means legacy dl mode. */ memcpy(cmd + 1, fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i + MTK_SEC_MAP_COMMON_SIZE, MTK_SEC_MAP_NEED_SEND_SIZE); wmt_params.op = BTMTK_WMT_PATCH_DWNLD; wmt_params.status = &status; wmt_params.flag = 0; wmt_params.dlen = MTK_SEC_MAP_NEED_SEND_SIZE + 1; wmt_params.data = &cmd; err = wmt_cmd_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", err); goto err_release_fw; } if (status == BTMTK_WMT_PATCH_UNDONE) { break; } else if (status == BTMTK_WMT_PATCH_PROGRESS) { msleep(100); retry--; } else if (status == BTMTK_WMT_PATCH_DONE) { goto next_section; } else { bt_dev_err(hdev, "Failed wmt patch dwnld status (%d)", status); err = -EIO; goto err_release_fw; } } /* If retry exhausted goto err_release_fw */ if (retry == 0) { err = -EIO; goto err_release_fw; } fw_ptr += section_offset; wmt_params.op = BTMTK_WMT_PATCH_DWNLD; while (dl_size > 0) { dlen = min_t(int, 250, dl_size); if (first_block == 1) { flag = 1; first_block = 0; } else if (dl_size - dlen <= 0) { flag = 3; } else { flag = 2; } wmt_params.flag = flag; wmt_params.dlen = dlen; wmt_params.data = fw_ptr; err = wmt_cmd_sync(hdev, &wmt_params); /* Status BTMTK_WMT_PATCH_PROGRESS indicates firmware is * in process of being downloaded, which is not expected to * occur here. */ if (status == BTMTK_WMT_PATCH_PROGRESS) { err = -EIO; goto err_release_fw; } else if (err < 0) { bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", err); goto err_release_fw; } dl_size -= dlen; fw_ptr += dlen; } }next_section: continue; } /* Wait a few moments for firmware activation done */ usleep_range(100000, 120000); err_release_fw: release_firmware(fw); return err;}EXPORT_SYMBOL_GPL(btmtk_setup_firmware_79xx); int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname, wmt_cmd_sync_func_t wmt_cmd_sync){ struct btmtk_hci_wmt_params wmt_params; const struct firmware *fw; const u8 *fw_ptr; size_t fw_size; int err, dlen; u8 flag, param; err = request_firmware(&fw, fwname, &hdev->dev); if (err < 0) { bt_dev_err(hdev, "Failed to load firmware file (%d)", err); return err; } /* Power on data RAM the firmware relies on. */ param = 1; wmt_params.op = BTMTK_WMT_FUNC_CTRL; wmt_params.flag = 3; wmt_params.dlen = sizeof(param); wmt_params.data = ¶m; wmt_params.status = NULL; err = wmt_cmd_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to power on data RAM (%d)", err); goto err_release_fw; } fw_ptr = fw->data; fw_size = fw->size; /* The size of patch header is 30 bytes, should be skip */ if (fw_size < 30) { err = -EINVAL; goto err_release_fw; } fw_size -= 30; fw_ptr += 30; flag = 1; wmt_params.op = BTMTK_WMT_PATCH_DWNLD; wmt_params.status = NULL; while (fw_size > 0) { dlen = min_t(int, 250, fw_size); /* Tell device the position in sequence */ if (fw_size - dlen <= 0) flag = 3; else if (fw_size < fw->size - 30) flag = 2; wmt_params.flag = flag; wmt_params.dlen = dlen; wmt_params.data = fw_ptr; err = wmt_cmd_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", err); goto err_release_fw; } fw_size -= dlen; fw_ptr += dlen; } wmt_params.op = BTMTK_WMT_RST; wmt_params.flag = 4; wmt_params.dlen = 0; wmt_params.data = NULL; wmt_params.status = NULL; /* Activate function the firmware providing to */ err = wmt_cmd_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt rst (%d)", err); goto err_release_fw; } /* Wait a few moments for firmware activation done */ usleep_range(10000, 12000); err_release_fw: release_firmware(fw); return err;}EXPORT_SYMBOL_GPL(btmtk_setup_firmware); int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr){ struct sk_buff *skb; long ret; skb = __hci_cmd_sync(hdev, 0xfc1a, 6, bdaddr, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); bt_dev_err(hdev, "changing Mediatek device address failed (%ld)", ret); return ret; } kfree_skb(skb); return 0;}EXPORT_SYMBOL_GPL(btmtk_set_bdaddr); void btmtk_reset_sync(struct hci_dev *hdev){ struct btmtk_data *reset_work = hci_get_priv(hdev); int err; hci_dev_lock(hdev); err = hci_cmd_sync_queue(hdev, reset_work->reset_sync, NULL, NULL); if (err) bt_dev_err(hdev, "failed to reset (%d)", err); hci_dev_unlock(hdev);}EXPORT_SYMBOL_GPL(btmtk_reset_sync); int btmtk_register_coredump(struct hci_dev *hdev, const char *name, u32 fw_version){ struct btmtk_data *data = hci_get_priv(hdev); if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) return -EOPNOTSUPP; data->cd_info.fw_version = fw_version; data->cd_info.state = HCI_DEVCOREDUMP_IDLE; data->cd_info.driver_name = name; return hci_devcd_register(hdev, btmtk_coredump, btmtk_coredump_hdr, btmtk_coredump_notify);}EXPORT_SYMBOL_GPL(btmtk_register_coredump); int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb){ struct btmtk_data *data = hci_get_priv(hdev); int err; bool complete = false; if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) { kfree_skb(skb); return 0; } switch (data->cd_info.state) { case HCI_DEVCOREDUMP_IDLE: err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE); if (err < 0) { kfree_skb(skb); break; } data->cd_info.cnt = 0; /* It is supposed coredump can be done within 5 seconds */ schedule_delayed_work(&hdev->dump.dump_timeout, msecs_to_jiffies(5000)); fallthrough; case HCI_DEVCOREDUMP_ACTIVE: default: /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */ if (data->cd_info.cnt >= MTK_COREDUMP_NUM && skb->len > MTK_COREDUMP_END_LEN) if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN], MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) complete = true; err = hci_devcd_append(hdev, skb); if (err < 0) break; data->cd_info.cnt++; if (complete) { bt_dev_info(hdev, "Mediatek coredump end"); hci_devcd_complete(hdev); } break; } return err;}EXPORT_SYMBOL_GPL(btmtk_process_coredump); #if IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK)/* Known MT6639 (MT7927) Bluetooth USB devices. * Used to scope the zero-CHIPID workaround to real MT6639 hardware, * since some boards return 0x0000 from the MMIO chip ID register. */static const struct { u16 vendor; u16 product;} btmtk_mt6639_devs[] = { { 0x0489, 0xe13a }, /* ASUS ROG Crosshair X870E Hero */ { 0x0489, 0xe0fa }, /* Lenovo Legion Pro 7 16ARX9 */ { 0x0489, 0xe10f }, /* Gigabyte Z790 AORUS MASTER X */ { 0x0489, 0xe110 }, /* MSI X870E Ace Max */ { 0x0489, 0xe116 }, /* TP-Link Archer TBE550E */ { 0x13d3, 0x3588 }, /* ASUS ROG STRIX X870E-E */}; static void btmtk_usb_wmt_recv(struct urb *urb){ struct hci_dev *hdev = urb->context; struct btmtk_data *data = hci_get_priv(hdev); struct sk_buff *skb; int err; if (urb->status == 0 && urb->actual_length > 0) { hdev->stat.byte_rx += urb->actual_length; /* WMT event shouldn't be fragmented and the size should be * less than HCI_WMT_MAX_EVENT_SIZE. */ skb = bt_skb_alloc(HCI_WMT_MAX_EVENT_SIZE, GFP_ATOMIC); if (!skb) {Lines 1–500 of 1582. Load more
// SPDX-License-Identifier: ISC /* Copyright (C) 2021 MediaTek Inc. * */ #include <linux/module.h> #include <linux/firmware.h> #include <linux/usb.h> #include <linux/iopoll.h> #include <linux/unaligned.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include "btmtk.h" #define VERSION "0.1" /* It is for mt79xx download rom patch*/ #define MTK_FW_ROM_PATCH_HEADER_SIZE 32 #define MTK_FW_ROM_PATCH_GD_SIZE 64 #define MTK_FW_ROM_PATCH_SEC_MAP_SIZE 64 #define MTK_SEC_MAP_COMMON_SIZE 12 #define MTK_SEC_MAP_NEED_SEND_SIZE 52 /* It is for mt79xx iso data transmission setting */ #define MTK_ISO_THRESHOLD 264 struct btmtk_patch_header { u8 datetime[16]; u8 platform[4]; __le16 hwver; __le16 swver; __le32 magicnum; } __packed; struct btmtk_global_desc { __le32 patch_ver; __le32 sub_sys; __le32 feature_opt; __le32 section_num; } __packed; struct btmtk_section_map { __le32 sectype; __le32 secoffset; __le32 secsize; union { __le32 u4SecSpec[13]; struct { __le32 dlAddr; __le32 dlsize; __le32 seckeyidx; __le32 alignlen; __le32 sectype; __le32 dlmodecrctype; __le32 crc; __le32 reserved[6]; } bin_info_spec; }; } __packed; static void btmtk_coredump(struct hci_dev *hdev) { int err; err = __hci_cmd_send(hdev, 0xfd5b, 0, NULL); if (err < 0) bt_dev_err(hdev, "Coredump failed (%d)", err); } static void btmtk_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb) { struct btmtk_data *data = hci_get_priv(hdev); char buf[80]; snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n", data->dev_id); skb_put_data(skb, buf, strlen(buf)); snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n", data->cd_info.fw_version); skb_put_data(skb, buf, strlen(buf)); snprintf(buf, sizeof(buf), "Driver: %s\n", data->cd_info.driver_name); skb_put_data(skb, buf, strlen(buf)); snprintf(buf, sizeof(buf), "Vendor: MediaTek\n"); skb_put_data(skb, buf, strlen(buf)); } static void btmtk_coredump_notify(struct hci_dev *hdev, int state) { struct btmtk_data *data = hci_get_priv(hdev); switch (state) { case HCI_DEVCOREDUMP_IDLE: data->cd_info.state = HCI_DEVCOREDUMP_IDLE; break; case HCI_DEVCOREDUMP_ACTIVE: data->cd_info.state = HCI_DEVCOREDUMP_ACTIVE; break; case HCI_DEVCOREDUMP_TIMEOUT: case HCI_DEVCOREDUMP_ABORT: case HCI_DEVCOREDUMP_DONE: data->cd_info.state = HCI_DEVCOREDUMP_IDLE; btmtk_reset_sync(hdev); break; } } void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver, u32 fw_flavor) { if (dev_id == 0x6639) snprintf(buf, size, "mediatek/mt7927/BT_RAM_CODE_MT%04x_2_%x_hdr.bin", dev_id & 0xffff, (fw_ver & 0xff) + 1); else if (dev_id == 0x7925) snprintf(buf, size, "mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin", dev_id & 0xffff, dev_id & 0xffff, (fw_ver & 0xff) + 1); else if (dev_id == 0x7961 && fw_flavor) snprintf(buf, size, "mediatek/BT_RAM_CODE_MT%04x_1a_%x_hdr.bin", dev_id & 0xffff, (fw_ver & 0xff) + 1); else snprintf(buf, size, "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin", dev_id & 0xffff, (fw_ver & 0xff) + 1); } EXPORT_SYMBOL_GPL(btmtk_fw_get_filename); int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, wmt_cmd_sync_func_t wmt_cmd_sync, u32 dev_id) { struct btmtk_hci_wmt_params wmt_params; struct btmtk_patch_header *hdr; struct btmtk_global_desc *globaldesc = NULL; struct btmtk_section_map *sectionmap; const struct firmware *fw; const u8 *fw_ptr; const u8 *fw_bin_ptr; int err, dlen, i, status; u8 flag, first_block, retry; u32 section_num, dl_size, section_offset; u8 cmd[64]; err = request_firmware(&fw, fwname, &hdev->dev); if (err < 0) { bt_dev_err(hdev, "Failed to load firmware file (%d)", err); return err; } fw_ptr = fw->data; fw_bin_ptr = fw_ptr; hdr = (struct btmtk_patch_header *)fw_ptr; globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE); section_num = le32_to_cpu(globaldesc->section_num); bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s", le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime); for (i = 0; i < section_num; i++) { first_block = 1; fw_ptr = fw_bin_ptr; sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i); section_offset = le32_to_cpu(sectionmap->secoffset); dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize); /* MT6639: only download sections where dlmode byte0 == 0x01, * matching the Windows driver behavior which skips WiFi/other * sections that would cause the chip to hang. */ if (dev_id == 0x6639 && dl_size > 0 && (le32_to_cpu(sectionmap->bin_info_spec.dlmodecrctype) & 0xff) != 0x01) continue; if (dl_size > 0) { retry = 20; while (retry > 0) { cmd[0] = 0; /* 0 means legacy dl mode. */ memcpy(cmd + 1, fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i + MTK_SEC_MAP_COMMON_SIZE, MTK_SEC_MAP_NEED_SEND_SIZE); wmt_params.op = BTMTK_WMT_PATCH_DWNLD; wmt_params.status = &status; wmt_params.flag = 0; wmt_params.dlen = MTK_SEC_MAP_NEED_SEND_SIZE + 1; wmt_params.data = &cmd; err = wmt_cmd_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", err); goto err_release_fw; } if (status == BTMTK_WMT_PATCH_UNDONE) { break; } else if (status == BTMTK_WMT_PATCH_PROGRESS) { msleep(100); retry--; } else if (status == BTMTK_WMT_PATCH_DONE) { goto next_section; } else { bt_dev_err(hdev, "Failed wmt patch dwnld status (%d)", status); err = -EIO; goto err_release_fw; } } /* If retry exhausted goto err_release_fw */ if (retry == 0) { err = -EIO; goto err_release_fw; } fw_ptr += section_offset; wmt_params.op = BTMTK_WMT_PATCH_DWNLD; while (dl_size > 0) { dlen = min_t(int, 250, dl_size); if (first_block == 1) { flag = 1; first_block = 0; } else if (dl_size - dlen <= 0) { flag = 3; } else { flag = 2; } wmt_params.flag = flag; wmt_params.dlen = dlen; wmt_params.data = fw_ptr; err = wmt_cmd_sync(hdev, &wmt_params); /* Status BTMTK_WMT_PATCH_PROGRESS indicates firmware is * in process of being downloaded, which is not expected to * occur here. */ if (status == BTMTK_WMT_PATCH_PROGRESS) { err = -EIO; goto err_release_fw; } else if (err < 0) { bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", err); goto err_release_fw; } dl_size -= dlen; fw_ptr += dlen; } } next_section: continue; } /* Wait a few moments for firmware activation done */ usleep_range(100000, 120000); err_release_fw: release_firmware(fw); return err; } EXPORT_SYMBOL_GPL(btmtk_setup_firmware_79xx); int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname, wmt_cmd_sync_func_t wmt_cmd_sync) { struct btmtk_hci_wmt_params wmt_params; const struct firmware *fw; const u8 *fw_ptr; size_t fw_size; int err, dlen; u8 flag, param; err = request_firmware(&fw, fwname, &hdev->dev); if (err < 0) { bt_dev_err(hdev, "Failed to load firmware file (%d)", err); return err; } /* Power on data RAM the firmware relies on. */ param = 1; wmt_params.op = BTMTK_WMT_FUNC_CTRL; wmt_params.flag = 3; wmt_params.dlen = sizeof(param); wmt_params.data = ¶m; wmt_params.status = NULL; err = wmt_cmd_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to power on data RAM (%d)", err); goto err_release_fw; } fw_ptr = fw->data; fw_size = fw->size; /* The size of patch header is 30 bytes, should be skip */ if (fw_size < 30) { err = -EINVAL; goto err_release_fw; } fw_size -= 30; fw_ptr += 30; flag = 1; wmt_params.op = BTMTK_WMT_PATCH_DWNLD; wmt_params.status = NULL; while (fw_size > 0) { dlen = min_t(int, 250, fw_size); /* Tell device the position in sequence */ if (fw_size - dlen <= 0) flag = 3; else if (fw_size < fw->size - 30) flag = 2; wmt_params.flag = flag; wmt_params.dlen = dlen; wmt_params.data = fw_ptr; err = wmt_cmd_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", err); goto err_release_fw; } fw_size -= dlen; fw_ptr += dlen; } wmt_params.op = BTMTK_WMT_RST; wmt_params.flag = 4; wmt_params.dlen = 0; wmt_params.data = NULL; wmt_params.status = NULL; /* Activate function the firmware providing to */ err = wmt_cmd_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt rst (%d)", err); goto err_release_fw; } /* Wait a few moments for firmware activation done */ usleep_range(10000, 12000); err_release_fw: release_firmware(fw); return err; } EXPORT_SYMBOL_GPL(btmtk_setup_firmware); int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) { struct sk_buff *skb; long ret; skb = __hci_cmd_sync(hdev, 0xfc1a, 6, bdaddr, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); bt_dev_err(hdev, "changing Mediatek device address failed (%ld)", ret); return ret; } kfree_skb(skb); return 0; } EXPORT_SYMBOL_GPL(btmtk_set_bdaddr); void btmtk_reset_sync(struct hci_dev *hdev) { struct btmtk_data *reset_work = hci_get_priv(hdev); int err; hci_dev_lock(hdev); err = hci_cmd_sync_queue(hdev, reset_work->reset_sync, NULL, NULL); if (err) bt_dev_err(hdev, "failed to reset (%d)", err); hci_dev_unlock(hdev); } EXPORT_SYMBOL_GPL(btmtk_reset_sync); int btmtk_register_coredump(struct hci_dev *hdev, const char *name, u32 fw_version) { struct btmtk_data *data = hci_get_priv(hdev); if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) return -EOPNOTSUPP; data->cd_info.fw_version = fw_version; data->cd_info.state = HCI_DEVCOREDUMP_IDLE; data->cd_info.driver_name = name; return hci_devcd_register(hdev, btmtk_coredump, btmtk_coredump_hdr, btmtk_coredump_notify); } EXPORT_SYMBOL_GPL(btmtk_register_coredump); int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) { struct btmtk_data *data = hci_get_priv(hdev); int err; bool complete = false; if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) { kfree_skb(skb); return 0; } switch (data->cd_info.state) { case HCI_DEVCOREDUMP_IDLE: err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE); if (err < 0) { kfree_skb(skb); break; } data->cd_info.cnt = 0; /* It is supposed coredump can be done within 5 seconds */ schedule_delayed_work(&hdev->dump.dump_timeout, msecs_to_jiffies(5000)); fallthrough; case HCI_DEVCOREDUMP_ACTIVE: default: /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */ if (data->cd_info.cnt >= MTK_COREDUMP_NUM && skb->len > MTK_COREDUMP_END_LEN) if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN], MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) complete = true; err = hci_devcd_append(hdev, skb); if (err < 0) break; data->cd_info.cnt++; if (complete) { bt_dev_info(hdev, "Mediatek coredump end"); hci_devcd_complete(hdev); } break; } return err; } EXPORT_SYMBOL_GPL(btmtk_process_coredump); #if IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) /* Known MT6639 (MT7927) Bluetooth USB devices. * Used to scope the zero-CHIPID workaround to real MT6639 hardware, * since some boards return 0x0000 from the MMIO chip ID register. */ static const struct { u16 vendor; u16 product; } btmtk_mt6639_devs[] = { { 0x0489, 0xe13a }, /* ASUS ROG Crosshair X870E Hero */ { 0x0489, 0xe0fa }, /* Lenovo Legion Pro 7 16ARX9 */ { 0x0489, 0xe10f }, /* Gigabyte Z790 AORUS MASTER X */ { 0x0489, 0xe110 }, /* MSI X870E Ace Max */ { 0x0489, 0xe116 }, /* TP-Link Archer TBE550E */ { 0x13d3, 0x3588 }, /* ASUS ROG STRIX X870E-E */ }; static void btmtk_usb_wmt_recv(struct urb *urb) { struct hci_dev *hdev = urb->context; struct btmtk_data *data = hci_get_priv(hdev); struct sk_buff *skb; int err; if (urb->status == 0 && urb->actual_length > 0) { hdev->stat.byte_rx += urb->actual_length; /* WMT event shouldn't be fragmented and the size should be * less than HCI_WMT_MAX_EVENT_SIZE. */ skb = bt_skb_alloc(HCI_WMT_MAX_EVENT_SIZE, GFP_ATOMIC); if (!skb) {