Skip to contentSkip to conversation

interconnect: qcom: add MSM8x60 (MSM8660/APQ8060) NoC driver

PATCH In review Herman van Hazendonk 4 participants 7 messages Jun 3

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover interconnect: qcom: add MSM8x60 (MSM8660/APQ8060) NoC driver

Add interconnect support for the MSM8x60 family (MSM8260, MSM8660, APQ8060) — Qualcomm's Scorpion dual-core SoC generation used in devices like the HP TouchPad, HTC EVO 3D and HTC Sensation.

The chip's Network-on-Chip fabric is divided into four sub-fabrics:

AFAB - Applications fabric: Scorpion CPU + L2 cache, paths to EBI SFAB - System fabric: DMA engines, SPS, USB HS, LPASS, MSS MMFAB - Multimedia fabric: MDP, GPU, camera (VFE/JPEG), video codec DFAB - Daytona fabric: eMMC/SD (SDC), ADM DMA, USB voter

Bandwidth requests are committed to the RPM firmware via its shared-memory arbitration tables using the qcom-rpm driver backend; each fabric also has a bus clock whose rate is derived from the aggregated bandwidth.

The driver includes a 384 MHz bus clock floor, replacing the previous 266 MHz minimum that caused USB starvation on real hardware, and careful devm/device_link lifecycle to handle EPROBE_DEFER from both RPM and clock lookups without leaking clock prepare/enable references.

Herman van Hazendonk (2):
dt-bindings: interconnect: qcom: add msm8660 fabric IDs
interconnect: qcom: add MSM8x60 NoC driver

 drivers/interconnect/qcom/Kconfig             |   14 +
 drivers/interconnect/qcom/Makefile            |    2 +
 drivers/interconnect/qcom/msm8660.c           | 1147 +++++++++++++++++
 .../dt-bindings/interconnect/qcom,msm8660.h   |  156 +++
 4 files changed, 1319 insertions(+)
 create mode 100644 drivers/interconnect/qcom/msm8660.c
 create mode 100644 include/dt-bindings/interconnect/qcom,msm8660.h

base-commit: 944125b4c454b58d2fe6e35f1087a932b2050dff

Signature · 1 line
2.43.0
#1 lore raw

PATCH 1/2 dt-bindings: interconnect: qcom: add msm8660 fabric IDs

Add the dt-binding interconnect master/slave ID header for the MSM8x60 family (MSM8260/MSM8660/APQ8060) fabric mesh. The chip's NoC fabric is split into multiple sub-fabrics that the qnoc-msm8660 driver models:

AFAB - Applications fabric (Scorpion CPU + L2) SFAB - System fabric (DMA, SPS, security)
MMFAB - Multimedia fabric (MDP, GPU, camera, video, rotator)

  DFAB  - Daytona fabric (SDC, ADM master/slave)
  SFPB  - System Fast Peripheral Bridge (RPM, MPM, PMIC SSBI)
  CFPB  - CPU Subsystem Fast Peripheral Bus (GSBI UART/QUP, USB FS,

TSIF, TSSC, PDM, PRNG)

IDs derived from the legacy vendor msm_bus_board_8660.c master/slave enums, normalised to the upstream interconnect-framework naming.

---
 .../dt-bindings/interconnect/qcom,msm8660.h   | 156 ++++++++++++++++++
 1 file changed, 156 insertions(+)
 create mode 100644 include/dt-bindings/interconnect/qcom,msm8660.h
include/dt-bindings/interconnect/qcom,msm8660.h new file +156 -0
new file mode 100644
index 000000000000..c9ce3f5a5276
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Qualcomm MSM8x60 family (MSM8260/MSM8660/APQ8060) interconnect IDs
+ *
+ * Copyright (c) 2026 Herman van Hazendonk <[email protected]>
+ *
+ * Based on webOS kernel msm_bus_board_8660.c
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ */
+
+#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_MSM8660_H
+#define __DT_BINDINGS_INTERCONNECT_QCOM_MSM8660_H
+
+/*
+ * MSM8x60 has a fabric-based bus architecture:
+ * - APPSS Fabric: CPU and memory interface
+ * - System Fabric: System peripherals and DMA
+ * - MMSS Fabric: Multimedia subsystem (display, camera, video)
+ * - Daytona Fabric: Peripheral bus (SDCC, ADM DMA)
+ * - System FPB: System Fast Peripheral Bus
+ * - CPSS FPB: CPU Subsystem Fast Peripheral Bus
+ */
+
+/* APPSS Fabric - Apps processor fabric */
+#define AFAB_MAS_AMPSS_M0		0
+#define AFAB_MAS_AMPSS_M1		1
+#define AFAB_SLV_EBI_CH0		2
+#define AFAB_SLV_AMPSS_L2		3
+#define AFAB_TO_MMSS			4
+#define AFAB_TO_SYSTEM			5
+
+/* System Fabric - System bus */
+#define SFAB_MAS_APPSS			0
+#define SFAB_MAS_SPS			1
+#define SFAB_MAS_ADM0_PORT0		2
+#define SFAB_MAS_ADM0_PORT1		3
+#define SFAB_MAS_ADM1_PORT0		4
+#define SFAB_MAS_ADM1_PORT1		5
+#define SFAB_MAS_LPASS_PROC		6
+#define SFAB_MAS_MSS_PROCI		7
+#define SFAB_MAS_MSS_PROCD		8
+#define SFAB_MAS_MSS_MDM_PORT0		9
+#define SFAB_MAS_LPASS			10
+#define SFAB_MAS_MMSS_FPB		11
+#define SFAB_MAS_ADM1_CI		12
+#define SFAB_MAS_ADM0_CI		13
+#define SFAB_MAS_MSS_MDM_PORT1		14
+#define SFAB_MAS_USB_HS			15
+#define SFAB_TO_APPSS			16
+#define SFAB_TO_SYSTEM_FPB		17
+#define SFAB_TO_CPSS_FPB		18
+#define SFAB_SLV_SPS			19
+#define SFAB_SLV_SYSTEM_IMEM		20
+#define SFAB_SLV_AMPSS			21
+#define SFAB_SLV_MSS			22
+#define SFAB_SLV_LPASS			23
+#define SFAB_SLV_MMSS_FPB		24
+#define SFAB_TO_DFAB			25
+
+/* MMSS Fabric - Multimedia subsystem */
+#define MMFAB_MAS_MDP_PORT0		0
+#define MMFAB_MAS_MDP_PORT1		1
+#define MMFAB_MAS_ADM1_PORT0		2
+#define MMFAB_MAS_ROTATOR		3
+#define MMFAB_MAS_GRAPHICS_3D		4
+#define MMFAB_MAS_JPEG_DEC		5
+#define MMFAB_MAS_GRAPHICS_2D_CORE0	6
+#define MMFAB_MAS_VFE			7
+#define MMFAB_MAS_VPE			8
+#define MMFAB_MAS_JPEG_ENC		9
+#define MMFAB_MAS_GRAPHICS_2D_CORE1	10
+#define MMFAB_MAS_HD_CODEC_PORT0	11
+#define MMFAB_MAS_HD_CODEC_PORT1	12
+#define MMFAB_TO_APPSS			13
+#define MMFAB_SLV_SMI			14
+#define MMFAB_SLV_MM_IMEM		15
+
+/*
+ * Daytona Fabric (DFAB) - Peripheral bus
+ *
+ * DFAB connects slower peripherals (SDCC, ADM DMA) to the system fabric.
+ * The webOS kernel managed DFAB bandwidth via voter clocks (dfab_sdc*_clk,
+ * dfab_usb_hs_clk). In mainline, this is handled by the interconnect framework.
+ *
+ * USB HS is included as a DFAB voter for compatibility with the legacy clock
+ * voting mechanism. The webOS kernel comment said: "if usb link is in sps
+ * there is no need for usb pclk as daytona fabric clock will be used instead".
+ * This keeps DFAB clock stable when USB is active.
+ */
+#define DFAB_MAS_SDC1			0
+#define DFAB_MAS_SDC2			1
+#define DFAB_MAS_SDC3			2
+#define DFAB_MAS_SDC4			3
+#define DFAB_MAS_SDC5			4
+#define DFAB_MAS_ADM0_MASTER		5
+#define DFAB_MAS_ADM1_MASTER		6
+#define DFAB_TO_SFAB			7
+#define DFAB_SLV_SDC1			8
+#define DFAB_SLV_SDC2			9
+#define DFAB_SLV_SDC3			10
+#define DFAB_SLV_SDC4			11
+#define DFAB_SLV_SDC5			12
+#define DFAB_MAS_USB_HS			13
+#define DFAB_MAS_DSPS			14
+
+/* System FPB - Slow peripheral bus for system */
+#define SFPB_MAS_SYSTEM			0
+#define SFPB_MAS_SPDM			1
+#define SFPB_MAS_RPM			2
+#define SFPB_SLV_SPDM			3
+#define SFPB_SLV_RPM			4
+#define SFPB_SLV_RPM_MSG_RAM		5
+#define SFPB_SLV_MPM			6
+#define SFPB_SLV_PMIC1_SSBI1_A		7
+#define SFPB_SLV_PMIC1_SSBI1_B		8
+#define SFPB_SLV_PMIC1_SSBI1_C		9
+#define SFPB_SLV_PMIC2_SSBI2_A		10
+#define SFPB_SLV_PMIC2_SSBI2_B		11
+
+/* CPSS FPB - CPU subsystem fast peripheral bus */
+#define CFPB_MAS_SYSTEM			0
+#define CFPB_SLV_GSBI1_UART		1
+#define CFPB_SLV_GSBI2_UART		2
+#define CFPB_SLV_GSBI3_UART		3
+#define CFPB_SLV_GSBI4_UART		4
+#define CFPB_SLV_GSBI5_UART		5
+#define CFPB_SLV_GSBI6_UART		6
+#define CFPB_SLV_GSBI7_UART		7
+#define CFPB_SLV_GSBI8_UART		8
+#define CFPB_SLV_GSBI9_UART		9
+#define CFPB_SLV_GSBI10_UART		10
+#define CFPB_SLV_GSBI11_UART		11
+#define CFPB_SLV_GSBI12_UART		12
+#define CFPB_SLV_GSBI1_QUP		13
+#define CFPB_SLV_GSBI2_QUP		14
+#define CFPB_SLV_GSBI3_QUP		15
+#define CFPB_SLV_GSBI4_QUP		16
+#define CFPB_SLV_GSBI5_QUP		17
+#define CFPB_SLV_GSBI6_QUP		18
+#define CFPB_SLV_GSBI7_QUP		19
+#define CFPB_SLV_GSBI8_QUP		20
+#define CFPB_SLV_GSBI9_QUP		21
+#define CFPB_SLV_GSBI10_QUP		22
+#define CFPB_SLV_GSBI11_QUP		23
+#define CFPB_SLV_GSBI12_QUP		24
+#define CFPB_SLV_EBI2_NAND		25
+#define CFPB_SLV_USB_FS1		26
+#define CFPB_SLV_USB_FS2		27
+#define CFPB_SLV_TSIF			28
+#define CFPB_SLV_MSM_TSSC		29
+#define CFPB_SLV_MSM_PDM		30
+#define CFPB_SLV_MSM_DIMEM		31
+#define CFPB_SLV_MSM_TCSR		32
+#define CFPB_SLV_MSM_PRNG		33
+
+#endif /* __DT_BINDINGS_INTERCONNECT_QCOM_MSM8660_H */
Signature · 1 line
2.43.0
#2 lore raw

Re: [PATCH 1/2] dt-bindings: interconnect: qcom: add msm8660 fabric IDs

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] The commit message incorrectly claims the associated driver models the SFPB and CFPB fabrics. --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The commit message incorrectly claims the associated driver models the SFPB and CFPB fabrics. --

commit f2c1f888ae217770de22883ba69e0e4f0206a9ee
Author: Herman van Hazendonk <[email protected]>

dt-bindings: interconnect: qcom: add msm8660 fabric IDs

This commit adds the interconnect master and slave IDs for the MSM8x60 family fabric mesh. It defines IDs for the various sub-fabrics including AFAB, SFAB, MMFAB, DFAB, SFPB, and CFPB based on the legacy vendor driver.

Quoted 11 lines

The chip's
NoC fabric is split into multiple sub-fabrics that the qnoc-msm8660 driver models:

AFAB - Applications fabric (Scorpion CPU + L2)
SFAB - System fabric (DMA, SPS, security)
MMFAB - Multimedia fabric (MDP, GPU, camera, video, rotator) DFAB - Daytona fabric (SDC, ADM master/slave)
SFPB - System Fast Peripheral Bridge (RPM, MPM, PMIC SSBI) CFPB - CPU Subsystem Fast Peripheral Bus (GSBI UART/QUP, USB FS,
TSIF, TSSC, PDM, PRNG)

[Severity: Low]
Is this description accurate regarding SFPB and CFPB?

The commit message states that the qnoc-msm8660 driver models SFPB and CFPB, but looking at the driver implementation introduced in this series, it appears to only model AFAB, SFAB, MMFAB, and DFAB.

Could the commit message be updated to clarify that SFPB and CFPB are not actually modeled by the driver?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
#3 lore raw

PATCH 2/2 interconnect: qcom: add MSM8x60 NoC driver

In reply to Herman van Hazendonk

Add a Qualcomm interconnect driver for the MSM8x60 family modelling the four NoC fabrics (APPSS, System, MMSS, DFAB) that connect masters and slaves on these Scorpion-class SoCs. The driver implements the interconnect-provider API to manage bandwidth between specific masters and slaves via the RPM arbitration tables.

Each fabric carries:
- A bus clock (managed via clk_bulk APIs) whose rate is the aggregated bandwidth divided by the fabric bus width, with a minimum floor of 384 MHz to prevent USB starvation observed when the fabric drops to the previously-used 266 MHz minimum.
- An RPM arbitration buffer (arb / bwsum) that the RPM firmware consumes via its shared-memory protocol; commits go via the qcom-rpm driver's set_resource API.

msm8660_get_rpm() pins the supplier with device_link_add() before reading drvdata so an unbind/rebind window cannot leave a stale qcom_rpm pointer. clk_bulk_prepare_enable is paired with a devm_add_action_or_reset cleanup so an EPROBE_DEFER from the RPM lookup does not leak the prepare/enable refcount across retries. The fabric rate cap uses min_t(u64,...) so a bandwidth request exceeding 4 GiB/s cannot wrap through u32 truncation into a near-zero clock rate that would halt the interconnect.

---
 drivers/interconnect/qcom/Kconfig             |   14 +
 drivers/interconnect/qcom/Makefile            |    2 +
 drivers/interconnect/qcom/msm8660.c           | 1147 +++++++++++++++++
 .../dt-bindings/interconnect/qcom,msm8660.h   |    6 +-
 4 files changed, 1166 insertions(+), 3 deletions(-)
 create mode 100644 drivers/interconnect/qcom/msm8660.c
drivers/interconnect/qcom/Kconfig +14 -0
index 786b4eda44b4..d0a8df7cc700 100644
@@ -80,6 +80,20 @@ config INTERCONNECT_QCOM_MSM8953
 	  This is a driver for the Qualcomm Network-on-Chip on msm8953-based
 	  platforms.
 
+config INTERCONNECT_QCOM_MSM8660
+	# bool, not tristate: this provider must be registered at
+	# core_initcall to be ready before icc_init (subsys_initcall) walks
+	# devicetree consumers; a loadable module cannot satisfy that
+	# ordering. Build-in only.
+	bool "Qualcomm MSM8x60 interconnect driver"
+	depends on INTERCONNECT_QCOM=y
+	depends on MFD_QCOM_RPM
+	help
+	  This is a driver for the Qualcomm fabric-based bus interconnect
+	  on MSM8x60 family (MSM8260/MSM8660/APQ8060) platforms (e.g., HP TouchPad).
+	  The driver manages APPSS, System, and MMSS fabrics and sends
+	  per-port bandwidth arbitration requests to RPM firmware.
+
 config INTERCONNECT_QCOM_MSM8974
 	tristate "Qualcomm MSM8974 interconnect driver"
 	depends on INTERCONNECT_QCOM
drivers/interconnect/qcom/Makefile +2 -0
index cdf2c6c9fbf3..0c849c30a907 100644
@@ -13,6 +13,7 @@ qnoc-msm8916-objs			:= msm8916.o
 qnoc-msm8937-objs			:= msm8937.o
 qnoc-msm8939-objs			:= msm8939.o
 qnoc-msm8953-objs			:= msm8953.o
+qnoc-msm8660-objs			:= msm8660.o
 qnoc-msm8974-objs			:= msm8974.o
 qnoc-msm8976-objs			:= msm8976.o
 qnoc-msm8996-objs			:= msm8996.o
@@ -58,6 +59,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8937) += qnoc-msm8937.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) += qnoc-msm8939.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8953) += qnoc-msm8953.o
+obj-$(CONFIG_INTERCONNECT_QCOM_MSM8660) += qnoc-msm8660.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8976) += qnoc-msm8976.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) += qnoc-msm8996.o
drivers/interconnect/qcom/msm8660.c new file +1147 -0

1,147 lines not on this page · raw message

include/dt-bindings/interconnect/qcom,msm8660.h +3 -3
index c9ce3f5a5276..bac9fc423da2 100644
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2026 Herman van Hazendonk <[email protected]>
  *
- * Based on webOS kernel msm_bus_board_8660.c
+ * Based on legacy vendor kernel msm_bus_board_8660.c
  * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
  */
 
@@ -79,11 +79,11 @@
  * Daytona Fabric (DFAB) - Peripheral bus
  *
  * DFAB connects slower peripherals (SDCC, ADM DMA) to the system fabric.
- * The webOS kernel managed DFAB bandwidth via voter clocks (dfab_sdc*_clk,
+ * The legacy vendor kernel managed DFAB bandwidth via voter clocks (dfab_sdc*_clk,
  * dfab_usb_hs_clk). In mainline, this is handled by the interconnect framework.
  *
  * USB HS is included as a DFAB voter for compatibility with the legacy clock
- * voting mechanism. The webOS kernel comment said: "if usb link is in sps
+ * voting mechanism. The legacy vendor kernel comment said: "if usb link is in sps
  * there is no need for usb pclk as daytona fabric clock will be used instead".
  * This keeps DFAB clock stable when USB is active.
  */
Signature · 1 line
2.43.0
#4 lore raw

Re: [PATCH 2/2] interconnect: qcom: add MSM8x60 NoC driver

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] Double/Triple counting of bandwidth leads to artificially inflated clock rates. - [Low] Kconfig…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Double/Triple counting of bandwidth leads to artificially inflated clock rates.
- [Low] Kconfig dependency allows built-in driver to reference module symbols, causing linker errors.
- [Low] The name field in struct msm8660_icc_node is incorrectly typed as unsigned char * instead of const char *. --

commit 55dcd848add92308b8d692adbadfc253e5ad283f
Author: Herman van Hazendonk <[email protected]>

interconnect: qcom: add MSM8x60 NoC driver

Add a Qualcomm interconnect driver for the MSM8x60 family modelling the four NoC fabrics (APPSS, System, MMSS, DFAB) that connect masters and slaves on these Scorpion-class SoCs.

Quoted 3 lines
drivers/interconnect/qcom/Kconfig +0 -0

[ ... ]

drivers/interconnect/qcom/Kconfig config INTERCONNECT_QCOM_MSM8953 · line 90

Quoted 8 lines
drivers/interconnect/qcom/Kconfig +8 -0
+config INTERCONNECT_QCOM_MSM8660
+	# bool, not tristate: this provider must be registered at
+	# core_initcall to be ready before icc_init (subsys_initcall) walks
+	# devicetree consumers; a loadable module cannot satisfy that
+	# ordering. Build-in only.
+	bool "Qualcomm MSM8x60 interconnect driver"
+	depends on INTERCONNECT_QCOM=y
+	depends on MFD_QCOM_RPM

[Severity: Low]
Does this allow the driver to be built-in while MFD_QCOM_RPM is a module?

Since INTERCONNECT_QCOM_MSM8660 is a bool symbol, depending on MFD_QCOM_RPM without =y means this can be selected as =y even if MFD_QCOM_RPM=m. This would result in undefined reference linker errors for qcom_rpm_write.

Quoted 3 lines
drivers/interconnect/qcom/msm8660.c new file +0 -0

[ ... ]

drivers/interconnect/qcom/msm8660.c line 205

Quoted 2 lines
drivers/interconnect/qcom/msm8660.c new file +2 -0
+struct msm8660_icc_node {
+	unsigned char *name;

[Severity: Low]
This isn't a bug, but should name be a const char * rather than unsigned char *?

Initializing this with string literals (via the DEFINE_QNODE macro) and assigning it to node->name (which expects const char *) results in compiler warnings about pointer type mismatches.

[ ... ]

Quoted 7 lines
drivers/interconnect/qcom/msm8660.c new file +7 -0
+static int msm8660_icc_set(struct icc_node *src, struct icc_node *dst)
+{
+	struct msm8660_icc_node *src_qn;
+	struct msm8660_icc_provider *qp;
+	u64 sum_bw, max_peak_bw, rate;
+	u32 agg_avg = 0, agg_peak = 0;
+	struct icc_provider *provider;

drivers/interconnect/qcom/msm8660.c line 761

Quoted 10 lines
drivers/interconnect/qcom/msm8660.c new file +10 -0
+	struct icc_node *n;
+	int ret, i;
+
+	src_qn = src->data;
+	provider = src->provider;
+	qp = to_msm8660_icc_provider(provider);
+
+	list_for_each_entry(n, &provider->nodes, node_list)
+		provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
+				    &agg_avg, &agg_peak);

[Severity: High]
Does this loop result in double counting the requested bandwidth?

Because an interconnect path traverses multiple nodes (e.g., a master and a slave) and the framework applies the requested bandwidth to all nodes along the path, summing all nodes in the provider means the same traffic is counted multiple times.

This artificially inflates the computed clock rate, which could cause clk_set_rate() to fail or unnecessarily waste power.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#5 lore raw

Re: [PATCH 2/2] interconnect: qcom: add MSM8x60 NoC driver

In reply to Herman van Hazendonk
Quoted 15 lines · Herman van Hazendonk

Add a Qualcomm interconnect driver for the MSM8x60 family modelling the four NoC fabrics (APPSS, System, MMSS, DFAB) that connect masters and slaves on these Scorpion-class SoCs. The driver implements the interconnect-provider API to manage bandwidth between specific masters and slaves via the RPM arbitration tables.

Each fabric carries:
- A bus clock (managed via clk_bulk APIs) whose rate is the aggregated bandwidth divided by the fabric bus width, with a minimum floor of 384 MHz to prevent USB starvation observed when the fabric drops to the previously-used 266 MHz minimum.
- An RPM arbitration buffer (arb / bwsum) that the RPM firmware consumes via its shared-memory protocol; commits go via the qcom-rpm driver's set_resource API.

Quoted 8 lines

msm8660_get_rpm() pins the supplier with device_link_add() before reading drvdata so an unbind/rebind window cannot leave a stale qcom_rpm pointer. clk_bulk_prepare_enable is paired with a devm_add_action_or_reset cleanup so an EPROBE_DEFER from the RPM lookup does not leak the prepare/enable refcount across retries. The fabric rate cap uses min_t(u64,...) so a bandwidth request exceeding 4 GiB/s cannot wrap through u32 truncation into a near-zero clock rate that would halt the interconnect.

Thanks for working on this.

Quoted 22 lines
---
 drivers/interconnect/qcom/Kconfig             |   14 +
 drivers/interconnect/qcom/Makefile            |    2 +
 drivers/interconnect/qcom/msm8660.c           | 1147 +++++++++++++++++
 .../dt-bindings/interconnect/qcom,msm8660.h   |    6 +-
 4 files changed, 1166 insertions(+), 3 deletions(-)
 create mode 100644 drivers/interconnect/qcom/msm8660.c
drivers/interconnect/qcom/msm8660.c new file +12 -0
+
+/*
+ * RPM fabric arbitration data format (from legacy vendor kernel msm_bus_fabric.c):
+ *
+ * Each u16 arb entry: bit 15 = tier (1=TIER1 high priority), bits 14-0 = BW
+ * Bandwidth is in 128KB units (bytes >> 17).
+ * Two u16 values are packed into each u32 RPM register word.
+ *
+ * Buffer layout: [bwsum pairs] [arb pairs]
+ * bwsum[slave_port] = total bandwidth to that slave
+ * arb[(tier-1)*nmasters + master_port] = per-master arbitration entry
+ */

drivers/interconnect/qcom/msm8660.c line 172

Quoted 10 lines
drivers/interconnect/qcom/msm8660.c new file +10 -0
+#define ARB_BWMASK		0x7FFF
+#define ARB_TIERMASK		0x8000
+#define ARB_TIER1		1
+#define ARB_TIER2		2
+
+static const struct clk_bulk_data msm8660_afab_clocks[] = {
+	{ .id = "bus" },
+	{ .id = "bus_a" },
+	{ .id = "ebi1" },
+	{ .id = "ebi1_a" },

What clocks are those? Please provide the actual dt-bindings schema (together with the examples). In the past we had bus / bus_a clocks for the SMD-RPM-based interconnects, but lyter they were ripped out and replaced with the direct voting for the resources.

drivers/interconnect/qcom/msm8660.c line 282

Quoted 13 lines
drivers/interconnect/qcom/msm8660.c new file +13 -0
+};
+
+
+/*
+ * Node definitions with RPM port mapping.
+ *
+ * DEFINE_QNODE(_name, _id, _buswidth, _mas_port, _slv_port, _tier, links...)
+ *
+ * _mas_port: master port index for RPM ARB array (-1 if not a master)
+ * _slv_port: slave port index for RPM bwsum array (-1 if not a slave)
+ * _tier: master priority tier (ARB_TIER1=1, ARB_TIER2=2, 0 if N/A)
+ */
+#define DEFINE_QNODE(_name, _id, _buswidth, _mas, _slv, _tier, ...)	\

Please expand the macro.

Quoted 11 lines
drivers/interconnect/qcom/msm8660.c new file +11 -0
+	static struct msm8660_icc_node _name = {			\
+		.name = #_name,						\
+		.id = _id,						\
+		.buswidth = _buswidth,					\
+		.num_links = COUNT_ARGS(__VA_ARGS__),			\
+		.links = { __VA_ARGS__ },				\
+		.mas_port = _mas,					\
+		.slv_port = _slv,					\
+		.mas_tier = _tier,					\
+	}
+

[...]

Quoted 18 lines
drivers/interconnect/qcom/msm8660.c new file +18 -0
+/*
+ * Look up the RPM that owns fabric arbitration writes.
+ *
+ * Returns NULL if the DT does not have a "qcom,rpm" phandle (in which
+ * case the caller silently drops RPM ARB and runs the fabric purely
+ * via clk_set_rate).
+ *
+ * Returns ERR_PTR(-EPROBE_DEFER) if the RPM device exists in DT but
+ * its driver has not finished probing yet, or if device_link_add()
+ * fails. The caller is expected to propagate this so the interconnect
+ * driver gets retried once the RPM is ready.
+ *
+ * On success returns the qcom_rpm handle and pins the RPM device
+ * lifetime to ours via a consumer-supplier device link, so the
+ * devres-allocated qcom_rpm cannot be freed while we still hold a
+ * pointer to it.
+ */
+static struct qcom_rpm *msm8660_get_rpm(struct device *dev)

drivers/interconnect/qcom/msm8660.c line 859

Quoted 10 lines
drivers/interconnect/qcom/msm8660.c new file +10 -0
+{
+	struct device_node *rpm_np;
+	struct platform_device *rpm_pdev;
+	struct device_link *link;
+	struct qcom_rpm *rpm;
+
+	rpm_np = of_parse_phandle(dev->of_node, "qcom,rpm", 0);
+	if (!rpm_np) {
+		dev_dbg(dev, "no qcom,rpm phandle, RPM ARB disabled\n");
+		return NULL;

Here and further, return dev_err_ptr_probe().

Quoted 76 lines
drivers/interconnect/qcom/msm8660.c new file +76 -0
+	}
+
+	rpm_pdev = of_find_device_by_node(rpm_np);
+	of_node_put(rpm_np);
+	if (!rpm_pdev) {
+		dev_dbg(dev, "RPM device not found yet, deferring probe\n");
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	/*
+	 * Pin the supplier BEFORE reading its drvdata. The device link
+	 * (MANAGED, the default state) prevents the RPM driver from being
+	 * unbound while we hold the link, which closes the window where a
+	 * concurrent unbind+rebind could free the qcom_rpm pointer between
+	 * dev_get_drvdata() and the link being established. If the link
+	 * cannot be added (e.g. supplier is in the process of being
+	 * removed) we defer and retry.
+	 */
+	link = device_link_add(dev, &rpm_pdev->dev,
+			       DL_FLAG_AUTOREMOVE_CONSUMER);
+	put_device(&rpm_pdev->dev);
+	if (!link) {
+		dev_warn(dev, "failed to add device link to RPM, deferring\n");
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	/*
+	 * Safe to read drvdata now: the device link pins the supplier so
+	 * it cannot be unbound until our consumer (this interconnect
+	 * provider) is unbound first.
+	 */
+	rpm = dev_get_drvdata(&rpm_pdev->dev);
+	if (!rpm) {
+		dev_dbg(dev, "RPM not ready, deferring probe\n");
+		device_link_remove(dev, &rpm_pdev->dev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	return rpm;
+}
+
+static int msm8660_icc_probe(struct platform_device *pdev)
+{
+	const struct msm8660_icc_desc *desc;
+	struct msm8660_icc_node * const *qnodes;
+	struct msm8660_icc_provider *qp;
+	struct device *dev = &pdev->dev;
+	struct icc_onecell_data *data;
+	struct icc_provider *provider;
+	struct icc_node *node;
+	size_t num_nodes, i;
+	int ret;
+
+	desc = of_device_get_match_data(dev);
+	if (!desc)
+		return -EINVAL;
+
+	qnodes = desc->nodes;
+	num_nodes = desc->num_nodes;
+
+	qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
+	if (!qp)
+		return -ENOMEM;
+
+	data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	data->num_nodes = num_nodes;
+
+	qp->bus_clks = devm_kmemdup(dev, desc->bus_clks,
+				    desc->num_clks * sizeof(*desc->bus_clks),
+				    GFP_KERNEL);
+	if (!qp->bus_clks)
+		return -ENOMEM;
+

drivers/interconnect/qcom/msm8660.c line 945

Quoted 10 lines
drivers/interconnect/qcom/msm8660.c new file +10 -0
+	qp->num_clks = desc->num_clks;
+
+	/*
+	 * MSM8660 fabric clocks are managed by RPM firmware and may not be
+	 * available in mainline Linux yet. Once the clock provider exists,
+	 * we want to honour it; until then we run without per-fabric clock
+	 * scaling. The crucial part is that -EPROBE_DEFER means "the
+	 * provider exists but hasn't probed yet" and MUST be propagated so
+	 * we get retried; only other errors (genuine -ENOENT, etc.) get
+	 * downgraded to "no clocks, continue".

Please limit to -ENOENT only.

Quoted 89 lines
drivers/interconnect/qcom/msm8660.c new file +89 -0
+	 */
+	ret = devm_clk_bulk_get_optional(dev, qp->num_clks, qp->bus_clks);
+	if (ret == -EPROBE_DEFER)
+		return ret;
+	if (ret) {
+		dev_warn(dev, "Failed to get bus clocks: %d (continuing without clock scaling)\n",
+			 ret);
+		qp->num_clks = 0;
+	}
+
+	if (qp->num_clks) {
+		ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
+		if (ret) {
+			dev_warn(dev, "Failed to enable bus clocks: %d\n", ret);
+			qp->num_clks = 0;
+		} else {
+			/*
+			 * Register the cleanup right after a successful
+			 * prepare_enable so any later -EPROBE_DEFER or other
+			 * probe error path (e.g. msm8660_get_rpm failing
+			 * with -EPROBE_DEFER below) does not leak a clock
+			 * prepare/enable reference across the retry.
+			 */
+			ret = devm_add_action_or_reset(dev,
+				msm8660_icc_clk_release, qp);
+			if (ret)
+				return ret;
+		}
+	}
+
+	/* Set up RPM fabric arbitration */
+	qp->desc = desc;
+	if (desc->rpm_resource >= 0) {
+		qp->rpm = msm8660_get_rpm(dev);
+		if (IS_ERR(qp->rpm))
+			return PTR_ERR(qp->rpm);
+		if (qp->rpm) {
+			int arb_size = desc->nmasters * desc->ntieredslaves;
+
+			qp->bwsum = devm_kcalloc(dev, desc->nslaves,
+						 sizeof(u16), GFP_KERNEL);
+			qp->arb = devm_kcalloc(dev, arb_size,
+					       sizeof(u16), GFP_KERNEL);
+			qp->rpm_buf = devm_kcalloc(dev, desc->rpm_buf_size,
+						   sizeof(u32), GFP_KERNEL);
+			if (!qp->bwsum || !qp->arb || !qp->rpm_buf) {
+				dev_warn(dev, "RPM buffer alloc failed, ARB disabled\n");
+				qp->rpm = NULL;
+			} else {
+				int rc;
+
+				dev_info(dev, "RPM fabric ARB enabled (%d masters, %d slaves, %d tiered)\n",
+					 desc->nmasters, desc->nslaves,
+					 desc->ntieredslaves);
+
+				/*
+				 * One-shot sleep-context vote of zero bandwidth.
+				 * Without an explicit SLEEP_STATE write, RPM has no
+				 * fabric bandwidth target for deep-sleep and may
+				 * keep the active vote applied indefinitely,
+				 * preventing DDR from dropping its rate when CPUs
+				 * power-collapse. The buffer is devm_kcalloc'd so
+				 * it is all-zero at this point — written before
+				 * any consumer can drive an active vote that would
+				 * dirty it.
+				 *
+				 * msm8660_rpm_commit() writes ACTIVE_STATE only;
+				 * SLEEP_STATE remains zero for the provider's
+				 * lifetime, so this vote does not need refreshing.
+				 */
+				rc = qcom_rpm_write(qp->rpm,
+						    QCOM_RPM_SLEEP_STATE,
+						    desc->rpm_resource,
+						    qp->rpm_buf,
+						    desc->rpm_buf_size);
+				if (rc)
+					dev_warn(dev, "RPM fabric sleep vote failed: %d\n",
+						 rc);
+			}
+		}
+	}
+
+	provider = &qp->provider;
+	provider->dev = dev;
+	provider->set = msm8660_icc_set;
+	provider->aggregate = msm8660_icc_aggregate;
+	provider->xlate = of_icc_xlate_onecell;
+	provider->data = data;
+	provider->get_bw = msm8660_get_bw;

drivers/interconnect/qcom/msm8660.c line 1044

Quoted 10 lines
drivers/interconnect/qcom/msm8660.c new file +10 -0
+
+	icc_provider_init(provider);
+
+	for (i = 0; i < num_nodes; i++) {
+		size_t j;
+
+		if (!qnodes[i])
+			continue;
+
+		node = icc_node_create(qnodes[i]->id);

Please switch to the dynamic ICC node numbers (see icc-rpmh)

Quoted 9 lines
drivers/interconnect/qcom/msm8660.c new file +9 -0
+		if (IS_ERR(node)) {
+			ret = PTR_ERR(node);
+			goto err_remove_nodes;
+		}
+
+		node->name = qnodes[i]->name;
+		node->data = qnodes[i];
+		icc_node_add(node, provider);
+
Signature · 2 lines
With best wishes
Dmitry
#6 lore raw
In reply to Herman van Hazendonk
Quoted 4 lines · Herman van Hazendonk

Add interconnect support for the MSM8x60 family (MSM8260, MSM8660, APQ8060) — Qualcomm's Scorpion dual-core SoC generation used in devices like the HP TouchPad, HTC EVO 3D and HTC Sensation.

Missed dt-binding doc for the new added driver.

Thanks,
Jie

Quoted 32 lines

The chip's Network-on-Chip fabric is divided into four sub-fabrics:

AFAB - Applications fabric: Scorpion CPU + L2 cache, paths to EBI SFAB - System fabric: DMA engines, SPS, USB HS, LPASS, MSS MMFAB - Multimedia fabric: MDP, GPU, camera (VFE/JPEG), video codec DFAB - Daytona fabric: eMMC/SD (SDC), ADM DMA, USB voter

Bandwidth requests are committed to the RPM firmware via its shared-memory arbitration tables using the qcom-rpm driver backend; each fabric also has a bus clock whose rate is derived from the aggregated bandwidth.

The driver includes a 384 MHz bus clock floor, replacing the previous 266 MHz minimum that caused USB starvation on real hardware, and careful devm/device_link lifecycle to handle EPROBE_DEFER from both RPM and clock lookups without leaking clock prepare/enable references.

Herman van Hazendonk (2):
dt-bindings: interconnect: qcom: add msm8660 fabric IDs
interconnect: qcom: add MSM8x60 NoC driver

  drivers/interconnect/qcom/Kconfig             |   14 +
  drivers/interconnect/qcom/Makefile            |    2 +
  drivers/interconnect/qcom/msm8660.c           | 1147 +++++++++++++++++
  .../dt-bindings/interconnect/qcom,msm8660.h   |  156 +++
  4 files changed, 1319 insertions(+)

create mode 100644 drivers/interconnect/qcom/msm8660.c create mode 100644 include/dt-bindings/interconnect/qcom,msm8660.h

base-commit: 944125b4c454b58d2fe6e35f1087a932b2050dff