Devicetree
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Add Qualcomm CAMNOC ICC provider
@ 2026-08-19  9:32 Atanas Filipov
  2026-08-19  9:32 ` [PATCH v2 1/3] dt-bindings: interconnect: Add Qualcomm CAMNOC ICC binding Atanas Filipov
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Atanas Filipov @ 2026-08-19  9:32 UTC (permalink / raw)
  To: Georgi Djakov, linux-arm-msm, linux-pm
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree, linux-kernel, Dmitry Baryshkov,
	Gjorgji Rosikopulos

This series adds a device tree binding and driver for the Qualcomm
Camera Network-on-Chip (CAMNOC) interconnect provider for SM8250.

CAMNOC is the internal AXI interconnect within the camera subsystem.
Multiple camera sub-devices (IFE, JPEG, BPS, IPE, etc.) share
CAM_CC_CAMNOC_AXI_CLK. Direct clk_set_rate() calls from each consumer
cause a last-writer-wins race. This series introduces a lightweight ICC
provider that aggregates bandwidth votes from all consumers and applies
a single clk_set_rate() call.

Changes since v1:
- dt-bindings: add all SM8250 CAMNOC master port IDs to qcom,camnoc.h
  (IFE 0/1, IFE Lite 0-4, BPS, IPE 0/1, JPEG, JPEG DMA, CDM, FD, SBI,
  ICP) with a short comment per group (Dmitry Baryshkov)
- dt-bindings: add IFE simple consumer example alongside the JPEG
  OPP-based example; clarify opp-hz and opp-peak-kBps semantics in
  comments; fix maintainer email; align provider node name with DTS
- driver: register all SM8250 CAMNOC master nodes

Atanas Filipov (3):
  dt-bindings: interconnect: Add Qualcomm CAMNOC ICC binding
  interconnect: qcom: Add CAMNOC interconnect provider driver
  arm64: dts: qcom: sm8250: Add CAMNOC ICC provider node

 .../bindings/interconnect/qcom,camnoc.yaml    | 124 ++++++++
 arch/arm64/boot/dts/qcom/sm8250.dtsi          |   8 +
 drivers/interconnect/qcom/Kconfig             |  10 +
 drivers/interconnect/qcom/Makefile            |   2 +
 drivers/interconnect/qcom/qcom-camnoc.c       | 279 ++++++++++++++++++
 .../dt-bindings/interconnect/qcom,camnoc.h    |  52 ++++
 6 files changed, 475 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,camnoc.yaml
 create mode 100644 drivers/interconnect/qcom/qcom-camnoc.c
 create mode 100644 include/dt-bindings/interconnect/qcom,camnoc.h


base-commit: 9e970952a9503d6ab471a2fea4c10b6a2785406f
-- 
2.34.1


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

* [PATCH v2 1/3] dt-bindings: interconnect: Add Qualcomm CAMNOC ICC binding
  2026-08-19  9:32 [PATCH v2 0/3] Add Qualcomm CAMNOC ICC provider Atanas Filipov
@ 2026-08-19  9:32 ` Atanas Filipov
  2026-08-19  9:32 ` [PATCH v2 2/3] interconnect: qcom: Add CAMNOC interconnect provider driver Atanas Filipov
  2026-08-19  9:32 ` [PATCH v2 3/3] arm64: dts: qcom: sm8250: Add CAMNOC ICC provider node Atanas Filipov
  2 siblings, 0 replies; 5+ messages in thread
From: Atanas Filipov @ 2026-08-19  9:32 UTC (permalink / raw)
  To: Georgi Djakov, linux-arm-msm, linux-pm
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree, linux-kernel, Dmitry Baryshkov,
	Gjorgji Rosikopulos

Add binding for the Qualcomm CAMNOC interconnect provider. CAMNOC is
the internal AXI interconnect within the camera subsystem. Multiple
sub-devices share CAM_CC_CAMNOC_AXI_CLK; the ICC provider aggregates
their bandwidth votes and scales the clock accordingly, avoiding the
last-writer-wins race from direct clk_set_rate() calls.

Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
---
 .../bindings/interconnect/qcom,camnoc.yaml    | 124 ++++++++++++++++++
 .../dt-bindings/interconnect/qcom,camnoc.h    |  52 ++++++++
 2 files changed, 176 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,camnoc.yaml
 create mode 100644 include/dt-bindings/interconnect/qcom,camnoc.h

diff --git a/Documentation/devicetree/bindings/interconnect/qcom,camnoc.yaml b/Documentation/devicetree/bindings/interconnect/qcom,camnoc.yaml
new file mode 100644
index 000000000000..b2659db2cf27
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom,camnoc.yaml
@@ -0,0 +1,124 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/qcom,camnoc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Camera NOC (CAMNOC) Interconnect Provider
+
+maintainers:
+  - Atanas Filipov <atanas.filipov@oss.qualcomm.com>
+
+description:
+  The Camera Network-on-Chip (CAMNOC) is the internal AXI interconnect
+  within the Qualcomm camera subsystem. It arbitrates AXI bandwidth
+  between camera sub-devices (IFE, JPEG, BPS, IPE, etc.) and the external
+  memory interconnect. Multiple consumers may independently request
+  bandwidth via icc_set_bw(); the CAMNOC ICC provider aggregates all active
+  votes and scales CAM_CC_CAMNOC_AXI_CLK accordingly, avoiding the
+  last-writer-wins race that arises when each consumer calls clk_set_rate()
+  directly on the shared clock.
+
+  Each camera sub-device driver that shares the CAMNOC AXI clock should
+  obtain an ICC path from its master port to SLAVE_CAMNOC_AXI and vote for
+  bandwidth using the port IDs defined in
+  include/dt-bindings/interconnect/qcom,camnoc.h.
+
+properties:
+  compatible:
+    enum:
+      - qcom,sm8250-cam-virt
+
+  clocks:
+    items:
+      - description: CAMNOC AXI clock
+
+  clock-names:
+    items:
+      - const: camnoc_axi
+
+  '#interconnect-cells':
+    const: 1
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - '#interconnect-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,camcc-sm8250.h>
+    #include <dt-bindings/interconnect/qcom,camnoc.h>
+
+    /* CAMNOC ICC provider node */
+    cam_virt: interconnect-cam-virt {
+        compatible = "qcom,sm8250-cam-virt";
+        clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>;
+        clock-names = "camnoc_axi";
+        #interconnect-cells = <1>;
+    };
+
+    /*
+     * Simple consumer example: IFE sub-device voting for CAMNOC bandwidth
+     * directly via icc_set_bw().
+     */
+    camera-ife@0 {
+        reg = <0x0 0x1000>;
+
+        interconnects = <&cam_virt MASTER_CAMNOC_IFE_0
+                         &cam_virt SLAVE_CAMNOC_AXI>;
+        interconnect-names = "camnoc";
+    };
+
+    /*
+     * OPP-based consumer example: JPEG encoder driving its CAMNOC bandwidth
+     * vote from the same OPP entry that selects its core clock rate and
+     * RPMh performance state. opp-peak-kBps is the minimum CAMNOC bandwidth
+     * required at each operating point; the actual value depends on the
+     * target resolution and quality settings.
+     *
+     * opp-hz refers to the JPEG dedicated core clock rate. All shared
+     * clocks (e.g. CAMNOC AXI) are managed by the ICC framework so that
+     * votes from multiple consumers are aggregated before the rate is
+     * applied to the hardware.
+     */
+    camera-jpeg@ac53000 {
+        reg = <0x0ac53000 0x1000>;
+
+        interconnects = <&cam_virt MASTER_CAMNOC_JPEG
+                         &cam_virt SLAVE_CAMNOC_AXI>;
+        interconnect-names = "camnoc";
+
+        operating-points-v2 = <&jpeg_opp_table>;
+
+        jpeg_opp_table: opp-table {
+            compatible = "operating-points-v2";
+
+            opp-100000000 {
+                opp-hz = /bits/ 64 <100000000>;
+                opp-peak-kBps = <22246>;
+                required-opps = <&rpmhpd_opp_min_svs>;
+            };
+
+            opp-200000000 {
+                opp-hz = /bits/ 64 <200000000>;
+                opp-peak-kBps = <44492>;
+                required-opps = <&rpmhpd_opp_low_svs>;
+            };
+
+            opp-400000000 {
+                opp-hz = /bits/ 64 <400000000>;
+                opp-peak-kBps = <88983>;
+                required-opps = <&rpmhpd_opp_svs>;
+            };
+
+            opp-480000000 {
+                opp-hz = /bits/ 64 <480000000>;
+                opp-peak-kBps = <106780>;
+                required-opps = <&rpmhpd_opp_svs_l1>;
+            };
+        };
+    };
diff --git a/include/dt-bindings/interconnect/qcom,camnoc.h b/include/dt-bindings/interconnect/qcom,camnoc.h
new file mode 100644
index 000000000000..9b6468f852ec
--- /dev/null
+++ b/include/dt-bindings/interconnect/qcom,camnoc.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_CAMNOC_H
+#define __DT_BINDINGS_INTERCONNECT_QCOM_CAMNOC_H
+
+/*
+ * CAMNOC master port IDs for SM8250 (Kona).
+ * Each ID identifies a camera sub-device that can vote for CAMNOC AXI
+ * bandwidth via icc_set_bw().  Only ports wired on this SoC are listed.
+ */
+
+/* Image Front End */
+#define MASTER_CAMNOC_IFE_0		0
+#define MASTER_CAMNOC_IFE_0_RDI		1
+#define MASTER_CAMNOC_IFE_1		2
+#define MASTER_CAMNOC_IFE_1_RDI		3
+#define MASTER_CAMNOC_IFE_LITE_0	4
+#define MASTER_CAMNOC_IFE_LITE_1	5
+#define MASTER_CAMNOC_IFE_LITE_2	6
+#define MASTER_CAMNOC_IFE_LITE_3	7
+#define MASTER_CAMNOC_IFE_LITE_4	8
+
+/* Bayer Processing Segment */
+#define MASTER_CAMNOC_BPS		9
+
+/* Image Processing Engine */
+#define MASTER_CAMNOC_IPE_0		10
+#define MASTER_CAMNOC_IPE_1		11
+
+/* JPEG encoder and DMA */
+#define MASTER_CAMNOC_JPEG		12
+#define MASTER_CAMNOC_JPEG_DMA		13
+
+/* Camera Data Mover */
+#define MASTER_CAMNOC_CDM		14
+
+/* Face Detection */
+#define MASTER_CAMNOC_FD		15
+
+/* Sensor Bayer Interface */
+#define MASTER_CAMNOC_SBI		16
+
+/* Image Control Processor */
+#define MASTER_CAMNOC_ICP		17
+
+/* CAMNOC AXI slave (single exit point to external interconnect) */
+#define SLAVE_CAMNOC_AXI		18
+
+#endif /* __DT_BINDINGS_INTERCONNECT_QCOM_CAMNOC_H */
-- 
2.34.1


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

* [PATCH v2 2/3] interconnect: qcom: Add CAMNOC interconnect provider driver
  2026-08-19  9:32 [PATCH v2 0/3] Add Qualcomm CAMNOC ICC provider Atanas Filipov
  2026-08-19  9:32 ` [PATCH v2 1/3] dt-bindings: interconnect: Add Qualcomm CAMNOC ICC binding Atanas Filipov
@ 2026-08-19  9:32 ` Atanas Filipov
  2026-08-19  9:41   ` sashiko-bot
  2026-08-19  9:32 ` [PATCH v2 3/3] arm64: dts: qcom: sm8250: Add CAMNOC ICC provider node Atanas Filipov
  2 siblings, 1 reply; 5+ messages in thread
From: Atanas Filipov @ 2026-08-19  9:32 UTC (permalink / raw)
  To: Georgi Djakov, linux-arm-msm, linux-pm
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree, linux-kernel, Dmitry Baryshkov,
	Gjorgji Rosikopulos

Add an ICC provider for the Qualcomm Camera NOC (CAMNOC). Multiple
camera sub-devices share CAM_CC_CAMNOC_AXI_CLK; direct clk_set_rate()
calls from each consumer cause a last-writer-wins race.

Each consumer obtains an ICC path to SLAVE_CAMNOC_AXI and votes via
icc_set_bw(). The ICC core aggregates votes (max peak_bw) and the
set() callback converts the result to clk_set_rate(). Consumers
encode the required frequency as peak_bw in kBps.

Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
---
 drivers/interconnect/qcom/Kconfig       |  10 +
 drivers/interconnect/qcom/Makefile      |   2 +
 drivers/interconnect/qcom/qcom-camnoc.c | 279 ++++++++++++++++++++++++
 3 files changed, 291 insertions(+)
 create mode 100644 drivers/interconnect/qcom/qcom-camnoc.c

diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
index 5b8a094ca4ed..9d9d238019a0 100644
--- a/drivers/interconnect/qcom/Kconfig
+++ b/drivers/interconnect/qcom/Kconfig
@@ -135,6 +135,16 @@ config INTERCONNECT_QCOM_NORD
 	  the RPMh hardware and communicates via Bus Clock Manager (BCM)
 	  through the Resource State Coordinator (RSC).
 
+config INTERCONNECT_QCOM_CAMNOC
+	tristate "Qualcomm CAMNOC interconnect driver"
+	depends on INTERCONNECT_QCOM || COMPILE_TEST
+	depends on ARM64 || COMPILE_TEST
+	help
+	  Say y here to support the Camera Network-on-Chip (CAMNOC)
+	  interconnect driver for Qualcomm SoCs. It aggregates bandwidth
+	  requests from camera sub-devices (IFE, JPEG, BPS, etc.) and
+	  scales CAM_CC_CAMNOC_AXI_CLK accordingly.
+
 config INTERCONNECT_QCOM_OSM_L3
 	tristate "Qualcomm OSM L3 interconnect driver"
 	depends on INTERCONNECT_QCOM || COMPILE_TEST
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
index 1c7d410b40cc..52a5998ae6a8 100644
--- a/drivers/interconnect/qcom/Makefile
+++ b/drivers/interconnect/qcom/Makefile
@@ -18,6 +18,7 @@ qnoc-msm8974-objs			:= msm8974.o
 qnoc-msm8976-objs			:= msm8976.o
 qnoc-msm8996-objs			:= msm8996.o
 qnoc-nord-objs				:= nord.o
+icc-camnoc-objs				:= qcom-camnoc.o
 icc-osm-l3-objs				:= osm-l3.o
 qnoc-qcm2290-objs			:= qcm2290.o
 qnoc-qcs404-objs			:= qcs404.o
@@ -66,6 +67,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8976) += qnoc-msm8976.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) += qnoc-msm8996.o
 obj-$(CONFIG_INTERCONNECT_QCOM_NORD) += qnoc-nord.o
+obj-$(CONFIG_INTERCONNECT_QCOM_CAMNOC) += icc-camnoc.o
 obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o
 obj-$(CONFIG_INTERCONNECT_QCOM_QCM2290) += qnoc-qcm2290.o
 obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o
diff --git a/drivers/interconnect/qcom/qcom-camnoc.c b/drivers/interconnect/qcom/qcom-camnoc.c
new file mode 100644
index 000000000000..9a703b052b2d
--- /dev/null
+++ b/drivers/interconnect/qcom/qcom-camnoc.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * Qualcomm Camera NOC (CAMNOC) interconnect provider.
+ *
+ * CAMNOC is the internal AXI interconnect within the Qualcomm camera
+ * subsystem. Multiple camera sub-devices (IFE, JPEG, BPS, etc.) share
+ * CAM_CC_CAMNOC_AXI_CLK. This driver acts as an ICC provider so that
+ * each sub-device can independently vote for bandwidth; the ICC core
+ * aggregates the votes (max of peak_bw across all consumers) and this
+ * driver translates the result into a clk_set_rate() call, avoiding
+ * the last-writer-wins race that occurs with direct clk_set_rate().
+ *
+ * Consumers express their required clock rate directly as peak_bw in
+ * kBps (e.g. 400000 for 400 MHz).  The driver converts kBps → Hz:
+ *   rate_hz = peak_bw_kBps * 1000
+ */
+
+#include <linux/clk.h>
+#include <linux/interconnect-provider.h>
+#include <linux/interconnect.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <dt-bindings/interconnect/qcom,camnoc.h>
+
+#define to_camnoc_provider(_p) \
+	container_of(_p, struct qcom_camnoc_icc_provider, provider)
+
+struct qcom_camnoc_icc_provider {
+	struct clk *clk;
+	struct icc_provider provider;
+};
+
+struct qcom_camnoc_node {
+	const char *name;
+	u16 buswidth;
+};
+
+/* IFE */
+static const struct qcom_camnoc_node camnoc_master_ife_0 = {
+	.name = "master-camnoc-ife-0", .buswidth = 16
+};
+
+static const struct qcom_camnoc_node camnoc_master_ife_0_rdi = {
+	.name = "master-camnoc-ife-0-rdi", .buswidth = 16
+};
+
+static const struct qcom_camnoc_node camnoc_master_ife_1 = {
+	.name = "master-camnoc-ife-1", .buswidth = 16
+};
+
+static const struct qcom_camnoc_node camnoc_master_ife_1_rdi = {
+	.name = "master-camnoc-ife-1-rdi", .buswidth = 16
+};
+
+static const struct qcom_camnoc_node camnoc_master_ife_lite_0 = {
+	.name = "master-camnoc-ife-lite-0", .buswidth = 8
+};
+
+static const struct qcom_camnoc_node camnoc_master_ife_lite_1 = {
+	.name = "master-camnoc-ife-lite-1", .buswidth = 8
+};
+
+static const struct qcom_camnoc_node camnoc_master_ife_lite_2 = {
+	.name = "master-camnoc-ife-lite-2", .buswidth = 8
+};
+
+static const struct qcom_camnoc_node camnoc_master_ife_lite_3 = {
+	.name = "master-camnoc-ife-lite-3", .buswidth = 8
+};
+
+static const struct qcom_camnoc_node camnoc_master_ife_lite_4 = {
+	.name = "master-camnoc-ife-lite-4", .buswidth = 8
+};
+
+/* BPS */
+static const struct qcom_camnoc_node camnoc_master_bps = {
+	.name = "master-camnoc-bps", .buswidth = 16
+};
+
+/* IPE */
+static const struct qcom_camnoc_node camnoc_master_ipe_0 = {
+	.name = "master-camnoc-ipe-0", .buswidth = 16
+};
+
+static const struct qcom_camnoc_node camnoc_master_ipe_1 = {
+	.name = "master-camnoc-ipe-1", .buswidth = 16
+};
+
+/* JPEG */
+static const struct qcom_camnoc_node camnoc_master_jpeg = {
+	.name = "master-camnoc-jpeg", .buswidth = 16
+};
+
+static const struct qcom_camnoc_node camnoc_master_jpeg_dma = {
+	.name = "master-camnoc-jpeg-dma", .buswidth = 16
+};
+
+/* CDM */
+static const struct qcom_camnoc_node camnoc_master_cdm = {
+	.name = "master-camnoc-cdm", .buswidth = 4
+};
+
+/* FD */
+static const struct qcom_camnoc_node camnoc_master_fd = {
+	.name = "master-camnoc-fd", .buswidth = 16
+};
+
+/* SBI */
+static const struct qcom_camnoc_node camnoc_master_sbi = {
+	.name = "master-camnoc-sbi", .buswidth = 16
+};
+
+/* ICP */
+static const struct qcom_camnoc_node camnoc_master_icp = {
+	.name = "master-camnoc-icp", .buswidth = 8
+};
+
+/* Slave */
+static const struct qcom_camnoc_node camnoc_slave_axi = {
+	.name = "slave-camnoc-axi", .buswidth = 32
+};
+
+static const struct qcom_camnoc_node * const camnoc_nodes[] = {
+	[MASTER_CAMNOC_IFE_0]      = &camnoc_master_ife_0,
+	[MASTER_CAMNOC_IFE_0_RDI]  = &camnoc_master_ife_0_rdi,
+	[MASTER_CAMNOC_IFE_1]      = &camnoc_master_ife_1,
+	[MASTER_CAMNOC_IFE_1_RDI]  = &camnoc_master_ife_1_rdi,
+	[MASTER_CAMNOC_IFE_LITE_0] = &camnoc_master_ife_lite_0,
+	[MASTER_CAMNOC_IFE_LITE_1] = &camnoc_master_ife_lite_1,
+	[MASTER_CAMNOC_IFE_LITE_2] = &camnoc_master_ife_lite_2,
+	[MASTER_CAMNOC_IFE_LITE_3] = &camnoc_master_ife_lite_3,
+	[MASTER_CAMNOC_IFE_LITE_4] = &camnoc_master_ife_lite_4,
+	[MASTER_CAMNOC_BPS]        = &camnoc_master_bps,
+	[MASTER_CAMNOC_IPE_0]      = &camnoc_master_ipe_0,
+	[MASTER_CAMNOC_IPE_1]      = &camnoc_master_ipe_1,
+	[MASTER_CAMNOC_JPEG]       = &camnoc_master_jpeg,
+	[MASTER_CAMNOC_JPEG_DMA]   = &camnoc_master_jpeg_dma,
+	[MASTER_CAMNOC_CDM]        = &camnoc_master_cdm,
+	[MASTER_CAMNOC_FD]         = &camnoc_master_fd,
+	[MASTER_CAMNOC_SBI]        = &camnoc_master_sbi,
+	[MASTER_CAMNOC_ICP]        = &camnoc_master_icp,
+	[SLAVE_CAMNOC_AXI]         = &camnoc_slave_axi,
+};
+
+#define CAMNOC_NUM_NODES	ARRAY_SIZE(camnoc_nodes)
+
+static int qcom_camnoc_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
+{
+	*avg = 0;
+	*peak = 0;
+
+	return 0;
+}
+
+static int qcom_camnoc_set(struct icc_node *src, struct icc_node *dst)
+{
+	struct qcom_camnoc_icc_provider *cp =
+		to_camnoc_provider(src->provider);
+	unsigned long rate;
+
+	/*
+	 * peak_bw is the aggregated max across all consumers (kBps).
+	 * Consumers encode the required clock frequency directly as kBps,
+	 * so the conversion is simply: rate_hz = peak_bw * 1000.
+	 * A vote of 0 means no requirement; leave the clock at its minimum.
+	 */
+	rate = icc_units_to_bps(dst->peak_bw);
+
+	return clk_set_rate(cp->clk, rate);
+}
+
+static void qcom_camnoc_remove(struct platform_device *pdev)
+{
+	struct qcom_camnoc_icc_provider *cp = platform_get_drvdata(pdev);
+
+	icc_provider_deregister(&cp->provider);
+	icc_nodes_remove(&cp->provider);
+}
+
+static int qcom_camnoc_probe(struct platform_device *pdev)
+{
+	struct qcom_camnoc_icc_provider *cp;
+	struct icc_onecell_data *data;
+	struct icc_provider *provider;
+	struct icc_node *node;
+	unsigned int i;
+	int ret;
+
+	cp = devm_kzalloc(&pdev->dev, sizeof(*cp), GFP_KERNEL);
+	if (!cp)
+		return -ENOMEM;
+
+	cp->clk = devm_clk_get(&pdev->dev, "camnoc_axi");
+	if (IS_ERR(cp->clk))
+		return dev_err_probe(&pdev->dev, PTR_ERR(cp->clk),
+				     "failed to get camnoc_axi clock\n");
+
+	data = devm_kzalloc(&pdev->dev,
+			    struct_size(data, nodes, CAMNOC_NUM_NODES),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->num_nodes = CAMNOC_NUM_NODES;
+
+	provider = &cp->provider;
+	provider->dev = &pdev->dev;
+	provider->get_bw = qcom_camnoc_get_bw;
+	provider->set = qcom_camnoc_set;
+	provider->aggregate = icc_std_aggregate;
+	provider->xlate = of_icc_xlate_onecell;
+	provider->data = data;
+
+	icc_provider_init(provider);
+
+	for (i = 0; i < CAMNOC_NUM_NODES; i++) {
+		node = icc_node_create_dyn();
+		if (IS_ERR(node)) {
+			ret = PTR_ERR(node);
+			goto err_remove;
+		}
+
+		ret = icc_node_set_name(node, provider, camnoc_nodes[i]->name);
+		if (ret) {
+			icc_node_destroy(node->id);
+			goto err_remove;
+		}
+
+		node->data = (void *)camnoc_nodes[i];
+		icc_node_add(node, provider);
+		data->nodes[i] = node;
+	}
+
+	/* Link every master to the single CAMNOC AXI slave. */
+	for (i = 0; i < CAMNOC_NUM_NODES - 1; i++) {
+		if (camnoc_nodes[i] == &camnoc_slave_axi)
+			continue;
+		ret = icc_link_nodes(data->nodes[i],
+				     &data->nodes[SLAVE_CAMNOC_AXI]);
+		if (ret)
+			goto err_remove;
+	}
+
+	ret = icc_provider_register(provider);
+	if (ret)
+		goto err_remove;
+
+	platform_set_drvdata(pdev, cp);
+
+	return 0;
+
+err_remove:
+	icc_nodes_remove(provider);
+	return ret;
+}
+
+static const struct of_device_id qcom_camnoc_of_match[] = {
+	{ .compatible = "qcom,sm8250-cam-virt" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, qcom_camnoc_of_match);
+
+static struct platform_driver qcom_camnoc_driver = {
+	.probe  = qcom_camnoc_probe,
+	.remove = qcom_camnoc_remove,
+	.driver = {
+		.name           = "qcom-camnoc-icc",
+		.of_match_table = qcom_camnoc_of_match,
+		.sync_state     = icc_sync_state,
+	},
+};
+module_platform_driver(qcom_camnoc_driver);
+
+MODULE_DESCRIPTION("Qualcomm CAMNOC interconnect driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1


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

* [PATCH v2 3/3] arm64: dts: qcom: sm8250: Add CAMNOC ICC provider node
  2026-08-19  9:32 [PATCH v2 0/3] Add Qualcomm CAMNOC ICC provider Atanas Filipov
  2026-08-19  9:32 ` [PATCH v2 1/3] dt-bindings: interconnect: Add Qualcomm CAMNOC ICC binding Atanas Filipov
  2026-08-19  9:32 ` [PATCH v2 2/3] interconnect: qcom: Add CAMNOC interconnect provider driver Atanas Filipov
@ 2026-08-19  9:32 ` Atanas Filipov
  2 siblings, 0 replies; 5+ messages in thread
From: Atanas Filipov @ 2026-08-19  9:32 UTC (permalink / raw)
  To: Georgi Djakov, linux-arm-msm, linux-pm
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree, linux-kernel, Dmitry Baryshkov,
	Gjorgji Rosikopulos

Add the cam_virt CAMNOC ICC provider node alongside the other virtual
interconnect nodes in the SM8250 DTSI.

Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/sm8250.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi
index 7076720413ab..33535c83a4d9 100644
--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi
@@ -11,6 +11,7 @@
 #include <dt-bindings/clock/qcom,rpmh.h>
 #include <dt-bindings/dma/qcom-gpi.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interconnect/qcom,camnoc.h>
 #include <dt-bindings/interconnect/qcom,osm-l3.h>
 #include <dt-bindings/interconnect/qcom,sm8250.h>
 #include <dt-bindings/mailbox/qcom-ipcc.h>
@@ -377,6 +378,13 @@ qup_virt: interconnect-qup-virt {
 		qcom,bcm-voters = <&apps_bcm_voter>;
 	};
 
+	cam_virt: interconnect-cam-virt {
+		compatible = "qcom,sm8250-cam-virt";
+		clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>;
+		clock-names = "camnoc_axi";
+		#interconnect-cells = <1>;
+	};
+
 	cpu0_opp_table: opp-table-cpu0 {
 		compatible = "operating-points-v2";
 		opp-shared;
-- 
2.34.1


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

* Re: [PATCH v2 2/3] interconnect: qcom: Add CAMNOC interconnect provider driver
  2026-08-19  9:32 ` [PATCH v2 2/3] interconnect: qcom: Add CAMNOC interconnect provider driver Atanas Filipov
@ 2026-08-19  9:41   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-08-19  9:41 UTC (permalink / raw)
  To: Atanas Filipov; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Low] Off-by-one error and dead code in interconnect node linking loop condition.
- [Low] The `buswidth` field in `struct qcom_camnoc_node` is initialized for all nodes but never used.
--

--- Patch [2]: [PATCH v2 2/3] interconnect: qcom: Add CAMNOC interconnect provider driver ---
commit 2b98e7c9cd72541b2414334c311ac7fd888628a6
Author: Atanas Filipov <atanas.filipov@oss.qualcomm.com>

interconnect: qcom: Add CAMNOC interconnect provider driver

This commit adds an interconnect provider for the Qualcomm Camera NOC (CAMNOC).
It aggregates bandwidth requests from camera sub-devices and translates them
into clock rate updates, resolving a last-writer-wins race condition from
direct clock manipulation.

> diff --git a/drivers/interconnect/qcom/qcom-camnoc.c b/drivers/interconnect/qcom/qcom-camnoc.c
> new file mode 100644
> index 0000000000000..9a703b052b2dd
> --- /dev/null
> +++ b/drivers/interconnect/qcom/qcom-camnoc.c

[ ... ]

> +struct qcom_camnoc_icc_provider {
> +	struct clk *clk;
> +	struct icc_provider provider;
> +};
> +
> +struct qcom_camnoc_node {
> +	const char *name;
> +	u16 buswidth;
> +};

[Severity: Low]
This isn't a bug, but the buswidth field is populated for all nodes but never
used. Could it be removed to simplify the code, since the driver directly
treats the requested peak_bw as a frequency vote?

[ ... ]

> +	/* Link every master to the single CAMNOC AXI slave. */
> +	for (i = 0; i < CAMNOC_NUM_NODES - 1; i++) {
> +		if (camnoc_nodes[i] == &camnoc_slave_axi)
> +			continue;
> +		ret = icc_link_nodes(data->nodes[i],
> +				     &data->nodes[SLAVE_CAMNOC_AXI]);
> +		if (ret)
> +			goto err_remove;
> +	}

[Severity: Low]
Does this loop condition unintentionally skip the last node, making the
camnoc_slave_axi check dead code?

Because the loop stops at CAMNOC_NUM_NODES - 2, it will never evaluate the
last element. Since camnoc_slave_axi happens to be the last node in the
array, the code works correctly now, but if the array is reordered or new
nodes are added after the slave, this logic could silently fail to link the
nodes.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260819093211.1436275-1-atanas.filipov@oss.qualcomm.com?part=2

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

end of thread, other threads:[~2026-08-19  9:41 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-19  9:32 [PATCH v2 0/3] Add Qualcomm CAMNOC ICC provider Atanas Filipov
2026-08-19  9:32 ` [PATCH v2 1/3] dt-bindings: interconnect: Add Qualcomm CAMNOC ICC binding Atanas Filipov
2026-08-19  9:32 ` [PATCH v2 2/3] interconnect: qcom: Add CAMNOC interconnect provider driver Atanas Filipov
2026-08-19  9:41   ` sashiko-bot
2026-08-19  9:32 ` [PATCH v2 3/3] arm64: dts: qcom: sm8250: Add CAMNOC ICC provider node Atanas Filipov

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