[PATCH ath-next 1/2] wifi: ath12k: add AHB platform descriptor support

Aaradhana Sahu aaradhana.sahu at oss.qualcomm.com
Mon Jul 20 23:50:37 PDT 2026


AHB-based platforms associate each device with a userPD ID that determines
the firmware name and Peripheral Authentication Service ID (PASID) used
during firmware authentication.

Current implementation does not support platforms with multiple devices
sharing the same compatible string but using different userPD IDs.
As a result, the driver cannot uniquely identify each device for firmware
selection and authentication.

Add an AHB platform descriptor to store device-specific configuration.
Implement userPD ID resolution by matching device tree reg properties, with
node name matching as a fallback. Centralize platform configuration to
simplify the probe path by removing hardware-specific conditionals.

Tested-on: IPQ5332 hw1.0 AHB WLAN.WBE.1.6-01275-QCAHKSWPL_SILICONZ-1

Signed-off-by: Aaradhana Sahu <aaradhana.sahu at oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/ahb.c       |  4 +-
 drivers/net/wireless/ath/ath12k/ahb.h       | 19 +++++
 drivers/net/wireless/ath/ath12k/hw.h        |  1 -
 drivers/net/wireless/ath/ath12k/wifi7/ahb.c | 90 +++++++++++++++++----
 4 files changed, 94 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c
index 07bb83710b1f..14ee696960c7 100644
--- a/drivers/net/wireless/ath/ath12k/ahb.c
+++ b/drivers/net/wireless/ath/ath12k/ahb.c
@@ -704,7 +704,7 @@ static int ath12k_ahb_map_service_to_pipe(struct ath12k_base *ab, u16 service_id
 	return 0;
 }
 
-static const struct ath12k_hif_ops ath12k_ahb_hif_ops = {
+const struct ath12k_hif_ops ath12k_ahb_hif_ops = {
 	.start = ath12k_ahb_start,
 	.stop = ath12k_ahb_stop,
 	.read32 = ath12k_ahb_read32,
@@ -715,6 +715,7 @@ static const struct ath12k_hif_ops ath12k_ahb_hif_ops = {
 	.power_up = ath12k_ahb_power_up,
 	.power_down = ath12k_ahb_power_down,
 };
+EXPORT_SYMBOL(ath12k_ahb_hif_ops);
 
 static irqreturn_t ath12k_userpd_irq_handler(int irq, void *data)
 {
@@ -1038,7 +1039,6 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
 
 	ab_ahb = ath12k_ab_to_ahb(ab);
 	ab_ahb->ab = ab;
-	ab->hif.ops = &ath12k_ahb_hif_ops;
 	ab->pdev = pdev;
 	platform_set_drvdata(pdev, ab);
 
diff --git a/drivers/net/wireless/ath/ath12k/ahb.h b/drivers/net/wireless/ath/ath12k/ahb.h
index a153db6cf1d3..037347ccd21b 100644
--- a/drivers/net/wireless/ath/ath12k/ahb.h
+++ b/drivers/net/wireless/ath/ath12k/ahb.h
@@ -30,6 +30,24 @@
 #define ATH12K_USERPD_ID_MASK			GENMASK(10, 8)
 #define ATH12K_USERPD_FW_NAME_LEN		35
 
+enum ath12k_ahb_userpd_id {
+	ATH12K_AHB_USERPD_ID_0 = 1,
+	ATH12K_AHB_USERPD_ID_1,
+	ATH12K_AHB_USERPD_ID_2,
+};
+
+struct ath12k_ahb_userpd_map {
+	phys_addr_t io_start;
+	const char *node_name;
+	u32 upd_id;
+};
+
+struct ath12k_ahb_desc {
+	enum ath12k_hw_rev hw_rev;
+	bool auth_enabled;
+	const struct ath12k_hif_ops *ops;
+};
+
 enum ath12k_ahb_smp2p_msg_id {
 	ATH12K_AHB_POWER_SAVE_ENTER = 1,
 	ATH12K_AHB_POWER_SAVE_EXIT,
@@ -43,6 +61,7 @@ enum ath12k_ahb_userpd_irq {
 };
 
 struct ath12k_base;
+extern const struct ath12k_hif_ops ath12k_ahb_hif_ops;
 
 struct ath12k_ahb_device_family_ops {
 	int (*probe)(struct platform_device *pdev);
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index 49cfd5dfc70a..3ed38f8f2b48 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -100,7 +100,6 @@ struct ieee80211_rx_status;
 #define ATH12K_REGDB_FILE_NAME		"regdb.bin"
 
 #define ATH12K_PCIE_MAX_PAYLOAD_SIZE	128
-#define ATH12K_IPQ5332_USERPD_ID	1
 
 enum ath12k_hw_rate_cck {
 	ATH12K_HW_RATE_CCK_LP_11M = 0,
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/ahb.c b/drivers/net/wireless/ath/ath12k/wifi7/ahb.c
index 6a8b8b2a56f9..98a6606ffd76 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/ahb.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/ahb.c
@@ -15,44 +15,100 @@
 #include "dp.h"
 #include "core.h"
 
+/*
+ * Node name to UserPD ID mapping
+ *
+ * The io_start field is used for additional validation when the reg
+ * property is present in the device tree. If io_start is 0, only
+ * node_name matching is performed.
+ *
+ * For platforms where not all WiFi nodes have a 'reg' property, set
+ * io_start to 0 for those entries. The driver will match purely by
+ * node name in such cases.
+ */
+static const struct ath12k_ahb_userpd_map ath12k_wifi7_ahb_userpd_map[] = {
+	{ .io_start = 0x0c000000, .node_name = "wifi", .upd_id = ATH12K_AHB_USERPD_ID_0 },
+};
+
+static const struct ath12k_ahb_desc ath12k_wifi7_ahb_desc[] = {
+	[ATH12K_HW_IPQ5332_HW10] = {
+		.hw_rev = ATH12K_HW_IPQ5332_HW10,
+		.auth_enabled = true,
+		.ops = &ath12k_ahb_hif_ops,
+	},
+	[ATH12K_HW_IPQ5424_HW10] = {
+		.hw_rev = ATH12K_HW_IPQ5424_HW10,
+		.auth_enabled = false,
+		.ops = &ath12k_ahb_hif_ops,
+	},
+};
+
 static const struct of_device_id ath12k_wifi7_ahb_of_match[] = {
 	{ .compatible = "qcom,ipq5332-wifi",
-	  .data = (void *)ATH12K_HW_IPQ5332_HW10,
+	  .data = (void *)&ath12k_wifi7_ahb_desc[ATH12K_HW_IPQ5332_HW10],
 	},
 	{ .compatible = "qcom,ipq5424-wifi",
-	  .data = (void *)ATH12K_HW_IPQ5424_HW10,
+	  .data = (void *)&ath12k_wifi7_ahb_desc[ATH12K_HW_IPQ5424_HW10],
 	},
 	{ }
 };
 
 MODULE_DEVICE_TABLE(of, ath12k_wifi7_ahb_of_match);
 
+/*
+ * ath12k_wifi7_ahb_get_userpd_id - Resolve UserPD ID from DT properties
+ * @ab: ath12k base structure
+ *
+ * Returns: UserPD ID (1-based) on success, 0 on failure
+ *
+ * Resolution logic:
+ * 1. If reg property exist in DT, get userpd_id from io_start
+ * 2. If reg property is absent, get userpd_id from DT node name
+ * 3. Return 0 if no match found (probe will fail)
+ */
+static u32 ath12k_wifi7_ahb_get_userpd_id(struct ath12k_base *ab)
+{
+	const struct ath12k_ahb_userpd_map *map;
+	struct resource *res;
+	size_t i;
+
+	res = platform_get_resource(ab->pdev, IORESOURCE_MEM, 0);
+
+	for (i = 0; i < ARRAY_SIZE(ath12k_wifi7_ahb_userpd_map); i++) {
+		map = &ath12k_wifi7_ahb_userpd_map[i];
+
+		if (res) {
+			if (map->io_start && map->io_start == res->start)
+				return map->upd_id;
+		} else if (map->node_name &&
+			   of_node_name_eq(ab->dev->of_node, map->node_name)) {
+			return map->upd_id;
+		}
+	}
+
+	return 0;
+}
+
 static int ath12k_wifi7_ahb_probe(struct platform_device *pdev)
 {
+	const struct ath12k_ahb_desc *desc;
 	struct ath12k_ahb *ab_ahb;
-	enum ath12k_hw_rev hw_rev;
 	struct ath12k_base *ab;
 	int ret;
 
 	ab = platform_get_drvdata(pdev);
 	ab_ahb = ath12k_ab_to_ahb(ab);
-
-	hw_rev = (enum ath12k_hw_rev)(kernel_ulong_t)of_device_get_match_data(&pdev->dev);
-	switch (hw_rev) {
-	case ATH12K_HW_IPQ5332_HW10:
-		ab_ahb->userpd_id = ATH12K_IPQ5332_USERPD_ID;
-		ab_ahb->scm_auth_enabled = true;
-		break;
-	case ATH12K_HW_IPQ5424_HW10:
-		ab_ahb->userpd_id = ATH12K_IPQ5332_USERPD_ID;
-		ab_ahb->scm_auth_enabled = false;
-		break;
-	default:
+	desc = of_device_get_match_data(&pdev->dev);
+	if (!desc)
 		return -EOPNOTSUPP;
-	}
 
 	ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT;
-	ab->hw_rev = hw_rev;
+	ab->hw_rev = desc->hw_rev;
+	ab->hif.ops = desc->ops;
+	ab_ahb->scm_auth_enabled = desc->auth_enabled;
+	ab_ahb->userpd_id = ath12k_wifi7_ahb_get_userpd_id(ab);
+	if (!ab_ahb->userpd_id)
+		return -EOPNOTSUPP;
 
 	ret = ath12k_wifi7_hw_init(ab);
 	if (ret) {
-- 
2.34.1




More information about the ath12k mailing list