Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v5 0/6] Add support for IPQ5018 Bluetooth
@ 2026-07-09  9:18 George Moussalem via B4 Relay
  2026-07-09  9:18 ` [PATCH v5 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller George Moussalem via B4 Relay
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: George Moussalem via B4 Relay @ 2026-07-09  9:18 UTC (permalink / raw)
  To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	George Moussalem, Krzysztof Kozlowski, Bartosz Golaszewski,
	Konrad Dybcio, Dmitry Baryshkov

Hello,

This patch series introduces Bluetooth support for IPQ5018.

Bluetooth firmware is loaded by the host into a dedicated reserved
memory carveout and authenticated by TrustZone. A Secure Channel Manager
(SCM) call safely brings the peripheral core out of reset.

A shared memory ring buffer topology handles runtime data frame
transport between the host APSS and the Bluetooth controller.
An outgoing APCS IPC bit and an incoming GIC interrupt handle
host/guest signaling.

This series has been tested and verified on various IPQ5018 router
boards utilizing firmware extracted from GPL distributions, using both
mdt and mbn file formats.

[   14.781511] Bluetooth: hci0: QCA Product ID   :0x00000016
[   14.781583] Bluetooth: hci0: QCA SOC Version  :0x20180100
[   14.785926] Bluetooth: hci0: QCA ROM Version  :0x00000100
[   14.791546] Bluetooth: hci0: QCA Patch Version:0x00003ded
[   14.796698] Bluetooth: hci0: QCA controller version 0x01000100
[   14.802217] Bluetooth: hci0: QCA Downloading qca/mpnv10.bin
[   16.393850] Bluetooth: hci0: QCA FW build version: BTFW.MAPLE.1.0.0-00102-MPL_ROM_PATCHZ-1

Best regards,
George Moussalem

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
Changes in v5:
- Updated the bindings file to change from using a memory-region
  property to using a reg property for the shared memory area and made
  reg a required property.
- Added Bartosz G. to the maintainers list in the bindings file.
- Updated the driver to acquire the memory region as platform resource
  using devm_platform_get_and_ioremap_resource()
- Replaced macros with unsafe arithmetic with inline functions that
  safely calculate the size by reading values using endian functions
  le**_to_cpu().
- Update btss_lbuf_size to guard against division by zero and against
  the offset extending beyond the total size of the context info struct.
- Updated btqcomipc_send to enqueue packets before releasing the
  spinlock to avoid stranding packets in the queue indefinitely.
- Added an explicit DMA read barrier in the RX loop before reading and
  processing each ring entry to guarantee memory ordering.
- Added strict arithmetic validation for long-message metadata handling
  before computing wrap segments and hardened the non-contiguous path to
  prevent underflow.
- Hardened split-segment firmware loading error handling. If
  request_firmware() for a segment fails, the code now exits that path
  immediately instead of falling through to memcpy_toio() and added
  explicit split-file size validation before copy.
- Updated HCI dev close path state teardown to avoid stale transport
  stale after PAS shutdown. btqcomipc_close() now explicitly sets
  running state to false under lock after shutdown.
- Made IRQ registration safe against spurious interrupts by keeping the
  line disabled after request (flags includes now IRQF_NO_AUTOEN).
  IRQ is now enabled only in btqcomipc_open() right before firmware boot
  and disabled again on open-failure and close paths.
- Reordered remove-path teardown to eliminate worker vs HCI lifetime
  race. It now unregisters HCI first to stop new traffic, then calls
  btqcomipc_deinit() to stop async processing, and only then frees hdev.
- Removed reserved memory area from the dtsi, moved bluetooth node under
  the soc node, and added unit address and reg property.
- Link to v4: https://lore.kernel.org/r/20260706-ipq5018-bluetooth-v4-0-350262a30959@outlook.com

Changes in v4:
- Ordered switch statements in btqca.c. NOTE: left enum qca_bt_soc_type
  unordered in the header file as the btqca driver has conditionally
  checks whether bt_soc_type is above a certain value:
  'if (soc_type >= QCA_WCN3991)' is found in 5 places
- Fixed TX path serialization by protecting btqcomipc_send and
  btss_send ring access with desc->lock, preventing concurrent updates
  of ring indices and free counters from TX and worker contexts.
- Fixed and simplified firmware ring traversal to decode little-endian
  next and translate firmware offsets via TO_APPS_ADDR in all ring
  walks, avoiding invalid pointer dereferences.
- Added short-message RX length validation (msg_len must not exceed
  IPC_MSG_PLD_SZ when not long message), preventing out-of-bounds read
  from inline shared-memory payloads.
- Fixed RX allocation failure behavior to advance ring index and
  continue, preventing permanent RX ring stall on transient kmalloc
  failures.
- Replace macro for calculting large buffer size that performed unsafe
  arithmetic by an inline function that safely calculates the size by
  reading values using endian functions le**_to_cpu().
- Declared aux_ptr as a zero-initialized struct as opposed to using
  memset and changed struct definition by updating its member to use
  u32 as opposed to __le32 as these values aren't set by firmware and
  need not be validated on endianness.
- Fixed long-message slot leak when short TX ring is full by
  snapshotting and rolling back long-buffer accounting on
  allocation-success/short-ring-fail path.
- Updated firmware load logic to remove call to qcom_mdt_pas_init for
  which the export was recently removed and replaced it by calls to
  read the metadata and the validation of it using SCM.
  NOTE: Sashiko correctly pointed out that the firmware ELF/mdt headers
  weren't validated in the driver. However, this is done by the call to
  qcom_mdt_read_metadata which returns -EINVAL if the mdt header isn't
  valid.
- Hardened firmware segment bounds checks against integer overflow by
  using subtraction form (filesz <= mem_size - vaddr).
- Replaced unsafe firmware split name rewrite with validated stem
  handling and kasprintf formatting, removing underflow/overflow risk.
- Converted workqueue allocation to devm_alloc_ordered_workqueue to fix
  workqueue leak in IRQ registration failure path.
- Added cleanup path in btqcomipc_open to shut down controller on
  startup timeout, avoiding leaving peripheral powered after failed open
- Reordered probe sequence to allocate/attach hdev before IRQ
  registration, eliminating early-spurious-IRQ dereference window for
  desc->hdev.
- Reordered remove path to unregister/free hdev before driver deinit,
  preventing send path from racing against queue/work teardown.
- Corrected HCI command packet length parsing to use 8-bit plen directly
  instead of using le16_to_cpu.
- Fixed endianness and address translation in TX ACK processing path.
  Converted firmware-owned ring metadata before use in btss_process_ack:
  rbuf base offset, msg header, long-message pointer, and message length
  are now read via le32_to_cpu or le16_to_cpu prior to reclaim logic.
- Added explicit producer ordering barrier in TX ring publish path.
  Inserted dma_wmb between payload or header writes and widx update so
  firmware cannot observe producer index advancement before data becomes
  visible.
- Removed info message printing FW build info as that was recently
  introduced in the kernel in commit bdea21b3be43
- Added dependency on OF and ARCH_QCOM symbols to Kconfig. In addition,
  also select QCOM_MDT_LOADER and QCOM_SCM.
- Removed syscon compatible from mailbox node, avoiding dt_binding_check
  failures and update the syscon acquisition logic in driver probe
  accordingly.
- Link to v3: https://lore.kernel.org/r/20260703-ipq5018-bluetooth-v3-0-62da72818ab3@outlook.com

Changes in v3:
- Consolidated the SCM and helper call into one function which now
  checks availability of the SCM call inline.
- Changed argument to boolean type to set ECO power mode on or off as
  opposed to passing a raw power mode value.
- Removed unneeded parentheses in if statement
- Declared aux_ptr as a zero-initialized struct as opposed to using
  memset
- Changed for loop to a while loop for better readability
- Reordered function definition of btqcomipc_update_stats to avoid the
  need for a forward declaration.
- Removed unneeded header files from btqcomipc.c (bits.h, device.h,
  init.h, kernel.h, of_irq.h, types.h)
- Link to v2: https://lore.kernel.org/r/20260629-ipq5018-bluetooth-v2-0-02770f03b6bb@outlook.com

Changes in v2:
- removed unused struct member btss_reset from m0_btss struct.
- used devm_reset_control_get_exclusive_deasserted to acquire and
  deassert btss_reset in one call. No need to explicitly assert upon
  unbind since devres will handle it.
- As per Bjorn's comments, collapsed the rproc and BT driver into one
  which now handles firmware loading and transport.
- As per further review comments and above change, squashed the two
  devicetree bindings into one to represent the Bluetooth controller
- Added new SCM call to drive Bluetooth power modes. Based on testing on
  more router boards, this is required during start/stop sequences to
  avoid the controller hanging. This is only supported on relatively
  newer QSEE versions, so the SCM call is checked for availability
  before use.
- Refactored resource lifecycle management in the driver so that IRQ and
  work queue are managed at the driver level (probe/remove) while FW
  loading and powering on/off the controller is handled upon hdev
  open/close.
- Consolidated TX send functions for custom IPC and HCI frames into one
  and solved a potential NULL pointer dereference issue under TX
  pressure.
- Replace code to load and initialize firmware metadate by existing
  qcom_mdt_pas_init function.
- Solved an off byone calculation error in the RX parser.
- Added entry to MAINTAINERS file
- Link to v1: https://lore.kernel.org/r/20260625-ipq5018-bluetooth-v1-0-d999be0e04f7@outlook.com

---
George Moussalem (6):
      dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
      Bluetooth: btqca: Add IPQ5018 support
      firmware: qcom: scm: Add support for setting Bluetooth power modes
      Bluetooth: Introduce Qualcomm IPQ5018 IPC based HCI driver
      arm64: dts: qcom: ipq5018: add node required for Bluetooth support
      MAINTAINERS: Add IPQ5018 driver to Qualcomm Bluetooth driver entry

 .../bindings/net/bluetooth/qcom,ipq5018-bt.yaml    |   87 ++
 MAINTAINERS                                        |    1 +
 arch/arm64/boot/dts/qcom/ipq5018.dtsi              |   16 +
 drivers/bluetooth/Kconfig                          |   14 +
 drivers/bluetooth/Makefile                         |    1 +
 drivers/bluetooth/btqca.c                          |   16 +
 drivers/bluetooth/btqca.h                          |    3 +
 drivers/bluetooth/btqcomipc.c                      | 1230 ++++++++++++++++++++
 drivers/firmware/qcom/qcom_scm.c                   |   44 +
 drivers/firmware/qcom/qcom_scm.h                   |    1 +
 include/linux/firmware/qcom/qcom_scm.h             |    1 +
 11 files changed, 1414 insertions(+)
---
base-commit: ca75417ab1793f23b3ddc91869f0809b593d6954
change-id: 20260625-ipq5018-bluetooth-06ff66c9d753
prerequisite-message-id: <20260703-block-as-nvmem-v8-0-98ae32bfc49a@oss.qualcomm.com>
prerequisite-patch-id: 467ba5e0fde0e9a1e9d0a6faf3d22ba2126c62a7
prerequisite-patch-id: 9168930e40551e842c8171d5433a6f39ad4b78a4
prerequisite-patch-id: 64fecfbd1e085d7d2ab0ae23295ca34ec8e14c5e
prerequisite-patch-id: 7bf282ed9312b2ffdbe420429bbe355622620272
prerequisite-patch-id: 29a7d652948d13f91bdd4fc5fb8e6dbcd6e5fcc5
prerequisite-patch-id: c03136820a7749fd9630080e6d4459a298b3b630
prerequisite-patch-id: 43975fc425bf2f5dd5c1de66aaa78c4b4bde568c
prerequisite-patch-id: 75caa99e3bbcdf41b6462b9f5f703bea1d4a65fa
prerequisite-patch-id: b9b2a2f80a4827b457166b20f54644e57d90b824

Best regards,
-- 
George Moussalem <george.moussalem@outlook.com>



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v5 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
  2026-07-09  9:18 [PATCH v5 0/6] Add support for IPQ5018 Bluetooth George Moussalem via B4 Relay
@ 2026-07-09  9:18 ` George Moussalem via B4 Relay
  2026-07-09 12:21   ` Add support for IPQ5018 Bluetooth bluez.test.bot
  2026-07-09  9:18 ` [PATCH v5 2/6] Bluetooth: btqca: Add IPQ5018 support George Moussalem via B4 Relay
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: George Moussalem via B4 Relay @ 2026-07-09  9:18 UTC (permalink / raw)
  To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	George Moussalem, Krzysztof Kozlowski, Bartosz Golaszewski

From: George Moussalem <george.moussalem@outlook.com>

Document the Qualcomm IPQ5018 Bluetooth controller.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 .../bindings/net/bluetooth/qcom,ipq5018-bt.yaml    | 87 ++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,ipq5018-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,ipq5018-bt.yaml
new file mode 100644
index 000000000000..6bd74c01b821
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,ipq5018-bt.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/bluetooth/qcom,ipq5018-bt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm IPQ5018 Bluetooth
+
+maintainers:
+  - Bartosz Golaszewski <brgl@kernel.org>
+  - George Moussalem <george.moussalem@outlook.com>
+
+properties:
+  compatible:
+    enum:
+      - qcom,ipq5018-bt
+
+  reg:
+    items:
+      - description: |
+          Shared memory for firmware loading and runtime data transport between
+          the host and the Bluetooth controller.
+
+  clocks:
+    items:
+      - description: Bluetooth Subsystem low power oscillator clock
+
+  clock-names:
+    items:
+      - const: lpo
+
+  firmware-name:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  qcom,ipc:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: syscon node representing the APCS registers
+          - description: offset to the register within the syscon
+          - description: IPC bit within the register
+    description: |
+      The outgoing IPC bit used for signaling the Bluetooth controller of a host
+      event or for sending an ACK if the remote processor expects it.
+
+  resets:
+    items:
+      - description: Bluetooth Subsystem reset
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - firmware-name
+  - interrupts
+  - qcom,ipc
+  - reg
+  - resets
+
+allOf:
+  - $ref: bluetooth-controller.yaml#
+  - $ref: qcom,bluetooth-common.yaml
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
+
+    bluetooth@7000000 {
+      compatible = "qcom,ipq5018-bt";
+      reg = <0x07000000 0x58000>;
+
+      firmware-name = "qca/bt_fw_patch.mbn";
+
+      clocks = <&gcc GCC_BTSS_LPO_CLK>;
+      clock-names = "lpo";
+      resets = <&gcc GCC_BTSS_BCR>;
+
+      qcom,ipc = <&apcs_glb 8 23>;
+      interrupts = <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>;
+    };

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v5 2/6] Bluetooth: btqca: Add IPQ5018 support
  2026-07-09  9:18 [PATCH v5 0/6] Add support for IPQ5018 Bluetooth George Moussalem via B4 Relay
  2026-07-09  9:18 ` [PATCH v5 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller George Moussalem via B4 Relay
@ 2026-07-09  9:18 ` George Moussalem via B4 Relay
  2026-07-09  9:18 ` [PATCH v5 3/6] firmware: qcom: scm: Add support for setting Bluetooth power modes George Moussalem via B4 Relay
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: George Moussalem via B4 Relay @ 2026-07-09  9:18 UTC (permalink / raw)
  To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	George Moussalem, Bartosz Golaszewski

From: George Moussalem <george.moussalem@outlook.com>

Add the IPQ5018 SoC type and support for loading its firmware.

The firmware tested has been taken from GPL sources of various router
boards. Firmware files needed are:
- qca/bt_fw_patch.mbn
- qca/mpnv10.bin

Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/bluetooth/btqca.c | 16 ++++++++++++++++
 drivers/bluetooth/btqca.h |  3 +++
 2 files changed, 19 insertions(+)

diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 08600b0fc041..eed30a4480e0 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -361,6 +361,9 @@ static int qca_tlv_check_data(struct hci_dev *hdev,
 		break;
 
 	case TLV_TYPE_NVM:
+		if (soc_type == QCA_IPQ5018)
+			break;
+
 		if (fw_size < sizeof(struct tlv_type_hdr))
 			return -EINVAL;
 
@@ -778,6 +781,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
 	else
 		rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
 
+	if (soc_type == QCA_IPQ5018)
+		goto download_nvm;
+
 	if (soc_type == QCA_WCN6750)
 		qca_send_patch_config_cmd(hdev);
 
@@ -865,6 +871,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
 	if (soc_type == QCA_QCA2066 || soc_type == QCA_WCN7850)
 		qca_read_fw_board_id(hdev, &boardid);
 
+download_nvm:
 	/* Download NVM configuration */
 	config.type = TLV_TYPE_NVM;
 	if (firmware_name) {
@@ -878,6 +885,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
 		}
 	} else {
 		switch (soc_type) {
+		case QCA_IPQ5018:
+			snprintf(config.fwname, sizeof(config.fwname),
+				 "qca/mpnv%02x.bin", rom_ver);
+			break;
 		case QCA_QCA2066:
 			qca_get_nvm_name_by_board(config.fwname,
 						  sizeof(config.fwname),
@@ -942,7 +953,11 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
 		return err;
 	}
 
+	if (soc_type == QCA_IPQ5018)
+		msleep(NVM_READY_DELAY_MS);
+
 	switch (soc_type) {
+	case QCA_IPQ5018:
 	case QCA_QCA2066:
 	case QCA_QCA6390:
 	case QCA_WCN3991:
@@ -982,6 +997,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
 	bt_dev_dbg(hdev, "QCA HCI_RESET succeed");
 
 	switch (soc_type) {
+	case QCA_IPQ5018:
 	case QCA_WCN3991:
 	case QCA_WCN6750:
 	case QCA_WCN6855:
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index 8f3c1b1c77b3..343cd62d1137 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -54,6 +54,8 @@
 #define QCA_HSP_GF_SOC_ID		0x1200
 #define QCA_HSP_GF_SOC_MASK		0x0000ff00
 
+#define NVM_READY_DELAY_MS		1500
+
 enum qca_baudrate {
 	QCA_BAUDRATE_115200	= 0,
 	QCA_BAUDRATE_57600,
@@ -158,6 +160,7 @@ enum qca_btsoc_type {
 	QCA_WCN6750,
 	QCA_WCN6855,
 	QCA_WCN7850,
+	QCA_IPQ5018,
 };
 
 #if IS_ENABLED(CONFIG_BT_QCA)

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v5 3/6] firmware: qcom: scm: Add support for setting Bluetooth power modes
  2026-07-09  9:18 [PATCH v5 0/6] Add support for IPQ5018 Bluetooth George Moussalem via B4 Relay
  2026-07-09  9:18 ` [PATCH v5 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller George Moussalem via B4 Relay
  2026-07-09  9:18 ` [PATCH v5 2/6] Bluetooth: btqca: Add IPQ5018 support George Moussalem via B4 Relay
@ 2026-07-09  9:18 ` George Moussalem via B4 Relay
  2026-07-09  9:18 ` [PATCH v5 4/6] Bluetooth: Introduce Qualcomm IPQ5018 IPC based HCI driver George Moussalem via B4 Relay
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: George Moussalem via B4 Relay @ 2026-07-09  9:18 UTC (permalink / raw)
  To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	George Moussalem, Bartosz Golaszewski, Konrad Dybcio,
	Dmitry Baryshkov

From: George Moussalem <george.moussalem@outlook.com>

The Bluetooth subsystem (BTSS) on the IPQ5018 SoC supports setting power
modes which are required to be configured through a Secure Channel
Manager (SCM) call to TrustZone. However, not all Trusted Execution
Environment (QSEE) images support this call, so first check if the call
is available.

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/firmware/qcom/qcom_scm.c       | 44 ++++++++++++++++++++++++++++++++++
 drivers/firmware/qcom/qcom_scm.h       |  1 +
 include/linux/firmware/qcom/qcom_scm.h |  1 +
 3 files changed, 46 insertions(+)

diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 9b06a69d3a6d..d51e3f4339d8 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -1094,6 +1094,50 @@ bool qcom_scm_pas_supported(u32 pas_id)
 }
 EXPORT_SYMBOL_GPL(qcom_scm_pas_supported);
 
+/**
+ * qcom_scm_pas_set_bluetooth_power_mode() - Configure power mode for the
+ *					     Bluetooth subsystem (BTSS)
+ * @pas_id:	peripheral authentication service id
+ * @eco_mode:	true for ECO mode, false for normal operation
+ *
+ * Return: 0 on success, negative errno on failure.
+ * Returns -EOPNOTSUPP if the firmware configuration call is unavailable.
+ */
+int qcom_scm_pas_set_bluetooth_power_mode(u32 pas_id, bool eco_mode)
+{
+	struct qcom_scm_desc desc = {
+		.svc = QCOM_SCM_SVC_PIL,
+		.cmd = QCOM_SCM_PIL_PAS_BT_PWR_MODE,
+		.arginfo = QCOM_SCM_ARGS(2),
+		.args[0] = pas_id,
+		.args[1] = eco_mode ? 0x4 : 0x0,
+		.owner = ARM_SMCCC_OWNER_SIP,
+	};
+	struct qcom_scm_res res;
+	int ret;
+
+	if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
+					  QCOM_SCM_PIL_PAS_BT_PWR_MODE))
+		return -EOPNOTSUPP;
+
+	ret = qcom_scm_clk_enable();
+	if (ret)
+		return ret;
+
+	ret = qcom_scm_bw_enable();
+	if (ret)
+		goto disable_clk;
+
+	ret = qcom_scm_call(__scm->dev, &desc, &res);
+	qcom_scm_bw_disable();
+
+disable_clk:
+	qcom_scm_clk_disable();
+
+	return ret ? : res.result[0];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_set_bluetooth_power_mode);
+
 static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
 {
 	struct qcom_scm_desc desc = {
diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h
index caab80a73e17..5579df5a2aca 100644
--- a/drivers/firmware/qcom/qcom_scm.h
+++ b/drivers/firmware/qcom/qcom_scm.h
@@ -105,6 +105,7 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev);
 #define QCOM_SCM_PIL_PAS_SHUTDOWN	0x06
 #define QCOM_SCM_PIL_PAS_IS_SUPPORTED	0x07
 #define QCOM_SCM_PIL_PAS_MSS_RESET	0x0a
+#define QCOM_SCM_PIL_PAS_BT_PWR_MODE	0x21
 #define QCOM_SCM_PIL_PAS_GET_RSCTABLE	0x21
 
 #define QCOM_SCM_SVC_IO			0x05
diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h
index 5747bd191bf1..aca937ac8ddd 100644
--- a/include/linux/firmware/qcom/qcom_scm.h
+++ b/include/linux/firmware/qcom/qcom_scm.h
@@ -93,6 +93,7 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
 						  size_t *output_rt_size);
 
 int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx);
+int qcom_scm_pas_set_bluetooth_power_mode(u32 pas_id, bool eco_mode);
 
 int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
 int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v5 4/6] Bluetooth: Introduce Qualcomm IPQ5018 IPC based HCI driver
  2026-07-09  9:18 [PATCH v5 0/6] Add support for IPQ5018 Bluetooth George Moussalem via B4 Relay
                   ` (2 preceding siblings ...)
  2026-07-09  9:18 ` [PATCH v5 3/6] firmware: qcom: scm: Add support for setting Bluetooth power modes George Moussalem via B4 Relay
@ 2026-07-09  9:18 ` George Moussalem via B4 Relay
  2026-07-09  9:18 ` [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support George Moussalem via B4 Relay
  2026-07-09  9:18 ` [PATCH v5 6/6] MAINTAINERS: Add IPQ5018 driver to Qualcomm Bluetooth driver entry George Moussalem via B4 Relay
  5 siblings, 0 replies; 16+ messages in thread
From: George Moussalem via B4 Relay @ 2026-07-09  9:18 UTC (permalink / raw)
  To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Add support for the Bluetooth controller found in the IPQ5018 SoC.
This driver implements firmware loading and the transport layer between
the HCI core and the Bluetooth controller.

The firmware is loaded by the host into the memory area shared by the
host and the controller and is authenticated by TrustZone. A Secure
Channel Manager (SCM) call brings the peripheral core out of reset.

A shared memory ring buffer topology handles runtime data frame
transport between the host APSS and the controller.

An outgoing APCS IPC bit and an incoming GIC interrupt handle host/guest
signaling.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/bluetooth/Kconfig     |   14 +
 drivers/bluetooth/Makefile    |    1 +
 drivers/bluetooth/btqcomipc.c | 1230 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1245 insertions(+)

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 4e8c24d757e9..a2d82f27f07a 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -413,6 +413,20 @@ config BT_MTKUART
 	  Say Y here to compile support for MediaTek Bluetooth UART devices
 	  into the kernel or say M to compile it as module (btmtkuart).
 
+config BT_QCOMIPC
+	tristate "Qualcomm IPQ5018 IPC based HCI support"
+	depends on OF && ARCH_QCOM
+	select BT_QCA
+	select QCOM_MDT_LOADER
+	select QCOM_SCM
+	help
+	  Qualcomm IPQ5018 IPC based HCI driver.
+	  This driver is used to load firmware and bridge HCI data onto shared
+	  memory between the host and the Bluetooth controller.
+
+	  Say Y here to compile support for HCI over Qualcomm IPC into the
+	  kernel or say M to compile as a module.
+
 config BT_QCOMSMD
 	tristate "Qualcomm SMD based HCI support"
 	depends on RPMSG || (COMPILE_TEST && RPMSG=n)
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index e6b1c1180d1d..05f19047bed0 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_BT_MRVL)		+= btmrvl.o
 obj-$(CONFIG_BT_MRVL_SDIO)	+= btmrvl_sdio.o
 obj-$(CONFIG_BT_MTKSDIO)	+= btmtksdio.o
 obj-$(CONFIG_BT_MTKUART)	+= btmtkuart.o
