Commit cd9b6f47 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'for-net-next-2024-07-15' of...

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.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 30b35600 23e88450
# 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
- vddwlcx-supply
- vddwlmx-supply
- vddrfa0p8-supply
- vddrfa1p2-supply
- vddrfa1p8-supply
- if:
properties:
compatible:
contains:
enum:
- qcom,qca6390-bt
then:
required:
- vddrfacmn-supply
- vddaon-supply
- vdddig-supply
- vddbtcmx-supply
- vddrfa0p8-supply
- vddrfa1p2-supply
- vddrfa1p9-supply
- vddrfa1p7-supply
examples:
- |
......
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).
......
This diff is collapsed.
......@@ -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);
......
This diff is collapsed.
......@@ -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 inline int btmtk_register_coredump(struct hci_dev *hdev,
const char *name, u32 fw_version)
{
return -EOPNOTSUPP;
}
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 int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
u32 fw_version)
static inline int btmtk_usb_setup(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
static int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
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>
......
This diff is collapsed.
......@@ -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;
......
This diff is collapsed.
// 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;
......
......@@ -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);
......
......@@ -633,7 +633,7 @@ static int vhci_open(struct inode *inode, struct file *file)
{
struct vhci_data *data;
data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
......
# SPDX-License-Identifier: GPL-2.0-only
source "drivers/power/reset/Kconfig"
source "drivers/power/sequencing/Kconfig"
source "drivers/power/supply/Kconfig"
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_POWER_RESET) += reset/
obj-$(CONFIG_POWER_SEQUENCING) += sequencing/
obj-$(CONFIG_POWER_SUPPLY) += supply/
# SPDX-License-Identifier: GPL-2.0-only
menuconfig POWER_SEQUENCING
tristate "Power Sequencing support"
help
Say Y here to enable the Power Sequencing subsystem.
This subsystem is designed to control power to devices that share
complex resources and/or require specific power sequences to be run
during power-up.
If unsure, say no.
if POWER_SEQUENCING
config POWER_SEQUENCING_QCOM_WCN
tristate "Qualcomm WCN family PMU driver"
default m if ARCH_QCOM
help
Say Y here to enable the power sequencing driver for Qualcomm
WCN Bluetooth/WLAN chipsets.
Typically, a package from the Qualcomm WCN family contains the BT
and WLAN modules whose power is controlled by the PMU module. As the
former two share the power-up sequence which is executed by the PMU,
this driver is needed for correct power control or else we'd risk not
respecting the required delays between enabling Bluetooth and WLAN.
endif
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_POWER_SEQUENCING) += pwrseq-core.o
pwrseq-core-y := core.o
obj-$(CONFIG_POWER_SEQUENCING_QCOM_WCN) += pwrseq-qcom-wcn.o
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2024 Linaro Ltd.
*/
#ifndef __POWER_SEQUENCING_CONSUMER_H__
#define __POWER_SEQUENCING_CONSUMER_H__
#include <linux/err.h>
struct device;
struct pwrseq_desc;
#if IS_ENABLED(CONFIG_POWER_SEQUENCING)
struct pwrseq_desc * __must_check
pwrseq_get(struct device *dev, const char *target);
void pwrseq_put(struct pwrseq_desc *desc);
struct pwrseq_desc * __must_check
devm_pwrseq_get(struct device *dev, const char *target);
int pwrseq_power_on(struct pwrseq_desc *desc);
int pwrseq_power_off(struct pwrseq_desc *desc);
#else /* CONFIG_POWER_SEQUENCING */
static inline struct pwrseq_desc * __must_check
pwrseq_get(struct device *dev, const char *target)
{
return ERR_PTR(-ENOSYS);
}
static inline void pwrseq_put(struct pwrseq_desc *desc)
{
}
static inline struct pwrseq_desc * __must_check
devm_pwrseq_get(struct device *dev, const char *target)
{
return ERR_PTR(-ENOSYS);
}
static inline int pwrseq_power_on(struct pwrseq_desc *desc)
{
return -ENOSYS;
}
static inline int pwrseq_power_off(struct pwrseq_desc *desc)
{
return -ENOSYS;
}
#endif /* CONFIG_POWER_SEQUENCING */
#endif /* __POWER_SEQUENCING_CONSUMER_H__ */
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2024 Linaro Ltd.
*/
#ifndef __POWER_SEQUENCING_PROVIDER_H__
#define __POWER_SEQUENCING_PROVIDER_H__
struct device;
struct module;
struct pwrseq_device;
typedef int (*pwrseq_power_state_func)(struct pwrseq_device *);
typedef int (*pwrseq_match_func)(struct pwrseq_device *, struct device *);
/**
* struct pwrseq_unit_data - Configuration of a single power sequencing
* unit.
* @name: Name of the unit.
* @deps: Units that must be enabled before this one and disabled after it
* in the order they come in this array. Must be NULL-terminated.
* @enable: Callback running the part of the power-on sequence provided by
* this unit.
* @disable: Callback running the part of the power-off sequence provided
* by this unit.
*/
struct pwrseq_unit_data {
const char *name;
const struct pwrseq_unit_data **deps;
pwrseq_power_state_func enable;
pwrseq_power_state_func disable;
};
/**
* struct pwrseq_target_data - Configuration of a power sequencing target.
* @name: Name of the target.
* @unit: Final unit that this target must reach in order to be considered
* enabled.
* @post_enable: Callback run after the target unit has been enabled, *after*
* the state lock has been released. It's useful for implementing
* boot-up delays without blocking other users from powering up
* using the same power sequencer.
*/
struct pwrseq_target_data {
const char *name;
const struct pwrseq_unit_data *unit;
pwrseq_power_state_func post_enable;
};
/**
* struct pwrseq_config - Configuration used for registering a new provider.
* @parent: Parent device for the sequencer. Must be set.
* @owner: Module providing this device.
* @drvdata: Private driver data.
* @match: Provider callback used to match the consumer device to the sequencer.
* @targets: Array of targets for this power sequencer. Must be NULL-terminated.
*/
struct pwrseq_config {
struct device *parent;
struct module *owner;
void *drvdata;
pwrseq_match_func match;
const struct pwrseq_target_data **targets;
};
struct pwrseq_device *
pwrseq_device_register(const struct pwrseq_config *config);
void pwrseq_device_unregister(struct pwrseq_device *pwrseq);
struct pwrseq_device *
devm_pwrseq_device_register(struct device *dev,
const struct pwrseq_config *config);
void *pwrseq_device_get_drvdata(struct pwrseq_device *pwrseq);
#endif /* __POWER_SEQUENCING_PROVIDER_H__ */
......@@ -441,6 +441,10 @@ typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status, u16 opcode);
typedef void (*hci_req_complete_skb_t)(struct hci_dev *hdev, u8 status,
u16 opcode, struct sk_buff *skb);
void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status,
hci_req_complete_t *req_complete,
hci_req_complete_skb_t *req_complete_skb);
#define HCI_REQ_START BIT(0)
#define HCI_REQ_SKB BIT(1)
......
This diff is collapsed.
......@@ -144,7 +144,7 @@ struct hci_dev_req {
struct hci_dev_list_req {
__u16 dev_num;
struct hci_dev_req dev_req[]; /* hci_dev_req structures */
struct hci_dev_req dev_req[] __counted_by(dev_num);
};
struct hci_conn_list_req {
......
This diff is collapsed.
......@@ -355,7 +355,7 @@ struct rfcomm_dev_info {
struct rfcomm_dev_list_req {
u16 dev_num;
struct rfcomm_dev_info dev_info[];
struct rfcomm_dev_info dev_info[] __counted_by(dev_num);
};
int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
......
......@@ -14,8 +14,7 @@ bluetooth_6lowpan-y := 6lowpan.o
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o \
eir.o hci_sync.o
ecdh_helper.o mgmt_util.o mgmt_config.o hci_codec.o eir.o hci_sync.o
bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment