* [PATCH 0/3] Bluetooth: qca: enable QCC2072 on RB3 Gen 2 Industrial Mezz reworked for BT over UART
@ 2026-07-23 12:31 Rahul Samana
2026-07-23 12:31 ` [PATCH 1/3] Bluetooth: qca: add QCC2072 support Rahul Samana
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Rahul Samana @ 2026-07-23 12:31 UTC (permalink / raw)
To: Luiz Augusto von Dentz, Krzysztof Kozlowski, Marcel Holtmann,
Bartosz Golaszewski, Conor Dooley, Rob Herring, Bjorn Andersson,
Konrad Dybcio
Cc: Rahul Samana, linux-bluetooth, linux-kernel, quic_hbandi,
devicetree, linux-arm-msm, quic_anubhavg, quic_mohamull
The RB3 Gen 2 Industrial mezzanine normally uses the M.2 E-key slot for
Bluetooth over USB. This series enables a reworked Industrial mezzanine
variant where the same M.2 E-key Bluetooth path is routed over UART4
instead.
The BT UART overlay is applied on top of the existing Industrial
mezzanine overlay because the reworked board keeps the common Industrial
mezzanine hardware description and only changes the Bluetooth transport
routing.
To support this board variant, add QCC2072 support to the Qualcomm
Bluetooth UART driver. QCC2072 uses ORN firmware naming, board-id based
NVM lookup, and requires the BCS calibration TLV to be combined with the
selected NVM before download.
The DTS changes also mark the QCS6490 PCIe root port as a PCI bridge so
child nodes below the enumerated PCI topology can be matched. This is
needed for the M.2 E-key connector graph endpoints used by the BT UART
overlay.
The series is split as follows:
- Patch 1 adds QCC2072 support to the Qualcomm Bluetooth UART driver,
including ORN firmware naming, board-id based NVM lookup and BCS
calibration TLV download together with the selected NVM.
- Patch 2 marks the QCS6490 PCIe root port as a PCI bridge so the PCI
subsystem can associate the DT node with the enumerated PCI-to-PCI
bridge device used by the M.2 E-key graph.
- Patch 3 describes the reworked RB3 Gen 2 Industrial mezzanine BT UART
path by adding the M.2 E-key connector graph links from port@0 to PCIe
and from port@3 to UART4, and composes this overlay on top of the
existing Industrial mezzanine overlay.
This series depends on two M.2 power sequencing changes already posted
upstream. The Eliza EVK series adds the QCC2072 PCI ID to the M.2 E-key
power sequencing driver, which lets the connector power sequence bind to
the enumerated QCC2072 WLAN function:
https://lore.kernel.org/all/20260703-eliza_evk-v1-0-7624440bd76d@oss.qualcomm.com/
The Monza wireless series adds the generic hci_qca OF graph handling used
by M.2 Bluetooth devices, so the Bluetooth serdev controller can acquire
the UART power sequence from the M.2 connector graph instead of carrying a
board-specific power-control path in this series:
https://lore.kernel.org/all/20260710-monza-wireless-v3-0-46253587af64@oss.qualcomm.com/
Tested on RB3 Gen 2 with the reworked Industrial mezzanine. Bluetooth
setup completed successfully over UART4. The QCC2072 NVM and BCS
calibration loading path was verified to request board-specific files
when available and fall back to the default files otherwise.
Signed-off-by: Rahul Samana <rahul.samana@oss.qualcomm.com>
---
Rahul Samana (3):
Bluetooth: qca: add QCC2072 support
arm64: dts: qcom: kodiak: mark PCIe root port as bridge
arm64: dts: qcom: rb3gen2: add Industrial BT UART overlay
arch/arm64/boot/dts/qcom/Makefile | 2 +
arch/arm64/boot/dts/qcom/kodiak.dtsi | 1 +
...s6490-rb3gen2-industrial-mezzanine-bt-uart.dtso | 133 +++++++++++++++++++++
drivers/bluetooth/btqca.c | 70 ++++++++++-
drivers/bluetooth/btqca.h | 2 +
drivers/bluetooth/hci_qca.c | 24 ++++
6 files changed, 231 insertions(+), 1 deletion(-)
---
base-commit: 248951ddc14de84de3910f9b13f51491a8cd91df
change-id: 20260723-rb3-industrial-bt-uart-f98acaffc9f5
Best regards,
--
Rahul Samana <rahul.samana@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/3] Bluetooth: qca: add QCC2072 support
2026-07-23 12:31 [PATCH 0/3] Bluetooth: qca: enable QCC2072 on RB3 Gen 2 Industrial Mezz reworked for BT over UART Rahul Samana
@ 2026-07-23 12:31 ` Rahul Samana
2026-07-23 12:48 ` sashiko-bot
2026-07-23 12:31 ` [PATCH 2/3] arm64: dts: qcom: kodiak: mark PCIe root port as bridge Rahul Samana
2026-07-23 12:31 ` [PATCH 3/3] arm64: dts: qcom: rb3gen2: add Industrial BT UART overlay Rahul Samana
2 siblings, 1 reply; 7+ messages in thread
From: Rahul Samana @ 2026-07-23 12:31 UTC (permalink / raw)
To: Luiz Augusto von Dentz, Krzysztof Kozlowski, Marcel Holtmann,
Bartosz Golaszewski, Conor Dooley, Rob Herring, Bjorn Andersson,
Konrad Dybcio
Cc: Rahul Samana, linux-bluetooth, linux-kernel, quic_hbandi,
devicetree, linux-arm-msm, quic_anubhavg, quic_mohamull
Add QCC2072 as a supported Qualcomm Bluetooth controller.
QCC2072 uses the ORN firmware and NVM naming scheme. Select the NVM file
and BCS calibration file using the controller board ID when available,
with fallback to the default files.
Register the QCC2072 compatible with hci_qca and route it through the
same UART setup, speed switching and power-control paths as recent
Qualcomm Bluetooth controllers.
Signed-off-by: Rahul Samana <rahul.samana@oss.qualcomm.com>
---
drivers/bluetooth/btqca.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-
drivers/bluetooth/btqca.h | 2 ++
drivers/bluetooth/hci_qca.c | 24 ++++++++++++++++
3 files changed, 95 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 10c496eaea2c..69427cc7eb5a 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -569,6 +569,54 @@ static int qca_inject_cmd_complete_event(struct hci_dev *hdev)
return hci_recv_frame(hdev, skb);
}
+static void qca_combine_nvm_calib(struct hci_dev *hdev, u8 **data,
+ int *size, char *calib_name,
+ size_t max_size)
+{
+ const struct firmware *calib_fw;
+ struct tlv_type_hdr *outer_hdr;
+ size_t inner_len, combined_size;
+ u8 *combined_data;
+ int err;
+
+ err = request_firmware(&calib_fw, calib_name, &hdev->dev);
+ if (err) {
+ if (qca_get_alt_nvm_file(calib_name, max_size))
+ err = request_firmware(&calib_fw, calib_name, &hdev->dev);
+
+ if (err) {
+ bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
+ calib_name, err);
+ return;
+ }
+ }
+
+ bt_dev_info(hdev, "QCA Downloading %s", calib_name);
+
+ inner_len = *size + calib_fw->size;
+ combined_size = sizeof(*outer_hdr) + inner_len;
+ combined_data = vmalloc(combined_size);
+ if (!combined_data) {
+ bt_dev_warn(hdev,
+ "QCA Failed to allocate memory for file: %s",
+ calib_name);
+ release_firmware(calib_fw);
+ return;
+ }
+
+ outer_hdr = (struct tlv_type_hdr *)combined_data;
+ /* high 24 bits = payload length, low 8 bits = type */
+ outer_hdr->type_len = cpu_to_le32((inner_len << 8) | 4);
+ memcpy(combined_data + sizeof(*outer_hdr), *data, *size);
+ memcpy(combined_data + sizeof(*outer_hdr) + *size,
+ calib_fw->data, calib_fw->size);
+ release_firmware(calib_fw);
+
+ vfree(*data);
+ *data = combined_data;
+ *size = combined_size;
+}
+
static int qca_download_firmware(struct hci_dev *hdev,
struct qca_fw_config *config,
enum qca_btsoc_type soc_type,
@@ -614,6 +662,11 @@ static int qca_download_firmware(struct hci_dev *hdev,
memcpy(data, fw->data, size);
release_firmware(fw);
+ if (soc_type == QCA_QCC2072 && config->type == TLV_TYPE_NVM)
+ qca_combine_nvm_calib(hdev, &data, &size,
+ config->calib_name,
+ sizeof(config->calib_name));
+
ret = qca_tlv_check_data(hdev, config, data, size, soc_type);
if (ret)
goto out;
@@ -845,6 +898,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
snprintf(config.fwname, sizeof(config.fwname),
"qca/hmtbtfw%02x.tlv", rom_ver);
break;
+ case QCA_QCC2072:
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/ornbtfw%02x.tlv", rom_ver);
+ break;
default:
snprintf(config.fwname, sizeof(config.fwname),
"qca/rampatch_%08x.bin", soc_ver);
@@ -878,7 +935,8 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
/* Give the controller some time to get ready to receive the NVM */
msleep(10);
- if (soc_type == QCA_QCA2066 || soc_type == QCA_WCN7850)
+ if (soc_type == QCA_QCA2066 || soc_type == QCA_WCN7850 ||
+ soc_type == QCA_QCC2072)
qca_read_fw_board_id(hdev, &boardid);
/* Download NVM configuration */
@@ -939,6 +997,15 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
"hmtnv", soc_type, ver, rom_ver, boardid);
break;
+ case QCA_QCC2072:
+ qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
+ "ornnv", soc_type, ver,
+ rom_ver, boardid);
+ qca_get_nvm_name_by_board(config.calib_name,
+ sizeof(config.calib_name),
+ "ornbcscal", soc_type, ver,
+ rom_ver, boardid);
+ break;
default:
snprintf(config.fwname, sizeof(config.fwname),
"qca/nvm_%08x.bin", soc_ver);
@@ -1001,6 +1068,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
/* get fw build info */
err = qca_read_fw_build_info(hdev);
if (err < 0)
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index 8f3c1b1c77b3..425133096eda 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -94,6 +94,7 @@ enum qca_tlv_type {
struct qca_fw_config {
u8 type;
char fwname[64];
+ char calib_name[64];
uint8_t user_baud_rate;
enum qca_tlv_dnld_mode dnld_mode;
enum qca_tlv_dnld_mode dnld_type;
@@ -158,6 +159,7 @@ enum qca_btsoc_type {
QCA_WCN6750,
QCA_WCN6855,
QCA_WCN7850,
+ QCA_QCC2072,
};
#if IS_ENABLED(CONFIG_BT_QCA)
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 1222f97800f4..6fe3aab688e6 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -1375,6 +1375,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
/* Give the controller time to process the request */
switch (qca_soc_type(hu)) {
+ case QCA_QCC2072:
case QCA_WCN3950:
case QCA_WCN3988:
case QCA_WCN3990:
@@ -1462,6 +1463,7 @@ static unsigned int qca_get_speed(struct hci_uart *hu,
static int qca_check_speeds(struct hci_uart *hu)
{
switch (qca_soc_type(hu)) {
+ case QCA_QCC2072:
case QCA_WCN3950:
case QCA_WCN3988:
case QCA_WCN3990:
@@ -1513,6 +1515,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
hci_uart_set_flow_control(hu, true);
break;
@@ -1548,6 +1551,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
hci_uart_set_flow_control(hu, false);
break;
@@ -1864,6 +1868,7 @@ static int qca_power_on(struct hci_dev *hdev)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
ret = qca_regulator_init(hu);
break;
@@ -1963,6 +1968,10 @@ static int qca_setup(struct hci_uart *hu)
soc_name = "wcn7850";
break;
+ case QCA_QCC2072:
+ soc_name = "qcc2072";
+ break;
+
default:
soc_name = "ROME/QCA6390";
}
@@ -1986,6 +1995,7 @@ static int qca_setup(struct hci_uart *hu)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
if (qcadev && qcadev->bdaddr_property_broken)
hci_set_quirk(hdev, HCI_QUIRK_BDADDR_PROPERTY_BROKEN);
@@ -2019,6 +2029,7 @@ static int qca_setup(struct hci_uart *hu)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
break;
default:
@@ -2172,6 +2183,12 @@ static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = {
.num_vregs = 4,
};
+static const struct qca_device_data qca_soc_data_qcc2072 __maybe_unused = {
+ .soc_type = QCA_QCC2072,
+ .num_vregs = 0,
+ .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
+};
+
static const struct qca_device_data qca_soc_data_wcn6750 __maybe_unused = {
.soc_type = QCA_WCN6750,
.vregs = (struct qca_vreg []) {
@@ -2274,6 +2291,7 @@ static void qca_power_off(struct hci_uart *hu)
case QCA_WCN6750:
case QCA_WCN6855:
+ case QCA_QCC2072:
gpiod_set_value_cansleep(qcadev->bt_en, 0);
msleep(100);
qca_regulator_disable(qcadev);
@@ -2429,6 +2447,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
qcadev->bt_power = devm_kzalloc(&serdev->dev,
sizeof(struct qca_power),
GFP_KERNEL);
@@ -2448,6 +2467,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
if (!device_property_present(&serdev->dev, "enable-gpios")) {
/*
* Backward compatibility with old DT sources. If the
@@ -2490,6 +2510,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (!qcadev->bt_en &&
(data->soc_type == QCA_WCN6750 ||
data->soc_type == QCA_WCN6855 ||
+ data->soc_type == QCA_QCC2072 ||
data->soc_type == QCA_WCN7850))
power_ctrl_enabled = false;
@@ -2498,6 +2519,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (IS_ERR(qcadev->sw_ctrl) &&
(data->soc_type == QCA_WCN6750 ||
data->soc_type == QCA_WCN6855 ||
+ data->soc_type == QCA_QCC2072 ||
data->soc_type == QCA_WCN7850)) {
dev_err(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
return PTR_ERR(qcadev->sw_ctrl);
@@ -2576,6 +2598,7 @@ static void qca_serdev_remove(struct serdev_device *serdev)
struct qca_power *power = qcadev->bt_power;
switch (qcadev->btsoc_type) {
+ case QCA_QCC2072:
case QCA_WCN3988:
case QCA_WCN3990:
case QCA_WCN3991:
@@ -2785,6 +2808,7 @@ static const struct of_device_id qca_bluetooth_of_match[] = {
{ .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750},
{ .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855},
{ .compatible = "qcom,wcn7850-bt", .data = &qca_soc_data_wcn7850},
+ { .compatible = "qcom,qcc2072-bt", .data = &qca_soc_data_qcc2072},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/3] arm64: dts: qcom: kodiak: mark PCIe root port as bridge
2026-07-23 12:31 [PATCH 0/3] Bluetooth: qca: enable QCC2072 on RB3 Gen 2 Industrial Mezz reworked for BT over UART Rahul Samana
2026-07-23 12:31 ` [PATCH 1/3] Bluetooth: qca: add QCC2072 support Rahul Samana
@ 2026-07-23 12:31 ` Rahul Samana
2026-07-23 12:38 ` Konrad Dybcio
2026-07-23 12:31 ` [PATCH 3/3] arm64: dts: qcom: rb3gen2: add Industrial BT UART overlay Rahul Samana
2 siblings, 1 reply; 7+ messages in thread
From: Rahul Samana @ 2026-07-23 12:31 UTC (permalink / raw)
To: Luiz Augusto von Dentz, Krzysztof Kozlowski, Marcel Holtmann,
Bartosz Golaszewski, Conor Dooley, Rob Herring, Bjorn Andersson,
Konrad Dybcio
Cc: Rahul Samana, linux-bluetooth, linux-kernel, quic_hbandi,
devicetree, linux-arm-msm, quic_anubhavg, quic_mohamull
Add the PCI class compatible to pcie0_port so child nodes below the PCI
bridge can be matched against the enumerated PCI topology.
This is needed by the M.2 E-key graph description used by the RB3 Gen 2
Industrial mezzanine Bluetooth UART overlay.
Signed-off-by: Rahul Samana <rahul.samana@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/kodiak.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
index fa540d8c2615..12594967d2c2 100644
--- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
+++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
@@ -2296,6 +2296,7 @@ pcie0: pcie@1c00000 {
status = "disabled";
pcie0_port: pcie@0 {
+ compatible = "pciclass,0604";
device_type = "pci";
reg = <0x0 0x0 0x0 0x0 0x0>;
bus-range = <0x01 0xff>;
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/3] arm64: dts: qcom: rb3gen2: add Industrial BT UART overlay
2026-07-23 12:31 [PATCH 0/3] Bluetooth: qca: enable QCC2072 on RB3 Gen 2 Industrial Mezz reworked for BT over UART Rahul Samana
2026-07-23 12:31 ` [PATCH 1/3] Bluetooth: qca: add QCC2072 support Rahul Samana
2026-07-23 12:31 ` [PATCH 2/3] arm64: dts: qcom: kodiak: mark PCIe root port as bridge Rahul Samana
@ 2026-07-23 12:31 ` Rahul Samana
2026-07-23 12:49 ` sashiko-bot
2 siblings, 1 reply; 7+ messages in thread
From: Rahul Samana @ 2026-07-23 12:31 UTC (permalink / raw)
To: Luiz Augusto von Dentz, Krzysztof Kozlowski, Marcel Holtmann,
Bartosz Golaszewski, Conor Dooley, Rob Herring, Bjorn Andersson,
Konrad Dybcio
Cc: Rahul Samana, linux-bluetooth, linux-kernel, quic_hbandi,
devicetree, linux-arm-msm, quic_anubhavg, quic_mohamull
Add an overlay for the RB3 Gen 2 Industrial mezzanine variant that routes
QCC2072 Bluetooth over UART4 and models the M.2 E-key connector graph
endpoints for PCIe and UART.
The default Industrial mezzanine overlay describes the common mezzanine
hardware. Build this variant by applying the common Industrial mezzanine
overlay first, followed by the BT UART overlay, because the reworked board
keeps the common mezzanine description and only changes the Bluetooth
transport routing.
The overlay also disables the on-board WCN6750 PMU and UART7 path so the
M.2 QCC2072 Bluetooth controller can be used instead.
Signed-off-by: Rahul Samana <rahul.samana@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/Makefile | 2 +
...s6490-rb3gen2-industrial-mezzanine-bt-uart.dtso | 133 +++++++++++++++++++++
2 files changed, 135 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 6f33c4e2f09c..45786d3db14a 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -179,8 +179,10 @@ dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2.dtb
qcs6490-rb3gen2-vision-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-vision-mezzanine.dtbo
qcs6490-rb3gen2-industrial-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-industrial-mezzanine.dtbo
+qcs6490-rb3gen2-industrial-mezzanine-bt-uart-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-industrial-mezzanine.dtbo qcs6490-rb3gen2-industrial-mezzanine-bt-uart.dtbo
dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-industrial-mezzanine.dtb
+dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-industrial-mezzanine-bt-uart.dtb
dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-vision-mezzanine.dtb
dtb-$(CONFIG_ARCH_QCOM) += qcs6490-thundercomm-minipc-g1iot.dtb
dtb-$(CONFIG_ARCH_QCOM) += qcs6490-thundercomm-rubikpi3.dtb
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-industrial-mezzanine-bt-uart.dtso b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-industrial-mezzanine-bt-uart.dtso
new file mode 100644
index 000000000000..06560df0a719
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-industrial-mezzanine-bt-uart.dtso
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2026 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&{/} {
+ vreg_wcn_3p3: regulator-wcn-3p3 {
+ compatible = "regulator-fixed";
+ regulator-name = "VREG_WCN_3P3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-boot-on;
+ };
+
+ m2_e_connector: m2-e-connector {
+ compatible = "pcie-m2-e-connector";
+ vpcie3v3-supply = <&vreg_wcn_3p3>;
+
+ m2_e_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ m2_e_pcie_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&pcie0_m2_e_ep>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ m2_e_uart_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&uart4_m2_e_ep>;
+ };
+ };
+ };
+ };
+};
+
+&qup_uart4_cts {
+ bias-bus-hold;
+};
+
+&qup_uart4_rts {
+ drive-strength = <2>;
+ bias-disable;
+};
+
+&qup_uart4_rx {
+ bias-pull-up;
+};
+
+&qup_uart4_tx {
+ drive-strength = <2>;
+ bias-disable;
+};
+
+&tlmm {
+ qup_uart4_sleep_cts: qup-uart4-sleep-cts-state {
+ pins = "gpio16";
+ function = "gpio";
+ bias-bus-hold;
+ };
+
+ qup_uart4_sleep_rts: qup-uart4-sleep-rts-state {
+ pins = "gpio17";
+ function = "gpio";
+ bias-pull-down;
+ };
+
+ qup_uart4_sleep_tx: qup-uart4-sleep-tx-state {
+ pins = "gpio18";
+ function = "gpio";
+ bias-pull-up;
+ };
+
+ qup_uart4_sleep_rx: qup-uart4-sleep-rx-state {
+ pins = "gpio19";
+ function = "gpio";
+ bias-pull-up;
+ };
+};
+
+&pcie0_port {
+ pcie@0,0 {
+ pcie@2,0 {
+ port {
+ pcie0_m2_e_ep: endpoint {
+ remote-endpoint = <&m2_e_pcie_ep>;
+ };
+ };
+ };
+ };
+};
+
+&uart4 {
+ status = "okay";
+ /delete-property/ interrupts;
+ interrupts-extended = <&intc GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH>,
+ <&tlmm 19 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-1 = <&qup_uart4_sleep_cts>, <&qup_uart4_sleep_rts>,
+ <&qup_uart4_sleep_tx>, <&qup_uart4_sleep_rx>;
+
+ port {
+ uart4_m2_e_ep: endpoint {
+ remote-endpoint = <&m2_e_uart_ep>;
+ };
+ };
+};
+
+&uart7 {
+ status = "disabled";
+};
+
+&{/wcn6750-pmu} {
+ status = "disabled";
+};
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/3] arm64: dts: qcom: kodiak: mark PCIe root port as bridge
2026-07-23 12:31 ` [PATCH 2/3] arm64: dts: qcom: kodiak: mark PCIe root port as bridge Rahul Samana
@ 2026-07-23 12:38 ` Konrad Dybcio
0 siblings, 0 replies; 7+ messages in thread
From: Konrad Dybcio @ 2026-07-23 12:38 UTC (permalink / raw)
To: Rahul Samana, Luiz Augusto von Dentz, Krzysztof Kozlowski,
Marcel Holtmann, Bartosz Golaszewski, Conor Dooley, Rob Herring,
Bjorn Andersson, Konrad Dybcio
Cc: linux-bluetooth, linux-kernel, quic_hbandi, devicetree,
linux-arm-msm, quic_anubhavg, quic_mohamull
On 7/23/26 2:31 PM, Rahul Samana wrote:
> Add the PCI class compatible to pcie0_port so child nodes below the PCI
> bridge can be matched against the enumerated PCI topology.
>
> This is needed by the M.2 E-key graph description used by the RB3 Gen 2
> Industrial mezzanine Bluetooth UART overlay.
>
> Signed-off-by: Rahul Samana <rahul.samana@oss.qualcomm.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/3] Bluetooth: qca: add QCC2072 support
2026-07-23 12:31 ` [PATCH 1/3] Bluetooth: qca: add QCC2072 support Rahul Samana
@ 2026-07-23 12:48 ` sashiko-bot
0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-07-23 12:48 UTC (permalink / raw)
To: Rahul Samana; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Uninitialized `config.calib_name` when using the `firmware-name` device tree property causes failure to load calibration data.
Pre-existing issues:
- [High] Unbounded polling loop on the TX queue can lead to a permanent task hang.
--
--- Patch [1]: [PATCH 1/3] Bluetooth: qca: add QCC2072 support ---
commit a8d57bcf86987ec0c8079a742e8a1f1f50322cdc
Author: Rahul Samana <rahul.samana@oss.qualcomm.com>
Bluetooth: qca: add QCC2072 support
Add QCC2072 as a supported Qualcomm Bluetooth controller.
> diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
> index 10c496eaea2c1..69427cc7eb5a9 100644
> --- a/drivers/bluetooth/btqca.c
> +++ b/drivers/bluetooth/btqca.c
[ ... ]
> @@ -614,6 +662,11 @@ static int qca_download_firmware(struct hci_dev *hdev,
> memcpy(data, fw->data, size);
> release_firmware(fw);
>
> + if (soc_type == QCA_QCC2072 && config->type == TLV_TYPE_NVM)
> + qca_combine_nvm_calib(hdev, &data, &size,
> + config->calib_name,
> + sizeof(config->calib_name));
> +
> ret = qca_tlv_check_data(hdev, config, data, size, soc_type);
[Severity: High]
Does this code handle custom firmware names properly?
In qca_uart_setup(), if the firmware-name device tree property is set, the
driver enters the if (firmware_name) branch:
if (firmware_name) {
/* The firmware name has an extension, use it directly */
if (qca_filename_has_extension(firmware_name)) {
When this path is taken, config.calib_name is never initialized. Then,
qca_download_firmware() unconditionally passes the empty string to
qca_combine_nvm_calib() for the QCC2072 controller.
This causes request_firmware() to fail with -EINVAL, logging a spurious error
and skipping the calibration data append.
Could we initialize config.calib_name when a custom firmware name is provided
via the device tree?
[ ... ]
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index 1222f97800f4a..6fe3aab688e64 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
[ ... ]
> @@ -1375,6 +1375,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
>
> /* Give the controller time to process the request */
> switch (qca_soc_type(hu)) {
> + case QCA_QCC2072:
> case QCA_WCN3950:
[Severity: High]
This is a pre-existing issue, but can this lead to a permanent task hang?
Just above this switch statement in qca_set_baudrate(), there is a polling
loop that checks the transmit queue:
while (!skb_queue_empty(&qca->txq))
usleep_range(100, 200);
This loop polls the transmit queue indefinitely without a bounding timeout.
If the UART hardware stops accepting bytes, for example due to stuck flow
control or a hardware crash, the queue is never emptied and the loop will spin
indefinitely.
Could a timeout mechanism be added here to prevent a task hang if the hardware
malfunctions?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723-rb3-industrial-bt-uart-v1-0-3c8e580c09d1@oss.qualcomm.com?part=1
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 3/3] arm64: dts: qcom: rb3gen2: add Industrial BT UART overlay
2026-07-23 12:31 ` [PATCH 3/3] arm64: dts: qcom: rb3gen2: add Industrial BT UART overlay Rahul Samana
@ 2026-07-23 12:49 ` sashiko-bot
0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-07-23 12:49 UTC (permalink / raw)
To: Rahul Samana; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Device Tree Overlay attempts to use `/delete-property/` which is not supported, resulting in schema validation errors.
--
--- Patch [3]: [PATCH 3/3] arm64: dts: qcom: rb3gen2: add Industrial BT UART overlay ---
commit 28aeca4684147ad8ef66aae33d88bd048694447b
Author: Rahul Samana <rahul.samana@oss.qualcomm.com>
arm64: dts: qcom: rb3gen2: add Industrial BT UART overlay
Add an overlay for the RB3 Gen 2 Industrial mezzanine variant that routes
QCC2072 Bluetooth over UART4 and models the M.2 E-key connector graph
endpoints for PCIe and UART. The overlay also disables the on-board WCN6750
PMU and UART7 path so the M.2 QCC2072 Bluetooth controller can be used instead.
> diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-industrial-mezzanine-bt-uart.dtso b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-industrial-mezzanine-bt-uart.dtso
> new file mode 100644
> index 0000000000000..06560df0a7192
> --- /dev/null
> +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-industrial-mezzanine-bt-uart.dtso
[ ... ]
> +&uart4 {
> + status = "okay";
> + /delete-property/ interrupts;
> + interrupts-extended = <&intc GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH>,
> + <&tlmm 19 IRQ_TYPE_EDGE_FALLING>;
[Severity: Medium]
Does this /delete-property/ directive get ignored by the device tree compiler
since it is inside an overlay file?
Because the FDT overlay format lacks a standard mechanism for property
deletions, dtc silently drops this directive when compiling the overlay.
As a result, both the original interrupts property and the new
interrupts-extended property will coexist in the uart4 node when the
overlay is applied.
Does this violate the device tree schema by having both interrupt properties
and cause validation errors during dtbs_check?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723-rb3-industrial-bt-uart-v1-0-3c8e580c09d1@oss.qualcomm.com?part=3
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-23 12:49 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-23 12:31 [PATCH 0/3] Bluetooth: qca: enable QCC2072 on RB3 Gen 2 Industrial Mezz reworked for BT over UART Rahul Samana
2026-07-23 12:31 ` [PATCH 1/3] Bluetooth: qca: add QCC2072 support Rahul Samana
2026-07-23 12:48 ` sashiko-bot
2026-07-23 12:31 ` [PATCH 2/3] arm64: dts: qcom: kodiak: mark PCIe root port as bridge Rahul Samana
2026-07-23 12:38 ` Konrad Dybcio
2026-07-23 12:31 ` [PATCH 3/3] arm64: dts: qcom: rb3gen2: add Industrial BT UART overlay Rahul Samana
2026-07-23 12:49 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox