mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'for-net-next-2024-07-15' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Luiz Augusto von Dentz says: ==================== bluetooth-next pull request for net-next: - qca: use the power sequencer for QCA6390 - btusb: mediatek: add ISO data transmission functions - hci_bcm4377: Add BCM4388 support - btintel: Add support for BlazarU core - btintel: Add support for Whale Peak2 - btnxpuart: Add support for AW693 A1 chipset - btnxpuart: Add support for IW615 chipset - btusb: Add Realtek RTL8852BE support ID 0x13d3:0x3591 * tag 'for-net-next-2024-07-15' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (71 commits) Bluetooth: btmtk: Mark all stub functions as inline Bluetooth: hci_qca: Fix build error Bluetooth: hci_qca: use the power sequencer for wcn7850 and wcn6855 Bluetooth: hci_qca: make pwrseq calls the default if available Bluetooth: hci_qca: unduplicate calls to hci_uart_register_device() Bluetooth: hci_qca: schedule a devm action for disabling the clock dt-bindings: bluetooth: qualcomm: describe the inputs from PMU for wcn7850 Bluetooth: btnxpuart: Fix warnings for suspend and resume functions Bluetooth: btnxpuart: Add system suspend and resume handlers Bluetooth: btnxpuart: Add support for IW615 chipset Bluetooth: btnxpuart: Add support for AW693 A1 chipset Bluetooth: btintel: Add support for Whale Peak2 Bluetooth: btintel: Add support for BlazarU core Bluetooth: btusb: mediatek: add ISO data transmission functions Bluetooth: btmtk: move btusb_recv_acl_mtk to btmtk.c Bluetooth: btmtk: move btusb_mtk_[setup, shutdown] to btmtk.c Bluetooth: btmtk: move btusb_mtk_hci_wmt_sync to btmtk.c Bluetooth: btusb: add callback function in btusb suspend/resume Bluetooth: btmtk: rename btmediatek_data Bluetooth: btusb: mediatek: return error for failed reg access ... ==================== Link: https://patch.msgid.link/20240715142543.303944-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/bluetooth/mediatek,mt7622-bluetooth.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek SoC built-in Bluetooth
|
||||
|
||||
description:
|
||||
This device is a serial attached device to BTIF device and thus it must be a
|
||||
child node of the serial node with BTIF. The dt-bindings details for BTIF
|
||||
device can be known via Documentation/devicetree/bindings/serial/8250.yaml.
|
||||
|
||||
maintainers:
|
||||
- Sean Wang <sean.wang@mediatek.com>
|
||||
|
||||
allOf:
|
||||
- $ref: bluetooth-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mediatek,mt7622-bluetooth
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: ref
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/power/mt7622-power.h>
|
||||
|
||||
serial {
|
||||
bluetooth {
|
||||
compatible = "mediatek,mt7622-bluetooth";
|
||||
power-domains = <&scpsys MT7622_POWER_DOMAIN_WB>;
|
||||
clocks = <&clk25m>;
|
||||
clock-names = "ref";
|
||||
};
|
||||
};
|
||||
@@ -31,6 +31,9 @@ properties:
|
||||
This property depends on the module vendor's
|
||||
configuration.
|
||||
|
||||
firmware-name:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
@@ -42,5 +45,6 @@ examples:
|
||||
bluetooth {
|
||||
compatible = "nxp,88w8987-bt";
|
||||
fw-init-baudrate = <3000000>;
|
||||
firmware-name = "uartuart8987_bt_v0.bin";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -62,6 +62,9 @@ properties:
|
||||
vdddig-supply:
|
||||
description: VDD_DIG supply regulator handle
|
||||
|
||||
vddbtcmx-supply:
|
||||
description: VDD_BT_CMX supply regulator handle
|
||||
|
||||
vddbtcxmx-supply:
|
||||
description: VDD_BT_CXMX supply regulator handle
|
||||
|
||||
@@ -74,6 +77,9 @@ properties:
|
||||
vddrfa1p7-supply:
|
||||
description: VDD_RFA_1P7 supply regulator handle
|
||||
|
||||
vddrfa1p8-supply:
|
||||
description: VDD_RFA_1P8 supply regulator handle
|
||||
|
||||
vddrfa1p2-supply:
|
||||
description: VDD_RFA_1P2 supply regulator handle
|
||||
|
||||
@@ -86,6 +92,12 @@ properties:
|
||||
vddasd-supply:
|
||||
description: VDD_ASD supply regulator handle
|
||||
|
||||
vddwlcx-supply:
|
||||
description: VDD_WLCX supply regulator handle
|
||||
|
||||
vddwlmx-supply:
|
||||
description: VDD_WLMX supply regulator handle
|
||||
|
||||
max-speed:
|
||||
description: see Documentation/devicetree/bindings/serial/serial.yaml
|
||||
|
||||
@@ -176,14 +188,27 @@ allOf:
|
||||
- qcom,wcn7850-bt
|
||||
then:
|
||||
required:
|
||||
- enable-gpios
|
||||
- swctrl-gpios
|
||||
- vddio-supply
|
||||
- vddrfacmn-supply
|
||||
- vddaon-supply
|
||||
- vdddig-supply
|
||||
- vddwlcx-supply
|
||||
- vddwlmx-supply
|
||||
- vddrfa0p8-supply
|
||||
- vddrfa1p2-supply
|
||||
- vddrfa1p9-supply
|
||||
- vddrfa1p8-supply
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,qca6390-bt
|
||||
then:
|
||||
required:
|
||||
- vddrfacmn-supply
|
||||
- vddaon-supply
|
||||
- vddbtcmx-supply
|
||||
- vddrfa0p8-supply
|
||||
- vddrfa1p2-supply
|
||||
- vddrfa1p7-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
@@ -1,39 +1,3 @@
|
||||
MediaTek SoC built-in Bluetooth Devices
|
||||
==================================
|
||||
|
||||
This device is a serial attached device to BTIF device and thus it must be a
|
||||
child node of the serial node with BTIF. The dt-bindings details for BTIF
|
||||
device can be known via Documentation/devicetree/bindings/serial/8250.yaml.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be
|
||||
"mediatek,mt7622-bluetooth": for MT7622 SoC
|
||||
- clocks: Should be the clock specifiers corresponding to the entry in
|
||||
clock-names property.
|
||||
- clock-names: Should contain "ref" entries.
|
||||
- power-domains: Phandle to the power domain that the device is part of
|
||||
|
||||
Example:
|
||||
|
||||
btif: serial@1100c000 {
|
||||
compatible = "mediatek,mt7622-btif",
|
||||
"mediatek,mtk-btif";
|
||||
reg = <0 0x1100c000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&pericfg CLK_PERI_BTIF_PD>;
|
||||
clock-names = "main";
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
|
||||
bluetooth {
|
||||
compatible = "mediatek,mt7622-bluetooth";
|
||||
power-domains = <&scpsys MT7622_POWER_DOMAIN_WB>;
|
||||
clocks = <&clk25m>;
|
||||
clock-names = "ref";
|
||||
};
|
||||
};
|
||||
|
||||
MediaTek UART based Bluetooth Devices
|
||||
==================================
|
||||
|
||||
|
||||
@@ -17908,6 +17908,14 @@ F: include/linux/pm_*
|
||||
F: include/linux/powercap.h
|
||||
F: kernel/configs/nopm.config
|
||||
|
||||
POWER SEQUENCING
|
||||
M: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
|
||||
F: drivers/power/sequencing/
|
||||
F: include/linux/pwrseq/
|
||||
|
||||
POWER STATE COORDINATION INTERFACE (PSCI)
|
||||
M: Mark Rutland <mark.rutland@arm.com>
|
||||
M: Lorenzo Pieralisi <lpieralisi@kernel.org>
|
||||
|
||||
@@ -105,6 +105,7 @@ config BT_HCIUART
|
||||
tristate "HCI UART driver"
|
||||
depends on SERIAL_DEV_BUS || !SERIAL_DEV_BUS
|
||||
depends on NVMEM || !NVMEM
|
||||
depends on POWER_SEQUENCING || !POWER_SEQUENCING
|
||||
depends on TTY
|
||||
help
|
||||
Bluetooth HCI UART driver.
|
||||
@@ -287,12 +288,12 @@ config BT_HCIBCM203X
|
||||
|
||||
|
||||
config BT_HCIBCM4377
|
||||
tristate "HCI BCM4377/4378/4387 PCIe driver"
|
||||
tristate "HCI BCM4377/4378/4387/4388 PCIe driver"
|
||||
depends on PCI
|
||||
select FW_LOADER
|
||||
help
|
||||
Support for Broadcom BCM4377/4378/4387 Bluetooth chipsets attached via
|
||||
PCIe. These are usually found in Apple machines.
|
||||
Support for Broadcom BCM4377/4378/4387/4388 Bluetooth chipsets
|
||||
attached via PCIe. These are usually found in Apple machines.
|
||||
|
||||
Say Y here to compile support for HCI BCM4377 family devices into the
|
||||
kernel or say M to compile it as module (hci_bcm4377).
|
||||
|
||||
+133
-111
@@ -26,21 +26,11 @@
|
||||
#define ECDSA_OFFSET 644
|
||||
#define ECDSA_HEADER_LEN 320
|
||||
|
||||
#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;
|
||||
u32 mode;
|
||||
acpi_status status;
|
||||
struct hci_dev *hdev;
|
||||
};
|
||||
|
||||
#define CMD_WRITE_BOOT_PARAMS 0xfc0e
|
||||
struct cmd_write_boot_params {
|
||||
__le32 boot_addr;
|
||||
@@ -482,6 +472,7 @@ int btintel_version_info_tlv(struct hci_dev *hdev,
|
||||
case 0x19: /* Slr-F */
|
||||
case 0x1b: /* Mgr */
|
||||
case 0x1c: /* Gale Peak (GaP) */
|
||||
case 0x1d: /* BlazarU (BzrU) */
|
||||
case 0x1e: /* BlazarI (Bzr) */
|
||||
break;
|
||||
default:
|
||||
@@ -641,6 +632,10 @@ int btintel_parse_version_tlv(struct hci_dev *hdev,
|
||||
case INTEL_TLV_GIT_SHA1:
|
||||
version->git_sha1 = get_unaligned_le32(tlv->val);
|
||||
break;
|
||||
case INTEL_TLV_FW_ID:
|
||||
snprintf(version->fw_id, sizeof(version->fw_id),
|
||||
"%s", tlv->val);
|
||||
break;
|
||||
default:
|
||||
/* Ignore rest of information */
|
||||
break;
|
||||
@@ -1324,65 +1319,6 @@ static int btintel_read_debug_features(struct hci_dev *hdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data,
|
||||
void **ret)
|
||||
{
|
||||
acpi_status status;
|
||||
size_t len;
|
||||
struct btintel_ppag *ppag = data;
|
||||
union acpi_object *p, *elements;
|
||||
struct acpi_buffer string = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
struct hci_dev *hdev = ppag->hdev;
|
||||
|
||||
status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
len = strlen(string.pointer);
|
||||
if (len < strlen(BTINTEL_PPAG_NAME)) {
|
||||
kfree(string.pointer);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
if (strncmp((char *)string.pointer + len - 4, BTINTEL_PPAG_NAME, 4)) {
|
||||
kfree(string.pointer);
|
||||
return AE_OK;
|
||||
}
|
||||
kfree(string.pointer);
|
||||
|
||||
status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ppag->status = status;
|
||||
bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
p = buffer.pointer;
|
||||
ppag = (struct btintel_ppag *)data;
|
||||
|
||||
if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 2) {
|
||||
kfree(buffer.pointer);
|
||||
bt_dev_warn(hdev, "PPAG-BT: Invalid object type: %d or package count: %d",
|
||||
p->type, p->package.count);
|
||||
ppag->status = AE_ERROR;
|
||||
return AE_ERROR;
|
||||
}
|
||||
|
||||
elements = p->package.elements;
|
||||
|
||||
/* PPAG table is located at element[1] */
|
||||
p = &elements[1];
|
||||
|
||||
ppag->domain = (u32)p->package.elements[0].integer.value;
|
||||
ppag->mode = (u32)p->package.elements[1].integer.value;
|
||||
ppag->status = AE_OK;
|
||||
kfree(buffer.pointer);
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
|
||||
static int btintel_set_debug_features(struct hci_dev *hdev,
|
||||
const struct intel_debug_features *features)
|
||||
{
|
||||
@@ -2202,30 +2138,61 @@ static void btintel_get_fw_name_tlv(const struct intel_version_tlv *ver,
|
||||
const char *suffix)
|
||||
{
|
||||
const char *format;
|
||||
/* The firmware file name for new generation controllers will be
|
||||
* ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step>
|
||||
*/
|
||||
switch (ver->cnvi_top & 0xfff) {
|
||||
u32 cnvi, cnvr;
|
||||
|
||||
cnvi = INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvi_top),
|
||||
INTEL_CNVX_TOP_STEP(ver->cnvi_top));
|
||||
|
||||
cnvr = INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvr_top),
|
||||
INTEL_CNVX_TOP_STEP(ver->cnvr_top));
|
||||
|
||||
/* Only Blazar product supports downloading of intermediate loader
|
||||
* image
|
||||
*/
|
||||
case BTINTEL_CNVI_BLAZARI:
|
||||
if (ver->img_type == BTINTEL_IMG_BOOTLOADER)
|
||||
format = "intel/ibt-%04x-%04x-iml.%s";
|
||||
else
|
||||
format = "intel/ibt-%04x-%04x.%s";
|
||||
break;
|
||||
default:
|
||||
format = "intel/ibt-%04x-%04x.%s";
|
||||
break;
|
||||
}
|
||||
if (INTEL_HW_VARIANT(ver->cnvi_bt) >= 0x1e) {
|
||||
u8 zero[BTINTEL_FWID_MAXLEN];
|
||||
|
||||
snprintf(fw_name, len, format,
|
||||
INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvi_top),
|
||||
INTEL_CNVX_TOP_STEP(ver->cnvi_top)),
|
||||
INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvr_top),
|
||||
INTEL_CNVX_TOP_STEP(ver->cnvr_top)),
|
||||
suffix);
|
||||
if (ver->img_type == BTINTEL_IMG_BOOTLOADER) {
|
||||
format = "intel/ibt-%04x-%04x-iml.%s";
|
||||
snprintf(fw_name, len, format, cnvi, cnvr, suffix);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(zero, 0, sizeof(zero));
|
||||
|
||||
/* ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step-fw_id> */
|
||||
if (memcmp(ver->fw_id, zero, sizeof(zero))) {
|
||||
format = "intel/ibt-%04x-%04x-%s.%s";
|
||||
snprintf(fw_name, len, format, cnvi, cnvr,
|
||||
ver->fw_id, suffix);
|
||||
return;
|
||||
}
|
||||
/* If firmware id is not present, fallback to legacy naming
|
||||
* convention
|
||||
*/
|
||||
}
|
||||
/* Fallback to legacy naming convention for other controllers
|
||||
* ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step>
|
||||
*/
|
||||
format = "intel/ibt-%04x-%04x.%s";
|
||||
snprintf(fw_name, len, format, cnvi, cnvr, suffix);
|
||||
}
|
||||
|
||||
static void btintel_get_iml_tlv(const struct intel_version_tlv *ver,
|
||||
char *fw_name, size_t len,
|
||||
const char *suffix)
|
||||
{
|
||||
const char *format;
|
||||
u32 cnvi, cnvr;
|
||||
|
||||
cnvi = INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvi_top),
|
||||
INTEL_CNVX_TOP_STEP(ver->cnvi_top));
|
||||
|
||||
cnvr = INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvr_top),
|
||||
INTEL_CNVX_TOP_STEP(ver->cnvr_top));
|
||||
|
||||
format = "intel/ibt-%04x-%04x-iml.%s";
|
||||
snprintf(fw_name, len, format, cnvi, cnvr, suffix);
|
||||
}
|
||||
|
||||
static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
|
||||
@@ -2233,7 +2200,7 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
|
||||
u32 *boot_param)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
char fwname[64];
|
||||
char fwname[128];
|
||||
int err;
|
||||
ktime_t calltime;
|
||||
|
||||
@@ -2268,7 +2235,20 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
|
||||
}
|
||||
}
|
||||
|
||||
btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
|
||||
if (ver->img_type == BTINTEL_IMG_OP) {
|
||||
/* Controller running OP image. In case of FW downgrade,
|
||||
* FWID TLV may not be present and driver may attempt to load
|
||||
* firmware image which doesn't exist. Lets compare the version
|
||||
* of IML image
|
||||
*/
|
||||
if (INTEL_HW_VARIANT(ver->cnvi_bt) >= 0x1e)
|
||||
btintel_get_iml_tlv(ver, fwname, sizeof(fwname), "sfi");
|
||||
else
|
||||
btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
|
||||
} else {
|
||||
btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
|
||||
}
|
||||
|
||||
err = firmware_request_nowarn(&fw, fwname, &hdev->dev);
|
||||
if (err < 0) {
|
||||
if (!btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
|
||||
@@ -2427,10 +2407,13 @@ error:
|
||||
|
||||
static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver)
|
||||
{
|
||||
struct btintel_ppag ppag;
|
||||
struct sk_buff *skb;
|
||||
struct hci_ppag_enable_cmd ppag_cmd;
|
||||
acpi_handle handle;
|
||||
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
union acpi_object *p, *elements;
|
||||
u32 domain, mode;
|
||||
acpi_status status;
|
||||
|
||||
/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
|
||||
switch (ver->cnvr_top & 0xFFF) {
|
||||
@@ -2448,22 +2431,34 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&ppag, 0, sizeof(ppag));
|
||||
|
||||
ppag.hdev = hdev;
|
||||
ppag.status = AE_NOT_FOUND;
|
||||
acpi_walk_namespace(ACPI_TYPE_PACKAGE, handle, 1, NULL,
|
||||
btintel_ppag_callback, &ppag, NULL);
|
||||
|
||||
if (ACPI_FAILURE(ppag.status)) {
|
||||
if (ppag.status == AE_NOT_FOUND) {
|
||||
status = acpi_evaluate_object(handle, "PPAG", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (status == AE_NOT_FOUND) {
|
||||
bt_dev_dbg(hdev, "PPAG-BT: ACPI entry not found");
|
||||
return;
|
||||
}
|
||||
bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ppag.domain != 0x12) {
|
||||
p = buffer.pointer;
|
||||
if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 2) {
|
||||
bt_dev_warn(hdev, "PPAG-BT: Invalid object type: %d or package count: %d",
|
||||
p->type, p->package.count);
|
||||
kfree(buffer.pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
elements = p->package.elements;
|
||||
|
||||
/* PPAG table is located at element[1] */
|
||||
p = &elements[1];
|
||||
|
||||
domain = (u32)p->package.elements[0].integer.value;
|
||||
mode = (u32)p->package.elements[1].integer.value;
|
||||
kfree(buffer.pointer);
|
||||
|
||||
if (domain != 0x12) {
|
||||
bt_dev_dbg(hdev, "PPAG-BT: Bluetooth domain is disabled in ACPI firmware");
|
||||
return;
|
||||
}
|
||||
@@ -2474,19 +2469,22 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
|
||||
* 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");
|
||||
mode &= 0x03;
|
||||
|
||||
if (!mode) {
|
||||
bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in BIOS");
|
||||
return;
|
||||
}
|
||||
|
||||
ppag_cmd.ppag_enable_flags = cpu_to_le32(ppag.mode);
|
||||
ppag_cmd.ppag_enable_flags = cpu_to_le32(mode);
|
||||
|
||||
skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
|
||||
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);
|
||||
bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", mode);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
@@ -2600,6 +2598,24 @@ static void btintel_set_dsm_reset_method(struct hci_dev *hdev,
|
||||
data->acpi_reset_method = btintel_acpi_reset_method;
|
||||
}
|
||||
|
||||
#define BTINTEL_ISODATA_HANDLE_BASE 0x900
|
||||
|
||||
static u8 btintel_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
/*
|
||||
* Distinguish ISO data packets form ACL data packets
|
||||
* based on their connection handle value range.
|
||||
*/
|
||||
if (hci_skb_pkt_type(skb) == HCI_ACLDATA_PKT) {
|
||||
__u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
|
||||
|
||||
if (hci_handle(handle) >= BTINTEL_ISODATA_HANDLE_BASE)
|
||||
return HCI_ISODATA_PKT;
|
||||
}
|
||||
|
||||
return hci_skb_pkt_type(skb);
|
||||
}
|
||||
|
||||
int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *ver)
|
||||
{
|
||||
@@ -2635,7 +2651,7 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
|
||||
return err;
|
||||
|
||||
/* If image type returned is BTINTEL_IMG_IML, then controller supports
|
||||
* intermediae loader image
|
||||
* intermediate loader image
|
||||
*/
|
||||
if (ver->img_type == BTINTEL_IMG_IML) {
|
||||
err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
|
||||
@@ -2703,6 +2719,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
|
||||
case 0x19:
|
||||
case 0x1b:
|
||||
case 0x1c:
|
||||
case 0x1d:
|
||||
case 0x1e:
|
||||
hci_set_msft_opcode(hdev, 0xFC1E);
|
||||
break;
|
||||
@@ -2713,7 +2730,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_set_msft_opcode);
|
||||
|
||||
static void btintel_print_fseq_info(struct hci_dev *hdev)
|
||||
void btintel_print_fseq_info(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u8 *p;
|
||||
@@ -2825,6 +2842,7 @@ static void btintel_print_fseq_info(struct hci_dev *hdev)
|
||||
|
||||
kfree_skb(skb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_print_fseq_info);
|
||||
|
||||
static int btintel_setup_combined(struct hci_dev *hdev)
|
||||
{
|
||||
@@ -3039,11 +3057,15 @@ static int btintel_setup_combined(struct hci_dev *hdev)
|
||||
err = btintel_bootloader_setup(hdev, &ver);
|
||||
btintel_register_devcoredump_support(hdev);
|
||||
break;
|
||||
case 0x18: /* GfP2 */
|
||||
case 0x1c: /* GaP */
|
||||
/* Re-classify packet type for controllers with LE audio */
|
||||
hdev->classify_pkt_type = btintel_classify_pkt_type;
|
||||
fallthrough;
|
||||
case 0x17:
|
||||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1b:
|
||||
case 0x1c:
|
||||
case 0x1d:
|
||||
case 0x1e:
|
||||
/* Display version information of TLV type */
|
||||
btintel_version_info_tlv(hdev, &ver_tlv);
|
||||
|
||||
@@ -42,7 +42,8 @@ enum {
|
||||
INTEL_TLV_SBE_TYPE,
|
||||
INTEL_TLV_OTP_BDADDR,
|
||||
INTEL_TLV_UNLOCKED_STATE,
|
||||
INTEL_TLV_GIT_SHA1
|
||||
INTEL_TLV_GIT_SHA1,
|
||||
INTEL_TLV_FW_ID = 0x50
|
||||
};
|
||||
|
||||
struct intel_tlv {
|
||||
@@ -57,6 +58,8 @@ struct intel_tlv {
|
||||
#define BTINTEL_IMG_IML 0x02 /* Intermediate image */
|
||||
#define BTINTEL_IMG_OP 0x03 /* Operational image */
|
||||
|
||||
#define BTINTEL_FWID_MAXLEN 64
|
||||
|
||||
struct intel_version_tlv {
|
||||
u32 cnvi_top;
|
||||
u32 cnvr_top;
|
||||
@@ -77,6 +80,7 @@ struct intel_version_tlv {
|
||||
u8 limited_cce;
|
||||
u8 sbe_type;
|
||||
u32 git_sha1;
|
||||
u8 fw_id[BTINTEL_FWID_MAXLEN];
|
||||
bdaddr_t otp_bd_addr;
|
||||
};
|
||||
|
||||
@@ -244,6 +248,7 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *ver);
|
||||
int btintel_shutdown_combined(struct hci_dev *hdev);
|
||||
void btintel_hw_error(struct hci_dev *hdev, u8 code);
|
||||
void btintel_print_fseq_info(struct hci_dev *hdev);
|
||||
#else
|
||||
|
||||
static inline int btintel_check_bdaddr(struct hci_dev *hdev)
|
||||
@@ -373,4 +378,8 @@ static inline int btintel_shutdown_combined(struct hci_dev *hdev)
|
||||
static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void btintel_print_fseq_info(struct hci_dev *hdev)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -797,7 +797,6 @@ static int btintel_pcie_setup_txq_bufs(struct btintel_pcie_data *data,
|
||||
kfree(txq->bufs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(txq->buf_v_addr, 0, txq->count * BTINTEL_PCIE_BUFFER_SIZE);
|
||||
|
||||
/* Setup the allocated DMA buffer to bufs. Each data_buf should
|
||||
* have virtual address and physical address
|
||||
@@ -842,7 +841,6 @@ static int btintel_pcie_setup_rxq_bufs(struct btintel_pcie_data *data,
|
||||
kfree(rxq->bufs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(rxq->buf_v_addr, 0, rxq->count * BTINTEL_PCIE_BUFFER_SIZE);
|
||||
|
||||
/* Setup the allocated DMA buffer to bufs. Each data_buf should
|
||||
* have virtual address and physical address
|
||||
@@ -1197,9 +1195,11 @@ static int btintel_pcie_setup(struct hci_dev *hdev)
|
||||
bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",
|
||||
INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
|
||||
err = -EINVAL;
|
||||
goto exit_error;
|
||||
break;
|
||||
}
|
||||
|
||||
btintel_print_fseq_info(hdev);
|
||||
exit_error:
|
||||
kfree_skb(skb);
|
||||
|
||||
@@ -1327,6 +1327,12 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
|
||||
data = pci_get_drvdata(pdev);
|
||||
|
||||
btintel_pcie_reset_bt(data);
|
||||
for (int i = 0; i < data->alloc_vecs; i++) {
|
||||
struct msix_entry *msix_entry;
|
||||
|
||||
msix_entry = &data->msix_entries[i];
|
||||
free_irq(msix_entry->vector, msix_entry);
|
||||
}
|
||||
|
||||
pci_free_irq_vectors(pdev);
|
||||
|
||||
|
||||
+1080
-5
File diff suppressed because it is too large
Load Diff
+109
-9
@@ -28,6 +28,21 @@
|
||||
#define MTK_COREDUMP_END_LEN (sizeof(MTK_COREDUMP_END))
|
||||
#define MTK_COREDUMP_NUM 255
|
||||
|
||||
/* UHW CR mapping */
|
||||
#define MTK_BT_MISC 0x70002510
|
||||
#define MTK_BT_SUBSYS_RST 0x70002610
|
||||
#define MTK_UDMA_INT_STA_BT 0x74000024
|
||||
#define MTK_UDMA_INT_STA_BT1 0x74000308
|
||||
#define MTK_BT_WDT_STATUS 0x740003A0
|
||||
#define MTK_EP_RST_OPT 0x74011890
|
||||
#define MTK_EP_RST_IN_OUT_OPT 0x00010001
|
||||
#define MTK_BT_RST_DONE 0x00000100
|
||||
#define MTK_BT_RESET_REG_CONNV3 0x70028610
|
||||
#define MTK_BT_READ_DEV_ID 0x70010200
|
||||
|
||||
/* MediaTek ISO Interface */
|
||||
#define MTK_ISO_IFNUM 2
|
||||
|
||||
enum {
|
||||
BTMTK_WMT_PATCH_DWNLD = 0x1,
|
||||
BTMTK_WMT_TEST = 0x2,
|
||||
@@ -126,6 +141,14 @@ struct btmtk_hci_wmt_params {
|
||||
u32 *status;
|
||||
};
|
||||
|
||||
enum {
|
||||
BTMTK_TX_WAIT_VND_EVT,
|
||||
BTMTK_FIRMWARE_LOADED,
|
||||
BTMTK_HW_RESET_ACTIVE,
|
||||
BTMTK_ISOPKT_OVER_INTR,
|
||||
BTMTK_ISOPKT_RUNNING,
|
||||
};
|
||||
|
||||
typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *);
|
||||
|
||||
struct btmtk_coredump_info {
|
||||
@@ -135,10 +158,25 @@ struct btmtk_coredump_info {
|
||||
int state;
|
||||
};
|
||||
|
||||
struct btmediatek_data {
|
||||
struct btmtk_data {
|
||||
const char *drv_name;
|
||||
unsigned long flags;
|
||||
u32 dev_id;
|
||||
btmtk_reset_sync_func_t reset_sync;
|
||||
struct btmtk_coredump_info cd_info;
|
||||
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
struct usb_anchor *ctrl_anchor;
|
||||
struct sk_buff *evt_skb;
|
||||
struct usb_endpoint_descriptor *isopkt_tx_ep;
|
||||
struct usb_endpoint_descriptor *isopkt_rx_ep;
|
||||
struct usb_interface *isopkt_intf;
|
||||
struct usb_anchor isopkt_anchor;
|
||||
struct sk_buff *isopkt_skb;
|
||||
|
||||
/* spinlock for ISO data transmission */
|
||||
spinlock_t isorxlock;
|
||||
};
|
||||
|
||||
typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
|
||||
@@ -160,6 +198,24 @@ 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);
|
||||
|
||||
void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver,
|
||||
u32 fw_flavor);
|
||||
|
||||
int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id);
|
||||
|
||||
int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
|
||||
struct urb *alloc_mtk_intr_urb(struct hci_dev *hdev, struct sk_buff *skb,
|
||||
usb_complete_t tx_complete);
|
||||
|
||||
int btmtk_usb_resume(struct hci_dev *hdev);
|
||||
|
||||
int btmtk_usb_suspend(struct hci_dev *hdev);
|
||||
|
||||
int btmtk_usb_setup(struct hci_dev *hdev);
|
||||
|
||||
int btmtk_usb_shutdown(struct hci_dev *hdev);
|
||||
#else
|
||||
|
||||
static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
|
||||
@@ -168,29 +224,73 @@ static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
|
||||
wmt_cmd_sync_func_t wmt_cmd_sync)
|
||||
static inline int btmtk_setup_firmware_79xx(struct hci_dev *hdev,
|
||||
const char *fwname,
|
||||
wmt_cmd_sync_func_t wmt_cmd_sync)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
|
||||
wmt_cmd_sync_func_t wmt_cmd_sync)
|
||||
static inline int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
|
||||
wmt_cmd_sync_func_t wmt_cmd_sync)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void btmtk_reset_sync(struct hci_dev *hdev)
|
||||
static inline void btmtk_reset_sync(struct hci_dev *hdev)
|
||||
{
|
||||
}
|
||||
|
||||
static int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
|
||||
u32 fw_version)
|
||||
static inline 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)
|
||||
static inline int btmtk_process_coredump(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id,
|
||||
u32 fw_ver, u32 fw_flavor)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct urb *alloc_mtk_intr_urb(struct hci_dev *hdev,
|
||||
struct sk_buff *skb,
|
||||
usb_complete_t tx_complete)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline int btmtk_usb_resume(struct hci_dev *hdev)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int btmtk_usb_suspend(struct hci_dev *hdev)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int btmtk_usb_setup(struct hci_dev *hdev)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int btmtk_usb_shutdown(struct hci_dev *hdev)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
@@ -1117,6 +1118,9 @@ static int btmtksdio_setup(struct hci_dev *hdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
btmtk_fw_get_filename(fwname, sizeof(fwname), dev_id,
|
||||
fw_version, 0);
|
||||
|
||||
snprintf(fwname, sizeof(fwname),
|
||||
"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
|
||||
dev_id & 0xffff, (fw_version & 0xff) + 1);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/serdev.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
+196
-46
@@ -29,27 +29,38 @@
|
||||
#define BTNXPUART_CHECK_BOOT_SIGNATURE 3
|
||||
#define BTNXPUART_SERDEV_OPEN 4
|
||||
#define BTNXPUART_IR_IN_PROGRESS 5
|
||||
#define BTNXPUART_FW_DOWNLOAD_ABORT 6
|
||||
|
||||
/* 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 FIRMWARE_W8987 "uart8987_bt_v0.bin"
|
||||
#define FIRMWARE_W8987_OLD "uartuart8987_bt.bin"
|
||||
#define FIRMWARE_W8997 "uart8997_bt_v4.bin"
|
||||
#define FIRMWARE_W8997_OLD "uartuart8997_bt_v4.bin"
|
||||
#define FIRMWARE_W9098 "uart9098_bt_v1.bin"
|
||||
#define FIRMWARE_W9098_OLD "uartuart9098_bt_v1.bin"
|
||||
#define FIRMWARE_IW416 "uartiw416_bt_v0.bin"
|
||||
#define FIRMWARE_IW612 "uartspi_n61x_v1.bin.se"
|
||||
#define FIRMWARE_IW615 "uartspi_iw610_v0.bin"
|
||||
#define FIRMWARE_SECURE_IW615 "uartspi_iw610_v0.bin.se"
|
||||
#define FIRMWARE_IW624 "uartiw624_bt.bin"
|
||||
#define FIRMWARE_SECURE_IW624 "uartiw624_bt.bin.se"
|
||||
#define FIRMWARE_AW693 "uartaw693_bt.bin"
|
||||
#define FIRMWARE_SECURE_AW693 "uartaw693_bt.bin.se"
|
||||
#define FIRMWARE_AW693_A1 "uartaw693_bt_v1.bin"
|
||||
#define FIRMWARE_SECURE_AW693_A1 "uartaw693_bt_v1.bin.se"
|
||||
#define FIRMWARE_HELPER "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 CHIP_ID_AW693a0 0x8200
|
||||
#define CHIP_ID_AW693a1 0x8201
|
||||
#define CHIP_ID_IW615a0 0x8800
|
||||
#define CHIP_ID_IW615a1 0x8801
|
||||
|
||||
#define FW_SECURE_MASK 0xc0
|
||||
#define FW_OPEN 0x00
|
||||
@@ -144,6 +155,7 @@ struct psmode_cmd_payload {
|
||||
struct btnxpuart_data {
|
||||
const char *helper_fw_name;
|
||||
const char *fw_name;
|
||||
const char *fw_name_old;
|
||||
};
|
||||
|
||||
struct btnxpuart_dev {
|
||||
@@ -159,6 +171,7 @@ struct btnxpuart_dev {
|
||||
u8 fw_name[MAX_FW_FILE_NAME_LEN];
|
||||
u32 fw_dnld_v1_offset;
|
||||
u32 fw_v1_sent_bytes;
|
||||
u32 fw_dnld_v3_offset;
|
||||
u32 fw_v3_offset_correction;
|
||||
u32 fw_v1_expected_len;
|
||||
u32 boot_reg_offset;
|
||||
@@ -187,6 +200,11 @@ struct btnxpuart_dev {
|
||||
#define NXP_NAK_V3 0x7b
|
||||
#define NXP_CRC_ERROR_V3 0x7c
|
||||
|
||||
/* Bootloader signature error codes */
|
||||
#define NXP_ACK_RX_TIMEOUT 0x0002 /* ACK not received from host */
|
||||
#define NXP_HDR_RX_TIMEOUT 0x0003 /* FW Header chunk not received */
|
||||
#define NXP_DATA_RX_TIMEOUT 0x0004 /* FW Data chunk not received */
|
||||
|
||||
#define HDR_LEN 16
|
||||
|
||||
#define NXP_RECV_CHIP_VER_V1 \
|
||||
@@ -277,6 +295,17 @@ struct nxp_bootloader_cmd {
|
||||
__be32 crc;
|
||||
} __packed;
|
||||
|
||||
struct nxp_v3_rx_timeout_nak {
|
||||
u8 nak;
|
||||
__le32 offset;
|
||||
u8 crc;
|
||||
} __packed;
|
||||
|
||||
union nxp_v3_rx_timeout_nak_u {
|
||||
struct nxp_v3_rx_timeout_nak pkt;
|
||||
u8 buf[6];
|
||||
};
|
||||
|
||||
static u8 crc8_table[CRC8_TABLE_SIZE];
|
||||
|
||||
/* Default configurations */
|
||||
@@ -328,7 +357,7 @@ static void ps_cancel_timer(struct btnxpuart_dev *nxpdev)
|
||||
struct ps_data *psdata = &nxpdev->psdata;
|
||||
|
||||
flush_work(&psdata->work);
|
||||
del_timer_sync(&psdata->ps_timer);
|
||||
timer_shutdown_sync(&psdata->ps_timer);
|
||||
}
|
||||
|
||||
static void ps_control(struct hci_dev *hdev, u8 ps_state)
|
||||
@@ -550,6 +579,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
|
||||
nxpdev->fw_v1_sent_bytes = 0;
|
||||
nxpdev->fw_v1_expected_len = HDR_LEN;
|
||||
nxpdev->boot_reg_offset = 0;
|
||||
nxpdev->fw_dnld_v3_offset = 0;
|
||||
nxpdev->fw_v3_offset_correction = 0;
|
||||
nxpdev->baudrate_changed = false;
|
||||
nxpdev->timeout_changed = false;
|
||||
@@ -564,14 +594,23 @@ static int nxp_download_firmware(struct hci_dev *hdev)
|
||||
!test_bit(BTNXPUART_FW_DOWNLOADING,
|
||||
&nxpdev->tx_state),
|
||||
msecs_to_jiffies(60000));
|
||||
|
||||
release_firmware(nxpdev->fw);
|
||||
memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
|
||||
|
||||
if (err == 0) {
|
||||
bt_dev_err(hdev, "FW Download Timeout.");
|
||||
bt_dev_err(hdev, "FW Download Timeout. offset: %d",
|
||||
nxpdev->fw_dnld_v1_offset ?
|
||||
nxpdev->fw_dnld_v1_offset :
|
||||
nxpdev->fw_dnld_v3_offset);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (test_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state)) {
|
||||
bt_dev_err(hdev, "FW Download Aborted");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
serdev_device_set_flow_control(nxpdev->serdev, true);
|
||||
release_firmware(nxpdev->fw);
|
||||
memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
|
||||
|
||||
/* Allow the downloaded FW to initialize */
|
||||
msleep(1200);
|
||||
@@ -682,19 +721,30 @@ static bool process_boot_signature(struct btnxpuart_dev *nxpdev)
|
||||
return is_fw_downloading(nxpdev);
|
||||
}
|
||||
|
||||
static int nxp_request_firmware(struct hci_dev *hdev, const char *fw_name)
|
||||
static int nxp_request_firmware(struct hci_dev *hdev, const char *fw_name,
|
||||
const char *fw_name_old)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
const char *fw_name_dt;
|
||||
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);
|
||||
if (strcmp(fw_name, FIRMWARE_HELPER) &&
|
||||
!device_property_read_string(&nxpdev->serdev->dev,
|
||||
"firmware-name",
|
||||
&fw_name_dt))
|
||||
fw_name = fw_name_dt;
|
||||
snprintf(nxpdev->fw_name, MAX_FW_FILE_NAME_LEN, "nxp/%s", fw_name);
|
||||
err = request_firmware_direct(&nxpdev->fw, nxpdev->fw_name, &hdev->dev);
|
||||
if (err < 0 && fw_name_old) {
|
||||
snprintf(nxpdev->fw_name, MAX_FW_FILE_NAME_LEN, "nxp/%s", fw_name_old);
|
||||
err = request_firmware_direct(&nxpdev->fw, nxpdev->fw_name, &hdev->dev);
|
||||
}
|
||||
|
||||
bt_dev_dbg(hdev, "Request Firmware: %s", nxpdev->fw_name);
|
||||
err = request_firmware(&nxpdev->fw, nxpdev->fw_name, &hdev->dev);
|
||||
bt_dev_info(hdev, "Request Firmware: %s", nxpdev->fw_name);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Firmware file %s not found", nxpdev->fw_name);
|
||||
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
@@ -773,15 +823,15 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
if (!nxp_data->helper_fw_name || nxpdev->helper_downloaded) {
|
||||
if (nxp_request_firmware(hdev, nxp_data->fw_name))
|
||||
if (nxp_request_firmware(hdev, nxp_data->fw_name, nxp_data->fw_name_old))
|
||||
goto free_skb;
|
||||
} else if (nxp_data->helper_fw_name && !nxpdev->helper_downloaded) {
|
||||
if (nxp_request_firmware(hdev, nxp_data->helper_fw_name))
|
||||
if (nxp_request_firmware(hdev, nxp_data->helper_fw_name, NULL))
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
bt_dev_dbg(hdev, "FW Downloaded Successfully: %zu bytes",
|
||||
bt_dev_info(hdev, "FW Download Complete: %zu bytes",
|
||||
nxpdev->fw->size);
|
||||
if (nxp_data->helper_fw_name && !nxpdev->helper_downloaded) {
|
||||
nxpdev->helper_downloaded = true;
|
||||
@@ -863,7 +913,7 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
|
||||
else
|
||||
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
|
||||
break;
|
||||
case CHIP_ID_AW693:
|
||||
case CHIP_ID_AW693a0:
|
||||
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
|
||||
fw_name = FIRMWARE_AW693;
|
||||
else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
|
||||
@@ -871,6 +921,23 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
|
||||
else
|
||||
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
|
||||
break;
|
||||
case CHIP_ID_AW693a1:
|
||||
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
|
||||
fw_name = FIRMWARE_AW693_A1;
|
||||
else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
|
||||
fw_name = FIRMWARE_SECURE_AW693_A1;
|
||||
else
|
||||
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
|
||||
break;
|
||||
case CHIP_ID_IW615a0:
|
||||
case CHIP_ID_IW615a1:
|
||||
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
|
||||
fw_name = FIRMWARE_IW615;
|
||||
else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
|
||||
fw_name = FIRMWARE_SECURE_IW615;
|
||||
else
|
||||
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unknown chip signature %04x", chipid);
|
||||
break;
|
||||
@@ -878,10 +945,25 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
|
||||
return fw_name;
|
||||
}
|
||||
|
||||
static char *nxp_get_old_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
|
||||
u8 loader_ver)
|
||||
{
|
||||
char *fw_name_old = NULL;
|
||||
|
||||
switch (chipid) {
|
||||
case CHIP_ID_W9098:
|
||||
fw_name_old = FIRMWARE_W9098_OLD;
|
||||
break;
|
||||
}
|
||||
return fw_name_old;
|
||||
}
|
||||
|
||||
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);
|
||||
const char *fw_name;
|
||||
const char *fw_name_old;
|
||||
u16 chip_id;
|
||||
u8 loader_ver;
|
||||
|
||||
@@ -890,8 +972,10 @@ static int nxp_recv_chip_ver_v3(struct hci_dev *hdev, struct sk_buff *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, loader_ver)))
|
||||
bt_dev_info(hdev, "ChipID: %04x, Version: %d", chip_id, loader_ver);
|
||||
fw_name = nxp_get_fw_name_from_chipid(hdev, chip_id, loader_ver);
|
||||
fw_name_old = nxp_get_old_fw_name_from_chipid(hdev, chip_id, loader_ver);
|
||||
if (!nxp_request_firmware(hdev, fw_name, fw_name_old))
|
||||
nxp_send_ack(NXP_ACK_V3, hdev);
|
||||
|
||||
free_skb:
|
||||
@@ -899,6 +983,32 @@ free_skb:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nxp_handle_fw_download_error(struct hci_dev *hdev, struct v3_data_req *req)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
__u32 offset = __le32_to_cpu(req->offset);
|
||||
__u16 err = __le16_to_cpu(req->error);
|
||||
union nxp_v3_rx_timeout_nak_u nak_tx_buf;
|
||||
|
||||
switch (err) {
|
||||
case NXP_ACK_RX_TIMEOUT:
|
||||
case NXP_HDR_RX_TIMEOUT:
|
||||
case NXP_DATA_RX_TIMEOUT:
|
||||
nak_tx_buf.pkt.nak = NXP_NAK_V3;
|
||||
nak_tx_buf.pkt.offset = __cpu_to_le32(offset);
|
||||
nak_tx_buf.pkt.crc = crc8(crc8_table, nak_tx_buf.buf,
|
||||
sizeof(nak_tx_buf) - 1, 0xff);
|
||||
serdev_device_write_buf(nxpdev->serdev, nak_tx_buf.buf,
|
||||
sizeof(nak_tx_buf));
|
||||
break;
|
||||
default:
|
||||
bt_dev_dbg(hdev, "Unknown bootloader error code: %d", err);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
@@ -913,7 +1023,12 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (!req || !nxpdev->fw)
|
||||
goto free_skb;
|
||||
|
||||
nxp_send_ack(NXP_ACK_V3, hdev);
|
||||
if (!req->error) {
|
||||
nxp_send_ack(NXP_ACK_V3, hdev);
|
||||
} else {
|
||||
nxp_handle_fw_download_error(hdev, req);
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
len = __le16_to_cpu(req->len);
|
||||
|
||||
@@ -934,15 +1049,12 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
if (req->len == 0) {
|
||||
bt_dev_dbg(hdev, "FW Downloaded Successfully: %zu bytes",
|
||||
bt_dev_info(hdev, "FW Download Complete: %zu bytes",
|
||||
nxpdev->fw->size);
|
||||
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q);
|
||||
goto free_skb;
|
||||
}
|
||||
if (req->error)
|
||||
bt_dev_dbg(hdev, "FW Download received err 0x%02x from chip",
|
||||
req->error);
|
||||
|
||||
offset = __le32_to_cpu(req->offset);
|
||||
if (offset < nxpdev->fw_v3_offset_correction) {
|
||||
@@ -954,8 +1066,9 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data + offset -
|
||||
nxpdev->fw_v3_offset_correction, len);
|
||||
nxpdev->fw_dnld_v3_offset = offset - nxpdev->fw_v3_offset_correction;
|
||||
serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data +
|
||||
nxpdev->fw_dnld_v3_offset, len);
|
||||
|
||||
free_skb:
|
||||
kfree_skb(skb);
|
||||
@@ -1037,7 +1150,7 @@ static int nxp_setup(struct hci_dev *hdev)
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
bt_dev_dbg(hdev, "FW already running.");
|
||||
bt_dev_info(hdev, "FW already running.");
|
||||
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
}
|
||||
|
||||
@@ -1253,8 +1366,10 @@ static int btnxpuart_close(struct hci_dev *hdev)
|
||||
ps_wakeup(nxpdev);
|
||||
serdev_device_close(nxpdev->serdev);
|
||||
skb_queue_purge(&nxpdev->txq);
|
||||
kfree_skb(nxpdev->rx_skb);
|
||||
nxpdev->rx_skb = NULL;
|
||||
if (!IS_ERR_OR_NULL(nxpdev->rx_skb)) {
|
||||
kfree_skb(nxpdev->rx_skb);
|
||||
nxpdev->rx_skb = NULL;
|
||||
}
|
||||
clear_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state);
|
||||
return 0;
|
||||
}
|
||||
@@ -1269,8 +1384,10 @@ static int btnxpuart_flush(struct hci_dev *hdev)
|
||||
|
||||
cancel_work_sync(&nxpdev->tx_work);
|
||||
|
||||
kfree_skb(nxpdev->rx_skb);
|
||||
nxpdev->rx_skb = NULL;
|
||||
if (!IS_ERR_OR_NULL(nxpdev->rx_skb)) {
|
||||
kfree_skb(nxpdev->rx_skb);
|
||||
nxpdev->rx_skb = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1385,28 +1502,56 @@ static void nxp_serdev_remove(struct serdev_device *serdev)
|
||||
struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev);
|
||||
struct hci_dev *hdev = nxpdev->hdev;
|
||||
|
||||
/* Restore FW baudrate to fw_init_baudrate if changed.
|
||||
* This will ensure FW baudrate is in sync with
|
||||
* driver baudrate in case this driver is re-inserted.
|
||||
*/
|
||||
if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) {
|
||||
nxpdev->new_baudrate = nxpdev->fw_init_baudrate;
|
||||
nxp_set_baudrate_cmd(hdev, NULL);
|
||||
if (is_fw_downloading(nxpdev)) {
|
||||
set_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state);
|
||||
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
wake_up_interruptible(&nxpdev->check_boot_sign_wait_q);
|
||||
wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q);
|
||||
} else {
|
||||
/* Restore FW baudrate to fw_init_baudrate if changed.
|
||||
* This will ensure FW baudrate is in sync with
|
||||
* driver baudrate in case this driver is re-inserted.
|
||||
*/
|
||||
if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) {
|
||||
nxpdev->new_baudrate = nxpdev->fw_init_baudrate;
|
||||
nxp_set_baudrate_cmd(hdev, NULL);
|
||||
}
|
||||
ps_cancel_timer(nxpdev);
|
||||
}
|
||||
|
||||
ps_cancel_timer(nxpdev);
|
||||
hci_unregister_dev(hdev);
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int nxp_serdev_suspend(struct device *dev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = dev_get_drvdata(dev);
|
||||
struct ps_data *psdata = &nxpdev->psdata;
|
||||
|
||||
ps_control(psdata->hdev, PS_STATE_SLEEP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nxp_serdev_resume(struct device *dev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = dev_get_drvdata(dev);
|
||||
struct ps_data *psdata = &nxpdev->psdata;
|
||||
|
||||
ps_control(psdata->hdev, PS_STATE_AWAKE);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct btnxpuart_data w8987_data __maybe_unused = {
|
||||
.helper_fw_name = NULL,
|
||||
.fw_name = FIRMWARE_W8987,
|
||||
.fw_name_old = FIRMWARE_W8987_OLD,
|
||||
};
|
||||
|
||||
static struct btnxpuart_data w8997_data __maybe_unused = {
|
||||
.helper_fw_name = FIRMWARE_HELPER,
|
||||
.fw_name = FIRMWARE_W8997,
|
||||
.fw_name_old = FIRMWARE_W8997_OLD,
|
||||
};
|
||||
|
||||
static const struct of_device_id nxpuart_of_match_table[] __maybe_unused = {
|
||||
@@ -1416,12 +1561,17 @@ static const struct of_device_id nxpuart_of_match_table[] __maybe_unused = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, nxpuart_of_match_table);
|
||||
|
||||
static const struct dev_pm_ops nxp_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(nxp_serdev_suspend, nxp_serdev_resume)
|
||||
};
|
||||
|
||||
static struct serdev_device_driver nxp_serdev_driver = {
|
||||
.probe = nxp_serdev_probe,
|
||||
.remove = nxp_serdev_remove,
|
||||
.driver = {
|
||||
.name = "btnxpuart",
|
||||
.of_match_table = of_match_ptr(nxpuart_of_match_table),
|
||||
.pm = &nxp_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -811,7 +811,7 @@ static int rtl_download_firmware(struct hci_dev *hdev,
|
||||
struct sk_buff *skb;
|
||||
struct hci_rp_read_local_version *rp;
|
||||
|
||||
dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL);
|
||||
dl_cmd = kmalloc(sizeof(*dl_cmd), GFP_KERNEL);
|
||||
if (!dl_cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
+80
-659
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
/*
|
||||
* Bluetooth HCI driver for Broadcom 4377/4378/4387 devices attached via PCIe
|
||||
* Bluetooth HCI driver for Broadcom 4377/4378/4387/4388 devices attached via PCIe
|
||||
*
|
||||
* Copyright (C) The Asahi Linux Contributors
|
||||
*/
|
||||
@@ -26,13 +26,16 @@ enum bcm4377_chip {
|
||||
BCM4377 = 0,
|
||||
BCM4378,
|
||||
BCM4387,
|
||||
BCM4388,
|
||||
};
|
||||
|
||||
#define BCM4377_DEVICE_ID 0x5fa0
|
||||
#define BCM4378_DEVICE_ID 0x5f69
|
||||
#define BCM4387_DEVICE_ID 0x5f71
|
||||
#define BCM4388_DEVICE_ID 0x5f72
|
||||
|
||||
#define BCM4377_TIMEOUT 1000
|
||||
#define BCM4377_TIMEOUT msecs_to_jiffies(1000)
|
||||
#define BCM4377_BOOT_TIMEOUT msecs_to_jiffies(5000)
|
||||
|
||||
/*
|
||||
* These devices only support DMA transactions inside a 32bit window
|
||||
@@ -487,6 +490,7 @@ struct bcm4377_data;
|
||||
* second window in BAR0
|
||||
* has_bar0_core2_window2: Set to true if this chip requires the second core's
|
||||
* second window to be configured
|
||||
* bar2_offset: Offset to the start of the variables in BAR2
|
||||
* clear_pciecfg_subsystem_ctrl_bit19: Set to true if bit 19 in the
|
||||
* vendor-specific subsystem control
|
||||
* register has to be cleared
|
||||
@@ -510,6 +514,7 @@ struct bcm4377_hw {
|
||||
u32 bar0_window1;
|
||||
u32 bar0_window2;
|
||||
u32 bar0_core2_window2;
|
||||
u32 bar2_offset;
|
||||
|
||||
unsigned long has_bar0_core2_window2 : 1;
|
||||
unsigned long clear_pciecfg_subsystem_ctrl_bit19 : 1;
|
||||
@@ -835,8 +840,8 @@ static irqreturn_t bcm4377_irq(int irq, void *data)
|
||||
struct bcm4377_data *bcm4377 = data;
|
||||
u32 bootstage, rti_status;
|
||||
|
||||
bootstage = ioread32(bcm4377->bar2 + BCM4377_BAR2_BOOTSTAGE);
|
||||
rti_status = ioread32(bcm4377->bar2 + BCM4377_BAR2_RTI_STATUS);
|
||||
bootstage = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_BOOTSTAGE);
|
||||
rti_status = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_STATUS);
|
||||
|
||||
if (bootstage != bcm4377->bootstage ||
|
||||
rti_status != bcm4377->rti_status) {
|
||||
@@ -1196,6 +1201,14 @@ static int bcm4387_send_calibration(struct bcm4377_data *bcm4377)
|
||||
bcm4377->taurus_cal_size);
|
||||
}
|
||||
|
||||
static int bcm4388_send_calibration(struct bcm4377_data *bcm4377)
|
||||
{
|
||||
/* BCM4388 always uses beamforming */
|
||||
return __bcm4378_send_calibration(
|
||||
bcm4377, bcm4377->taurus_beamforming_cal_blob,
|
||||
bcm4377->taurus_beamforming_cal_size);
|
||||
}
|
||||
|
||||
static const struct firmware *bcm4377_request_blob(struct bcm4377_data *bcm4377,
|
||||
const char *suffix)
|
||||
{
|
||||
@@ -1819,8 +1832,8 @@ static int bcm4377_boot(struct bcm4377_data *bcm4377)
|
||||
int ret = 0;
|
||||
u32 bootstage, rti_status;
|
||||
|
||||
bootstage = ioread32(bcm4377->bar2 + BCM4377_BAR2_BOOTSTAGE);
|
||||
rti_status = ioread32(bcm4377->bar2 + BCM4377_BAR2_RTI_STATUS);
|
||||
bootstage = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_BOOTSTAGE);
|
||||
rti_status = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_STATUS);
|
||||
|
||||
if (bootstage != 0) {
|
||||
dev_err(&bcm4377->pdev->dev, "bootstage is %d and not 0\n",
|
||||
@@ -1854,15 +1867,18 @@ static int bcm4377_boot(struct bcm4377_data *bcm4377)
|
||||
iowrite32(BCM4377_DMA_MASK,
|
||||
bcm4377->bar0 + BCM4377_BAR0_HOST_WINDOW_SIZE);
|
||||
|
||||
iowrite32(lower_32_bits(fw_dma), bcm4377->bar2 + BCM4377_BAR2_FW_LO);
|
||||
iowrite32(upper_32_bits(fw_dma), bcm4377->bar2 + BCM4377_BAR2_FW_HI);
|
||||
iowrite32(fw->size, bcm4377->bar2 + BCM4377_BAR2_FW_SIZE);
|
||||
iowrite32(lower_32_bits(fw_dma),
|
||||
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_FW_LO);
|
||||
iowrite32(upper_32_bits(fw_dma),
|
||||
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_FW_HI);
|
||||
iowrite32(fw->size,
|
||||
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_FW_SIZE);
|
||||
iowrite32(0, bcm4377->bar0 + BCM4377_BAR0_FW_DOORBELL);
|
||||
|
||||
dev_dbg(&bcm4377->pdev->dev, "waiting for firmware to boot\n");
|
||||
|
||||
ret = wait_for_completion_interruptible_timeout(&bcm4377->event,
|
||||
BCM4377_TIMEOUT);
|
||||
BCM4377_BOOT_TIMEOUT);
|
||||
if (ret == 0) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto out_dma_free;
|
||||
@@ -1913,16 +1929,16 @@ static int bcm4377_setup_rti(struct bcm4377_data *bcm4377)
|
||||
dev_dbg(&bcm4377->pdev->dev, "RTI is in state 1\n");
|
||||
|
||||
/* allow access to the entire IOVA space again */
|
||||
iowrite32(0, bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_LO);
|
||||
iowrite32(0, bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_HI);
|
||||
iowrite32(0, bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_WINDOW_LO);
|
||||
iowrite32(0, bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_WINDOW_HI);
|
||||
iowrite32(BCM4377_DMA_MASK,
|
||||
bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_SIZE);
|
||||
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_WINDOW_SIZE);
|
||||
|
||||
/* setup "Converged IPC" context */
|
||||
iowrite32(lower_32_bits(bcm4377->ctx_dma),
|
||||
bcm4377->bar2 + BCM4377_BAR2_CONTEXT_ADDR_LO);
|
||||
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_CONTEXT_ADDR_LO);
|
||||
iowrite32(upper_32_bits(bcm4377->ctx_dma),
|
||||
bcm4377->bar2 + BCM4377_BAR2_CONTEXT_ADDR_HI);
|
||||
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_CONTEXT_ADDR_HI);
|
||||
iowrite32(2, bcm4377->bar0 + BCM4377_BAR0_RTI_CONTROL);
|
||||
|
||||
ret = wait_for_completion_interruptible_timeout(&bcm4377->event,
|
||||
@@ -2488,6 +2504,21 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = {
|
||||
.send_calibration = bcm4387_send_calibration,
|
||||
.send_ptb = bcm4378_send_ptb,
|
||||
},
|
||||
|
||||
[BCM4388] = {
|
||||
.id = 0x4388,
|
||||
.otp_offset = 0x415c,
|
||||
.bar2_offset = 0x200000,
|
||||
.bar0_window1 = 0x18002000,
|
||||
.bar0_window2 = 0x18109000,
|
||||
.bar0_core2_window2 = 0x18106000,
|
||||
.has_bar0_core2_window2 = true,
|
||||
.broken_mws_transport_config = true,
|
||||
.broken_le_coded = true,
|
||||
.broken_le_ext_adv_report_phy = true,
|
||||
.send_calibration = bcm4388_send_calibration,
|
||||
.send_ptb = bcm4378_send_ptb,
|
||||
},
|
||||
};
|
||||
|
||||
#define BCM4377_DEVID_ENTRY(id) \
|
||||
@@ -2501,6 +2532,7 @@ static const struct pci_device_id bcm4377_devid_table[] = {
|
||||
BCM4377_DEVID_ENTRY(4377),
|
||||
BCM4377_DEVID_ENTRY(4378),
|
||||
BCM4377_DEVID_ENTRY(4387),
|
||||
BCM4377_DEVID_ENTRY(4388),
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, bcm4377_devid_table);
|
||||
@@ -2515,7 +2547,7 @@ static struct pci_driver bcm4377_pci_driver = {
|
||||
module_pci_driver(bcm4377_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
|
||||
MODULE_DESCRIPTION("Bluetooth support for Broadcom 4377/4378/4387 devices");
|
||||
MODULE_DESCRIPTION("Bluetooth support for Broadcom 4377/4378/4387/4388 devices");
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
MODULE_FIRMWARE("brcm/brcmbt4377*.bin");
|
||||
MODULE_FIRMWARE("brcm/brcmbt4377*.ptb");
|
||||
@@ -2523,3 +2555,5 @@ MODULE_FIRMWARE("brcm/brcmbt4378*.bin");
|
||||
MODULE_FIRMWARE("brcm/brcmbt4378*.ptb");
|
||||
MODULE_FIRMWARE("brcm/brcmbt4387*.bin");
|
||||
MODULE_FIRMWARE("brcm/brcmbt4387*.ptb");
|
||||
MODULE_FIRMWARE("brcm/brcmbt4388*.bin");
|
||||
MODULE_FIRMWARE("brcm/brcmbt4388*.ptb");
|
||||
|
||||
@@ -488,7 +488,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
|
||||
if (tty->ops->write == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL);
|
||||
hu = kzalloc(sizeof(*hu), GFP_KERNEL);
|
||||
if (!hu) {
|
||||
BT_ERR("Can't allocate control structure");
|
||||
return -ENFILE;
|
||||
|
||||
@@ -116,11 +116,6 @@ struct hci_nokia_neg_evt {
|
||||
#define SETUP_BAUD_RATE 921600
|
||||
#define INIT_BAUD_RATE 120000
|
||||
|
||||
struct hci_nokia_radio_hdr {
|
||||
u8 evt;
|
||||
u8 dlen;
|
||||
} __packed;
|
||||
|
||||
struct nokia_bt_dev {
|
||||
struct hci_uart hu;
|
||||
struct serdev_device *serdev;
|
||||
|
||||
+98
-35
@@ -28,6 +28,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwrseq/consumer.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/serdev.h>
|
||||
#include <linux/mutex.h>
|
||||
@@ -214,6 +215,7 @@ struct qca_power {
|
||||
struct regulator_bulk_data *vreg_bulk;
|
||||
int num_vregs;
|
||||
bool vregs_on;
|
||||
struct pwrseq_desc *pwrseq;
|
||||
};
|
||||
|
||||
struct qca_serdev {
|
||||
@@ -569,7 +571,7 @@ static int qca_open(struct hci_uart *hu)
|
||||
if (!hci_uart_has_flow_control(hu))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
qca = kzalloc(sizeof(struct qca_data), GFP_KERNEL);
|
||||
qca = kzalloc(sizeof(*qca), GFP_KERNEL);
|
||||
if (!qca)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1040,8 +1042,7 @@ static void qca_controller_memdump(struct work_struct *work)
|
||||
}
|
||||
|
||||
if (!qca_memdump) {
|
||||
qca_memdump = kzalloc(sizeof(struct qca_memdump_info),
|
||||
GFP_ATOMIC);
|
||||
qca_memdump = kzalloc(sizeof(*qca_memdump), GFP_ATOMIC);
|
||||
if (!qca_memdump) {
|
||||
mutex_unlock(&qca->hci_memdump_lock);
|
||||
return;
|
||||
@@ -1685,6 +1686,27 @@ static bool qca_wakeup(struct hci_dev *hdev)
|
||||
return wakeup;
|
||||
}
|
||||
|
||||
static int qca_port_reopen(struct hci_uart *hu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Now the device is in ready state to communicate with host.
|
||||
* To sync host with device we need to reopen port.
|
||||
* Without this, we will have RTS and CTS synchronization
|
||||
* issues.
|
||||
*/
|
||||
serdev_device_close(hu->serdev);
|
||||
ret = serdev_device_open(hu->serdev);
|
||||
if (ret) {
|
||||
bt_dev_err(hu->hdev, "failed to open port");
|
||||
return ret;
|
||||
}
|
||||
|
||||
hci_uart_set_flow_control(hu, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qca_regulator_init(struct hci_uart *hu)
|
||||
{
|
||||
enum qca_btsoc_type soc_type = qca_soc_type(hu);
|
||||
@@ -1696,6 +1718,7 @@ static int qca_regulator_init(struct hci_uart *hu)
|
||||
* off the voltage regulator.
|
||||
*/
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
|
||||
if (!qcadev->bt_power->vregs_on) {
|
||||
serdev_device_close(hu->serdev);
|
||||
ret = qca_regulator_enable(qcadev);
|
||||
@@ -1753,21 +1776,7 @@ static int qca_regulator_init(struct hci_uart *hu)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now the device is in ready state to communicate with host.
|
||||
* To sync host with device we need to reopen port.
|
||||
* Without this, we will have RTS and CTS synchronization
|
||||
* issues.
|
||||
*/
|
||||
serdev_device_close(hu->serdev);
|
||||
ret = serdev_device_open(hu->serdev);
|
||||
if (ret) {
|
||||
bt_dev_err(hu->hdev, "failed to open port");
|
||||
return ret;
|
||||
}
|
||||
|
||||
hci_uart_set_flow_control(hu, false);
|
||||
|
||||
return 0;
|
||||
return qca_port_reopen(hu);
|
||||
}
|
||||
|
||||
static int qca_power_on(struct hci_dev *hdev)
|
||||
@@ -1792,6 +1801,7 @@ static int qca_power_on(struct hci_dev *hdev)
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
case QCA_QCA6390:
|
||||
ret = qca_regulator_init(hu);
|
||||
break;
|
||||
|
||||
@@ -2130,6 +2140,7 @@ static void qca_power_shutdown(struct hci_uart *hu)
|
||||
unsigned long flags;
|
||||
enum qca_btsoc_type soc_type = qca_soc_type(hu);
|
||||
bool sw_ctrl_state;
|
||||
struct qca_power *power;
|
||||
|
||||
/* From this point we go into power off state. But serial port is
|
||||
* still open, stop queueing the IBS data and flush all the buffered
|
||||
@@ -2147,6 +2158,13 @@ static void qca_power_shutdown(struct hci_uart *hu)
|
||||
return;
|
||||
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
power = qcadev->bt_power;
|
||||
|
||||
if (power->pwrseq) {
|
||||
pwrseq_power_off(power->pwrseq);
|
||||
set_bit(QCA_BT_OFF, &qca->flags);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
@@ -2169,6 +2187,10 @@ static void qca_power_shutdown(struct hci_uart *hu)
|
||||
}
|
||||
break;
|
||||
|
||||
case QCA_QCA6390:
|
||||
pwrseq_power_off(qcadev->bt_power->pwrseq);
|
||||
break;
|
||||
|
||||
default:
|
||||
gpiod_set_value_cansleep(qcadev->bt_en, 0);
|
||||
}
|
||||
@@ -2204,6 +2226,9 @@ static int qca_regulator_enable(struct qca_serdev *qcadev)
|
||||
struct qca_power *power = qcadev->bt_power;
|
||||
int ret;
|
||||
|
||||
if (power->pwrseq)
|
||||
return pwrseq_power_on(power->pwrseq);
|
||||
|
||||
/* Already enabled */
|
||||
if (power->vregs_on)
|
||||
return 0;
|
||||
@@ -2272,6 +2297,13 @@ static int qca_init_regulators(struct qca_power *qca,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qca_clk_disable_unprepare(void *data)
|
||||
{
|
||||
struct clk *clk = data;
|
||||
|
||||
clk_disable_unprepare(clk);
|
||||
}
|
||||
|
||||
static int qca_serdev_probe(struct serdev_device *serdev)
|
||||
{
|
||||
struct qca_serdev *qcadev;
|
||||
@@ -2310,12 +2342,40 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
case QCA_QCA6390:
|
||||
qcadev->bt_power = devm_kzalloc(&serdev->dev,
|
||||
sizeof(struct qca_power),
|
||||
GFP_KERNEL);
|
||||
if (!qcadev->bt_power)
|
||||
return -ENOMEM;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (qcadev->btsoc_type) {
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
if (!device_property_present(&serdev->dev, "enable-gpios")) {
|
||||
/*
|
||||
* Backward compatibility with old DT sources. If the
|
||||
* node doesn't have the 'enable-gpios' property then
|
||||
* let's use the power sequencer. Otherwise, let's
|
||||
* drive everything outselves.
|
||||
*/
|
||||
qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->dev,
|
||||
"bluetooth");
|
||||
if (IS_ERR(qcadev->bt_power->pwrseq))
|
||||
return PTR_ERR(qcadev->bt_power->pwrseq);
|
||||
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
qcadev->bt_power->dev = &serdev->dev;
|
||||
err = qca_init_regulators(qcadev->bt_power, data->vregs,
|
||||
data->num_vregs);
|
||||
@@ -2353,12 +2413,13 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
||||
dev_err(&serdev->dev, "failed to acquire clk\n");
|
||||
return PTR_ERR(qcadev->susclk);
|
||||
}
|
||||
break;
|
||||
|
||||
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
|
||||
if (err) {
|
||||
BT_ERR("wcn3990 serdev registration failed");
|
||||
return err;
|
||||
}
|
||||
case QCA_QCA6390:
|
||||
qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->dev,
|
||||
"bluetooth");
|
||||
if (IS_ERR(qcadev->bt_power->pwrseq))
|
||||
return PTR_ERR(qcadev->bt_power->pwrseq);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2385,12 +2446,18 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
|
||||
if (err) {
|
||||
BT_ERR("Rome serdev registration failed");
|
||||
clk_disable_unprepare(qcadev->susclk);
|
||||
err = devm_add_action_or_reset(&serdev->dev,
|
||||
qca_clk_disable_unprepare,
|
||||
qcadev->susclk);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
|
||||
if (err) {
|
||||
BT_ERR("serdev registration failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
hdev = qcadev->serdev_hu.hdev;
|
||||
@@ -2428,15 +2495,11 @@ static void qca_serdev_remove(struct serdev_device *serdev)
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
if (power->vregs_on) {
|
||||
if (power->vregs_on)
|
||||
qca_power_shutdown(&qcadev->serdev_hu);
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
|
||||
break;
|
||||
default:
|
||||
if (qcadev->susclk)
|
||||
clk_disable_unprepare(qcadev->susclk);
|
||||
break;
|
||||
}
|
||||
|
||||
hci_uart_unregister_device(&qcadev->serdev_hu);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user