diff options
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/btbcm.c | 5 | ||||
-rw-r--r-- | drivers/bluetooth/btintel.c | 229 | ||||
-rw-r--r-- | drivers/bluetooth/btintel.h | 10 | ||||
-rw-r--r-- | drivers/bluetooth/btmtk.c | 133 | ||||
-rw-r--r-- | drivers/bluetooth/btmtk.h | 42 | ||||
-rw-r--r-- | drivers/bluetooth/btmtkuart.c | 1 | ||||
-rw-r--r-- | drivers/bluetooth/btnxpuart.c | 257 | ||||
-rw-r--r-- | drivers/bluetooth/btqca.c | 96 | ||||
-rw-r--r-- | drivers/bluetooth/btqca.h | 31 | ||||
-rw-r--r-- | drivers/bluetooth/btrtl.c | 233 | ||||
-rw-r--r-- | drivers/bluetooth/btrtl.h | 13 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 373 | ||||
-rw-r--r-- | drivers/bluetooth/hci_h5.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 3 | ||||
-rw-r--r-- | drivers/bluetooth/hci_nokia.c | 6 | ||||
-rw-r--r-- | drivers/bluetooth/hci_qca.c | 428 |
16 files changed, 1385 insertions, 477 deletions
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index de2ea589aa49..0a5445ac5e1b 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -24,6 +24,7 @@ #define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}}) #define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}}) #define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}}) +#define BDADDR_BCM43430A1 (&(bdaddr_t) {{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}}) #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) #define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}}) #define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}}) @@ -115,6 +116,9 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) * * The address 43:43:A0:12:1F:AC indicates a BCM43430A0 controller * with no configured address. + * + * The address AA:AA:AA:AA:AA:AA indicates a BCM43430A1 controller + * with no configured address. */ if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || !bacmp(&bda->bdaddr, BDADDR_BCM20702A1) || @@ -124,6 +128,7 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) !bacmp(&bda->bdaddr, BDADDR_BCM4334B0) || !bacmp(&bda->bdaddr, BDADDR_BCM4345C5) || !bacmp(&bda->bdaddr, BDADDR_BCM43430A0) || + !bacmp(&bda->bdaddr, BDADDR_BCM43430A1) || !bacmp(&bda->bdaddr, BDADDR_BCM43341B)) { /* Try falling back to BDADDR EFI variable */ if (btbcm_set_bdaddr_from_efi(hdev) != 0) { diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index d9349ba48281..2462796a512a 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -10,6 +10,7 @@ #include <linux/firmware.h> #include <linux/regmap.h> #include <linux/acpi.h> +#include <acpi/acpi_bus.h> #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -27,6 +28,11 @@ #define BTINTEL_PPAG_NAME "PPAG" +enum { + DSM_SET_WDISABLE2_DELAY = 1, + DSM_SET_RESET_METHOD = 3, +}; + /* structure to store the PPAG data read from ACPI table */ struct btintel_ppag { u32 domain; @@ -49,6 +55,10 @@ static struct { u32 fw_build_num; } coredump_info; +static const guid_t btintel_guid_dsm = + GUID_INIT(0xaa10f4e0, 0x81ac, 0x4233, + 0xab, 0xf6, 0x3b, 0x2a, 0xc5, 0x0e, 0x28, 0xd9); + int btintel_check_bdaddr(struct hci_dev *hdev) { struct hci_rp_read_bd_addr *bda; @@ -470,6 +480,7 @@ static int btintel_version_info_tlv(struct hci_dev *hdev, case 0x18: /* Slr */ case 0x19: /* Slr-F */ case 0x1b: /* Mgr */ + case 0x1c: /* Gale Peak (GaP) */ break; default: bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)", @@ -2390,7 +2401,7 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver { struct btintel_ppag ppag; struct sk_buff *skb; - struct btintel_loc_aware_reg ppag_cmd; + struct hci_ppag_enable_cmd ppag_cmd; acpi_handle handle; /* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */ @@ -2398,6 +2409,8 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver case 0x504: /* Hrp2 */ case 0x202: /* Jfp2 */ case 0x201: /* Jfp1 */ + bt_dev_dbg(hdev, "PPAG not supported for Intel CNVr (0x%3x)", + ver->cnvr_top & 0xFFF); return; } @@ -2423,27 +2436,142 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver } if (ppag.domain != 0x12) { - bt_dev_warn(hdev, "PPAG-BT: domain is not bluetooth"); + bt_dev_dbg(hdev, "PPAG-BT: Bluetooth domain is disabled in ACPI firmware"); return; } - /* PPAG mode, BIT0 = 0 Disabled, BIT0 = 1 Enabled */ - if (!(ppag.mode & BIT(0))) { - bt_dev_dbg(hdev, "PPAG-BT: disabled"); + /* PPAG mode + * BIT 0 : 0 Disabled in EU + * 1 Enabled in EU + * BIT 1 : 0 Disabled in China + * 1 Enabled in China + */ + if ((ppag.mode & 0x01) != BIT(0) && (ppag.mode & 0x02) != BIT(1)) { + bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in CB/BIOS"); return; } - ppag_cmd.mcc = cpu_to_le32(0); - ppag_cmd.sel = cpu_to_le32(0); /* 0 - Enable , 1 - Disable, 2 - Testing mode */ - ppag_cmd.delta = cpu_to_le32(0); - skb = __hci_cmd_sync(hdev, 0xfe19, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT); + ppag_cmd.ppag_enable_flags = cpu_to_le32(ppag.mode); + + skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT); if (IS_ERR(skb)) { bt_dev_warn(hdev, "Failed to send PPAG Enable (%ld)", PTR_ERR(skb)); return; } + bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", ppag.mode); kfree_skb(skb); } +static int btintel_acpi_reset_method(struct hci_dev *hdev) +{ + int ret = 0; + acpi_status status; + union acpi_object *p, *ref; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + status = acpi_evaluate_object(ACPI_HANDLE(GET_HCIDEV_DEV(hdev)), "_PRR", NULL, &buffer); + if (ACPI_FAILURE(status)) { + bt_dev_err(hdev, "Failed to run _PRR method"); + ret = -ENODEV; + return ret; + } + p = buffer.pointer; + + if (p->package.count != 1 || p->type != ACPI_TYPE_PACKAGE) { + bt_dev_err(hdev, "Invalid arguments"); + ret = -EINVAL; + goto exit_on_error; + } + + ref = &p->package.elements[0]; + if (ref->type != ACPI_TYPE_LOCAL_REFERENCE) { + bt_dev_err(hdev, "Invalid object type: 0x%x", ref->type); + ret = -EINVAL; + goto exit_on_error; + } + + status = acpi_evaluate_object(ref->reference.handle, "_RST", NULL, NULL); + if (ACPI_FAILURE(status)) { + bt_dev_err(hdev, "Failed to run_RST method"); + ret = -ENODEV; + goto exit_on_error; + } + +exit_on_error: + kfree(buffer.pointer); + return ret; +} + +static void btintel_set_dsm_reset_method(struct hci_dev *hdev, + struct intel_version_tlv *ver_tlv) +{ + struct btintel_data *data = hci_get_priv(hdev); + acpi_handle handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev)); + u8 reset_payload[4] = {0x01, 0x00, 0x01, 0x00}; + union acpi_object *obj, argv4; + enum { + RESET_TYPE_WDISABLE2, + RESET_TYPE_VSEC + }; + + handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev)); + + if (!handle) { + bt_dev_dbg(hdev, "No support for bluetooth device in ACPI firmware"); + return; + } + + if (!acpi_has_method(handle, "_PRR")) { + bt_dev_err(hdev, "No support for _PRR ACPI method"); + return; + } + + switch (ver_tlv->cnvi_top & 0xfff) { + case 0x910: /* GalePeak2 */ + reset_payload[2] = RESET_TYPE_VSEC; + break; + default: + /* WDISABLE2 is the default reset method */ + reset_payload[2] = RESET_TYPE_WDISABLE2; + + if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0, + BIT(DSM_SET_WDISABLE2_DELAY))) { + bt_dev_err(hdev, "No dsm support to set reset delay"); + return; + } + argv4.integer.type = ACPI_TYPE_INTEGER; + /* delay required to toggle BT power */ + argv4.integer.value = 160; + obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0, + DSM_SET_WDISABLE2_DELAY, &argv4); + if (!obj) { + bt_dev_err(hdev, "Failed to call dsm to set reset delay"); + return; + } + ACPI_FREE(obj); + } + + bt_dev_info(hdev, "DSM reset method type: 0x%02x", reset_payload[2]); + + if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0, + DSM_SET_RESET_METHOD)) { + bt_dev_warn(hdev, "No support for dsm to set reset method"); + return; + } + argv4.buffer.type = ACPI_TYPE_BUFFER; + argv4.buffer.length = sizeof(reset_payload); + argv4.buffer.pointer = reset_payload; + + obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0, + DSM_SET_RESET_METHOD, &argv4); + if (!obj) { + bt_dev_err(hdev, "Failed to call dsm to set reset method"); + return; + } + ACPI_FREE(obj); + data->acpi_reset_method = btintel_acpi_reset_method; +} + static int btintel_bootloader_setup_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver) { @@ -2528,6 +2656,7 @@ static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) case 0x18: case 0x19: case 0x1b: + case 0x1c: hci_set_msft_opcode(hdev, 0xFC1E); break; default: @@ -2658,6 +2787,9 @@ static int btintel_setup_combined(struct hci_dev *hdev) set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); + /* These variants don't seem to support LE Coded PHY */ + set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks); + /* Setup MSFT Extension support */ btintel_set_msft_opcode(hdev, ver.hw_variant); @@ -2729,6 +2861,9 @@ static int btintel_setup_combined(struct hci_dev *hdev) */ set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); + /* These variants don't seem to support LE Coded PHY */ + set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks); + /* Set Valid LE States quirk */ set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); @@ -2742,6 +2877,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) case 0x18: case 0x19: case 0x1b: + case 0x1c: /* Display version information of TLV type */ btintel_version_info_tlv(hdev, &ver_tlv); @@ -2757,6 +2893,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) /* Setup MSFT Extension support */ btintel_set_msft_opcode(hdev, INTEL_HW_VARIANT(ver_tlv.cnvi_bt)); + btintel_set_dsm_reset_method(hdev, &ver_tlv); err = btintel_bootloader_setup_tlv(hdev, &ver_tlv); btintel_register_devcoredump_support(hdev); @@ -2824,6 +2961,80 @@ int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name) } EXPORT_SYMBOL_GPL(btintel_configure_setup); +static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct intel_tlv *tlv = (void *)&skb->data[5]; + + /* The first event is always an event type TLV */ + if (tlv->type != INTEL_TLV_TYPE_ID) + goto recv_frame; + + switch (tlv->val[0]) { + case INTEL_TLV_SYSTEM_EXCEPTION: + case INTEL_TLV_FATAL_EXCEPTION: + case INTEL_TLV_DEBUG_EXCEPTION: + case INTEL_TLV_TEST_EXCEPTION: + /* Generate devcoredump from exception */ + if (!hci_devcd_init(hdev, skb->len)) { + hci_devcd_append(hdev, skb); + hci_devcd_complete(hdev); + } else { + bt_dev_err(hdev, "Failed to generate devcoredump"); + kfree_skb(skb); + } + return 0; + default: + bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]); + } + +recv_frame: + return hci_recv_frame(hdev, skb); +} + +int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_event_hdr *hdr = (void *)skb->data; + const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 }; + + if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff && + hdr->plen > 0) { + const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1; + unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1; + + if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) { + switch (skb->data[2]) { + case 0x02: + /* When switching to the operational firmware + * the device sends a vendor specific event + * indicating that the bootup completed. + */ + btintel_bootup(hdev, ptr, len); + break; + case 0x06: + /* When the firmware loading completes the + * device sends out a vendor specific event + * indicating the result of the firmware + * loading. + */ + btintel_secure_send_result(hdev, ptr, len); + break; + } + } + + /* Handle all diagnostics events separately. May still call + * hci_recv_frame. + */ + if (len >= sizeof(diagnostics_hdr) && + memcmp(&skb->data[2], diagnostics_hdr, + sizeof(diagnostics_hdr)) == 0) { + return btintel_diagnostics(hdev, skb); + } + } + + return hci_recv_frame(hdev, skb); +} +EXPORT_SYMBOL_GPL(btintel_recv_event); + void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len) { const struct intel_bootup *evt = ptr; diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index d6a1dc8d8a82..3a2d5b4219dd 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -137,10 +137,9 @@ struct intel_offload_use_cases { __u8 preset[8]; } __packed; -struct btintel_loc_aware_reg { - __le32 mcc; - __le32 sel; - __le32 delta; +#define INTEL_OP_PPAG_CMD 0xFE0B +struct hci_ppag_enable_cmd { + __le32 ppag_enable_flags; } __packed; #define INTEL_TLV_TYPE_ID 0x01 @@ -166,12 +165,14 @@ enum { INTEL_BROKEN_SHUTDOWN_LED, INTEL_ROM_LEGACY, INTEL_ROM_LEGACY_NO_WBS_SUPPORT, + INTEL_ACPI_RESET_ACTIVE, __INTEL_NUM_FLAGS, }; struct btintel_data { DECLARE_BITMAP(flags, __INTEL_NUM_FLAGS); + int (*acpi_reset_method)(struct hci_dev *hdev); }; #define btintel_set_flag(hdev, nr) \ @@ -220,6 +221,7 @@ int btintel_read_boot_params(struct hci_dev *hdev, int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver, const struct firmware *fw, u32 *boot_param); int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name); +int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb); void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len); void btintel_secure_send_result(struct hci_dev *hdev, const void *ptr, unsigned int len); diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 809762d64fc6..aaabb732082c 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -53,10 +53,61 @@ struct btmtk_section_map { }; } __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 btmediatek_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 btmediatek_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; + } +} + int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, wmt_cmd_sync_func_t wmt_cmd_sync) { 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; @@ -75,9 +126,13 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, 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; @@ -280,6 +335,83 @@ int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) } EXPORT_SYMBOL_GPL(btmtk_set_bdaddr); +void btmtk_reset_sync(struct hci_dev *hdev) +{ + struct btmediatek_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 btmediatek_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 btmediatek_data *data = hci_get_priv(hdev); + int err; + + if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) + return 0; + + switch (data->cd_info.state) { + case HCI_DEVCOREDUMP_IDLE: + err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE); + if (err < 0) + 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: + err = hci_devcd_append(hdev, skb); + if (err < 0) + break; + data->cd_info.cnt++; + + /* 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)) { + bt_dev_info(hdev, "Mediatek coredump end"); + hci_devcd_complete(hdev); + } + + break; + } + + if (err < 0) + kfree_skb(skb); + + return err; +} +EXPORT_SYMBOL_GPL(btmtk_process_coredump); + MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>"); MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION); @@ -289,3 +421,4 @@ MODULE_FIRMWARE(FIRMWARE_MT7622); MODULE_FIRMWARE(FIRMWARE_MT7663); MODULE_FIRMWARE(FIRMWARE_MT7668); MODULE_FIRMWARE(FIRMWARE_MT7961); +MODULE_FIRMWARE(FIRMWARE_MT7925); diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h index 2a88ea8e475e..56f5502baadf 100644 --- a/drivers/bluetooth/btmtk.h +++ b/drivers/bluetooth/btmtk.h @@ -5,6 +5,7 @@ #define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin" #define FIRMWARE_MT7668 "mediatek/mt7668pr2h.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 HCI_EV_WMT 0xe4 #define HCI_WMT_MAX_EVENT_SIZE 64 @@ -21,6 +22,11 @@ #define MT7921_DLSTATUS 0x7c053c10 #define BT_DL_STATE BIT(1) +#define MTK_COREDUMP_SIZE (1024 * 1000) +#define MTK_COREDUMP_END "coredump end" +#define MTK_COREDUMP_END_LEN (sizeof(MTK_COREDUMP_END)) +#define MTK_COREDUMP_NUM 255 + enum { BTMTK_WMT_PATCH_DWNLD = 0x1, BTMTK_WMT_TEST = 0x2, @@ -119,6 +125,21 @@ struct btmtk_hci_wmt_params { u32 *status; }; +typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *); + +struct btmtk_coredump_info { + const char *driver_name; + u32 fw_version; + u16 cnt; + int state; +}; + +struct btmediatek_data { + u32 dev_id; + btmtk_reset_sync_func_t reset_sync; + struct btmtk_coredump_info cd_info; +}; + typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *, struct btmtk_hci_wmt_params *); @@ -131,6 +152,13 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname, wmt_cmd_sync_func_t wmt_cmd_sync); + +void btmtk_reset_sync(struct hci_dev *hdev); + +int btmtk_register_coredump(struct hci_dev *hdev, const char *name, + u32 fw_version); + +int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb); #else static inline int btmtk_set_bdaddr(struct hci_dev *hdev, @@ -151,4 +179,18 @@ static int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname, return -EOPNOTSUPP; } +static void btmtk_reset_sync(struct hci_dev *hdev) +{ +} + +static int btmtk_register_coredump(struct hci_dev *hdev, const char *name, + u32 fw_version) +{ + return -EOPNOTSUPP; +} + +static int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) +{ + return -EOPNOTSUPP; +} #endif diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 7680c67cdb35..935feab815d9 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -17,7 +17,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 52ef44688d38..b7e66b7ac570 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -28,17 +28,34 @@ #define BTNXPUART_FW_DOWNLOADING 2 #define BTNXPUART_CHECK_BOOT_SIGNATURE 3 #define BTNXPUART_SERDEV_OPEN 4 - -#define FIRMWARE_W8987 "nxp/uartuart8987_bt.bin" -#define FIRMWARE_W8997 "nxp/uartuart8997_bt_v4.bin" -#define FIRMWARE_W9098 "nxp/uartuart9098_bt_v1.bin" -#define FIRMWARE_IW416 "nxp/uartiw416_bt_v0.bin" -#define FIRMWARE_IW612 "nxp/uartspi_n61x_v1.bin.se" -#define FIRMWARE_HELPER "nxp/helper_uart_3000000.bin" +#define BTNXPUART_IR_IN_PROGRESS 5 + +/* NXP HW err codes */ +#define BTNXPUART_IR_HW_ERR 0xb0 + +#define FIRMWARE_W8987 "nxp/uartuart8987_bt.bin" +#define FIRMWARE_W8997 "nxp/uartuart8997_bt_v4.bin" +#define FIRMWARE_W9098 "nxp/uartuart9098_bt_v1.bin" +#define FIRMWARE_IW416 "nxp/uartiw416_bt_v0.bin" +#define FIRMWARE_IW612 "nxp/uartspi_n61x_v1.bin.se" +#define FIRMWARE_IW624 "nxp/uartiw624_bt.bin" +#define FIRMWARE_SECURE_IW624 "nxp/uartiw624_bt.bin.se" +#define FIRMWARE_AW693 "nxp/uartaw693_bt.bin" +#define FIRMWARE_SECURE_AW693 "nxp/uartaw693_bt.bin.se" +#define FIRMWARE_HELPER "nxp/helper_uart_3000000.bin" #define CHIP_ID_W9098 0x5c03 #define CHIP_ID_IW416 0x7201 #define CHIP_ID_IW612 0x7601 +#define CHIP_ID_IW624a 0x8000 +#define CHIP_ID_IW624c 0x8001 +#define CHIP_ID_AW693 0x8200 + +#define FW_SECURE_MASK 0xc0 +#define FW_OPEN 0x00 +#define FW_AUTH_ILLEGAL 0x40 +#define FW_AUTH_PLAIN 0x80 +#define FW_AUTH_ENC 0xc0 #define HCI_NXP_PRI_BAUDRATE 115200 #define HCI_NXP_SEC_BAUDRATE 3000000 @@ -143,6 +160,7 @@ struct btnxpuart_dev { u32 fw_v1_sent_bytes; u32 fw_v3_offset_correction; u32 fw_v1_expected_len; + u32 boot_reg_offset; wait_queue_head_t fw_dnld_done_wait_q; wait_queue_head_t check_boot_sign_wait_q; @@ -366,39 +384,13 @@ static void ps_timeout_func(struct timer_list *t) } } -static int ps_init_work(struct hci_dev *hdev) +static void ps_setup(struct hci_dev *hdev) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct ps_data *psdata = &nxpdev->psdata; - psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS; - psdata->ps_state = PS_STATE_AWAKE; - psdata->target_ps_mode = DEFAULT_PS_MODE; psdata->hdev = hdev; - psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE; - psdata->c2h_wakeup_gpio = 0xff; - - switch (DEFAULT_H2C_WAKEUP_MODE) { - case WAKEUP_METHOD_DTR: - psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR; - break; - case WAKEUP_METHOD_BREAK: - default: - psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK; - break; - } - psdata->cur_psmode = PS_MODE_DISABLE; - psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID; INIT_WORK(&psdata->work, ps_work_func); - - return 0; -} - -static void ps_init_timer(struct hci_dev *hdev) -{ - struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); - struct ps_data *psdata = &nxpdev->psdata; - timer_setup(&psdata->ps_timer, ps_timeout_func, 0); } @@ -501,19 +493,31 @@ static void ps_init(struct hci_dev *hdev) serdev_device_set_tiocm(nxpdev->serdev, TIOCM_RTS, 0); usleep_range(5000, 10000); - switch (psdata->h2c_wakeupmode) { + psdata->ps_state = PS_STATE_AWAKE; + psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE; + psdata->c2h_wakeup_gpio = 0xff; + + psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID; + psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS; + switch (DEFAULT_H2C_WAKEUP_MODE) { case WAKEUP_METHOD_DTR: + psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR; serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR); serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0); break; case WAKEUP_METHOD_BREAK: default: + psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK; serdev_device_break_ctl(nxpdev->serdev, -1); usleep_range(5000, 10000); serdev_device_break_ctl(nxpdev->serdev, 0); usleep_range(5000, 10000); break; } + + psdata->cur_psmode = PS_MODE_DISABLE; + psdata->target_ps_mode = DEFAULT_PS_MODE; + if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode) hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL); if (psdata->cur_psmode != psdata->target_ps_mode) @@ -529,6 +533,7 @@ static int nxp_download_firmware(struct hci_dev *hdev) nxpdev->fw_dnld_v1_offset = 0; nxpdev->fw_v1_sent_bytes = 0; nxpdev->fw_v1_expected_len = HDR_LEN; + nxpdev->boot_reg_offset = 0; nxpdev->fw_v3_offset_correction = 0; nxpdev->baudrate_changed = false; nxpdev->timeout_changed = false; @@ -538,7 +543,7 @@ static int nxp_download_firmware(struct hci_dev *hdev) serdev_device_set_flow_control(nxpdev->serdev, false); nxpdev->current_baudrate = HCI_NXP_PRI_BAUDRATE; - /* Wait till FW is downloaded and CTS becomes low */ + /* Wait till FW is downloaded */ err = wait_event_interruptible_timeout(nxpdev->fw_dnld_done_wait_q, !test_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state), @@ -549,16 +554,11 @@ static int nxp_download_firmware(struct hci_dev *hdev) } serdev_device_set_flow_control(nxpdev->serdev, true); - err = serdev_device_wait_for_cts(nxpdev->serdev, 1, 60000); - if (err < 0) { - bt_dev_err(hdev, "CTS is still high. FW Download failed."); - return err; - } release_firmware(nxpdev->fw); memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); /* Allow the downloaded FW to initialize */ - usleep_range(800 * USEC_PER_MSEC, 1 * USEC_PER_SEC); + msleep(1200); return 0; } @@ -582,6 +582,12 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len) struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct nxp_bootloader_cmd nxp_cmd5; struct uart_config uart_config; + u32 clkdivaddr = CLKDIVADDR - nxpdev->boot_reg_offset; + u32 uartdivaddr = UARTDIVADDR - nxpdev->boot_reg_offset; + u32 uartmcraddr = UARTMCRADDR - nxpdev->boot_reg_offset; + u32 uartreinitaddr = UARTREINITADDR - nxpdev->boot_reg_offset; + u32 uarticraddr = UARTICRADDR - nxpdev->boot_reg_offset; + u32 uartfcraddr = UARTFCRADDR - nxpdev->boot_reg_offset; if (req_len == sizeof(nxp_cmd5)) { nxp_cmd5.header = __cpu_to_le32(5); @@ -594,17 +600,17 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len) serdev_device_write_buf(nxpdev->serdev, (u8 *)&nxp_cmd5, sizeof(nxp_cmd5)); nxpdev->fw_v3_offset_correction += req_len; } else if (req_len == sizeof(uart_config)) { - uart_config.clkdiv.address = __cpu_to_le32(CLKDIVADDR); + uart_config.clkdiv.address = __cpu_to_le32(clkdivaddr); uart_config.clkdiv.value = __cpu_to_le32(0x00c00000); - uart_config.uartdiv.address = __cpu_to_le32(UARTDIVADDR); + uart_config.uartdiv.address = __cpu_to_le32(uartdivaddr); uart_config.uartdiv.value = __cpu_to_le32(1); - uart_config.mcr.address = __cpu_to_le32(UARTMCRADDR); + uart_config.mcr.address = __cpu_to_le32(uartmcraddr); uart_config.mcr.value = __cpu_to_le32(MCR); - uart_config.re_init.address = __cpu_to_le32(UARTREINITADDR); + uart_config.re_init.address = __cpu_to_le32(uartreinitaddr); uart_config.re_init.value = __cpu_to_le32(INIT); - uart_config.icr.address = __cpu_to_le32(UARTICRADDR); + uart_config.icr.address = __cpu_to_le32(uarticraddr); uart_config.icr.value = __cpu_to_le32(ICR); - uart_config.fcr.address = __cpu_to_le32(UARTFCRADDR); + uart_config.fcr.address = __cpu_to_le32(uartfcraddr); uart_config.fcr.value = __cpu_to_le32(FCR); /* FW expects swapped CRC bytes */ uart_config.crc = __cpu_to_be32(crc32_be(0UL, (char *)&uart_config, @@ -665,6 +671,9 @@ static int nxp_request_firmware(struct hci_dev *hdev, const char *fw_name) struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); int err = 0; + if (!fw_name) + return -ENOENT; + if (!strlen(nxpdev->fw_name)) { snprintf(nxpdev->fw_name, MAX_FW_FILE_NAME_LEN, "%s", fw_name); @@ -690,7 +699,7 @@ static int nxp_recv_chip_ver_v1(struct hci_dev *hdev, struct sk_buff *skb) goto free_skb; chip_id = le16_to_cpu(req->chip_id ^ req->chip_id_comp); - if (chip_id == 0xffff) { + if (chip_id == 0xffff && nxpdev->fw_dnld_v1_offset) { nxpdev->fw_dnld_v1_offset = 0; nxpdev->fw_v1_sent_bytes = 0; nxpdev->fw_v1_expected_len = HDR_LEN; @@ -812,8 +821,10 @@ free_skb: return 0; } -static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid) +static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid, + u8 loader_ver) { + struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); char *fw_name = NULL; switch (chipid) { @@ -826,6 +837,24 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid) case CHIP_ID_IW612: fw_name = FIRMWARE_IW612; break; + case CHIP_ID_IW624a: + case CHIP_ID_IW624c: + nxpdev->boot_reg_offset = 1; + if ((loader_ver & FW_SECURE_MASK) == FW_OPEN) + fw_name = FIRMWARE_IW624; + else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL) + fw_name = FIRMWARE_SECURE_IW624; + else + bt_dev_err(hdev, "Illegal loader version %02x", loader_ver); + break; + case CHIP_ID_AW693: + if ((loader_ver & FW_SECURE_MASK) == FW_OPEN) + fw_name = FIRMWARE_AW693; + else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL) + fw_name = FIRMWARE_SECURE_AW693; + else + bt_dev_err(hdev, "Illegal loader version %02x", loader_ver); + break; default: bt_dev_err(hdev, "Unknown chip signature %04x", chipid); break; @@ -838,13 +867,15 @@ static int nxp_recv_chip_ver_v3(struct hci_dev *hdev, struct sk_buff *skb) struct v3_start_ind *req = skb_pull_data(skb, sizeof(*req)); struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); u16 chip_id; + u8 loader_ver; if (!process_boot_signature(nxpdev)) goto free_skb; chip_id = le16_to_cpu(req->chip_id); + loader_ver = req->loader_ver; if (!nxp_request_firmware(hdev, nxp_get_fw_name_from_chipid(hdev, - chip_id))) + chip_id, loader_ver))) nxp_send_ack(NXP_ACK_V3, hdev); free_skb: @@ -946,45 +977,13 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data) return 0; } -static int nxp_set_ind_reset(struct hci_dev *hdev, void *data) -{ - struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); - struct sk_buff *skb; - u8 *status; - u8 pcmd = 0; - int err = 0; - - skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - status = skb_pull_data(skb, 1); - if (!status || *status) - goto free_skb; - - set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); - err = nxp_download_firmware(hdev); - if (err < 0) - goto free_skb; - serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate); - nxpdev->current_baudrate = nxpdev->fw_init_baudrate; - if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) { - nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE; - nxp_set_baudrate_cmd(hdev, NULL); - } - hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL); - hci_cmd_sync_queue(hdev, send_ps_cmd, NULL, NULL); - -free_skb: - kfree_skb(skb); - return err; -} - -/* NXP protocol */ static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev) { serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE); - serdev_device_set_flow_control(nxpdev->serdev, true); + if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) + serdev_device_set_flow_control(nxpdev->serdev, false); + else + serdev_device_set_flow_control(nxpdev->serdev, true); set_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, &nxpdev->tx_state); return wait_event_interruptible_timeout(nxpdev->check_boot_sign_wait_q, @@ -993,15 +992,29 @@ static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev) msecs_to_jiffies(1000)); } +static int nxp_set_ind_reset(struct hci_dev *hdev, void *data) +{ + static const u8 ir_hw_err[] = { HCI_EV_HARDWARE_ERROR, + 0x01, BTNXPUART_IR_HW_ERR }; + struct sk_buff *skb; + + skb = bt_skb_alloc(3, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hci_skb_pkt_type(skb) = HCI_EVENT_PKT; + skb_put_data(skb, ir_hw_err, 3); + + /* Inject Hardware Error to upper stack */ + return hci_recv_frame(hdev, skb); +} + +/* NXP protocol */ static int nxp_setup(struct hci_dev *hdev) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); int err = 0; - set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); - init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q); - init_waitqueue_head(&nxpdev->check_boot_sign_wait_q); - if (nxp_check_boot_sign(nxpdev)) { bt_dev_dbg(hdev, "Need FW Download."); err = nxp_download_firmware(hdev); @@ -1012,10 +1025,6 @@ static int nxp_setup(struct hci_dev *hdev) clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); } - device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate", - &nxpdev->fw_init_baudrate); - if (!nxpdev->fw_init_baudrate) - nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE; serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate); nxpdev->current_baudrate = nxpdev->fw_init_baudrate; @@ -1026,6 +1035,46 @@ static int nxp_setup(struct hci_dev *hdev) ps_init(hdev); + if (test_and_clear_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) + hci_dev_clear_flag(hdev, HCI_SETUP); + + return 0; +} + +static void nxp_hw_err(struct hci_dev *hdev, u8 code) +{ + struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); + + switch (code) { + case BTNXPUART_IR_HW_ERR: + set_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state); + hci_dev_set_flag(hdev, HCI_SETUP); + break; + default: + break; + } +} + +static int nxp_shutdown(struct hci_dev *hdev) +{ + struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); + struct sk_buff *skb; + u8 *status; + u8 pcmd = 0; + + if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) { + skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + status = skb_pull_data(skb, 1); + if (status) { + serdev_device_set_flow_control(nxpdev->serdev, false); + set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); + } + kfree_skb(skb); + } + return 0; } @@ -1233,7 +1282,8 @@ static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data, nxpdev->rx_skb = NULL; return err; } - nxpdev->hdev->stat.byte_rx += count; + if (!is_fw_downloading(nxpdev)) + nxpdev->hdev->stat.byte_rx += count; return count; } @@ -1266,6 +1316,16 @@ static int nxp_serdev_probe(struct serdev_device *serdev) INIT_WORK(&nxpdev->tx_work, btnxpuart_tx_work); skb_queue_head_init(&nxpdev->txq); + init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q); + init_waitqueue_head(&nxpdev->check_boot_sign_wait_q); + + device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate", + &nxpdev->fw_init_baudrate); + if (!nxpdev->fw_init_baudrate) + nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE; + + set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); + crc8_populate_msb(crc8_table, POLYNOMIAL8); /* Initialize and register HCI device */ @@ -1286,6 +1346,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev) hdev->flush = btnxpuart_flush; hdev->setup = nxp_setup; hdev->send = nxp_enqueue; + hdev->hw_error = nxp_hw_err; + hdev->shutdown = nxp_shutdown; SET_HCIDEV_DEV(hdev, &serdev->dev); if (hci_register_dev(hdev) < 0) { @@ -1294,8 +1356,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev) return -ENODEV; } - ps_init_work(hdev); - ps_init_timer(hdev); + ps_setup(hdev); return 0; } diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index e7e58a956d15..5a35ac4138c6 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -594,30 +594,48 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, /* Firmware files to download are based on ROM version. * ROM version is derived from last two bytes of soc_ver. */ - rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f); + if (soc_type == QCA_WCN3988) + rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f); + else + rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f); if (soc_type == QCA_WCN6750) qca_send_patch_config_cmd(hdev); /* Download rampatch file */ config.type = TLV_TYPE_PATCH; - if (qca_is_wcn399x(soc_type)) { + switch (soc_type) { + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: snprintf(config.fwname, sizeof(config.fwname), "qca/crbtfw%02x.tlv", rom_ver); - } else if (soc_type == QCA_QCA6390) { + break; + case QCA_WCN3988: + snprintf(config.fwname, sizeof(config.fwname), + "qca/apbtfw%02x.tlv", rom_ver); + break; + case QCA_QCA6390: snprintf(config.fwname, sizeof(config.fwname), "qca/htbtfw%02x.tlv", rom_ver); - } else if (soc_type == QCA_WCN6750) { + break; + case QCA_WCN6750: /* Choose mbn file by default.If mbn file is not found * then choose tlv file */ config.type = ELF_TYPE_PATCH; snprintf(config.fwname, sizeof(config.fwname), "qca/msbtfw%02x.mbn", rom_ver); - } else if (soc_type == QCA_WCN6855) { + break; + case QCA_WCN6855: snprintf(config.fwname, sizeof(config.fwname), "qca/hpbtfw%02x.tlv", rom_ver); - } else { + break; + case QCA_WCN7850: + snprintf(config.fwname, sizeof(config.fwname), + "qca/hmtbtfw%02x.tlv", rom_ver); + break; + default: snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin", soc_ver); } @@ -633,30 +651,48 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, /* Download NVM configuration */ config.type = TLV_TYPE_NVM; - if (firmware_name) + if (firmware_name) { snprintf(config.fwname, sizeof(config.fwname), "qca/%s", firmware_name); - else if (qca_is_wcn399x(soc_type)) { - if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) { + } else { + switch (soc_type) { + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) { + snprintf(config.fwname, sizeof(config.fwname), + "qca/crnv%02xu.bin", rom_ver); + } else { + snprintf(config.fwname, sizeof(config.fwname), + "qca/crnv%02x.bin", rom_ver); + } + break; + case QCA_WCN3988: snprintf(config.fwname, sizeof(config.fwname), - "qca/crnv%02xu.bin", rom_ver); - } else { + "qca/apnv%02x.bin", rom_ver); + break; + case QCA_QCA6390: + snprintf(config.fwname, sizeof(config.fwname), + "qca/htnv%02x.bin", rom_ver); + break; + case QCA_WCN6750: + snprintf(config.fwname, sizeof(config.fwname), + "qca/msnv%02x.bin", rom_ver); + break; + case QCA_WCN6855: + snprintf(config.fwname, sizeof(config.fwname), + "qca/hpnv%02x.bin", rom_ver); + break; + case QCA_WCN7850: + snprintf(config.fwname, sizeof(config.fwname), + "qca/hmtnv%02x.bin", rom_ver); + break; + + default: snprintf(config.fwname, sizeof(config.fwname), - "qca/crnv%02x.bin", rom_ver); + "qca/nvm_%08x.bin", soc_ver); } } - else if (soc_type == QCA_QCA6390) - snprintf(config.fwname, sizeof(config.fwname), - "qca/htnv%02x.bin", rom_ver); - else if (soc_type == QCA_WCN6750) - snprintf(config.fwname, sizeof(config.fwname), - "qca/msnv%02x.bin", rom_ver); - else if (soc_type == QCA_WCN6855) - snprintf(config.fwname, sizeof(config.fwname), - "qca/hpnv%02x.bin", rom_ver); - else - snprintf(config.fwname, sizeof(config.fwname), - "qca/nvm_%08x.bin", soc_ver); err = qca_download_firmware(hdev, &config, soc_type, rom_ver); if (err < 0) { @@ -664,16 +700,25 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, return err; } - if (soc_type >= QCA_WCN3991) { + switch (soc_type) { + case QCA_WCN3991: + case QCA_QCA6390: + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: err = qca_disable_soc_logging(hdev); if (err < 0) return err; + break; + default: + break; } /* WCN399x and WCN6750 supports the Microsoft vendor extension with 0xFD70 as the * VsMsftOpCode. */ switch (soc_type) { + case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: case QCA_WCN3998: @@ -695,6 +740,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, case QCA_WCN3991: case QCA_WCN6750: case QCA_WCN6855: + case QCA_WCN7850: /* get fw build info */ err = qca_read_fw_build_info(hdev); if (err < 0) diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h index b884095bcd9d..03bff5c0059d 100644 --- a/drivers/bluetooth/btqca.h +++ b/drivers/bluetooth/btqca.h @@ -142,12 +142,14 @@ enum qca_btsoc_type { QCA_INVALID = -1, QCA_AR3002, QCA_ROME, + QCA_WCN3988, QCA_WCN3990, QCA_WCN3998, QCA_WCN3991, QCA_QCA6390, QCA_WCN6750, QCA_WCN6855, + QCA_WCN7850, }; #if IS_ENABLED(CONFIG_BT_QCA) @@ -160,20 +162,6 @@ int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver, enum qca_btsoc_type); int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); int qca_send_pre_shutdown_cmd(struct hci_dev *hdev); -static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type) -{ - return soc_type == QCA_WCN3990 || soc_type == QCA_WCN3991 || - soc_type == QCA_WCN3998; -} -static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type) -{ - return soc_type == QCA_WCN6750; -} -static inline bool qca_is_wcn6855(enum qca_btsoc_type soc_type) -{ - return soc_type == QCA_WCN6855; -} - #else static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) @@ -201,21 +189,6 @@ static inline int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) return -EOPNOTSUPP; } -static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type) -{ - return false; -} - -static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type) -{ - return false; -} - -static inline bool qca_is_wcn6855(enum qca_btsoc_type soc_type) -{ - return false; -} - static inline int qca_send_pre_shutdown_cmd(struct hci_dev *hdev) { return -EOPNOTSUPP; diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index d978e7cea873..84c2c2e1122f 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -32,6 +32,8 @@ #define RTL_ROM_LMP_8851B 0x8851 #define RTL_CONFIG_MAGIC 0x8723ab55 +#define RTL_VSC_OP_COREDUMP 0xfcff + #define IC_MATCH_FL_LMPSUBV (1 << 0) #define IC_MATCH_FL_HCIREV (1 << 1) #define IC_MATCH_FL_HCIVER (1 << 2) @@ -81,6 +83,7 @@ struct id_table { bool has_msft_ext; char *fw_name; char *cfg_name; + char *hw_info; }; struct btrtl_device_info { @@ -101,22 +104,25 @@ static const struct id_table ic_id_table[] = { { IC_INFO(RTL_ROM_LMP_8723A, 0xb, 0x6, HCI_USB), .config_needed = false, .has_rom_version = false, - .fw_name = "rtl_bt/rtl8723a_fw.bin", - .cfg_name = NULL }, + .fw_name = "rtl_bt/rtl8723a_fw", + .cfg_name = NULL, + .hw_info = "rtl8723au" }, /* 8723BS */ { IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_UART), .config_needed = true, .has_rom_version = true, - .fw_name = "rtl_bt/rtl8723bs_fw.bin", - .cfg_name = "rtl_bt/rtl8723bs_config" }, + .fw_name = "rtl_bt/rtl8723bs_fw", + .cfg_name = "rtl_bt/rtl8723bs_config", + .hw_info = "rtl8723bs" }, /* 8723B */ { IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_USB), .config_needed = false, .has_rom_version = true, - .fw_name = "rtl_bt/rtl8723b_fw.bin", - .cfg_name = "rtl_bt/rtl8723b_config" }, + .fw_name = "rtl_bt/rtl8723b_fw", + .cfg_name = "rtl_bt/rtl8723b_config", + .hw_info = "rtl8723bu" }, /* 8723CS-CG */ { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE | @@ -126,8 +132,9 @@ static const struct id_table ic_id_table[] = { .hci_bus = HCI_UART, .config_needed = true, .has_rom_version = true, - .fw_name = "rtl_bt/rtl8723cs_cg_fw.bin", - .cfg_name = "rtl_bt/rtl8723cs_cg_config" }, + .fw_name = "rtl_bt/rtl8723cs_cg_fw", + .cfg_name = "rtl_bt/rtl8723cs_cg_config", + .hw_info = "rtl8723cs-cg" }, /* 8723CS-VF */ { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE | @@ -137,8 +144,9 @@ static const struct id_table ic_id_table[] = { .hci_bus = HCI_UART, .config_needed = true, .has_rom_version = true, - .fw_name = "rtl_bt/rtl8723cs_vf_fw.bin", - .cfg_name = "rtl_bt/rtl8723cs_vf_config" }, + .fw_name = "rtl_bt/rtl8723cs_vf_fw", + .cfg_name = "rtl_bt/rtl8723cs_vf_config", + .hw_info = "rtl8723cs-vf" }, /* 8723CS-XX */ { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE | @@ -148,139 +156,157 @@ static const struct id_table ic_id_table[] = { .hci_bus = HCI_UART, .config_needed = true, .has_rom_version = true, - .fw_name = "rtl_bt/rtl8723cs_xx_fw.bin", - .cfg_name = "rtl_bt/rtl8723cs_xx_config" }, + .fw_name = "rtl_bt/rtl8723cs_xx_fw", + .cfg_name = "rtl_bt/rtl8723cs_xx_config", + .hw_info = "rtl8723cs" }, /* 8723D */ { IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_USB), .config_needed = true, .has_rom_version = true, - .fw_name = "rtl_bt/rtl8723d_fw.bin", - .cfg_name = "rtl_bt/rtl8723d_config" }, + .fw_name = "rtl_bt/rtl8723d_fw", + .cfg_name = "rtl_bt/rtl8723d_config", + .hw_info = "rtl8723du" }, /* 8723DS */ { IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_UART), .config_needed = true, .has_rom_version = true, - .fw_name = "rtl_bt/rtl8723ds_fw.bin", - .cfg_name = "rtl_bt/rtl8723ds_config" }, + .fw_name = "rtl_bt/rtl8723ds_fw", + .cfg_name = "rtl_bt/rtl8723ds_config", + .hw_info = "rtl8723ds" }, /* 8821A */ { IC_INFO(RTL_ROM_LMP_8821A, 0xa, 0x6, HCI_USB), .config_needed = false, .has_rom_version = true, - .fw_name = "rtl_bt/rtl8821a_fw.bin", - .cfg_name = "rtl_bt/rtl8821a_config" }, + .fw_name = "rtl_bt/rtl8821a_fw", + .cfg_name = "rtl_bt/rtl8821a_config", + .hw_info = "rtl8821au" }, /* 8821C */ { IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_USB), .config_needed = false, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8821c_fw.bin", - .cfg_name = "rtl_bt/rtl8821c_config" }, + .fw_name = "rtl_bt/rtl8821c_fw", + .cfg_name = "rtl_bt/rtl8821c_config", + .hw_info = "rtl8821cu" }, /* 8821CS */ { IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_UART), .config_needed = true, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8821cs_fw.bin", - .cfg_name = "rtl_bt/rtl8821cs_config" }, + .fw_name = "rtl_bt/rtl8821cs_fw", + .cfg_name = "rtl_bt/rtl8821cs_config", + .hw_info = "rtl8821cs" }, /* 8761A */ { IC_INFO(RTL_ROM_LMP_8761A, 0xa, 0x6, HCI_USB), .config_needed = false, .has_rom_version = true, - .fw_name = "rtl_bt/rtl8761a_fw.bin", - .cfg_name = "rtl_bt/rtl8761a_config" }, + .fw_name = "rtl_bt/rtl8761a_fw", + .cfg_name = "rtl_bt/rtl8761a_config", + .hw_info = "rtl8761au" }, /* 8761B */ { IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_UART), .config_needed = false, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8761b_fw.bin", - .cfg_name = "rtl_bt/rtl8761b_config" }, + .fw_name = "rtl_bt/rtl8761b_fw", + .cfg_name = "rtl_bt/rtl8761b_config", + .hw_info = "rtl8761btv" }, /* 8761BU */ { IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_USB), .config_needed = false, .has_rom_version = true, - .fw_name = "rtl_bt/rtl8761bu_fw.bin", - .cfg_name = "rtl_bt/rtl8761bu_config" }, + .fw_name = "rtl_bt/rtl8761bu_fw", + .cfg_name = "rtl_bt/rtl8761bu_config", + .hw_info = "rtl8761bu" }, /* 8822C with UART interface */ { IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0x8, HCI_UART), .config_needed = true, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8822cs_fw.bin", - .cfg_name = "rtl_bt/rtl8822cs_config" }, + .fw_name = "rtl_bt/rtl8822cs_fw", + .cfg_name = "rtl_bt/rtl8822cs_config", + .hw_info = "rtl8822cs" }, /* 8822C with UART interface */ { IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART), .config_needed = true, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8822cs_fw.bin", - .cfg_name = "rtl_bt/rtl8822cs_config" }, + .fw_name = "rtl_bt/rtl8822cs_fw", + .cfg_name = "rtl_bt/rtl8822cs_config", + .hw_info = "rtl8822cs" }, /* 8822C with USB interface */ { IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_USB), .config_needed = false, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8822cu_fw.bin", - .cfg_name = "rtl_bt/rtl8822cu_config" }, + .fw_name = "rtl_bt/rtl8822cu_fw", + .cfg_name = "rtl_bt/rtl8822cu_config", + .hw_info = "rtl8822cu" }, /* 8822B */ { IC_INFO(RTL_ROM_LMP_8822B, 0xb, 0x7, HCI_USB), .config_needed = true, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8822b_fw.bin", - .cfg_name = "rtl_bt/rtl8822b_config" }, + .fw_name = "rtl_bt/rtl8822b_fw", + .cfg_name = "rtl_bt/rtl8822b_config", + .hw_info = "rtl8822bu" }, /* 8852A */ { IC_INFO(RTL_ROM_LMP_8852A, 0xa, 0xb, HCI_USB), .config_needed = false, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8852au_fw.bin", - .cfg_name = "rtl_bt/rtl8852au_config" }, + .fw_name = "rtl_bt/rtl8852au_fw", + .cfg_name = "rtl_bt/rtl8852au_config", + .hw_info = "rtl8852au" }, /* 8852B with UART interface */ { IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_UART), .config_needed = true, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8852bs_fw.bin", - .cfg_name = "rtl_bt/rtl8852bs_config" }, + .fw_name = "rtl_bt/rtl8852bs_fw", + .cfg_name = "rtl_bt/rtl8852bs_config", + .hw_info = "rtl8852bs" }, /* 8852B */ { IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_USB), .config_needed = false, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8852bu_fw.bin", - .cfg_name = "rtl_bt/rtl8852bu_config" }, + .fw_name = "rtl_bt/rtl8852bu_fw", + .cfg_name = "rtl_bt/rtl8852bu_config", + .hw_info = "rtl8852bu" }, /* 8852C */ { IC_INFO(RTL_ROM_LMP_8852A, 0xc, 0xc, HCI_USB), .config_needed = false, .has_rom_version = true, .has_msft_ext = true, - .fw_name = "rtl_bt/rtl8852cu_fw.bin", - .cfg_name = "rtl_bt/rtl8852cu_config" }, + .fw_name = "rtl_bt/rtl8852cu_fw", + .cfg_name = "rtl_bt/rtl8852cu_config", + .hw_info = "rtl8852cu" }, /* 8851B */ { IC_INFO(RTL_ROM_LMP_8851B, 0xb, 0xc, HCI_USB), .config_needed = false, .has_rom_version = true, .has_msft_ext = false, - .fw_name = "rtl_bt/rtl8851bu_fw.bin", - .cfg_name = "rtl_bt/rtl8851bu_config" }, + .fw_name = "rtl_bt/rtl8851bu_fw", + .cfg_name = "rtl_bt/rtl8851bu_config", + .hw_info = "rtl8851bu" }, }; static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev, @@ -590,6 +616,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, unsigned char **_buf) { static const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; + struct btrealtek_data *coredump_info = hci_get_priv(hdev); struct rtl_epatch_header *epatch_info; unsigned char *buf; int i, len; @@ -705,8 +732,10 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, epatch_info = (struct rtl_epatch_header *)btrtl_dev->fw_data; num_patches = le16_to_cpu(epatch_info->num_patches); + BT_DBG("fw_version=%x, num_patches=%d", le32_to_cpu(epatch_info->fw_version), num_patches); + coredump_info->rtl_dump.fw_version = le32_to_cpu(epatch_info->fw_version); /* After the rtl_epatch_header there is a funky patch metadata section. * Assuming 2 patches, the layout is: @@ -903,6 +932,53 @@ out: return ret; } +static void btrtl_coredump(struct hci_dev *hdev) +{ + static const u8 param[] = { 0x00, 0x00 }; + + __hci_cmd_send(hdev, RTL_VSC_OP_COREDUMP, sizeof(param), param); +} + +static void btrtl_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct btrealtek_data *coredump_info = hci_get_priv(hdev); + char buf[80]; + + if (coredump_info->rtl_dump.controller) + snprintf(buf, sizeof(buf), "Controller Name: %s\n", + coredump_info->rtl_dump.controller); + else + snprintf(buf, sizeof(buf), "Controller Name: Unknown\n"); + skb_put_data(skb, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n", + coredump_info->rtl_dump.fw_version); + skb_put_data(skb, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Driver: %s\n", coredump_info->rtl_dump.driver_name); + skb_put_data(skb, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Vendor: Realtek\n"); + skb_put_data(skb, buf, strlen(buf)); +} + +static int btrtl_register_devcoredump_support(struct hci_dev *hdev) +{ + int err; + + err = hci_devcd_register(hdev, btrtl_coredump, btrtl_dmp_hdr, NULL); + + return err; +} + +void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name) +{ + struct btrealtek_data *coredump_info = hci_get_priv(hdev); + + coredump_info->rtl_dump.driver_name = driver_name; +} +EXPORT_SYMBOL_GPL(btrtl_set_driver_name); + static bool rtl_has_chip_type(u16 lmp_subver) { switch (lmp_subver) { @@ -964,15 +1040,16 @@ EXPORT_SYMBOL_GPL(btrtl_free); struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, const char *postfix) { + struct btrealtek_data *coredump_info = hci_get_priv(hdev); struct btrtl_device_info *btrtl_dev; struct sk_buff *skb; struct hci_rp_read_local_version *resp; + struct hci_command_hdr *cmd; + char fw_name[40]; char cfg_name[40]; u16 hci_rev, lmp_subver; u8 hci_ver, lmp_ver, chip_type = 0; int ret; - u16 opcode; - u8 cmd[2]; u8 reg_val[2]; btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL); @@ -1041,15 +1118,14 @@ next: btrtl_dev->drop_fw = false; if (btrtl_dev->drop_fw) { - opcode = hci_opcode_pack(0x3f, 0x66); - cmd[0] = opcode & 0xff; - cmd[1] = opcode >> 8; - - skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); + skb = bt_skb_alloc(sizeof(*cmd), GFP_KERNEL); if (!skb) goto err_free; - skb_put_data(skb, cmd, sizeof(cmd)); + cmd = skb_put(skb, HCI_COMMAND_HDR_SIZE); + cmd->opcode = cpu_to_le16(0xfc66); + cmd->plen = 0; + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; ret = hdev->send(hdev, skb); @@ -1079,8 +1155,26 @@ next: goto err_free; } - btrtl_dev->fw_len = rtl_load_file(hdev, btrtl_dev->ic_info->fw_name, - &btrtl_dev->fw_data); + if (!btrtl_dev->ic_info->fw_name) { + ret = -ENOMEM; + goto err_free; + } + + btrtl_dev->fw_len = -EIO; + if (lmp_subver == RTL_ROM_LMP_8852A && hci_rev == 0x000c) { + snprintf(fw_name, sizeof(fw_name), "%s_v2.bin", + btrtl_dev->ic_info->fw_name); + btrtl_dev->fw_len = rtl_load_file(hdev, fw_name, + &btrtl_dev->fw_data); + } + + if (btrtl_dev->fw_len < 0) { + snprintf(fw_name, sizeof(fw_name), "%s.bin", + btrtl_dev->ic_info->fw_name); + btrtl_dev->fw_len = rtl_load_file(hdev, fw_name, + &btrtl_dev->fw_data); + } + if (btrtl_dev->fw_len < 0) { rtl_dev_err(hdev, "firmware file %s not found", btrtl_dev->ic_info->fw_name); @@ -1113,6 +1207,9 @@ next: if (btrtl_dev->ic_info->has_msft_ext) hci_set_msft_opcode(hdev, 0xFCF0); + if (btrtl_dev->ic_info) + coredump_info->rtl_dump.controller = btrtl_dev->ic_info->hw_info; + return btrtl_dev; err_free: @@ -1125,6 +1222,8 @@ EXPORT_SYMBOL_GPL(btrtl_initialize); int btrtl_download_firmware(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev) { + int err = 0; + /* Match a set of subver values that correspond to stock firmware, * which is not compatible with standard btusb. * If matched, upload an alternative firmware that does conform to @@ -1133,12 +1232,14 @@ int btrtl_download_firmware(struct hci_dev *hdev, */ if (!btrtl_dev->ic_info) { rtl_dev_info(hdev, "assuming no firmware upload needed"); - return 0; + err = 0; + goto done; } switch (btrtl_dev->ic_info->lmp_subver) { case RTL_ROM_LMP_8723A: - return btrtl_setup_rtl8723a(hdev, btrtl_dev); + err = btrtl_setup_rtl8723a(hdev, btrtl_dev); + break; case RTL_ROM_LMP_8723B: case RTL_ROM_LMP_8821A: case RTL_ROM_LMP_8761A: @@ -1146,11 +1247,18 @@ int btrtl_download_firmware(struct hci_dev *hdev, case RTL_ROM_LMP_8852A: case RTL_ROM_LMP_8703B: case RTL_ROM_LMP_8851B: - return btrtl_setup_rtl8723b(hdev, btrtl_dev); + err = btrtl_setup_rtl8723b(hdev, btrtl_dev); + break; default: rtl_dev_info(hdev, "assuming no firmware upload needed"); - return 0; + break; } + +done: + if (!err) + err = btrtl_register_devcoredump_support(hdev); + + return err; } EXPORT_SYMBOL_GPL(btrtl_download_firmware); @@ -1180,6 +1288,10 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev) if (btrtl_dev->project_id == CHIP_ID_8852C) btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP); + if (btrtl_dev->project_id == CHIP_ID_8852A || + btrtl_dev->project_id == CHIP_ID_8852C) + set_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks); + hci_set_aosp_capable(hdev); break; default: @@ -1398,4 +1510,5 @@ MODULE_FIRMWARE("rtl_bt/rtl8852bs_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8852bu_fw.bin"); MODULE_FIRMWARE("rtl_bt/rtl8852bu_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw.bin"); +MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw_v2.bin"); MODULE_FIRMWARE("rtl_bt/rtl8852cu_config.bin"); diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h index adb4c2c9abc5..a2d9d34f9fb0 100644 --- a/drivers/bluetooth/btrtl.h +++ b/drivers/bluetooth/btrtl.h @@ -109,8 +109,16 @@ enum { __REALTEK_NUM_FLAGS, }; +struct rtl_dump_info { + const char *driver_name; + char *controller; + u32 fw_version; +}; + struct btrealtek_data { DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS); + + struct rtl_dump_info rtl_dump; }; #define btrealtek_set_flag(hdev, nr) \ @@ -139,6 +147,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev, unsigned int *controller_baudrate, u32 *device_baudrate, bool *flow_control); +void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name); #else @@ -182,4 +191,8 @@ static inline int btrtl_get_uart_settings(struct hci_dev *hdev, return -ENOENT; } +static inline void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name) +{ +} + #endif diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 5ec4ad0a5c86..82597ab4f747 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -175,7 +175,7 @@ static const struct usb_device_id btusb_table[] = { MODULE_DEVICE_TABLE(usb, btusb_table); -static const struct usb_device_id blacklist_table[] = { +static const struct usb_device_id quirks_table[] = { /* CSR BlueCore devices */ { USB_DEVICE(0x0a12, 0x0001), .driver_info = BTUSB_CSR }, @@ -476,6 +476,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x8087, 0x0032), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0035), .driver_info = BTUSB_INTEL_COMBINED }, + { USB_DEVICE(0x8087, 0x0036), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR }, { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED | BTUSB_INTEL_NO_WBS_SUPPORT | @@ -625,9 +626,24 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe0e4), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x0489, 0xe0f1), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, { USB_DEVICE(0x0489, 0xe0f2), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x0489, 0xe0f5), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x0489, 0xe0f6), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x0489, 0xe102), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, /* Additional Realtek 8723AE Bluetooth devices */ { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, @@ -860,10 +876,26 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); struct gpio_desc *reset_gpio = data->reset_gpio; + struct btintel_data *intel_data = hci_get_priv(hdev); if (++data->cmd_timeout_cnt < 5) return; + if (intel_data->acpi_reset_method) { + if (test_and_set_bit(INTEL_ACPI_RESET_ACTIVE, intel_data->flags)) { + bt_dev_err(hdev, "acpi: last reset failed ? Not resetting again"); + return; + } + + bt_dev_err(hdev, "Initiating acpi reset method"); + /* If ACPI reset method fails, lets try with legacy GPIO + * toggling + */ + if (!intel_data->acpi_reset_method(hdev)) { + return; + } + } + if (!reset_gpio) { btusb_reset(hdev); return; @@ -887,10 +919,49 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev) gpiod_set_value_cansleep(reset_gpio, 0); } +#define RTK_DEVCOREDUMP_CODE_MEMDUMP 0x01 +#define RTK_DEVCOREDUMP_CODE_HW_ERR 0x02 +#define RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT 0x03 + +#define RTK_SUB_EVENT_CODE_COREDUMP 0x34 + +struct rtk_dev_coredump_hdr { + u8 type; + u8 code; + u8 reserved[2]; +} __packed; + +static inline void btusb_rtl_alloc_devcoredump(struct hci_dev *hdev, + struct rtk_dev_coredump_hdr *hdr, u8 *buf, u32 len) +{ + struct sk_buff *skb; + + skb = alloc_skb(len + sizeof(*hdr), GFP_ATOMIC); + if (!skb) + return; + + skb_put_data(skb, hdr, sizeof(*hdr)); + if (len) + skb_put_data(skb, buf, len); + + if (!hci_devcd_init(hdev, skb->len)) { + hci_devcd_append(hdev, skb); + hci_devcd_complete(hdev); + } else { + bt_dev_err(hdev, "RTL: Failed to generate devcoredump"); + kfree_skb(skb); + } +} + static void btusb_rtl_cmd_timeout(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); struct gpio_desc *reset_gpio = data->reset_gpio; + struct rtk_dev_coredump_hdr hdr = { + .type = RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT, + }; + + btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0); if (++data->cmd_timeout_cnt < 5) return; @@ -917,6 +988,18 @@ static void btusb_rtl_cmd_timeout(struct hci_dev *hdev) gpiod_set_value_cansleep(reset_gpio, 0); } +static void btusb_rtl_hw_error(struct hci_dev *hdev, u8 code) +{ + struct rtk_dev_coredump_hdr hdr = { + .type = RTK_DEVCOREDUMP_CODE_HW_ERR, + .code = code, + }; + + bt_dev_err(hdev, "RTL: hw err, trigger devcoredump (%d)", code); + + btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0); +} + static void btusb_qca_cmd_timeout(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -2079,7 +2162,7 @@ static int btusb_switch_alt_setting(struct hci_dev *hdev, int new_alts) * alternate setting. */ spin_lock_irqsave(&data->rxlock, flags); - kfree_skb(data->sco_skb); + dev_kfree_skb_irq(data->sco_skb); data->sco_skb = NULL; spin_unlock_irqrestore(&data->rxlock, flags); @@ -2409,79 +2492,6 @@ static int btusb_recv_bulk_intel(struct btusb_data *data, void *buffer, return btusb_recv_bulk(data, buffer, count); } -static int btusb_intel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct intel_tlv *tlv = (void *)&skb->data[5]; - - /* The first event is always an event type TLV */ - if (tlv->type != INTEL_TLV_TYPE_ID) - goto recv_frame; - - switch (tlv->val[0]) { - case INTEL_TLV_SYSTEM_EXCEPTION: - case INTEL_TLV_FATAL_EXCEPTION: - case INTEL_TLV_DEBUG_EXCEPTION: - case INTEL_TLV_TEST_EXCEPTION: - /* Generate devcoredump from exception */ - if (!hci_devcd_init(hdev, skb->len)) { - hci_devcd_append(hdev, skb); - hci_devcd_complete(hdev); - } else { - bt_dev_err(hdev, "Failed to generate devcoredump"); - kfree_skb(skb); - } - return 0; - default: - bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]); - } - -recv_frame: - return hci_recv_frame(hdev, skb); -} - -static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct hci_event_hdr *hdr = (void *)skb->data; - const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 }; - - if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff && - hdr->plen > 0) { - const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1; - unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1; - - if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) { - switch (skb->data[2]) { - case 0x02: - /* When switching to the operational firmware - * the device sends a vendor specific event - * indicating that the bootup completed. - */ - btintel_bootup(hdev, ptr, len); - break; - case 0x06: - /* When the firmware loading completes the - * device sends out a vendor specific event - * indicating the result of the firmware - * loading. - */ - btintel_secure_send_result(hdev, ptr, len); - break; - } - } - - /* Handle all diagnostics events separately. May still call - * hci_recv_frame. - */ - if (len >= sizeof(diagnostics_hdr) && - memcmp(&skb->data[2], diagnostics_hdr, - sizeof(diagnostics_hdr)) == 0) { - return btusb_intel_diagnostics(hdev, skb); - } - } - - return hci_recv_frame(hdev, skb); -} - static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) { struct urb *urb; @@ -2562,6 +2572,25 @@ static int btusb_setup_realtek(struct hci_dev *hdev) return ret; } +static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb) +{ + if (skb->data[0] == HCI_VENDOR_PKT && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) { + struct rtk_dev_coredump_hdr hdr = { + .code = RTK_DEVCOREDUMP_CODE_MEMDUMP, + }; + + bt_dev_dbg(hdev, "RTL: received coredump vendor evt, len %u", + skb->len); + + btusb_rtl_alloc_devcoredump(hdev, &hdr, skb->data, skb->len); + kfree_skb(skb); + + return 0; + } + + return hci_recv_frame(hdev, skb); +} + /* UHW CR mapping */ #define MTK_BT_MISC 0x70002510 #define MTK_BT_SUBSYS_RST 0x70002610 @@ -2571,8 +2600,9 @@ static int btusb_setup_realtek(struct hci_dev *hdev) #define MTK_EP_RST_OPT 0x74011890 #define MTK_EP_RST_IN_OUT_OPT 0x00010001 #define MTK_BT_RST_DONE 0x00000100 -#define MTK_BT_RESET_WAIT_MS 100 -#define MTK_BT_RESET_NUM_TRIES 10 +#define MTK_BT_RESET_REG_CONNV3 0x70028610 +#define MTK_BT_READ_DEV_ID 0x70010200 + static void btusb_mtk_wmt_recv(struct urb *urb) { @@ -2943,6 +2973,88 @@ static int btusb_mtk_id_get(struct btusb_data *data, u32 reg, u32 *id) return btusb_mtk_reg_read(data, reg, id); } +static u32 btusb_mtk_reset_done(struct hci_dev *hdev) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + u32 val = 0; + + btusb_mtk_uhw_reg_read(data, MTK_BT_MISC, &val); + + return val & MTK_BT_RST_DONE; +} + +static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct btmediatek_data *mediatek; + u32 val; + int err; + + /* It's MediaTek specific bluetooth reset mechanism via USB */ + if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) { + bt_dev_err(hdev, "last reset failed? Not resetting again"); + return -EBUSY; + } + + err = usb_autopm_get_interface(data->intf); + if (err < 0) + return err; + + btusb_stop_traffic(data); + usb_kill_anchored_urbs(&data->tx_anchor); + mediatek = hci_get_priv(hdev); + + if (mediatek->dev_id == 0x7925) { + btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val); + val |= (1 << 5); + btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val); + btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val); + val &= 0xFFFF00FF; + val |= (1 << 13); + btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val); + btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, 0x00010001); + btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val); + val |= (1 << 0); + btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val); + btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF); + btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val); + btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF); + btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val); + msleep(100); + } else { + /* It's Device EndPoint Reset Option Register */ + bt_dev_dbg(hdev, "Initiating reset mechanism via uhw"); + btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT); + btusb_mtk_uhw_reg_read(data, MTK_BT_WDT_STATUS, &val); + + /* Reset the bluetooth chip via USB interface. */ + btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 1); + btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF); + btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val); + btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF); + btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val); + /* MT7921 need to delay 20ms between toggle reset bit */ + msleep(20); + btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 0); + btusb_mtk_uhw_reg_read(data, MTK_BT_SUBSYS_RST, &val); + } + + err = readx_poll_timeout(btusb_mtk_reset_done, hdev, val, + val & MTK_BT_RST_DONE, 20000, 1000000); + if (err < 0) + bt_dev_err(hdev, "Reset timeout"); + + btusb_mtk_id_get(data, 0x70010200, &val); + if (!val) + bt_dev_err(hdev, "Can't get device id, subsys reset fail."); + + usb_queue_reset_device(data->intf); + + clear_bit(BTUSB_HW_RESET_ACTIVE, &data->flags); + + return err; +} + static int btusb_mtk_setup(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -2953,10 +3065,11 @@ static int btusb_mtk_setup(struct hci_dev *hdev) struct sk_buff *skb; const char *fwname; int err, status; - u32 dev_id; + u32 dev_id = 0; char fw_bin_name[64]; u32 fw_version = 0; u8 param; + struct btmediatek_data *mediatek; calltime = ktime_get(); @@ -2966,7 +3079,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev) return err; } - if (!dev_id) { + if (!dev_id || dev_id != 0x7663) { err = btusb_mtk_id_get(data, 0x70010200, &dev_id); if (err < 0) { bt_dev_err(hdev, "Failed to get device id (%d)", err); @@ -2979,6 +3092,14 @@ static int btusb_mtk_setup(struct hci_dev *hdev) } } + mediatek = hci_get_priv(hdev); + mediatek->dev_id = dev_id; + mediatek->reset_sync = btusb_mtk_reset; + + err = btmtk_register_coredump(hdev, btusb_driver.name, fw_version); + if (err < 0) + bt_dev_err(hdev, "Failed to register coredump (%d)", err); + switch (dev_id) { case 0x7663: fwname = FIRMWARE_MT7663; @@ -2988,9 +3109,16 @@ static int btusb_mtk_setup(struct hci_dev *hdev) break; case 0x7922: case 0x7961: - snprintf(fw_bin_name, sizeof(fw_bin_name), - "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin", - dev_id & 0xffff, (fw_version & 0xff) + 1); + case 0x7925: + if (dev_id == 0x7925) + snprintf(fw_bin_name, sizeof(fw_bin_name), + "mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin", + dev_id & 0xffff, dev_id & 0xffff, (fw_version & 0xff) + 1); + else + snprintf(fw_bin_name, sizeof(fw_bin_name), + "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin", + dev_id & 0xffff, (fw_version & 0xff) + 1); + err = btmtk_setup_firmware_79xx(hdev, fw_bin_name, btusb_mtk_hci_wmt_sync); if (err < 0) { @@ -3128,67 +3256,11 @@ static int btusb_mtk_shutdown(struct hci_dev *hdev) return 0; } -static void btusb_mtk_cmd_timeout(struct hci_dev *hdev) -{ - struct btusb_data *data = hci_get_drvdata(hdev); - u32 val; - int err, retry = 0; - - /* It's MediaTek specific bluetooth reset mechanism via USB */ - if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) { - bt_dev_err(hdev, "last reset failed? Not resetting again"); - return; - } - - err = usb_autopm_get_interface(data->intf); - if (err < 0) - return; - - btusb_stop_traffic(data); - usb_kill_anchored_urbs(&data->tx_anchor); - - /* It's Device EndPoint Reset Option Register */ - bt_dev_dbg(hdev, "Initiating reset mechanism via uhw"); - btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT); - btusb_mtk_uhw_reg_read(data, MTK_BT_WDT_STATUS, &val); - - /* Reset the bluetooth chip via USB interface. */ - btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 1); - btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF); - btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val); - btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF); - btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val); - /* MT7921 need to delay 20ms between toggle reset bit */ - msleep(20); - btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 0); - btusb_mtk_uhw_reg_read(data, MTK_BT_SUBSYS_RST, &val); - - /* Poll the register until reset is completed */ - do { - btusb_mtk_uhw_reg_read(data, MTK_BT_MISC, &val); - if (val & MTK_BT_RST_DONE) { - bt_dev_dbg(hdev, "Bluetooth Reset Successfully"); - break; - } - - bt_dev_dbg(hdev, "Polling Bluetooth Reset CR"); - retry++; - msleep(MTK_BT_RESET_WAIT_MS); - } while (retry < MTK_BT_RESET_NUM_TRIES); - - btusb_mtk_id_get(data, 0x70010200, &val); - if (!val) - bt_dev_err(hdev, "Can't get device id, subsys reset fail."); - - usb_queue_reset_device(data->intf); - - clear_bit(BTUSB_HW_RESET_ACTIVE, &data->flags); -} - static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb) { struct btusb_data *data = hci_get_drvdata(hdev); u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle); + struct sk_buff *skb_cd; switch (handle) { case 0xfc6f: /* Firmware dump from device */ @@ -3196,6 +3268,15 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb) * suspend and thus disable auto-suspend. */ usb_disable_autosuspend(data->udev); + + /* We need to forward the diagnostic packet to userspace daemon + * for backward compatibility, so we have to clone the packet + * extraly for the in-kernel coredump support. + */ + skb_cd = skb_clone(skb, GFP_ATOMIC); + if (skb_cd) + btmtk_process_coredump(hdev, skb_cd); + fallthrough; case 0x05ff: /* Firmware debug logging 1 */ case 0x05fe: /* Firmware debug logging 2 */ @@ -4104,6 +4185,7 @@ static int btusb_probe(struct usb_interface *intf, BT_DBG("intf %p id %p", intf, id); if ((id->driver_info & BTUSB_IFNUM_2) && + (intf->cur_altsetting->desc.bInterfaceNumber != 0) && (intf->cur_altsetting->desc.bInterfaceNumber != 2)) return -ENODEV; @@ -4112,7 +4194,7 @@ static int btusb_probe(struct usb_interface *intf, if (!id->driver_info) { const struct usb_device_id *match; - match = usb_match_id(intf, blacklist_table); + match = usb_match_id(intf, quirks_table); if (match) id = match; } @@ -4195,11 +4277,16 @@ static int btusb_probe(struct usb_interface *intf, priv_size += sizeof(struct btintel_data); /* Override the rx handlers */ - data->recv_event = btusb_recv_event_intel; + data->recv_event = btintel_recv_event; data->recv_bulk = btusb_recv_bulk_intel; } else if (id->driver_info & BTUSB_REALTEK) { /* Allocate extra space for Realtek device */ priv_size += sizeof(struct btrealtek_data); + + data->recv_event = btusb_recv_event_realtek; + } else if (id->driver_info & BTUSB_MEDIATEK) { + /* Allocate extra space for Mediatek device */ + priv_size += sizeof(struct btmediatek_data); } data->recv_acl = hci_recv_frame; @@ -4306,7 +4393,7 @@ static int btusb_probe(struct usb_interface *intf, hdev->setup = btusb_mtk_setup; hdev->shutdown = btusb_mtk_shutdown; hdev->manufacturer = 70; - hdev->cmd_timeout = btusb_mtk_cmd_timeout; + hdev->cmd_timeout = btmtk_reset_sync; hdev->set_bdaddr = btmtk_set_bdaddr; set_bit(HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN, &hdev->quirks); set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); @@ -4363,9 +4450,11 @@ static int btusb_probe(struct usb_interface *intf, if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) && (id->driver_info & BTUSB_REALTEK)) { + btrtl_set_driver_name(hdev, btusb_driver.name); hdev->setup = btusb_setup_realtek; hdev->shutdown = btrtl_shutdown_realtek; hdev->cmd_timeout = btusb_rtl_cmd_timeout; + hdev->hw_error = btusb_rtl_hw_error; /* Realtek devices need to set remote wakeup on auto-suspend */ set_bit(BTUSB_WAKEUP_AUTOSUSPEND, &data->flags); diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index fefc37b98b4a..71e748a9477e 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -11,7 +11,7 @@ #include <linux/gpio/consumer.h> #include <linux/kernel.h> #include <linux/mod_devicetable.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/serdev.h> #include <linux/skbuff.h> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index efdda2c3fce8..a76eb98c0047 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -770,7 +770,8 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, unsigned int cmd, break; case HCIUARTGETPROTO: - if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + if (test_bit(HCI_UART_PROTO_SET, &hu->flags) && + test_bit(HCI_UART_PROTO_READY, &hu->flags)) err = hu->proto->id; else err = -EUNATCH; diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c index 05f7f6de6863..97da0b2bfd17 100644 --- a/drivers/bluetooth/hci_nokia.c +++ b/drivers/bluetooth/hci_nokia.c @@ -734,7 +734,11 @@ static int nokia_bluetooth_serdev_probe(struct serdev_device *serdev) return err; } - clk_prepare_enable(sysclk); + err = clk_prepare_enable(sysclk); + if (err) { + dev_err(dev, "could not enable sysclk: %d", err); + return err; + } btdev->sysclk_speed = clk_get_rate(sysclk); clk_disable_unprepare(sysclk); diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index e30c979535b1..4b57e15f9c7a 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -25,7 +25,7 @@ #include <linux/gpio/consumer.h> #include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/acpi.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> @@ -117,9 +117,7 @@ enum qca_memdump_states { QCA_MEMDUMP_TIMEOUT, }; -struct qca_memdump_data { - char *memdump_buf_head; - char *memdump_buf_tail; +struct qca_memdump_info { u32 current_seq_no; u32 received_dump; u32 ram_dump_size; @@ -160,13 +158,15 @@ struct qca_data { struct work_struct ws_tx_vote_off; struct work_struct ctrl_memdump_evt; struct delayed_work ctrl_memdump_timeout; - struct qca_memdump_data *qca_memdump; + struct qca_memdump_info *qca_memdump; unsigned long flags; struct completion drop_ev_comp; wait_queue_head_t suspend_wait_q; enum qca_memdump_states memdump_state; struct mutex hci_memdump_lock; + u16 fw_version; + u16 controller_id; /* For debugging purpose */ u64 ibs_sent_wacks; u64 ibs_sent_slps; @@ -233,6 +233,7 @@ static void qca_regulator_disable(struct qca_serdev *qcadev); static void qca_power_shutdown(struct hci_uart *hu); static int qca_power_off(struct hci_dev *hdev); static void qca_controller_memdump(struct work_struct *work); +static void qca_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb); static enum qca_btsoc_type qca_soc_type(struct hci_uart *hu) { @@ -606,9 +607,18 @@ static int qca_open(struct hci_uart *hu) if (hu->serdev) { qcadev = serdev_device_get_drvdata(hu->serdev); - if (qca_is_wcn399x(qcadev->btsoc_type) || - qca_is_wcn6750(qcadev->btsoc_type)) + switch (qcadev->btsoc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: hu->init_speed = qcadev->init_speed; + break; + + default: + break; + } if (qcadev->oper_speed) hu->oper_speed = qcadev->oper_speed; @@ -980,6 +990,28 @@ static int qca_recv_acl_data(struct hci_dev *hdev, struct sk_buff *skb) return hci_recv_frame(hdev, skb); } +static void qca_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + struct qca_data *qca = hu->priv; + char buf[80]; + + snprintf(buf, sizeof(buf), "Controller Name: 0x%x\n", + qca->controller_id); + skb_put_data(skb, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Firmware Version: 0x%x\n", + qca->fw_version); + skb_put_data(skb, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Vendor:Qualcomm\n"); + skb_put_data(skb, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Driver: %s\n", + hu->serdev->dev.driver->name); + skb_put_data(skb, buf, strlen(buf)); +} + static void qca_controller_memdump(struct work_struct *work) { struct qca_data *qca = container_of(work, struct qca_data, @@ -987,13 +1019,11 @@ static void qca_controller_memdump(struct work_struct *work) struct hci_uart *hu = qca->hu; struct sk_buff *skb; struct qca_memdump_event_hdr *cmd_hdr; - struct qca_memdump_data *qca_memdump = qca->qca_memdump; + struct qca_memdump_info *qca_memdump = qca->qca_memdump; struct qca_dump_size *dump; - char *memdump_buf; - char nullBuff[QCA_DUMP_PACKET_SIZE] = { 0 }; u16 seq_no; - u32 dump_size; u32 rx_size; + int ret = 0; enum qca_btsoc_type soc_type = qca_soc_type(hu); while ((skb = skb_dequeue(&qca->rx_memdump_q))) { @@ -1009,7 +1039,7 @@ static void qca_controller_memdump(struct work_struct *work) } if (!qca_memdump) { - qca_memdump = kzalloc(sizeof(struct qca_memdump_data), + qca_memdump = kzalloc(sizeof(struct qca_memdump_info), GFP_ATOMIC); if (!qca_memdump) { mutex_unlock(&qca->hci_memdump_lock); @@ -1035,44 +1065,49 @@ static void qca_controller_memdump(struct work_struct *work) set_bit(QCA_IBS_DISABLED, &qca->flags); set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); dump = (void *) skb->data; - dump_size = __le32_to_cpu(dump->dump_size); - if (!(dump_size)) { + qca_memdump->ram_dump_size = __le32_to_cpu(dump->dump_size); + if (!(qca_memdump->ram_dump_size)) { bt_dev_err(hu->hdev, "Rx invalid memdump size"); kfree(qca_memdump); kfree_skb(skb); - qca->qca_memdump = NULL; mutex_unlock(&qca->hci_memdump_lock); return; } - bt_dev_info(hu->hdev, "QCA collecting dump of size:%u", - dump_size); queue_delayed_work(qca->workqueue, &qca->ctrl_memdump_timeout, - msecs_to_jiffies(MEMDUMP_TIMEOUT_MS) - ); - - skb_pull(skb, sizeof(dump_size)); - memdump_buf = vmalloc(dump_size); - qca_memdump->ram_dump_size = dump_size; - qca_memdump->memdump_buf_head = memdump_buf; - qca_memdump->memdump_buf_tail = memdump_buf; - } + msecs_to_jiffies(MEMDUMP_TIMEOUT_MS)); + skb_pull(skb, sizeof(qca_memdump->ram_dump_size)); + qca_memdump->current_seq_no = 0; + qca_memdump->received_dump = 0; + ret = hci_devcd_init(hu->hdev, qca_memdump->ram_dump_size); + bt_dev_info(hu->hdev, "hci_devcd_init Return:%d", + ret); + if (ret < 0) { + kfree(qca->qca_memdump); + qca->qca_memdump = NULL; + qca->memdump_state = QCA_MEMDUMP_COLLECTED; + cancel_delayed_work(&qca->ctrl_memdump_timeout); + clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + mutex_unlock(&qca->hci_memdump_lock); + return; + } - memdump_buf = qca_memdump->memdump_buf_tail; + bt_dev_info(hu->hdev, "QCA collecting dump of size:%u", + qca_memdump->ram_dump_size); + + } /* If sequence no 0 is missed then there is no point in * accepting the other sequences. */ - if (!memdump_buf) { + if (!test_bit(QCA_MEMDUMP_COLLECTION, &qca->flags)) { bt_dev_err(hu->hdev, "QCA: Discarding other packets"); kfree(qca_memdump); kfree_skb(skb); - qca->qca_memdump = NULL; mutex_unlock(&qca->hci_memdump_lock); return; } - /* There could be chance of missing some packets from * the controller. In such cases let us store the dummy * packets in the buffer. @@ -1082,8 +1117,8 @@ static void qca_controller_memdump(struct work_struct *work) * bits, so skip this checking for missing packet. */ while ((seq_no > qca_memdump->current_seq_no + 1) && - (soc_type != QCA_QCA6390) && - seq_no != QCA_LAST_SEQUENCE_NUM) { + (soc_type != QCA_QCA6390) && + seq_no != QCA_LAST_SEQUENCE_NUM) { bt_dev_err(hu->hdev, "QCA controller missed packet:%d", qca_memdump->current_seq_no); rx_size = qca_memdump->received_dump; @@ -1094,43 +1129,38 @@ static void qca_controller_memdump(struct work_struct *work) qca_memdump->received_dump); break; } - memcpy(memdump_buf, nullBuff, QCA_DUMP_PACKET_SIZE); - memdump_buf = memdump_buf + QCA_DUMP_PACKET_SIZE; + hci_devcd_append_pattern(hu->hdev, 0x00, + QCA_DUMP_PACKET_SIZE); qca_memdump->received_dump += QCA_DUMP_PACKET_SIZE; qca_memdump->current_seq_no++; } - rx_size = qca_memdump->received_dump + skb->len; + rx_size = qca_memdump->received_dump + skb->len; if (rx_size <= qca_memdump->ram_dump_size) { if ((seq_no != QCA_LAST_SEQUENCE_NUM) && - (seq_no != qca_memdump->current_seq_no)) + (seq_no != qca_memdump->current_seq_no)) { bt_dev_err(hu->hdev, "QCA memdump unexpected packet %d", seq_no); + } bt_dev_dbg(hu->hdev, "QCA memdump packet %d with length %d", seq_no, skb->len); - memcpy(memdump_buf, (unsigned char *)skb->data, - skb->len); - memdump_buf = memdump_buf + skb->len; - qca_memdump->memdump_buf_tail = memdump_buf; - qca_memdump->current_seq_no = seq_no + 1; - qca_memdump->received_dump += skb->len; + hci_devcd_append(hu->hdev, skb); + qca_memdump->current_seq_no += 1; + qca_memdump->received_dump = rx_size; } else { bt_dev_err(hu->hdev, - "QCA memdump received %d, no space for packet %d", - qca_memdump->received_dump, seq_no); + "QCA memdump received no space for packet %d", + qca_memdump->current_seq_no); } - qca->qca_memdump = qca_memdump; - kfree_skb(skb); + if (seq_no == QCA_LAST_SEQUENCE_NUM) { bt_dev_info(hu->hdev, - "QCA memdump Done, received %d, total %d", - qca_memdump->received_dump, - qca_memdump->ram_dump_size); - memdump_buf = qca_memdump->memdump_buf_head; - dev_coredumpv(&hu->serdev->dev, memdump_buf, - qca_memdump->received_dump, GFP_KERNEL); + "QCA memdump Done, received %d, total %d", + qca_memdump->received_dump, + qca_memdump->ram_dump_size); + hci_devcd_complete(hu->hdev); cancel_delayed_work(&qca->ctrl_memdump_timeout); kfree(qca->qca_memdump); qca->qca_memdump = NULL; @@ -1320,12 +1350,20 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS)); /* Give the controller time to process the request */ - if (qca_is_wcn399x(qca_soc_type(hu)) || - qca_is_wcn6750(qca_soc_type(hu)) || - qca_is_wcn6855(qca_soc_type(hu))) + switch (qca_soc_type(hu)) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: usleep_range(1000, 10000); - else + break; + + default: msleep(300); + } return 0; } @@ -1398,13 +1436,20 @@ static unsigned int qca_get_speed(struct hci_uart *hu, static int qca_check_speeds(struct hci_uart *hu) { - if (qca_is_wcn399x(qca_soc_type(hu)) || - qca_is_wcn6750(qca_soc_type(hu)) || - qca_is_wcn6855(qca_soc_type(hu))) { + switch (qca_soc_type(hu)) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: if (!qca_get_speed(hu, QCA_INIT_SPEED) && !qca_get_speed(hu, QCA_OPER_SPEED)) return -EINVAL; - } else { + break; + + default: if (!qca_get_speed(hu, QCA_INIT_SPEED) || !qca_get_speed(hu, QCA_OPER_SPEED)) return -EINVAL; @@ -1433,14 +1478,29 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) /* Disable flow control for wcn3990 to deassert RTS while * changing the baudrate of chip and host. */ - if (qca_is_wcn399x(soc_type) || - qca_is_wcn6750(soc_type) || - qca_is_wcn6855(soc_type)) + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: hci_uart_set_flow_control(hu, true); + break; - if (soc_type == QCA_WCN3990) { + default: + break; + } + + switch (soc_type) { + case QCA_WCN3990: reinit_completion(&qca->drop_ev_comp); set_bit(QCA_DROP_VENDOR_EVENT, &qca->flags); + break; + + default: + break; } qca_baudrate = qca_get_baudrate_value(speed); @@ -1452,12 +1512,23 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) host_set_baudrate(hu, speed); error: - if (qca_is_wcn399x(soc_type) || - qca_is_wcn6750(soc_type) || - qca_is_wcn6855(soc_type)) + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: hci_uart_set_flow_control(hu, false); + break; + + default: + break; + } - if (soc_type == QCA_WCN3990) { + switch (soc_type) { + case QCA_WCN3990: /* Wait for the controller to send the vendor event * for the baudrate change command. */ @@ -1469,6 +1540,10 @@ error: } clear_bit(QCA_DROP_VENDOR_EVENT, &qca->flags); + break; + + default: + break; } } @@ -1541,8 +1616,8 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code) mutex_lock(&qca->hci_memdump_lock); if (qca->memdump_state != QCA_MEMDUMP_COLLECTED) { bt_dev_err(hu->hdev, "clearing allocated memory due to memdump timeout"); + hci_devcd_abort(hu->hdev); if (qca->qca_memdump) { - vfree(qca->qca_memdump->memdump_buf_head); kfree(qca->qca_memdump); qca->qca_memdump = NULL; } @@ -1630,12 +1705,20 @@ static int qca_regulator_init(struct hci_uart *hu) } } - if (qca_is_wcn399x(soc_type)) { + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: /* Forcefully enable wcn399x to enter in to boot mode. */ host_set_baudrate(hu, 2400); ret = qca_send_power_pulse(hu, false); if (ret) return ret; + break; + + default: + break; } /* For wcn6750 need to enable gpio bt_en */ @@ -1652,10 +1735,18 @@ static int qca_regulator_init(struct hci_uart *hu) qca_set_speed(hu, QCA_INIT_SPEED); - if (qca_is_wcn399x(soc_type)) { + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: ret = qca_send_power_pulse(hu, true); if (ret) return ret; + break; + + default: + break; } /* Now the device is in ready state to communicate with host. @@ -1689,11 +1780,18 @@ static int qca_power_on(struct hci_dev *hdev) if (!hu->serdev) return 0; - if (qca_is_wcn399x(soc_type) || - qca_is_wcn6750(soc_type) || - qca_is_wcn6855(soc_type)) { + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: ret = qca_regulator_init(hu); - } else { + break; + + default: qcadev = serdev_device_get_drvdata(hu->serdev); if (qcadev->bt_en) { gpiod_set_value_cansleep(qcadev->bt_en, 1); @@ -1706,6 +1804,17 @@ static int qca_power_on(struct hci_dev *hdev) return ret; } +static void hci_coredump_qca(struct hci_dev *hdev) +{ + static const u8 param[] = { 0x26 }; + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, 0xfc0c, 1, param, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) + bt_dev_err(hdev, "%s: trigger crash failed (%ld)", __func__, PTR_ERR(skb)); + kfree_skb(skb); +} + static int qca_setup(struct hci_uart *hu) { struct hci_dev *hdev = hu->hdev; @@ -1716,6 +1825,7 @@ static int qca_setup(struct hci_uart *hu) const char *firmware_name = qca_get_firmware_name(hu); int ret; struct qca_btsoc_version ver; + const char *soc_name; ret = qca_check_speeds(hu); if (ret) @@ -1730,10 +1840,30 @@ static int qca_setup(struct hci_uart *hu) */ set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); - bt_dev_info(hdev, "setting up %s", - qca_is_wcn399x(soc_type) ? "wcn399x" : - (soc_type == QCA_WCN6750) ? "wcn6750" : - (soc_type == QCA_WCN6855) ? "wcn6855" : "ROME/QCA6390"); + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + soc_name = "wcn399x"; + break; + + case QCA_WCN6750: + soc_name = "wcn6750"; + break; + + case QCA_WCN6855: + soc_name = "wcn6855"; + break; + + case QCA_WCN7850: + soc_name = "wcn7850"; + break; + + default: + soc_name = "ROME/QCA6390"; + } + bt_dev_info(hdev, "setting up %s", soc_name); qca->memdump_state = QCA_MEMDUMP_IDLE; @@ -1744,16 +1874,23 @@ retry: clear_bit(QCA_SSR_TRIGGERED, &qca->flags); - if (qca_is_wcn399x(soc_type) || - qca_is_wcn6750(soc_type) || - qca_is_wcn6855(soc_type)) { + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); hci_set_aosp_capable(hdev); ret = qca_read_soc_version(hdev, &ver, soc_type); if (ret) goto out; - } else { + break; + + default: qca_set_speed(hu, QCA_INIT_SPEED); } @@ -1767,9 +1904,17 @@ retry: qca_baudrate = qca_get_baudrate_value(speed); } - if (!(qca_is_wcn399x(soc_type) || - qca_is_wcn6750(soc_type) || - qca_is_wcn6855(soc_type))) { + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: + break; + + default: /* Get QCA version information */ ret = qca_read_soc_version(hdev, &ver, soc_type); if (ret) @@ -1820,6 +1965,9 @@ out: hu->hdev->set_bdaddr = qca_set_bdaddr_rome; else hu->hdev->set_bdaddr = qca_set_bdaddr; + qca->fw_version = le16_to_cpu(ver.patch_ver); + qca->controller_id = le16_to_cpu(ver.rom_ver); + hci_devcd_register(hdev, hci_coredump_qca, qca_dmp_hdr, NULL); return ret; } @@ -1839,6 +1987,17 @@ static const struct hci_uart_proto qca_proto = { .dequeue = qca_dequeue, }; +static const struct qca_device_data qca_soc_data_wcn3988 __maybe_unused = { + .soc_type = QCA_WCN3988, + .vregs = (struct qca_vreg []) { + { "vddio", 15000 }, + { "vddxo", 80000 }, + { "vddrf", 300000 }, + { "vddch0", 450000 }, + }, + .num_vregs = 4, +}; + static const struct qca_device_data qca_soc_data_wcn3990 __maybe_unused = { .soc_type = QCA_WCN3990, .vregs = (struct qca_vreg []) { @@ -1909,6 +2068,20 @@ static const struct qca_device_data qca_soc_data_wcn6855 __maybe_unused = { .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES, }; +static const struct qca_device_data qca_soc_data_wcn7850 __maybe_unused = { + .soc_type = QCA_WCN7850, + .vregs = (struct qca_vreg []) { + { "vddio", 5000 }, + { "vddaon", 26000 }, + { "vdddig", 126000 }, + { "vddrfa0p8", 102000 }, + { "vddrfa1p2", 257000 }, + { "vddrfa1p9", 302000 }, + }, + .num_vregs = 6, + .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES, +}; + static void qca_power_shutdown(struct hci_uart *hu) { struct qca_serdev *qcadev; @@ -1934,11 +2107,18 @@ static void qca_power_shutdown(struct hci_uart *hu) qcadev = serdev_device_get_drvdata(hu->serdev); - if (qca_is_wcn399x(soc_type)) { + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: host_set_baudrate(hu, 2400); qca_send_power_pulse(hu, false); qca_regulator_disable(qcadev); - } else if (soc_type == QCA_WCN6750 || soc_type == QCA_WCN6855) { + break; + + case QCA_WCN6750: + case QCA_WCN6855: gpiod_set_value_cansleep(qcadev->bt_en, 0); msleep(100); qca_regulator_disable(qcadev); @@ -1946,7 +2126,9 @@ static void qca_power_shutdown(struct hci_uart *hu) sw_ctrl_state = gpiod_get_value_cansleep(qcadev->sw_ctrl); bt_dev_dbg(hu->hdev, "SW_CTRL is %d", sw_ctrl_state); } - } else if (qcadev->bt_en) { + break; + + default: gpiod_set_value_cansleep(qcadev->bt_en, 0); } @@ -2071,11 +2253,19 @@ static int qca_serdev_probe(struct serdev_device *serdev) if (!qcadev->oper_speed) BT_DBG("UART will pick default operating speed"); - if (data && - (qca_is_wcn399x(data->soc_type) || - qca_is_wcn6750(data->soc_type) || - qca_is_wcn6855(data->soc_type))) { + if (data) qcadev->btsoc_type = data->soc_type; + else + qcadev->btsoc_type = QCA_ROME; + + switch (qcadev->btsoc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: qcadev->bt_power = devm_kzalloc(&serdev->dev, sizeof(struct qca_power), GFP_KERNEL); @@ -2105,7 +2295,8 @@ static int qca_serdev_probe(struct serdev_device *serdev) GPIOD_IN); if (IS_ERR_OR_NULL(qcadev->sw_ctrl) && (data->soc_type == QCA_WCN6750 || - data->soc_type == QCA_WCN6855)) + data->soc_type == QCA_WCN6855 || + data->soc_type == QCA_WCN7850)) dev_warn(&serdev->dev, "failed to acquire SW_CTRL gpio\n"); qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL); @@ -2119,12 +2310,9 @@ static int qca_serdev_probe(struct serdev_device *serdev) BT_ERR("wcn3990 serdev registration failed"); return err; } - } else { - if (data) - qcadev->btsoc_type = data->soc_type; - else - qcadev->btsoc_type = QCA_ROME; + break; + default: qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable", GPIOD_OUT_LOW); if (IS_ERR_OR_NULL(qcadev->bt_en)) { @@ -2180,13 +2368,24 @@ static void qca_serdev_remove(struct serdev_device *serdev) struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); struct qca_power *power = qcadev->bt_power; - if ((qca_is_wcn399x(qcadev->btsoc_type) || - qca_is_wcn6750(qcadev->btsoc_type) || - qca_is_wcn6855(qcadev->btsoc_type)) && - power->vregs_on) - qca_power_shutdown(&qcadev->serdev_hu); - else if (qcadev->susclk) - clk_disable_unprepare(qcadev->susclk); + switch (qcadev->btsoc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: + if (power->vregs_on) { + qca_power_shutdown(&qcadev->serdev_hu); + break; + } + fallthrough; + + default: + if (qcadev->susclk) + clk_disable_unprepare(qcadev->susclk); + } hci_uart_unregister_device(&qcadev->serdev_hu); } @@ -2363,11 +2562,13 @@ static const struct of_device_id qca_bluetooth_of_match[] = { { .compatible = "qcom,qca6174-bt" }, { .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390}, { .compatible = "qcom,qca9377-bt" }, + { .compatible = "qcom,wcn3988-bt", .data = &qca_soc_data_wcn3988}, { .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990}, { .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991}, { .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998}, { .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750}, { .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855}, + { .compatible = "qcom,wcn7850-bt", .data = &qca_soc_data_wcn7850}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match); @@ -2384,6 +2585,18 @@ static const struct acpi_device_id qca_bluetooth_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, qca_bluetooth_acpi_match); #endif +#ifdef CONFIG_DEV_COREDUMP +static void hciqca_coredump(struct device *dev) +{ + struct serdev_device *serdev = to_serdev_device(dev); + struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); + struct hci_uart *hu = &qcadev->serdev_hu; + struct hci_dev *hdev = hu->hdev; + + if (hdev->dump.coredump) + hdev->dump.coredump(hdev); +} +#endif static struct serdev_device_driver qca_serdev_driver = { .probe = qca_serdev_probe, @@ -2394,6 +2607,9 @@ static struct serdev_device_driver qca_serdev_driver = { .acpi_match_table = ACPI_PTR(qca_bluetooth_acpi_match), .shutdown = qca_serdev_shutdown, .pm = &qca_pm_ops, +#ifdef CONFIG_DEV_COREDUMP + .coredump = hciqca_coredump, +#endif }, }; |