+obj-$(CONFIG_BT_QCOMIPC)	+= btqcomipc.o
 obj-$(CONFIG_BT_QCOMSMD)	+= btqcomsmd.o
 obj-$(CONFIG_BT_BCM)		+= btbcm.o
 obj-$(CONFIG_BT_RTL)		+= btrtl.o
diff --git a/drivers/bluetooth/btqcomipc.c b/drivers/bluetooth/btqcomipc.c
new file mode 100644
index 000000000000..9d71fe611772
--- /dev/null
+++ b/drivers/bluetooth/btqcomipc.c
@@ -0,0 +1,1230 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2026 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/elf.h>
+#include <linux/firmware.h>
+#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/mdt_loader.h>
+#include <linux/workqueue.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btqca.h"
+
+/** Message header format.
+ *
+ *        ----------------------------------------------------------------
+ * BitPos |    15    | 14 | 13 | 12 | 11 | 10 |  9  |  8  |    7 - 0     |
+ *         ---------------------------------------------------------------
+ * Field  | long_msg |ACK |        RFU        |  pkt_type |    cmd       |
+ *        ----------------------------------------------------------------
+ *
+ * - long_msg   : If set, indicates that the payload is larger than the
+ *                IPC_MSG_PLD_SZ. The payload instead contains a pointer to the
+ *                long message buffer in the shared BTSS memory space.
+ *
+ * - ACK        : Set if sending ACK by IPC interrupt is required by firmware.
+ *
+ * - RFU        : Reserved for future use.
+ *
+ * - pkt_type   : IPC Packet Type
+ *
+ * - cmd        : Contains unique command ID
+ */
+
+#define IPC_MSG_HDR_SZ		4
+#define IPC_MSG_PLD_SZ		40
+#define IPC_TOTAL_MSG_SZ	(IPC_MSG_HDR_SZ + IPC_MSG_PLD_SZ)
+
+/* Message Header */
+#define IPC_HDR_LONG_MSG	BIT(15)
+#define IPC_HDR_REQ_ACK		BIT(14)
+#define IPC_HDR_PKT_TYPE_MASK	GENMASK(9, 8)
+#define  IPC_HDR_PKT_TYPE_CUST	0
+#define  IPC_HDR_PKT_TYPE_HCI	1
+#define  IPC_HDR_PKT_TYPE_AUDIO	2
+#define  IPC_HDR_PKT_TYPE_RFU	3
+#define IPC_HDR_CMD_MASK	GENMASK(7, 0)
+
+#define IPC_CMD_STOP		1
+#define IPC_CMD_SWITCH_TO_UART	2
+#define IPC_CMD_PREPARE_DUMP	3
+#define IPC_CMD_COLLECT_DUMP	4
+#define IPC_CMD_START		5
+
+#define IPC_TX_QSIZE		32
+
+#define	TO_APPS_ADDR(a)		((u8 *)desc->base + (a))
+#define	TO_BT_ADDR(a)		(a - desc->base)
+
+#define	GET_NO_OF_BLOCKS(a, b) ((a + b - 1) / b)
+
+#define BTSS_PAS_ID		0xc
+
+#define BTSS_PWR_CTRL_DELAY_MS	50
+
+struct long_msg_info {
+	u16 smsg_free_cnt;
+	u16 lmsg_free_cnt;
+	u8 ridx;
+	u8 widx;
+} __packed;
+
+struct ipc_aux_ptr {
+	u32 len;
+	u32 buf;
+};
+
+struct ring_buffer {
+	__le16 msg_hdr;
+	__le16 len;
+	union {
+		u8 smsg_data[IPC_MSG_PLD_SZ];
+		__le32 lmsg_data;
+	} payload;
+} __packed;
+
+struct ring_buffer_info {
+	__le32 rbuf;
+	u8 ring_buf_cnt;
+	u8 ridx;
+	u8 widx;
+	u8 tidx;
+	__le32 next;
+} __packed;
+
+struct context_info {
+	__le16 total_size;
+	u8 lmsg_buf_cnt;
+	u8 smsg_buf_cnt;
+	struct ring_buffer_info sring_buf_info;
+	__le32 sring_buf;
+	__le32 lring_buf;
+	__le32 reserved;
+} __packed;
+
+struct qcom_btss {
+	struct device *dev;
+	struct hci_dev *hdev;
+
+	struct regmap *regmap;
+	u32 offset;
+	u32 bit;
+	int irq;
+
+	const char *firmware;
+	void *base;
+	phys_addr_t mem_phys;
+	size_t mem_size;
+
+	struct sk_buff_head tx_q;
+	struct workqueue_struct *wq;
+	struct work_struct work;
+	wait_queue_head_t wait_q;
+	spinlock_t lock;
+
+	struct context_info *tx_ctxt;
+	struct context_info *rx_ctxt;
+	struct long_msg_info lmsg_ctxt;
+
+	bool running;
+};
+
+static inline u32 btss_lbuf_size(struct qcom_btss *desc,
+				 const struct context_info *ctxt)
+{
+	u32 end, lring_buf, total_size;
+
+	total_size = le16_to_cpu(ctxt->total_size);
+	lring_buf = le32_to_cpu(ctxt->lring_buf);
+	end = TO_BT_ADDR((void *)ctxt) + total_size;
+
+	if (!ctxt->lmsg_buf_cnt)
+		return 0;
+
+	if (lring_buf > end)
+		return 0;
+
+	return (end - lring_buf) / ctxt->lmsg_buf_cnt;
+}
+
+static inline u8 btss_get_buf_idx(const struct context_info *ctxt,
+				  u32 lmsg_data, u32 lsz)
+{
+	u32 lring_buf = le32_to_cpu(ctxt->lring_buf);
+
+	return (u8)((lmsg_data - lring_buf) / lsz);
+}
+
+static void btqcomipc_update_stats(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	u8 pkt_type = hci_skb_pkt_type(skb);
+
+	hdev->stat.byte_tx += skb->len;
+	switch (pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+	default:
+		break;
+	}
+}
+
+static void *btss_alloc_lmsg(struct qcom_btss *desc, u32 len,
+			     struct ipc_aux_ptr *aux_ptr, bool *is_lbuf_full)
+{
+	u8 idx, blks, blks_consumed;
+	u32 lring_buf, lsz;
+	void *ret_ptr;
+
+	lring_buf = le32_to_cpu(desc->tx_ctxt->lring_buf);
+
+	if (!lring_buf)
+		return ERR_PTR(-ENODEV);
+
+	lsz = btss_lbuf_size(desc, desc->tx_ctxt);
+	if (!lsz)
+		return ERR_PTR(-EINVAL);
+
+	blks = GET_NO_OF_BLOCKS(len, lsz);
+
+	if (!desc->lmsg_ctxt.lmsg_free_cnt ||
+			(blks > desc->lmsg_ctxt.lmsg_free_cnt))
+		return ERR_PTR(-EAGAIN);
+
+	idx = desc->lmsg_ctxt.widx;
+
+	if ((desc->lmsg_ctxt.widx + blks) > desc->tx_ctxt->lmsg_buf_cnt) {
+		blks_consumed = desc->tx_ctxt->lmsg_buf_cnt - idx;
+		aux_ptr->len = len - (blks_consumed * lsz);
+		aux_ptr->buf = desc->tx_ctxt->lring_buf;
+	}
+
+	desc->lmsg_ctxt.widx = (desc->lmsg_ctxt.widx + blks) %
+		desc->tx_ctxt->lmsg_buf_cnt;
+
+	desc->lmsg_ctxt.lmsg_free_cnt -= blks;
+
+	if (desc->lmsg_ctxt.lmsg_free_cnt <=
+			((desc->tx_ctxt->lmsg_buf_cnt * 20) / 100))
+		*is_lbuf_full = true;
+
+	ret_ptr = TO_APPS_ADDR(lring_buf) + (idx * lsz);
+
+	return ret_ptr;
+}
+
+static struct ring_buffer_info *btss_get_tx_rbuf(struct qcom_btss *desc,
+						 bool *is_sbuf_full)
+{
+	struct ring_buffer_info *rinfo;
+	u32 next;
+	u8 idx;
+
+	rinfo = &(desc->tx_ctxt->sring_buf_info);
+	while (rinfo != NULL) {
+		idx = (rinfo->widx + 1) % (desc->tx_ctxt->smsg_buf_cnt);
+
+		if (idx != rinfo->tidx) {
+			desc->lmsg_ctxt.smsg_free_cnt--;
+
+			if (desc->lmsg_ctxt.smsg_free_cnt <=
+				((desc->tx_ctxt->smsg_buf_cnt * 20) / 100))
+				*is_sbuf_full = true;
+
+			return rinfo;
+		}
+
+		next = le32_to_cpu(rinfo->next);
+		rinfo = next ? (struct ring_buffer_info *)TO_APPS_ADDR(next) : NULL;
+	}
+
+	return ERR_PTR(-EAGAIN);
+}
+
+static int btss_send(struct qcom_btss *desc, u16 msg_hdr,
+		     struct sk_buff *skb)
+{
+	struct hci_dev *hdev = desc->hdev;
+	struct ipc_aux_ptr aux_ptr = { };
+	struct ring_buffer_info *rinfo;
+	struct ring_buffer *rbuf;
+	bool is_lbuf_full = false;
+	bool is_sbuf_full = false;
+	u16 hdr = msg_hdr;
+	u16 lmsg_free_cnt;
+	void *ptr_buf;
+	u8 lmsg_widx;
+	u32 len;
+
+	/* Account for HCI packet type as it's not included in the skb payload */
+	len = skb ? skb->len + 1 : 0;
+
+	if (len > IPC_MSG_PLD_SZ) {
+		hdr |= IPC_HDR_LONG_MSG;
+
+		/* snapshot long message context in case we need to reverse */
+		lmsg_free_cnt = le16_to_cpu(desc->lmsg_ctxt.lmsg_free_cnt);
+		lmsg_widx = desc->lmsg_ctxt.widx;
+
+		ptr_buf = btss_alloc_lmsg(desc, len,
+					  &aux_ptr, &is_lbuf_full);
+		if (IS_ERR(ptr_buf)) {
+			bt_dev_err(hdev,
+				   "Failed to allocate long message buffer: %ld",
+				   PTR_ERR(ptr_buf));
+			hdev->stat.err_tx++;
+			return PTR_ERR(ptr_buf);
+		}
+	}
+
+	rinfo = btss_get_tx_rbuf(desc, &is_sbuf_full);
+	if (IS_ERR(rinfo)) {
+		bt_dev_err(hdev, "TX short buffers full");
+		hdev->stat.err_tx++;
+		if (len > IPC_MSG_PLD_SZ) {
+			/* reverse long message context if we allocated one */
+			desc->lmsg_ctxt.lmsg_free_cnt = cpu_to_le16(lmsg_free_cnt);
+			desc->lmsg_ctxt.widx = lmsg_widx;
+		}
+		return PTR_ERR(rinfo);
+	}
+
+	rbuf = &((struct ring_buffer *)(TO_APPS_ADDR(le32_to_cpu(rinfo->rbuf))))[rinfo->widx];
+
+	if (!skb)
+		goto complete_tx;
+
+	if (len > IPC_MSG_PLD_SZ)
+		rbuf->payload.lmsg_data = cpu_to_le32(TO_BT_ADDR(ptr_buf));
+	else
+		ptr_buf = rbuf->payload.smsg_data;
+
+	/* if it's a short message, the aux len and buf are NULL */
+	memcpy_toio(ptr_buf, &hci_skb_pkt_type(skb), 1);
+	memcpy_toio((u8 *)ptr_buf + 1, skb->data, skb->len - aux_ptr.len);
+	if (aux_ptr.buf) {
+		memcpy_toio(TO_APPS_ADDR(aux_ptr.buf),
+			    (skb->data + (skb->len - aux_ptr.len)),
+			    aux_ptr.len);
+	}
+
+	/*
+	 * if free buffer count is low, send ACK request to signal to the
+	 * firmware to process and free up queued buffers in the TX ring.
+	 */
+	if (is_sbuf_full || is_lbuf_full)
+		hdr |= IPC_HDR_REQ_ACK;
+
+complete_tx:
+	rbuf->msg_hdr = cpu_to_le16(hdr);
+	rbuf->len = cpu_to_le16(len);
+
+	dma_wmb();
+
+	rinfo->widx = (rinfo->widx + 1) % desc->tx_ctxt->smsg_buf_cnt;
+
+	regmap_set_bits(desc->regmap, desc->offset, BIT(desc->bit));
+
+	return 0;
+}
+
+static void btss_process_tx_queue(struct qcom_btss *desc)
+{
+	struct sk_buff *skb;
+	u16 hdr;
+	int ret;
+
+	while ((skb = skb_dequeue(&desc->tx_q))) {
+		hdr = FIELD_PREP(IPC_HDR_PKT_TYPE_MASK, IPC_HDR_PKT_TYPE_HCI);
+
+		ret = btss_send(desc, hdr, skb);
+		if (ret) {
+			bt_dev_err(desc->hdev, "Failed to send message");
+			skb_queue_head(&desc->tx_q, skb);
+			break;
+		}
+
+		btqcomipc_update_stats(desc->hdev, skb);
+		kfree_skb(skb);
+	}
+}
+
+static void btss_free_lmsg(struct qcom_btss *desc, u32 lmsg, u16 len)
+{
+	u8 blks, idx;
+	u32 lsz;
+
+	lsz = btss_lbuf_size(desc, desc->tx_ctxt);
+	if (!lsz) {
+		bt_dev_err(desc->hdev, "long message buffer size is zero");
+		return;
+	}
+
+	idx = btss_get_buf_idx(desc->tx_ctxt, lmsg, lsz);
+
+	if (idx != desc->lmsg_ctxt.ridx)
+		return;
+
+	blks = GET_NO_OF_BLOCKS(len, lsz);
+
+	desc->lmsg_ctxt.ridx  = (desc->lmsg_ctxt.ridx + blks) %
+		desc->tx_ctxt->lmsg_buf_cnt;
+
+	desc->lmsg_ctxt.lmsg_free_cnt += blks;
+}
+
+static int btss_recv_cust_frame(struct qcom_btss *desc, u8 cmd)
+{
+	u16 msg_hdr = 0;
+	int ret;
+
+	/*
+	 * During firmware patch download, the controller temporarily stops the
+	 * IPC transport and signals the host with IPC_CMD_STOP. The host must
+	 * stop sending new frames until the controller signals IPC_CMD_START
+	 * back to the host after the patch download has completed.
+	 */
+	switch (cmd) {
+	case IPC_CMD_STOP:
+		spin_unlock(&desc->lock);
+		ret = qcom_scm_pas_set_bluetooth_power_mode(BTSS_PAS_ID, true);
+		spin_lock(&desc->lock);
+		if (ret && ret != -EOPNOTSUPP) {
+			bt_dev_err(desc->hdev,
+				   "Failed to apply BTSS power-save mode: %d",
+				   ret);
+			return ret;
+		}
+
+		msg_hdr |= cmd;
+		ret = btss_send(desc, msg_hdr, NULL);
+		if (ret)
+			bt_dev_err(desc->hdev,
+				   "Failed to send control message");
+
+		WRITE_ONCE(desc->running, false);
+		break;
+	case IPC_CMD_START:
+		spin_unlock(&desc->lock);
+		ret = qcom_scm_pas_set_bluetooth_power_mode(BTSS_PAS_ID, false);
+		spin_lock(&desc->lock);
+		if (ret && ret != -EOPNOTSUPP) {
+			bt_dev_err(desc->hdev,
+				   "Failed to apply BTSS active power mode: %d",
+				   ret);
+			return ret;
+		}
+
+		desc->tx_ctxt = (struct context_info *)((void *)desc->rx_ctxt +
+				le16_to_cpu(desc->rx_ctxt->total_size));
+		desc->lmsg_ctxt.widx = 0;
+		desc->lmsg_ctxt.ridx = 0;
+		desc->lmsg_ctxt.smsg_free_cnt = desc->tx_ctxt->smsg_buf_cnt;
+		desc->lmsg_ctxt.lmsg_free_cnt = desc->tx_ctxt->lmsg_buf_cnt;
+
+		WRITE_ONCE(desc->running, true);
+		wake_up(&desc->wait_q);
+		break;
+	default:
+		bt_dev_err(desc->hdev, "Unsupported CMD ID: %u", cmd);
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static inline int btss_recv_hci_frame(struct qcom_btss *desc, const u8 *data,
+				      size_t len)
+{
+	unsigned char pkt_type;
+	struct sk_buff *skb;
+	size_t pkt_len;
+
+	if (len < 1)
+		return -EPROTO;
+
+	pkt_type = data[0];
+
+	switch (pkt_type) {
+	case HCI_EVENT_PKT:
+	{
+		if (len < 1 + HCI_EVENT_HDR_SIZE)
+			return -EILSEQ;
+		struct hci_event_hdr *hdr = (struct hci_event_hdr *)(data + 1);
+
+		pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
+		break;
+	}
+	case HCI_COMMAND_PKT: {
+		if (len < 1 + HCI_COMMAND_HDR_SIZE)
+			return -EILSEQ;
+		struct hci_command_hdr *hdr = (struct hci_command_hdr *)(data + 1);
+
+		pkt_len = HCI_COMMAND_HDR_SIZE + hdr->plen;
+		break;
+	}
+	case HCI_ACLDATA_PKT:
+	{
+		if (len < 1 + HCI_ACL_HDR_SIZE)
+			return -EILSEQ;
+		struct hci_acl_hdr *hdr = (struct hci_acl_hdr *)(data + 1);
+
+		pkt_len = HCI_ACL_HDR_SIZE + le16_to_cpu(hdr->dlen);
+		break;
+	}
+	case HCI_SCODATA_PKT:
+	{
+		if (len < 1 + HCI_SCO_HDR_SIZE)
+			return -EILSEQ;
+		struct hci_sco_hdr *hdr = (struct hci_sco_hdr *)(data + 1);
+
+		pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
+		break;
+	}
+	default:
+		return -EPROTO;
+	}
+
+	if (pkt_len + 1 > len)
+		return -EINVAL;
+
+	skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
+	if (!skb) {
+		desc->hdev->stat.err_rx++;
+		return -ENOMEM;
+	}
+
+	skb->dev = (void *)desc->hdev;
+	hci_skb_pkt_type(skb) = pkt_type;
+	skb_put_data(skb, data + 1, pkt_len);
+
+	hci_recv_frame(desc->hdev, skb);
+	desc->hdev->stat.byte_rx += pkt_len;
+
+	return 0;
+}
+
+static inline int btss_process_rx(struct qcom_btss *desc,
+				  struct ring_buffer_info *rinfo,
+				  bool *ack, u8 *rx_count)
+{
+	u8 ridx, widx, lbuf_idx, blks_consumed, pkt_type, cmd;
+	u32 lmsg_data, lsz, lring_buf, lring_end;
+	struct ring_buffer *rbuf;
+	uint8_t *rxbuf = NULL;
+	unsigned char *buf;
+	u16 msg_hdr;
+	u16 msg_len;
+	int ret;
+
+	ridx = rinfo->ridx;
+	lring_buf = le32_to_cpu(desc->rx_ctxt->lring_buf);
+	widx = READ_ONCE(rinfo->widx);
+
+	while (ridx != widx) {
+		struct ipc_aux_ptr aux_ptr = { };
+
+		dma_rmb();
+
+		rbuf = &((struct ring_buffer *)(TO_APPS_ADDR(le32_to_cpu(rinfo->rbuf))))[ridx];
+		msg_hdr = le16_to_cpu(rbuf->msg_hdr);
+		msg_len = le16_to_cpu(rbuf->len);
+
+		if (!(msg_hdr & IPC_HDR_LONG_MSG) && msg_len > IPC_MSG_PLD_SZ) {
+			desc->hdev->stat.err_rx++;
+			bt_dev_err(desc->hdev,
+				   "Dropping short RX frame with invalid len %u",
+				   msg_len);
+			goto continue_rx;
+		}
+
+		if (msg_hdr & IPC_HDR_LONG_MSG) {
+			lmsg_data = le32_to_cpu(rbuf->payload.lmsg_data);
+			rxbuf = TO_APPS_ADDR(lmsg_data);
+			lsz = btss_lbuf_size(desc, desc->rx_ctxt);
+			if (!lsz) {
+				bt_dev_err(desc->hdev,
+					   "Long message buffer size is zero");
+				goto continue_rx;
+			} else if (lsz > (U32_MAX - lring_buf) / desc->rx_ctxt->lmsg_buf_cnt) {
+				bt_dev_err(desc->hdev,
+					   "Long message buffer size is too large");
+				goto continue_rx;
+			}
+
+			lring_end = lring_buf + lsz * desc->rx_ctxt->lmsg_buf_cnt;
+			if (lmsg_data < lring_buf || lmsg_data >= lring_end) {
+				desc->hdev->stat.err_rx++;
+				bt_dev_err(desc->hdev,
+					   "Dropping long RX frame with invalid address 0x%08x",
+					   lmsg_data);
+				goto continue_rx;
+			}
+
+			/*
+			 * Check if the long message buffer extends past the end
+			 * of the ring buffer
+			 */
+			if (msg_len > lring_end - lmsg_data) {
+				lbuf_idx = btss_get_buf_idx(desc->rx_ctxt,
+							    lmsg_data, lsz);
+
+				blks_consumed = desc->rx_ctxt->lmsg_buf_cnt - lbuf_idx;
+				if (blks_consumed > msg_len / lsz) {
+					desc->hdev->stat.err_rx++;
+					bt_dev_err(desc->hdev,
+						   "Dropping long RX frame with invalid length %u",
+						   msg_len);
+					goto continue_rx;
+				}
+				aux_ptr.len = msg_len - (blks_consumed * lsz);
+				aux_ptr.buf = lring_buf;
+			}
+		} else {
+			rxbuf = rbuf->payload.smsg_data;
+		}
+
+		*ack = msg_hdr & IPC_HDR_REQ_ACK;
+
+		pkt_type = FIELD_GET(IPC_HDR_PKT_TYPE_MASK, msg_hdr);
+
+		switch (pkt_type) {
+		case IPC_HDR_PKT_TYPE_HCI:
+			buf = kmalloc(msg_len, GFP_ATOMIC);
+			if (!buf) {
+				desc->hdev->stat.err_rx++;
+				bt_dev_err(desc->hdev,
+					   "Dropping HCI frame due to RX allocation failure");
+				ridx = (ridx + 1) % rinfo->ring_buf_cnt;
+				rinfo->ridx = ridx;
+				if (rx_count)
+					(*rx_count)++;
+				continue;
+			}
+
+			memcpy_fromio(buf, rxbuf, msg_len - aux_ptr.len);
+
+			if (aux_ptr.buf)
+				memcpy_fromio(buf + (msg_len - aux_ptr.len),
+					      TO_APPS_ADDR(aux_ptr.buf),
+					      aux_ptr.len);
+
+			ret = btss_recv_hci_frame(desc, buf, msg_len);
+			if (ret)
+				bt_dev_err(desc->hdev,
+					   "Failed to process HCI frame: %d",
+					   ret);
+			kfree(buf);
+			break;
+		case IPC_HDR_PKT_TYPE_CUST:
+			cmd = FIELD_GET(IPC_HDR_CMD_MASK, msg_hdr);
+			ret = btss_recv_cust_frame(desc, cmd);
+			if (ret)
+				bt_dev_warn(desc->hdev,
+					    "Failed to process custom frame: %d",
+					    ret);
+			break;
+		default:
+			break;
+		}
+
+continue_rx:
+		ridx = (ridx + 1) % rinfo->ring_buf_cnt;
+		rinfo->ridx = ridx;
+
+		if (rx_count)
+			(*rx_count)++;
+	}
+
+	return 0;
+}
+
+static void btss_process_ack(struct qcom_btss *desc)
+{
+	struct ring_buffer_info *rinfo;
+	struct ring_buffer *rbuf;
+	u16 msg_hdr;
+	u16 msg_len;
+	u32 next;
+	u32 lmsg;
+	u8 tidx;
+
+	rinfo = &desc->tx_ctxt->sring_buf_info;
+	while (rinfo != NULL) {
+		tidx = rinfo->tidx;
+		rbuf = (struct ring_buffer *)TO_APPS_ADDR(le32_to_cpu(rinfo->rbuf));
+
+		while (tidx != rinfo->ridx) {
+			msg_hdr = le16_to_cpu(rbuf[tidx].msg_hdr);
+			if (msg_hdr & IPC_HDR_LONG_MSG) {
+				lmsg = le32_to_cpu(rbuf[tidx].payload.lmsg_data);
+				msg_len = le16_to_cpu(rbuf[tidx].len);
+				btss_free_lmsg(desc, lmsg, msg_len);
+			}
+
+			tidx = (tidx + 1) % desc->tx_ctxt->smsg_buf_cnt;
+			desc->lmsg_ctxt.smsg_free_cnt++;
+		}
+
+		rinfo->tidx = tidx;
+
+		btss_process_tx_queue(desc);
+
+		next = le32_to_cpu(rinfo->next);
+		rinfo = next ? (struct ring_buffer_info *)TO_APPS_ADDR(next) : NULL;
+	}
+}
+
+static void btss_worker(struct work_struct *work)
+{
+	struct qcom_btss *desc = container_of(work, struct qcom_btss, work);
+	struct ring_buffer_info *rinfo;
+	bool ack = false;
+	u32 offset, next;
+	u16 total_size;
+	int ret;
+
+	spin_lock(&desc->lock);
+
+	if (unlikely(!READ_ONCE(desc->running))) {
+		/*
+		 * FW sets offset of RX context info at the start of the memory
+		 * region upon boot
+		 */
+		offset = readl(desc->base);
+		if (offset > desc->mem_size - sizeof(struct context_info)) {
+			bt_dev_err(desc->hdev,
+				   "Invalid offset after firmware boot: 0x%08x",
+				   offset);
+			goto spin_unlock;
+		}
+		dev_dbg(desc->dev, "offset after firmware boot: 0x%08x\n",
+			offset);
+
+		desc->rx_ctxt = (struct context_info *)(desc->base + offset);
+
+		total_size = le16_to_cpu(desc->rx_ctxt->total_size);
+		if (total_size < sizeof(struct context_info) ||
+		total_size > desc->mem_size - offset) {
+			bt_dev_err(desc->hdev, "Invalid total size: %u",
+				   total_size);
+			desc->rx_ctxt = NULL;
+			goto spin_unlock;
+		}
+	} else {
+		btss_process_ack(desc);
+	}
+
+	rinfo = &(desc->rx_ctxt->sring_buf_info);
+	while (rinfo != NULL) {
+		ret = btss_process_rx(desc, rinfo, &ack,
+				      &desc->rx_ctxt->smsg_buf_cnt);
+		if (ret) {
+			bt_dev_err(desc->hdev,
+				   "Failed to process peer msgs: %d", ret);
+			goto spin_unlock;
+		}
+		next = le32_to_cpu(rinfo->next);
+		rinfo = next ? (struct ring_buffer_info *)TO_APPS_ADDR(next) : NULL;
+	}
+
+	if (ack)
+		regmap_set_bits(desc->regmap, desc->offset, BIT(desc->bit));
+
+spin_unlock:
+	spin_unlock(&desc->lock);
+}
+
+static irqreturn_t btss_irq_handler(int irq, void *data)
+{
+	struct qcom_btss *desc = data;
+
+	queue_work(desc->wq, &desc->work);
+
+	return IRQ_HANDLED;
+}
+
+static int btcomqipc_firmware_load(struct qcom_btss *desc)
+{
+	const char *dot = strrchr(desc->firmware, '.');
+	const struct elf32_phdr *phdrs;
+	const struct firmware *seg_fw;
+	const struct elf32_phdr *phdr;
+	const struct elf32_hdr *ehdr;
+	const struct firmware *fw;
+	size_t metadata_len;
+	size_t stem_len;
+	void *metadata;
+	char *seg_name;
+	int i, ret;
+
+	if (!dot || dot != desc->firmware + strlen(desc->firmware) - 4) {
+		dev_err(desc->dev, "Invalid firmware name: %s\n",
+			desc->firmware);
+		return -EINVAL;
+	}
+
+	stem_len = dot - desc->firmware;
+
+	ret = request_firmware(&fw, desc->firmware, desc->dev);
+	if (ret) {
+		dev_err(desc->dev, "Failed to request firmware: %d\n",
+			ret);
+		return ret;
+	}
+
+	metadata = qcom_mdt_read_metadata(fw, &metadata_len, desc->firmware, desc->dev);
+	if (IS_ERR(metadata)) {
+		ret = PTR_ERR(metadata);
+		dev_err(desc->dev, "error %d reading firmware %s metadata\n",
+			ret, desc->firmware);
+		goto release_fw;
+	}
+
+	ret = qcom_scm_pas_init_image(BTSS_PAS_ID, metadata, metadata_len, NULL);
+	kfree(metadata);
+	if (ret) {
+		dev_err(desc->dev, "error %d initializing firmware %s\n",
+			ret, desc->firmware);
+		goto release_fw;
+	}
+
+	/*
+	 * qcom_mdt_read_metadata has already validated the ELF/mdt header, so
+	 * no need to revalidate it again here.
+	 */
+	ehdr = (const struct elf32_hdr *)fw->data;
+	phdrs = (const struct elf32_phdr *)(ehdr + 1);
+
+	/* guard against a large (incorrect) number of program headers */
+	if (ehdr->e_phnum > 99) {
+		dev_err(desc->dev, "Too many program headers: %d\n",
+			ehdr->e_phnum);
+		ret = -EINVAL;
+		goto release_fw;
+	}
+
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		phdr = &phdrs[i];
+
+		/* Only process valid loadable data segments */
+		if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
+			continue;
+
+		/*
+		 * The virtual instead of the physical address must be used as
+		 * the offset.
+		 */
+		if (phdr->p_vaddr > desc->mem_size ||
+		    phdr->p_filesz > desc->mem_size - phdr->p_vaddr) {
+			dev_err(desc->dev,
+				"Segment data exceeds the reserved memory area!\n");
+			goto release_fw;
+		}
+
+		/* Check if firmware is split across multiple segment files */
+		if (phdr->p_offset > fw->size ||
+		    phdr->p_filesz > fw->size - phdr->p_offset) {
+			seg_name = kasprintf(GFP_KERNEL, "%.*sb%02d",
+					     (int)stem_len, desc->firmware, i);
+			if (!seg_name) {
+				ret = -ENOMEM;
+				goto release_fw;
+			}
+
+			ret = request_firmware(&seg_fw, seg_name,
+					       desc->dev);
+			if (ret) {
+				dev_err(desc->dev,
+					"Could not find split segment binary: %s\n",
+					seg_name);
+				goto release_seg_name;
+			}
+
+			if (seg_fw->size != phdr->p_filesz) {
+				dev_err(desc->dev,
+					"Segment binary %s has unexpected file size!\n",
+					seg_name);
+				ret = -EINVAL;
+				goto release_seg_fw;
+			}
+			memcpy_toio(desc->base + phdr->p_vaddr,
+				    seg_fw->data, phdr->p_filesz);
+			if (phdr->p_memsz > phdr->p_filesz)
+				memset_io(desc->base + phdr->p_vaddr +
+					  phdr->p_filesz, 0,
+					  phdr->p_memsz - phdr->p_filesz);
+
+release_seg_fw:
+			release_firmware(seg_fw);
+release_seg_name:
+			kfree(seg_name);
+			seg_name = NULL;
+
+			if (ret)
+				goto release_fw;
+		} else {
+			memcpy_toio(desc->base + phdr->p_vaddr,
+				    fw->data + phdr->p_offset, phdr->p_filesz);
+			if (phdr->p_memsz > phdr->p_filesz)
+				memset_io(desc->base + phdr->p_vaddr +
+					  phdr->p_filesz, 0,
+					  phdr->p_memsz - phdr->p_filesz);
+		}
+	}
+
+release_fw:
+	release_firmware(fw);
+	return ret;
+}
+
+static int btqcomipc_open(struct hci_dev *hdev)
+{
+	struct qcom_btss *desc = hci_get_drvdata(hdev);
+	int ret;
+
+	if (!qcom_scm_pas_supported(BTSS_PAS_ID)) {
+		bt_dev_err(hdev,
+			   "PAS is not available for peripheral: 0x%x",
+			   BTSS_PAS_ID);
+		return -ENODEV;
+	}
+
+	ret = btcomqipc_firmware_load(desc);
+	if (ret) {
+		bt_dev_err(hdev, "Failed to load firmware: %d", ret);
+		return ret;
+	}
+
+	enable_irq(desc->irq);
+
+	/* Boot firmware */
+	ret = qcom_scm_pas_auth_and_reset(BTSS_PAS_ID);
+	if (ret) {
+		bt_dev_err(hdev, "Failed to boot firmware: %d", ret);
+		goto disable_irq;
+	}
+
+	msleep(BTSS_PWR_CTRL_DELAY_MS);
+	ret = wait_event_timeout(desc->wait_q, READ_ONCE(desc->running),
+				 msecs_to_jiffies(1000));
+
+	if (!ret) {
+		bt_dev_err(hdev, "Timeout waiting for BTSS start");
+		ret = -ETIMEDOUT;
+		goto shutdown;
+	}
+
+	return 0;
+
+shutdown:
+	qcom_scm_pas_shutdown(BTSS_PAS_ID);
+disable_irq:
+	disable_irq(desc->irq);
+
+	return ret;
+}
+
+static int btqcomipc_close(struct hci_dev *hdev)
+{
+	struct qcom_btss *desc = hci_get_drvdata(hdev);
+	unsigned long flags;
+	int ret;
+
+	ret = qcom_scm_pas_shutdown(BTSS_PAS_ID);
+	if (ret) {
+		bt_dev_err(hdev, "Failed to stop firmware: %d", ret);
+		return ret;
+	}
+
+	disable_irq(desc->irq);
+
+	spin_lock_irqsave(&desc->lock, flags);
+	WRITE_ONCE(desc->running, false);
+	spin_unlock_irqrestore(&desc->lock, flags);
+
+	msleep(BTSS_PWR_CTRL_DELAY_MS);
+
+	return 0;
+}
+
+static int btqcomipc_setup(struct hci_dev *hdev)
+{
+	struct qca_btsoc_version ver;
+	int ret;
+
+	/*
+	 * Enable controller to do both LE scan and BR/EDR inquiry
+	 * simultaneously.
+	 */
+	hci_set_quirk(hdev, HCI_QUIRK_SIMULTANEOUS_DISCOVERY);
+
+	/*
+	 * Enable NON_PERSISTENT_SETUP QUIRK to ensure to execute
+	 * setup for every hci up.
+	 */
+	hci_set_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_SETUP);
+	ret = qca_read_soc_version(hdev, &ver, QCA_IPQ5018);
+	if (ret)
+		return -EINVAL;
+
+	ret = qca_uart_setup(hdev, 0, QCA_IPQ5018, ver, NULL, NULL);
+	if (ret) {
+		bt_dev_err(hdev, "Failed to setup controller: %d\n", ret);
+		return ret;
+	}
+
+	/* Obtain and set BD address from NVMEM cell */
+	hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM);
+	hci_set_quirk(hdev, HCI_QUIRK_BDADDR_NVMEM_BE);
+
+	return 0;
+}
+
+static int btqcomipc_send(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	u16 hdr = FIELD_PREP(IPC_HDR_PKT_TYPE_MASK, IPC_HDR_PKT_TYPE_HCI);
+	struct qcom_btss *desc = hci_get_drvdata(hdev);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&desc->lock, flags);
+
+	if (unlikely(!READ_ONCE(desc->running))) {
+		bt_dev_err(hdev,
+			   "BTSS not initialized, failed to send message");
+		ret = -ENODEV;
+		goto spin_unlock;
+	}
+
+	ret = btss_send(desc, hdr, skb);
+	if (ret) {
+		if (ret == -EAGAIN) {
+			if (skb_queue_len(&desc->tx_q) >= IPC_TX_QSIZE) {
+				bt_dev_err(hdev,
+					   "TX queue full, dropping message");
+				hdev->stat.err_tx++;
+				ret = -ENOBUFS;
+			} else {
+				skb_queue_tail(&desc->tx_q, skb);
+				ret = 0;
+				skb = NULL;
+			}
+		} else {
+			bt_dev_err(hdev, "Failed to send message: %d", ret);
+			hdev->stat.err_tx++;
+		}
+	}
+
+spin_unlock:
+	spin_unlock_irqrestore(&desc->lock, flags);
+
+	if (!ret && skb) {
+		btqcomipc_update_stats(desc->hdev, skb);
+		kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+static int btqcomipc_flush(struct hci_dev *hdev)
+{
+	struct qcom_btss *desc = hci_get_drvdata(hdev);
+
+	skb_queue_purge(&desc->tx_q);
+
+	return 0;
+}
+
+static int btqcomipc_init(struct qcom_btss *desc)
+{
+	struct device *dev = desc->dev;
+	int ret;
+
+	init_waitqueue_head(&desc->wait_q);
+	spin_lock_init(&desc->lock);
+	skb_queue_head_init(&desc->tx_q);
+
+	desc->wq = devm_alloc_ordered_workqueue(dev, "btss_wq", 0);
+	if (!desc->wq) {
+		dev_err(dev, "Failed to initialize workqueue\n");
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&desc->work, btss_worker);
+
+	ret = devm_request_threaded_irq(dev, desc->irq, NULL, btss_irq_handler,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT | IRQF_NO_AUTOEN,
+					"btss_irq", desc);
+
+	if (ret) {
+		dev_err(dev, "error registering irq[%d] ret = %d\n",
+			desc->irq, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void btqcomipc_deinit(struct qcom_btss *desc)
+{
+	if (desc->wq)
+		flush_workqueue(desc->wq);
+	skb_queue_purge(&desc->tx_q);
+}
+
+static int btqcomipc_probe(struct platform_device *pdev)
+{
+	struct reset_control *btss_reset;
+	struct device *dev = &pdev->dev;
+	struct of_phandle_args args;
+	struct device_node *ipc_np;
+	struct qcom_btss *desc;
+	struct resource *res;
+	struct hci_dev *hdev;
+	struct clk *lpo_clk;
+	int ret;
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->dev = dev;
+
+	ret = of_property_read_string(dev->of_node, "firmware-name",
+				      &desc->firmware);
+	if (ret < 0)
+		return ret;
+
+	desc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(desc->base)) {
+		dev_err(dev, "unable to acquire memory-region resource\n");
+		return dev_err_probe(dev, PTR_ERR(desc->base),
+				     "unable to acquire memory-region resource\n");
+	}
+
+	desc->mem_phys = res->start;
+	desc->mem_size = resource_size(res);
+
+	ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,ipc", 2, 0,
+					       &args);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to get ipc node\n");
+
+	ipc_np = args.np;
+
+	desc->regmap = device_node_to_regmap(ipc_np);
+	if (IS_ERR(desc->regmap)) {
+		dev_err(dev, "Failed to get regmap from ipc node\n");
+		of_node_put(ipc_np);
+		return PTR_ERR(desc->regmap);
+	}
+
+	desc->offset = args.args[0];
+	desc->bit = args.args[1];
+
+	of_node_put(ipc_np);
+
+	lpo_clk = devm_clk_get_enabled(dev, "lpo");
+	if (IS_ERR(lpo_clk))
+		return dev_err_probe(dev, PTR_ERR(lpo_clk),
+				     "Failed to get lpo clock\n");
+
+	btss_reset = devm_reset_control_get_exclusive_deasserted(dev, NULL);
+	if (IS_ERR_OR_NULL(btss_reset))
+		return dev_err_probe(dev, PTR_ERR(btss_reset),
+				     "unable to deassert reset\n");
+
+	desc->irq = platform_get_irq(pdev, 0);
+	if (desc->irq < 0)
+		return dev_err_probe(dev, desc->irq, "Failed to acquire IRQ\n");
+
+	hdev = hci_alloc_dev();
+	if (!hdev)
+		return -ENOMEM;
+
+	hci_set_drvdata(hdev, desc);
+	desc->hdev = hdev;
+	SET_HCIDEV_DEV(hdev, &pdev->dev);
+	hdev->bus = HCI_IPC;
+
+	hdev->open = btqcomipc_open;
+	hdev->close = btqcomipc_close;
+	hdev->setup = btqcomipc_setup;
+	hdev->send = btqcomipc_send;
+	hdev->flush = btqcomipc_flush;
+	hdev->set_bdaddr = qca_set_bdaddr;
+
+	ret = btqcomipc_init(desc);
+	if (ret) {
+		hci_free_dev(hdev);
+		return dev_err_probe(dev, ret, "Failed to initialize\n");
+	}
+
+	ret = hci_register_dev(hdev);
+	if (ret < 0) {
+		btqcomipc_deinit(desc);
+		hci_free_dev(hdev);
+		return dev_err_probe(dev, -EBUSY, "Failed to register hdev\n");
+	}
+
+	platform_set_drvdata(pdev, desc);
+
+	return 0;
+}
+
+static void btqcomipc_remove(struct platform_device *pdev)
+{
+	struct qcom_btss *desc = platform_get_drvdata(pdev);
+
+	/* first unregister to stop incoming HCI traffic */
+	hci_unregister_dev(desc->hdev);
+
+	/* disable interrupt and asynchronous operations before teardown */
+	btqcomipc_deinit(desc);
+
+	hci_free_dev(desc->hdev);
+	desc->hdev = NULL;
+}
+
+static const struct of_device_id btqcomipc_of_match[] = {
+	{ .compatible = "qcom,ipq5018-bt" },
+	{ /* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, btqcomipc_of_match);
+
+static struct platform_driver btqcomipc_driver = {
+	.probe = btqcomipc_probe,
+	.remove = btqcomipc_remove,
+	.driver = {
+		.name = "btqcomipc",
+		.of_match_table = btqcomipc_of_match,
+	},
+};
+
+module_platform_driver(btqcomipc_driver);
+
+MODULE_DESCRIPTION("Qualcomm Bluetooth IPC Driver");
+MODULE_LICENSE("GPL");

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support
  2026-07-09  9:18 [PATCH v5 0/6] Add support for IPQ5018 Bluetooth George Moussalem via B4 Relay
                   ` (3 preceding siblings ...)
  2026-07-09  9:18 ` [PATCH v5 4/6] Bluetooth: Introduce Qualcomm IPQ5018 IPC based HCI driver George Moussalem via B4 Relay
@ 2026-07-09  9:18 ` George Moussalem via B4 Relay
  2026-07-09 18:16   ` Konrad Dybcio
  2026-07-09 18:17   ` Konrad Dybcio
  2026-07-09  9:18 ` [PATCH v5 6/6] MAINTAINERS: Add IPQ5018 driver to Qualcomm Bluetooth driver entry George Moussalem via B4 Relay
  5 siblings, 2 replies; 16+ messages in thread
From: George Moussalem via B4 Relay @ 2026-07-09  9:18 UTC (permalink / raw)
  To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	George Moussalem, Bartosz Golaszewski

From: George Moussalem <george.moussalem@outlook.com>

Add node to enable Bluetooth support on the IPQ5018 platform.

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 arch/arm64/boot/dts/qcom/ipq5018.dtsi | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
index 6f8004a22a1f..8c252fa3ff5b 100644
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
@@ -453,6 +453,22 @@ tcsr: syscon@1937000 {
 			reg = <0x01937000 0x21000>;
 		};
 
+		bluetooth: bluetooth@7000000 {
+			compatible = "qcom,ipq5018-bt";
+			reg = <0x07000000 0x58000>;
+
+			firmware-name = "qca/bt_fw_patch.mbn";
+
+			clocks = <&gcc GCC_BTSS_LPO_CLK>;
+			clock-names = "lpo";
+			resets = <&gcc GCC_BTSS_BCR>;
+
+			qcom,ipc = <&apcs_glb 8 23>;
+			interrupts = <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>;
+
+			status = "disabled";
+		};
+
 		sdhc_1: mmc@7804000 {
 			compatible = "qcom,ipq5018-sdhci", "qcom,sdhci-msm-v5";
 			reg = <0x7804000 0x1000>;

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v5 6/6] MAINTAINERS: Add IPQ5018 driver to Qualcomm Bluetooth driver entry
  2026-07-09  9:18 [PATCH v5 0/6] Add support for IPQ5018 Bluetooth George Moussalem via B4 Relay
                   ` (4 preceding siblings ...)
  2026-07-09  9:18 ` [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support George Moussalem via B4 Relay
@ 2026-07-09  9:18 ` George Moussalem via B4 Relay
  5 siblings, 0 replies; 16+ messages in thread
From: George Moussalem via B4 Relay @ 2026-07-09  9:18 UTC (permalink / raw)
  To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	George Moussalem, Bartosz Golaszewski

From: George Moussalem <george.moussalem@outlook.com>

Add the Qualcomm IPQ5018 Bluetooth driver to the existing entry for
Qualcomm Bluetooth drivers.

Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index eb8cdcc76324..33dd0c70c277 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21876,6 +21876,7 @@ L:	linux-arm-msm@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/net/bluetooth/qcom,*
 F:	drivers/bluetooth/btqca.[ch]
+F:	drivers/bluetooth/btqcomipc.c
 F:	drivers/bluetooth/btqcomsmd.c
 F:	drivers/bluetooth/hci_qca.c
 

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* RE: Add support for IPQ5018 Bluetooth
  2026-07-09  9:18 ` [PATCH v5 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller George Moussalem via B4 Relay
@ 2026-07-09 12:21   ` bluez.test.bot
  0 siblings, 0 replies; 16+ messages in thread
From: bluez.test.bot @ 2026-07-09 12:21 UTC (permalink / raw)
  To: linux-bluetooth, george.moussalem

[-- Attachment #1: Type: text/plain, Size: 4348 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1124520

---Test result---

Test Summary:
CheckPatch                    FAIL      5.36 seconds
VerifyFixes                   PASS      0.07 seconds
VerifySignedoff               PASS      0.07 seconds
GitLint                       FAIL      1.23 seconds
SubjectPrefix                 FAIL      0.43 seconds
BuildKernel                   PASS      27.68 seconds
CheckAllWarning               PASS      30.76 seconds
CheckSparse                   PASS      28.91 seconds
BuildKernel32                 PASS      27.09 seconds
CheckKernelLLVM               SKIP      0.00 seconds
TestRunnerSetup               PASS      503.36 seconds
TestRunner_l2cap-tester       PASS      58.63 seconds
TestRunner_iso-tester         PASS      75.61 seconds
TestRunner_bnep-tester        PASS      19.34 seconds
TestRunner_mgmt-tester        FAIL      214.55 seconds
TestRunner_rfcomm-tester      PASS      25.23 seconds
TestRunner_sco-tester         PASS      32.47 seconds
TestRunner_ioctl-tester       PASS      25.77 seconds
TestRunner_mesh-tester        FAIL      24.84 seconds
TestRunner_smp-tester         PASS      23.02 seconds
TestRunner_userchan-tester    PASS      19.89 seconds
TestRunner_6lowpan-tester     PASS      22.64 seconds
IncrementalBuild              PASS      33.55 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v5,1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#96: 
new file mode 100644

total: 0 errors, 1 warnings, 87 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14674953.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


[v5,4/6] Bluetooth: Introduce Qualcomm IPQ5018 IPC based HCI driver
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#143: 
new file mode 100644

total: 0 errors, 1 warnings, 1257 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14674958.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v5,1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller

1: T1 Title exceeds max length (84>80): "[v5,1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller"
##############################
Test: SubjectPrefix - FAIL
Desc: Check subject contains "Bluetooth" prefix
Output:
"Bluetooth: " prefix is not specified in the subject
"Bluetooth: " prefix is not specified in the subject
"Bluetooth: " prefix is not specified in the subject
"Bluetooth: " prefix is not specified in the subject
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4

Failed Test Cases
Read Exp Feature - Success                           Failed       0.236 seconds
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0

Failed Test Cases
Mesh - Send cancel - 1                               Timed out    1.824 seconds
Mesh - Send cancel - 2                               Timed out    1.992 seconds


https://github.com/bluez/bluetooth-next/pull/417

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support
  2026-07-09  9:18 ` [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support George Moussalem via B4 Relay
@ 2026-07-09 18:16   ` Konrad Dybcio
  2026-07-09 18:23     ` George Moussalem
  2026-07-09 18:17   ` Konrad Dybcio
  1 sibling, 1 reply; 16+ messages in thread
From: Konrad Dybcio @ 2026-07-09 18:16 UTC (permalink / raw)
  To: george.moussalem, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	Bartosz Golaszewski

On 7/9/26 11:18 AM, George Moussalem via B4 Relay wrote:
> From: George Moussalem <george.moussalem@outlook.com>
> 
> Add node to enable Bluetooth support on the IPQ5018 platform.
> 
> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---
>  arch/arm64/boot/dts/qcom/ipq5018.dtsi | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
> index 6f8004a22a1f..8c252fa3ff5b 100644
> --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
> +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
> @@ -453,6 +453,22 @@ tcsr: syscon@1937000 {
>  			reg = <0x01937000 0x21000>;
>  		};
>  
> +		bluetooth: bluetooth@7000000 {
> +			compatible = "qcom,ipq5018-bt";
> +			reg = <0x07000000 0x58000>;
> +
> +			firmware-name = "qca/bt_fw_patch.mbn";
> +
> +			clocks = <&gcc GCC_BTSS_LPO_CLK>;
> +			clock-names = "lpo";
> +			resets = <&gcc GCC_BTSS_BCR>;
> +
> +			qcom,ipc = <&apcs_glb 8 23>;
> +			interrupts = <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>;
> +
> +			status = "disabled";

Since the firmware is unsigned, I think it could make sense to
enable this by default

any which way

Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

Konrad

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support
  2026-07-09  9:18 ` [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support George Moussalem via B4 Relay
  2026-07-09 18:16   ` Konrad Dybcio
@ 2026-07-09 18:17   ` Konrad Dybcio
  2026-07-09 18:25     ` George Moussalem
  1 sibling, 1 reply; 16+ messages in thread
From: Konrad Dybcio @ 2026-07-09 18:17 UTC (permalink / raw)
  To: george.moussalem, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	Bartosz Golaszewski

On 7/9/26 11:18 AM, George Moussalem via B4 Relay wrote:
> From: George Moussalem <george.moussalem@outlook.com>
> 
> Add node to enable Bluetooth support on the IPQ5018 platform.
> 
> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---
>  arch/arm64/boot/dts/qcom/ipq5018.dtsi | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
> index 6f8004a22a1f..8c252fa3ff5b 100644
> --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
> +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
> @@ -453,6 +453,22 @@ tcsr: syscon@1937000 {
>  			reg = <0x01937000 0x21000>;
>  		};
>  
> +		bluetooth: bluetooth@7000000 {
> +			compatible = "qcom,ipq5018-bt";
> +			reg = <0x07000000 0x58000>;
> +
> +			firmware-name = "qca/bt_fw_patch.mbn";

Hm, rethinking this, it must have ipq5018 somewhere in the name

Konrad

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support
  2026-07-09 18:16   ` Konrad Dybcio
@ 2026-07-09 18:23     ` George Moussalem
  0 siblings, 0 replies; 16+ messages in thread
From: George Moussalem @ 2026-07-09 18:23 UTC (permalink / raw)
  To: Konrad Dybcio, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	Bartosz Golaszewski

On 7/9/26 22:16, Konrad Dybcio wrote:
> On 7/9/26 11:18 AM, George Moussalem via B4 Relay wrote:
>> From: George Moussalem <george.moussalem@outlook.com>
>>
>> Add node to enable Bluetooth support on the IPQ5018 platform.
>>
>> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>> ---
>>  arch/arm64/boot/dts/qcom/ipq5018.dtsi | 16 ++++++++++++++++
>>  1 file changed, 16 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>> index 6f8004a22a1f..8c252fa3ff5b 100644
>> --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>> +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>> @@ -453,6 +453,22 @@ tcsr: syscon@1937000 {
>>  			reg = <0x01937000 0x21000>;
>>  		};
>>  
>> +		bluetooth: bluetooth@7000000 {
>> +			compatible = "qcom,ipq5018-bt";
>> +			reg = <0x07000000 0x58000>;
>> +
>> +			firmware-name = "qca/bt_fw_patch.mbn";
>> +
>> +			clocks = <&gcc GCC_BTSS_LPO_CLK>;
>> +			clock-names = "lpo";
>> +			resets = <&gcc GCC_BTSS_BCR>;
>> +
>> +			qcom,ipc = <&apcs_glb 8 23>;
>> +			interrupts = <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>;
>> +
>> +			status = "disabled";
> 
> Since the firmware is unsigned, I think it could make sense to
> enable this by default
> 
> any which way

I've found that the controller is not wired up on all ipq5018 boards.
For ex. Linksys router boards have it enabled and wired up by default
while you can enable the controller on some Xiaomi and Gl.Inet boards
but the controller isn't connected to anything.

> 
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> 
> Konrad

George

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support
  2026-07-09 18:17   ` Konrad Dybcio
@ 2026-07-09 18:25     ` George Moussalem
  2026-07-09 18:40       ` Konrad Dybcio
  0 siblings, 1 reply; 16+ messages in thread
From: George Moussalem @ 2026-07-09 18:25 UTC (permalink / raw)
  To: Konrad Dybcio, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Philipp Zabel
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	Bartosz Golaszewski

On 7/9/26 22:17, Konrad Dybcio wrote:
> On 7/9/26 11:18 AM, George Moussalem via B4 Relay wrote:
>> From: George Moussalem <george.moussalem@outlook.com>
>>
>> Add node to enable Bluetooth support on the IPQ5018 platform.
>>
>> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>> ---
>>  arch/arm64/boot/dts/qcom/ipq5018.dtsi | 16 ++++++++++++++++
>>  1 file changed, 16 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>> index 6f8004a22a1f..8c252fa3ff5b 100644
>> --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>> +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>> @@ -453,6 +453,22 @@ tcsr: syscon@1937000 {
>>  			reg = <0x01937000 0x21000>;
>>  		};
>>  
>> +		bluetooth: bluetooth@7000000 {
>> +			compatible = "qcom,ipq5018-bt";
>> +			reg = <0x07000000 0x58000>;
>> +
>> +			firmware-name = "qca/bt_fw_patch.mbn";
> 
> Hm, rethinking this, it must have ipq5018 somewhere in the name

I agree but all QCA BT firmware and rampatches are published in the
/lib/firmware/qca directory, see:
https://git.kernel.org/pub/scm/linux/kernel/git/ath/linux-firmware.git/tree/qca

> 
> Konrad

George

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support
  2026-07-09 18:25     ` George Moussalem
@ 2026-07-09 18:40       ` Konrad Dybcio
  2026-07-10  9:14         ` Bartosz Golaszewski
  0 siblings, 1 reply; 16+ messages in thread
From: Konrad Dybcio @ 2026-07-09 18:40 UTC (permalink / raw)
  To: George Moussalem, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Philipp Zabel,
	Jeff Johnson, Bartosz Golaszewski
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	Bartosz Golaszewski

On 7/9/26 8:25 PM, George Moussalem wrote:
> On 7/9/26 22:17, Konrad Dybcio wrote:
>> On 7/9/26 11:18 AM, George Moussalem via B4 Relay wrote:
>>> From: George Moussalem <george.moussalem@outlook.com>
>>>
>>> Add node to enable Bluetooth support on the IPQ5018 platform.
>>>
>>> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>>> ---
>>>  arch/arm64/boot/dts/qcom/ipq5018.dtsi | 16 ++++++++++++++++
>>>  1 file changed, 16 insertions(+)
>>>
>>> diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>> index 6f8004a22a1f..8c252fa3ff5b 100644
>>> --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>> +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>> @@ -453,6 +453,22 @@ tcsr: syscon@1937000 {
>>>  			reg = <0x01937000 0x21000>;
>>>  		};
>>>  
>>> +		bluetooth: bluetooth@7000000 {
>>> +			compatible = "qcom,ipq5018-bt";
>>> +			reg = <0x07000000 0x58000>;
>>> +
>>> +			firmware-name = "qca/bt_fw_patch.mbn";
>>
>> Hm, rethinking this, it must have ipq5018 somewhere in the name
> 
> I agree but all QCA BT firmware and rampatches are published in the
> /lib/firmware/qca directory, see:
> https://git.kernel.org/pub/scm/linux/kernel/git/ath/linux-firmware.git/tree/qca

+Jeff, Bartosz?

Konrad

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support
  2026-07-09 18:40       ` Konrad Dybcio
@ 2026-07-10  9:14         ` Bartosz Golaszewski
  2026-07-10  9:23           ` Konrad Dybcio
  0 siblings, 1 reply; 16+ messages in thread
From: Bartosz Golaszewski @ 2026-07-10  9:14 UTC (permalink / raw)
  To: Konrad Dybcio
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	Bartosz Golaszewski, George Moussalem, Bartosz Golaszewski,
	Marcel Holtmann, Luiz Augusto von Dentz, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
	Philipp Zabel, Jeff Johnson

On Thu, 9 Jul 2026 20:40:04 +0200, Konrad Dybcio
<konrad.dybcio@oss.qualcomm.com> said:
> On 7/9/26 8:25 PM, George Moussalem wrote:
>> On 7/9/26 22:17, Konrad Dybcio wrote:
>>> On 7/9/26 11:18 AM, George Moussalem via B4 Relay wrote:
>>>> From: George Moussalem <george.moussalem@outlook.com>
>>>>
>>>> Add node to enable Bluetooth support on the IPQ5018 platform.
>>>>
>>>> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>>>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>>>> ---
>>>>  arch/arm64/boot/dts/qcom/ipq5018.dtsi | 16 ++++++++++++++++
>>>>  1 file changed, 16 insertions(+)
>>>>
>>>> diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>>> index 6f8004a22a1f..8c252fa3ff5b 100644
>>>> --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>>> +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>>> @@ -453,6 +453,22 @@ tcsr: syscon@1937000 {
>>>>  			reg = <0x01937000 0x21000>;
>>>>  		};
>>>>
>>>> +		bluetooth: bluetooth@7000000 {
>>>> +			compatible = "qcom,ipq5018-bt";
>>>> +			reg = <0x07000000 0x58000>;
>>>> +
>>>> +			firmware-name = "qca/bt_fw_patch.mbn";
>>>
>>> Hm, rethinking this, it must have ipq5018 somewhere in the name
>>
>> I agree but all QCA BT firmware and rampatches are published in the
>> /lib/firmware/qca directory, see:
>> https://git.kernel.org/pub/scm/linux/kernel/git/ath/linux-firmware.git/tree/qca
>
> +Jeff, Bartosz?
>

I'm not sure what the question is. This particular blob doesn't seem to exist
anywhere in linux-firmware yet. I agree, ideally the platform name should be in
the firmware name so let's upstream it to linux-firmware as such? Am I missing
something?

Bartosz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support
  2026-07-10  9:14         ` Bartosz Golaszewski
@ 2026-07-10  9:23           ` Konrad Dybcio
  2026-07-10  9:32             ` George Moussalem
  0 siblings, 1 reply; 16+ messages in thread
From: Konrad Dybcio @ 2026-07-10  9:23 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	Bartosz Golaszewski, George Moussalem, Marcel Holtmann,
	Luiz Augusto von Dentz, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Philipp Zabel,
	Jeff Johnson

On 7/10/26 11:14 AM, Bartosz Golaszewski wrote:
> On Thu, 9 Jul 2026 20:40:04 +0200, Konrad Dybcio
> <konrad.dybcio@oss.qualcomm.com> said:
>> On 7/9/26 8:25 PM, George Moussalem wrote:
>>> On 7/9/26 22:17, Konrad Dybcio wrote:
>>>> On 7/9/26 11:18 AM, George Moussalem via B4 Relay wrote:
>>>>> From: George Moussalem <george.moussalem@outlook.com>
>>>>>
>>>>> Add node to enable Bluetooth support on the IPQ5018 platform.
>>>>>
>>>>> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>>>>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>>>>> ---
>>>>>  arch/arm64/boot/dts/qcom/ipq5018.dtsi | 16 ++++++++++++++++
>>>>>  1 file changed, 16 insertions(+)
>>>>>
>>>>> diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>>>> index 6f8004a22a1f..8c252fa3ff5b 100644
>>>>> --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>>>> +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>>>> @@ -453,6 +453,22 @@ tcsr: syscon@1937000 {
>>>>>  			reg = <0x01937000 0x21000>;
>>>>>  		};
>>>>>
>>>>> +		bluetooth: bluetooth@7000000 {
>>>>> +			compatible = "qcom,ipq5018-bt";
>>>>> +			reg = <0x07000000 0x58000>;
>>>>> +
>>>>> +			firmware-name = "qca/bt_fw_patch.mbn";
>>>>
>>>> Hm, rethinking this, it must have ipq5018 somewhere in the name
>>>
>>> I agree but all QCA BT firmware and rampatches are published in the
>>> /lib/firmware/qca directory, see:
>>> https://git.kernel.org/pub/scm/linux/kernel/git/ath/linux-firmware.git/tree/qca
>>
>> +Jeff, Bartosz?
>>
> 
> I'm not sure what the question is. This particular blob doesn't seem to exist
> anywhere in linux-firmware yet. I agree, ideally the platform name should be in
> the firmware name so let's upstream it to linux-firmware as such? Am I missing
> something?

That's what I'd like to happen - just wanted to make sure you're in the
loop, so that a platform-specific MBN doesn't end up with such a generic
name in case that was the plan.

Konrad

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support
  2026-07-10  9:23           ` Konrad Dybcio
@ 2026-07-10  9:32             ` George Moussalem
  0 siblings, 0 replies; 16+ messages in thread
From: George Moussalem @ 2026-07-10  9:32 UTC (permalink / raw)
  To: Konrad Dybcio, Bartosz Golaszewski
  Cc: linux-arm-msm, linux-bluetooth, devicetree, linux-kernel,
	Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Philipp Zabel, Jeff Johnson

On 7/10/26 13:23, Konrad Dybcio wrote:
> On 7/10/26 11:14 AM, Bartosz Golaszewski wrote:
>> On Thu, 9 Jul 2026 20:40:04 +0200, Konrad Dybcio
>> <konrad.dybcio@oss.qualcomm.com> said:
>>> On 7/9/26 8:25 PM, George Moussalem wrote:
>>>> On 7/9/26 22:17, Konrad Dybcio wrote:
>>>>> On 7/9/26 11:18 AM, George Moussalem via B4 Relay wrote:
>>>>>> From: George Moussalem <george.moussalem@outlook.com>
>>>>>>
>>>>>> Add node to enable Bluetooth support on the IPQ5018 platform.
>>>>>>
>>>>>> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>>>>>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>>>>>> ---
>>>>>>  arch/arm64/boot/dts/qcom/ipq5018.dtsi | 16 ++++++++++++++++
>>>>>>  1 file changed, 16 insertions(+)
>>>>>>
>>>>>> diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>>>>> index 6f8004a22a1f..8c252fa3ff5b 100644
>>>>>> --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>>>>> +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
>>>>>> @@ -453,6 +453,22 @@ tcsr: syscon@1937000 {
>>>>>>  			reg = <0x01937000 0x21000>;
>>>>>>  		};
>>>>>>
>>>>>> +		bluetooth: bluetooth@7000000 {
>>>>>> +			compatible = "qcom,ipq5018-bt";
>>>>>> +			reg = <0x07000000 0x58000>;
>>>>>> +
>>>>>> +			firmware-name = "qca/bt_fw_patch.mbn";
>>>>>
>>>>> Hm, rethinking this, it must have ipq5018 somewhere in the name
>>>>
>>>> I agree but all QCA BT firmware and rampatches are published in the
>>>> /lib/firmware/qca directory, see:
>>>> https://git.kernel.org/pub/scm/linux/kernel/git/ath/linux-firmware.git/tree/qca
>>>
>>> +Jeff, Bartosz?
>>>
>>
>> I'm not sure what the question is. This particular blob doesn't seem to exist
>> anywhere in linux-firmware yet. I agree, ideally the platform name should be in
>> the firmware name so let's upstream it to linux-firmware as such? Am I missing
>> something?
> 
> That's what I'd like to happen - just wanted to make sure you're in the
> loop, so that a platform-specific MBN doesn't end up with such a generic
> name in case that was the plan.

Perfect, kindly let me know what the name of the MBN that will be
upstreamed to linux-firmware will be and I'll adjust the name in the
next version. The current name was taken as-is from firmware images
distributed to vendors and as available in code.qualcomm.com.

If it will be provided as MBN format, shall I remove support for loading
MDT in the driver or leave as is?

> 
> Konrad

George

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2026-07-10  9:32 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-09  9:18 [PATCH v5 0/6] Add support for IPQ5018 Bluetooth George Moussalem via B4 Relay
2026-07-09  9:18 ` [PATCH v5 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller George Moussalem via B4 Relay
2026-07-09 12:21   ` Add support for IPQ5018 Bluetooth bluez.test.bot
2026-07-09  9:18 ` [PATCH v5 2/6] Bluetooth: btqca: Add IPQ5018 support George Moussalem via B4 Relay
2026-07-09  9:18 ` [PATCH v5 3/6] firmware: qcom: scm: Add support for setting Bluetooth power modes George Moussalem via B4 Relay
2026-07-09  9:18 ` [PATCH v5 4/6] Bluetooth: Introduce Qualcomm IPQ5018 IPC based HCI driver George Moussalem via B4 Relay
2026-07-09  9:18 ` [PATCH v5 5/6] arm64: dts: qcom: ipq5018: add node required for Bluetooth support George Moussalem via B4 Relay
2026-07-09 18:16   ` Konrad Dybcio
2026-07-09 18:23     ` George Moussalem
2026-07-09 18:17   ` Konrad Dybcio
2026-07-09 18:25     ` George Moussalem
2026-07-09 18:40       ` Konrad Dybcio
2026-07-10  9:14         ` Bartosz Golaszewski
2026-07-10  9:23           ` Konrad Dybcio
2026-07-10  9:32             ` George Moussalem
2026-07-09  9:18 ` [PATCH v5 6/6] MAINTAINERS: Add IPQ5018 driver to Qualcomm Bluetooth driver entry George Moussalem via B4 Relay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox