diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index c3e5975b9f37..cef7a6405e1d 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -25,6 +25,22 @@ /* It is for mt79xx iso data transmission setting */ #define MTK_ISO_THRESHOLD 264 +/* 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 */ +}; + struct btmtk_patch_header { u8 datetime[16]; u8 platform[4]; @@ -112,7 +128,11 @@ static void btmtk_coredump_notify(struct hci_dev *hdev, int state) void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver, u32 fw_flavor) { - if (dev_id == 0x7925) + 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); @@ -128,7 +148,8 @@ void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver, 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) + wmt_cmd_sync_func_t wmt_cmd_sync, + u32 dev_id) { struct btmtk_hci_wmt_params wmt_params; struct btmtk_patch_header *hdr; @@ -166,6 +187,14 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, 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) { @@ -852,7 +881,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id) if (err < 0) return err; msleep(100); - } else if (dev_id == 0x7925) { + } else if (dev_id == 0x7925 || dev_id == 0x6639) { err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val); if (err < 0) return err; @@ -938,7 +967,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id) } err = btmtk_usb_id_get(hdev, 0x70010200, &val); - if (err < 0 || !val) + if (err < 0 || (!val && dev_id != 0x6639)) bt_dev_err(hdev, "Can't get device id, subsys reset fail."); return err; @@ -1303,6 +1332,24 @@ int btmtk_usb_setup(struct hci_dev *hdev) fw_flavor = (fw_flavor & 0x00000080) >> 7; } + if (!dev_id) { + u16 vid = le16_to_cpu(btmtk_data->udev->descriptor.idVendor); + u16 pid = le16_to_cpu(btmtk_data->udev->descriptor.idProduct); + int i; + + for (i = 0; i < ARRAY_SIZE(btmtk_mt6639_devs); i++) { + if (vid == btmtk_mt6639_devs[i].vendor && + pid == btmtk_mt6639_devs[i].product) { + dev_id = 0x6639; + break; + } + } + + if (dev_id) + bt_dev_info(hdev, "MT6639: CHIPID=0x0000 with VID=%04x PID=%04x, using 0x6639", + vid, pid); + } + btmtk_data->dev_id = dev_id; err = btmtk_register_coredump(hdev, btmtk_data->drv_name, fw_version); @@ -1320,11 +1367,13 @@ int btmtk_usb_setup(struct hci_dev *hdev) case 0x7925: case 0x7961: case 0x7902: + case 0x6639: btmtk_fw_get_filename(fw_bin_name, sizeof(fw_bin_name), dev_id, fw_version, fw_flavor); err = btmtk_setup_firmware_79xx(hdev, fw_bin_name, - btmtk_usb_hci_wmt_sync); + btmtk_usb_hci_wmt_sync, + dev_id); if (err < 0) { /* retry once if setup firmware error */ if (!test_and_set_bit(BTMTK_FIRMWARE_DL_RETRY, &btmtk_data->flags)) @@ -1497,3 +1546,4 @@ MODULE_FIRMWARE(FIRMWARE_MT7668); MODULE_FIRMWARE(FIRMWARE_MT7922); MODULE_FIRMWARE(FIRMWARE_MT7961); MODULE_FIRMWARE(FIRMWARE_MT7925); +MODULE_FIRMWARE(FIRMWARE_MT7927); diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h index adaf385626ee..c564aedc0ce0 100644 --- a/drivers/bluetooth/btmtk.h +++ b/drivers/bluetooth/btmtk.h @@ -8,6 +8,7 @@ #define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin" #define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin" #define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin" +#define FIRMWARE_MT7927 "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin" #define HCI_EV_WMT 0xe4 #define HCI_WMT_MAX_EVENT_SIZE 64 @@ -189,7 +190,8 @@ typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *, int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, - wmt_cmd_sync_func_t wmt_cmd_sync); + wmt_cmd_sync_func_t wmt_cmd_sync, + u32 dev_id); int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname, wmt_cmd_sync_func_t wmt_cmd_sync); @@ -228,7 +230,8 @@ static inline int btmtk_set_bdaddr(struct hci_dev *hdev, static inline int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, - wmt_cmd_sync_func_t wmt_cmd_sync) + wmt_cmd_sync_func_t wmt_cmd_sync, + u32 dev_id) { return -EOPNOTSUPP; } diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 042064464d34..5b0fab7b89b5 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -883,7 +883,7 @@ static int mt79xx_setup(struct hci_dev *hdev, const char *fwname) u8 param = 0x1; int err; - err = btmtk_setup_firmware_79xx(hdev, fwname, mtk_hci_wmt_sync); + err = btmtk_setup_firmware_79xx(hdev, fwname, mtk_hci_wmt_sync, 0); if (err < 0) { bt_dev_err(hdev, "Failed to setup 79xx firmware (%d)", err); return err;