From nobody Mon Jun 8 08:28:04 2026 Received: from outbound10.mail.transip.nl (outbound10.mail.transip.nl [136.144.136.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9830A275AF5; Sun, 31 May 2026 04:09:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.144.136.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780200560; cv=none; b=pAaNzkNUo0lvvZZxfVxNLS1kRXtnhDTzpb8Xn1SKJnN3VkT46gNZckDEoSXQU5lnhN06FJuIfHk8vKDZxz7Nd5M5w6olrGZxyyuNGagNO5XDfriXN2DiiYKh93oQ7WDHywWTw61t6QOVLWH/BAPczLifcka8fMuWEO3VwcJH0xA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780200560; c=relaxed/simple; bh=YmoV3AGwA/puyIqfk0XLJzavVS4zNqa4oNK/aBfU5mA=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kgAWH6bN+6EQ8v0h/+L7NSIj1q+d2/76u5EEAgPYYeVUW2WiXgyOOw6dQrolapk4X+reLj0dZvnKDPjLydf7F832ry62XkXFMNUKc/0+dU2hmgzPqc9omyA4uW9vCTDkIlU3r7pPUA2avKMiM9GDDcbTYDHRl+PzYDW2grJEB0o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=herrie.org; spf=pass smtp.mailfrom=herrie.org; dkim=pass (2048-bit key) header.d=herrie.org header.i=@herrie.org header.b=uNpvAr3s; arc=none smtp.client-ip=136.144.136.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=herrie.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=herrie.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=herrie.org header.i=@herrie.org header.b="uNpvAr3s" Received: from submission3.mail.transip.nl (unknown [10.100.4.72]) by outbound10.mail.transip.nl (Postfix) with ESMTP id 4gSk9x12KszTPNjL; Sun, 31 May 2026 06:09:09 +0200 (CEST) Received: from herrie-desktop.. (180-93-184-31.ftth.glasoperator.nl [31.184.93.180]) by submission3.mail.transip.nl (Postfix) with ESMTPA id 4gSk9w4Msrzf52b5; Sun, 31 May 2026 06:09:08 +0200 (CEST) From: Herman van Hazendonk To: Conor Dooley , devicetree@vger.kernel.org, Georgi Djakov , Krzysztof Kozlowski , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Rob Herring Subject: [PATCH v2 1/2] dt-bindings: interconnect: qcom: add msm8660 fabric IDs Date: Sun, 31 May 2026 06:09:06 +0200 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: ClueGetter at submission3.mail.transip.nl DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=transip-a; d=herrie.org; t=1780200548; h=from:subject:to:references: in-reply-to:date:mime-version; bh=UZ0iX3Gj77ummUnifDlRQO0HGw8lRcxgldhHGrIsmmE=; b=uNpvAr3stpMDc5gWemmkagoxmoLMtsYGuyd7kZbihi+WsFKvcZ5UJGJLTGPbxna78LCbNl 1i2lW+opUlOfr5p6R7yMktaY4ftVFyFuQ/uVtcnvQViqS+Poso7HYxQVDgyn5UebKAeCPS Btb359qjL0JBjuvaMaDdgLe+BtfdxooQRbcZspujg2TsQbHy6ndHAlv7KiNXv1b+zgQ0gH PbMXKRVP2Uk4N2+jzeTDx6lFKlILM5wtCMQ9cnEotiTZSZcxsajfpKucmvGKLTSxWos0hP pNVlNogddJhncDyqCqJV0kOCyUlc6NEhtzKUaIjAsvlKdXlwUAhSmJYfOg22Dg== X-Report-Abuse-To: abuse@transip.nl Content-Type: text/plain; charset="utf-8" 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 webOS msm_bus_board_8660.c master/slave enums, normalised to the upstream interconnect-framework naming. Signed-off-by: Herman van Hazendonk --- .../dt-bindings/interconnect/qcom,msm8660.h | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 include/dt-bindings/interconnect/qcom,msm8660.h diff --git a/include/dt-bindings/interconnect/qcom,msm8660.h b/include/dt-b= indings/interconnect/qcom,msm8660.h new file mode 100644 index 000000000000..c9ce3f5a5276 --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,msm8660.h @@ -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 + * + * 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 fram= ework. + * + * USB HS is included as a DFAB voter for compatibility with the legacy cl= ock + * 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 inst= ead". + * 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 */ --=20 2.43.0 From nobody Mon Jun 8 08:28:04 2026 Received: from outbound7.mail.transip.nl (outbound7.mail.transip.nl [136.144.136.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 129C3302163; Sun, 31 May 2026 04:09:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.144.136.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780200566; cv=none; b=ZnAhVGRslf8plKKTwzjldmBOe8Pgi1HvZlPqOn+qdjKt+ZoHhtLreqS1UJe/K/1pUIcfFrW3fgicu1azu4gvOyhM+tFO6eieIk3j6PiBUfbj5bB/xkqDAM0xbKzKYf9YRoaPr2S+qs+VkSt/jBTg8srbLADPUZzK0oTZOG4r7e8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780200566; c=relaxed/simple; bh=jdYU3v9jcoHlWkVNU9SgZVEx2LWQRH/PAZ+65QGDegQ=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qZa+eTvzeGHiip7qlwA/wEVKJ9z6NQ2N9JO/YxFr2HHDK6lFENInedALngqVSNNyvzATsSWy30MHdj/GyzbxaYeSy5OL5543ni5sLytzZLU1rqbrnLg8m0Zif/3nPbeojS5oL15raZqULOPWGbviA/tkEdNG1SFtcq4sQIReE8Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=herrie.org; spf=pass smtp.mailfrom=herrie.org; dkim=pass (2048-bit key) header.d=herrie.org header.i=@herrie.org header.b=K4evxA9W; arc=none smtp.client-ip=136.144.136.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=herrie.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=herrie.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=herrie.org header.i=@herrie.org header.b="K4evxA9W" Received: from submission4.mail.transip.nl (unknown [10.103.8.155]) by outbound7.mail.transip.nl (Postfix) with ESMTP id 4gSkB74T6qzQvv7w; Sun, 31 May 2026 06:09:19 +0200 (CEST) Received: from herrie-desktop.. (180-93-184-31.ftth.glasoperator.nl [31.184.93.180]) by submission4.mail.transip.nl (Postfix) with ESMTPA id 4gSkB66M8sz3R3nyd; Sun, 31 May 2026 06:09:18 +0200 (CEST) From: Herman van Hazendonk To: Amit Kucheria , Conor Dooley , Daniel Lezcano , devicetree@vger.kernel.org, Krzysztof Kozlowski , Lee Jones , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Lukasz Luba , "Rafael J. Wysocki" , Rob Herring , Satya Priya , Thara Gopinath , van Hazendonk , Zhang Rui Subject: [PATCH v2 1/3] dt-bindings: mfd: qcom-pm8xxx: allow temp-alarm subnode Date: Sun, 31 May 2026 06:09:14 +0200 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: ClueGetter at submission4.mail.transip.nl DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=transip-a; d=herrie.org; t=1780200559; h=from:subject:to:references: in-reply-to:date:mime-version; bh=lJ63rCL+Dm5XTJifQ6TD8ogzWBpe0HZNaI2plvhoceM=; b=K4evxA9WfoNu9jusCxliIfzDhbp4cTpLp0DJ67ZlAaor4t5D0EG3QIWeM8XV5lSb8TLHl9 RAxjLTxmOQlqUs5AfOtE52luaApO+Yl9R/ik7caHeag9CyeziLXwdvLkBUffQY2oCEZ+xr twUCcMG229AxgzDp3M3f56jY0ALXOkAB9BSaBNT7Ufb9+hxOatWI7TfAorkLqT2U/qJa+h qAwWP4h+VNOZ/LQxWjTlInaEDneFLukVe/p1NjehGfMohPK0AMvYHQ8If31qnjA+9fsf4Q rapeMzRRHPP66LiJyJLhBBqUSC3sLUAPSeV0FFEaFMjBzg8jcr6WTucbhA9iZw== X-Report-Abuse-To: abuse@transip.nl Content-Type: text/plain; charset="utf-8" The qcom,pm8xxx parent schema closes its child set via `additionalProperties: false` and an explicit list of `patternProperties`. PM8901 (and prospectively other parts in the family) exposes an over-temperature alarm block as an SSBI sub-node; without a matching pattern here, any board DT that instantiates `temp-alarm@` under a PM8xxx parent fails dtbs_check. Add the `temp-alarm@[0-9a-f]+$` pattern, referencing the new qcom,pm8901-temp-alarm schema, so the temperature-alarm sub-node validates as a recognised child of the PMIC. Signed-off-by: Herman van Hazendonk --- Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml b/Docum= entation/devicetree/bindings/mfd/qcom-pm8xxx.yaml index 63e18d6a9c21..dde290569b03 100644 --- a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml @@ -68,6 +68,10 @@ patternProperties: type: object $ref: /schemas/rtc/qcom-pm8xxx-rtc.yaml# =20 + "temp-alarm@[0-9a-f]+$": + type: object + $ref: /schemas/thermal/qcom,pm8901-temp-alarm.yaml# + "vibrator@[0-9a-f]+$": type: object $ref: /schemas/input/qcom,pm8xxx-vib.yaml# --=20 2.43.0 From nobody Mon Jun 8 08:28:04 2026 Received: from outbound7.mail.transip.nl (outbound7.mail.transip.nl [136.144.136.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0AF272F7F19; Sun, 31 May 2026 04:09:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.144.136.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780200557; cv=none; b=Q6MHuceQUTKgqDo6qMwCaLou7pD58sP9XCvswI6uIFmffbcIFC1zNrgMO699ekDawLnM4eNP/M5Ll+hGyzgQZkqInWH+FWzDZ1J65GbWxRR5vzWo6Pq4AJZ6v/R25tdUNSLPeV4vDiE7/w+fWw5do6dw5YshXC+Lp/3FcJ0HO2Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780200557; c=relaxed/simple; bh=jv90lZ0W2lYoJ+Ay/wsGq1xYqX2QU6pzoKfgxJWknv0=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=H7MUvcNPkPUu8UsMAY9+peZvv9ndcuvuD6u9po9Vkaxq2jjEYjWqImfiqtdcvGajZCBbTVDyMVequRTeeeTDwSbzs1ZtIffAcTgX0yCNYABpTlfp/IXKyP9XUG8vWEu7SzpsJxs9syO2pXK+038jZZ/mqftRYzIVaRZ/mCeGJBQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=herrie.org; spf=pass smtp.mailfrom=herrie.org; dkim=pass (2048-bit key) header.d=herrie.org header.i=@herrie.org header.b=axzo1Pod; arc=none smtp.client-ip=136.144.136.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=herrie.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=herrie.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=herrie.org header.i=@herrie.org header.b="axzo1Pod" Received: from submission3.mail.transip.nl (unknown [10.100.4.72]) by outbound7.mail.transip.nl (Postfix) with ESMTP id 4gSk9y1ZwQzQvv7w; Sun, 31 May 2026 06:09:10 +0200 (CEST) Received: from herrie-desktop.. (180-93-184-31.ftth.glasoperator.nl [31.184.93.180]) by submission3.mail.transip.nl (Postfix) with ESMTPA id 4gSk9x1fSrzf52b6; Sun, 31 May 2026 06:09:09 +0200 (CEST) From: Herman van Hazendonk To: Conor Dooley , devicetree@vger.kernel.org, Georgi Djakov , Krzysztof Kozlowski , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Rob Herring Subject: [PATCH v2 2/2] interconnect: qcom: add MSM8x60 NoC driver Date: Sun, 31 May 2026 06:09:07 +0200 Message-ID: <314e71d651e4bbe9eedc904d3b94cf306ce5aab5.1780197411.git.github.com@herrie.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: ClueGetter at submission3.mail.transip.nl DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=transip-a; d=herrie.org; t=1780200549; h=from:subject:to:references: in-reply-to:date:mime-version:content-type; bh=3nCKm+IZ41vAgBrH4sI8NkuMHoqYtmqKUg/rQ8YRg/4=; b=axzo1PodCgfuX9MzdUmXirs/KpnZcc7F5mH59cWmA4DQXzMpojD797NJAiKhVhWK7b6SXw FjP80Zl/moPQQF2TWPwhwfuTy3/q9FG3vffbYLgeX5aeMxJfZUPD3qKajEw/JQwrMA7B0Y IdBsE9RAlsuPtc+mzrz0W4o1F9pq//8r/MR+ymnd1sjXmYbe7A6rLEsEH6eh2yd4lmSg2R 3kh6N5QSiCJOYaMMlhSSvOoQ5MF7tUuwYAq4UxUg9zcm7lmI8eZewjkexPLJw71p/+ZsKp RpCPTc0cTLcCKtjDz1lPeGCb152qhyxEaeh+eN+6vDLreBmEqtszzq63H6Em2g== X-Report-Abuse-To: abuse@transip.nl Add a Qualcomm interconnect driver for the MSM8x60 family (MSM8260/MSM8660/APQ8060), modelling the four fabrics that connect masters and slaves on these Scorpion-class SoCs: - AFAB : Application/CPU fabric - SFAB : System fabric (peripherals, USB, SDCC, etc.) - MMFAB : Multimedia fabric (MDP, VFE, VIDC, GPU, JPEG, VPE, ROT) - DFAB : Daytona fabric (low-bandwidth peripherals) The driver implements the interconnect-provider API so that consumer drivers (display, camera, video, GPU, USB, MMC) can request bandwidth between specific masters and slaves via icc_set_bw(), letting the firmware-managed bus-scaling decide actual NoC clock rates. Used on the HP TouchPad (Tenderloin) and on the Pre3 / Veer form-factors; without it, the multimedia and storage paths are starved of bandwidth and run at minimum NoC clocks. Signed-off-by: Herman van Hazendonk --- drivers/interconnect/qcom/Kconfig | 10 + drivers/interconnect/qcom/Makefile | 2 + drivers/interconnect/qcom/msm8660.c | 1069 +++++++++++++++++++++++++++ 3 files changed, 1081 insertions(+) create mode 100644 drivers/interconnect/qcom/msm8660.c diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/= Kconfig index 786b4eda44b4..17364be522c7 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -80,6 +80,16 @@ config INTERCONNECT_QCOM_MSM8953 This is a driver for the Qualcomm Network-on-Chip on msm8953-based platforms. =20 +config INTERCONNECT_QCOM_MSM8660 + tristate "Qualcomm MSM8x60 interconnect driver" + depends on INTERCONNECT_QCOM + 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 TouchPa= d). + 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 diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom= /Makefile index cdf2c6c9fbf3..0c849c30a907 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -13,6 +13,7 @@ qnoc-msm8916-objs :=3D msm8916.o qnoc-msm8937-objs :=3D msm8937.o qnoc-msm8939-objs :=3D msm8939.o qnoc-msm8953-objs :=3D msm8953.o +qnoc-msm8660-objs :=3D msm8660.o qnoc-msm8974-objs :=3D msm8974.o qnoc-msm8976-objs :=3D msm8976.o qnoc-msm8996-objs :=3D msm8996.o @@ -58,6 +59,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) +=3D qnoc-msm8916= .o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8937) +=3D qnoc-msm8937.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) +=3D qnoc-msm8939.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8953) +=3D qnoc-msm8953.o +obj-$(CONFIG_INTERCONNECT_QCOM_MSM8660) +=3D qnoc-msm8660.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) +=3D qnoc-msm8974.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8976) +=3D qnoc-msm8976.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) +=3D qnoc-msm8996.o diff --git a/drivers/interconnect/qcom/msm8660.c b/drivers/interconnect/qco= m/msm8660.c new file mode 100644 index 000000000000..174bc59da74f --- /dev/null +++ b/drivers/interconnect/qcom/msm8660.c @@ -0,0 +1,1069 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm MSM8x60 family (MSM8260/MSM8660/APQ8060) interconnect driver + * + * Copyright (c) 2026 Herman van Hazendonk + * + * Based on msm8974.c by Brian Masney + * and webOS kernel msm_bus_board_8660.c / msm_bus_fabric.c + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * MSM8x60 has a fabric-based bus architecture: + * + * +------------------+ + * | APPSS Fabric | (CPU, L2, Memory) + * +--------+---------+ + * | + * +-------------+-------------+ + * | | + * +------+------+ +-------+-------+ + * | MMSS Fabric | | System Fabric | + * | (Display, | | (Peripherals, | + * | Camera, | | DMA, etc) | + * | Video) | +-------+-------+ + * +-------------+ | + * +---------+---------+ + * | | + * +------+------+ +------+------+ + * | System FPB | | CPSS FPB | + * | (RPM, PMIC) | | (GSBI, USB) | + * +-------------+ +-------------+ + * + * Each fabric has an RPM arbitration interface that programs per-port + * bandwidth and priority tier via MM_FABRIC_ARB / SYS_FABRIC_ARB / + * APPS_FABRIC_ARB registers. The webOS kernel sent these as packed + * u16 arrays (bwsum + arb) through msm_rpm_set(). This driver uses + * the mainline qcom_rpm_write() interface to do the same. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Internal node IDs - these map to the DT binding IDs plus fabric offset = */ +enum { + /* APPSS Fabric nodes */ + MSM8660_AFAB_MAS_AMPSS_M0 =3D 1, + MSM8660_AFAB_MAS_AMPSS_M1, + MSM8660_AFAB_SLV_EBI_CH0, + MSM8660_AFAB_SLV_AMPSS_L2, + MSM8660_AFAB_TO_MMSS, + MSM8660_AFAB_TO_SYSTEM, + + /* System Fabric nodes */ + MSM8660_SFAB_MAS_APPSS, + MSM8660_SFAB_MAS_SPS, + MSM8660_SFAB_MAS_ADM0_PORT0, + MSM8660_SFAB_MAS_ADM0_PORT1, + MSM8660_SFAB_MAS_ADM1_PORT0, + MSM8660_SFAB_MAS_ADM1_PORT1, + MSM8660_SFAB_MAS_LPASS_PROC, + MSM8660_SFAB_MAS_MSS_PROCI, + MSM8660_SFAB_MAS_MSS_PROCD, + MSM8660_SFAB_MAS_MSS_MDM_PORT0, + MSM8660_SFAB_MAS_LPASS, + MSM8660_SFAB_MAS_MMSS_FPB, + MSM8660_SFAB_MAS_ADM1_CI, + MSM8660_SFAB_MAS_ADM0_CI, + MSM8660_SFAB_MAS_MSS_MDM_PORT1, + MSM8660_SFAB_MAS_USB_HS, + MSM8660_SFAB_TO_APPSS, + MSM8660_SFAB_TO_SYSTEM_FPB, + MSM8660_SFAB_TO_CPSS_FPB, + MSM8660_SFAB_SLV_SPS, + MSM8660_SFAB_SLV_SYSTEM_IMEM, + MSM8660_SFAB_SLV_AMPSS, + MSM8660_SFAB_SLV_MSS, + MSM8660_SFAB_SLV_LPASS, + MSM8660_SFAB_SLV_MMSS_FPB, + MSM8660_SFAB_TO_DFAB, + + /* Daytona Fabric nodes (DFAB) - peripheral bus */ + MSM8660_DFAB_MAS_SDC1, + MSM8660_DFAB_MAS_SDC2, + MSM8660_DFAB_MAS_SDC3, + MSM8660_DFAB_MAS_SDC4, + MSM8660_DFAB_MAS_SDC5, + MSM8660_DFAB_MAS_ADM0_MASTER, + MSM8660_DFAB_MAS_ADM1_MASTER, + MSM8660_DFAB_TO_SFAB, + MSM8660_DFAB_SLV_SDC1, + MSM8660_DFAB_SLV_SDC2, + MSM8660_DFAB_SLV_SDC3, + MSM8660_DFAB_SLV_SDC4, + MSM8660_DFAB_SLV_SDC5, + MSM8660_DFAB_MAS_USB_HS, /* USB HS DFAB voter */ + MSM8660_DFAB_MAS_DSPS, /* DSPS DFAB voter */ + + /* MMSS Fabric nodes */ + MSM8660_MMFAB_MAS_MDP_PORT0, + MSM8660_MMFAB_MAS_MDP_PORT1, + MSM8660_MMFAB_MAS_ADM1_PORT0, + MSM8660_MMFAB_MAS_ROTATOR, + MSM8660_MMFAB_MAS_GRAPHICS_3D, + MSM8660_MMFAB_MAS_JPEG_DEC, + MSM8660_MMFAB_MAS_GRAPHICS_2D_CORE0, + MSM8660_MMFAB_MAS_VFE, + MSM8660_MMFAB_MAS_VPE, + MSM8660_MMFAB_MAS_JPEG_ENC, + MSM8660_MMFAB_MAS_GRAPHICS_2D_CORE1, + MSM8660_MMFAB_MAS_HD_CODEC_PORT0, + MSM8660_MMFAB_MAS_HD_CODEC_PORT1, + MSM8660_MMFAB_TO_APPSS, + MSM8660_MMFAB_SLV_SMI, + MSM8660_MMFAB_SLV_MM_IMEM, +}; + +#define to_msm8660_icc_provider(_provider) \ + container_of(_provider, struct msm8660_icc_provider, provider) + +/* + * Minimum fabric clock rate to prevent bus starvation. + * + * When no consumers request bandwidth, the rate calculation yields 0, + * causing fabric clocks to drop to minimum. This creates bimodal + * performance: fast when other subsystems (like display) happen to + * request bandwidth, slow otherwise. + * + * 384 MHz keeps fabric fast during concurrent MDP display scanout + * and USB gadget traffic. webOS docs: "AXI bus frequency needs to be + * kept at maximum value while USB data transfers are happening." + * 266 MHz was insufficient - USB crashed during display activity. + */ +#define MSM8660_FABRIC_MIN_RATE 384000000UL /* 384 MHz */ + +/* + * Maximum RPM ARB buffer size across all fabrics. + * MM fabric is largest at 23 u32 words. + */ +#define MSM8660_MAX_RPM_BUF 23 + +/* + * RPM fabric arbitration data format (from webOS msm_bus_fabric.c): + * + * Each u16 arb entry: bit 15 =3D tier (1=3DTIER1 high priority), bits 14-= 0 =3D 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] =3D total bandwidth to that slave + * arb[(tier-1)*nmasters + master_port] =3D per-master arbitration entry + */ +#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[] =3D { + { .id =3D "bus" }, + { .id =3D "bus_a" }, + { .id =3D "ebi1" }, + { .id =3D "ebi1_a" }, +}; + +static const struct clk_bulk_data msm8660_sfab_clocks[] =3D { + { .id =3D "bus" }, + { .id =3D "bus_a" }, +}; + +static const struct clk_bulk_data msm8660_mmfab_clocks[] =3D { + { .id =3D "bus" }, + { .id =3D "bus_a" }, + { .id =3D "smi" }, + { .id =3D "smi_a" }, +}; + +static const struct clk_bulk_data msm8660_dfab_clocks[] =3D { + { .id =3D "bus" }, + { .id =3D "bus_a" }, +}; + +/** + * struct msm8660_icc_node - MSM8660 specific interconnect nodes + * @name: the node name used in debugfs + * @id: a unique node identifier + * @links: an array of nodes where we can go next while traversing + * @num_links: the total number of @links + * @buswidth: width of the interconnect between a node and the bus (bytes) + * @rate: current bus clock rate in Hz + * @mas_port: master port index for RPM ARB (-1 if not a master) + * @slv_port: slave port index for RPM bwsum (-1 if not a slave) + * @mas_tier: master priority tier (ARB_TIER1 or ARB_TIER2, 0 if N/A) + */ +struct msm8660_icc_node { + unsigned char *name; + u16 id; +#define MSM8660_ICC_MAX_LINKS 3 + u16 links[MSM8660_ICC_MAX_LINKS]; + u16 num_links; + u16 buswidth; + s8 mas_port; + s8 slv_port; + u8 mas_tier; +}; + +/** + * struct msm8660_icc_desc - Fabric descriptor + * @nodes: array of node pointers + * @num_nodes: number of nodes + * @bus_clks: clock definitions + * @num_clks: number of clocks + * @rpm_resource: QCOM_RPM_*_FABRIC_ARB constant, or -1 for no ARB + * @nmasters: number of master ports in this fabric (for ARB array sizing) + * @nslaves: number of slave ports in this fabric (for bwsum array sizing) + * @ntieredslaves: number of tiered slaves (ARB rows) + * @default_tiered_slave: 1-based index of default tiered slave for masters + * @rpm_buf_size: number of u32 words for RPM write + * @bus_width: representative fabric bus width in bytes, used as the + * divisor for translating aggregate bytes/sec into a single + * clock rate that drives the whole fabric + */ +struct msm8660_icc_desc { + struct msm8660_icc_node * const *nodes; + size_t num_nodes; + const struct clk_bulk_data *bus_clks; + size_t num_clks; + int rpm_resource; + u8 nmasters; + u8 nslaves; + u8 ntieredslaves; + u8 default_tiered_slave; + u8 rpm_buf_size; + u8 bus_width; +}; + +/** + * struct msm8660_icc_provider - MSM8660 specific interconnect provider + * @provider: generic interconnect provider + * @bus_clks: the clk_bulk_data table of bus clocks + * @num_clks: the total number of clk_bulk_data entries + * @rpm: RPM handle for fabric arbitration writes + * @desc: fabric descriptor with RPM metadata + * @arb: pre-allocated arbitration array (nmasters * ntieredslaves u16 ent= ries) + * @bwsum: pre-allocated bandwidth sum array (nslaves u16 entries) + * @rpm_buf: pre-allocated RPM write buffer (rpm_buf_size u32 entries) + * @rate: last clock rate applied to the fabric bus_clks, used as the + * single source of truth for whether the rate actually needs to + * be reprogrammed (per-node caching would desync when different + * masters update at different times) + */ +struct msm8660_icc_provider { + struct icc_provider provider; + struct clk_bulk_data *bus_clks; + int num_clks; + struct qcom_rpm *rpm; + const struct msm8660_icc_desc *desc; + u16 *arb; + u16 *bwsum; + u32 *rpm_buf; + u32 rate; +}; + +/* + * 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=3D1, ARB_TIER2=3D2, 0 if N/A) + */ +#define DEFINE_QNODE(_name, _id, _buswidth, _mas, _slv, _tier, ...) \ + static struct msm8660_icc_node _name =3D { \ + .name =3D #_name, \ + .id =3D _id, \ + .buswidth =3D _buswidth, \ + .num_links =3D COUNT_ARGS(__VA_ARGS__), \ + .links =3D { __VA_ARGS__ }, \ + .mas_port =3D _mas, \ + .slv_port =3D _slv, \ + .mas_tier =3D _tier, \ + } + +/* + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * APPSS Fabric nodes + * + * 4 masters, 4 slaves, 2 tiered slaves + * Master ports: SMPSS_M0=3D0, SMPSS_M1=3D1, FAB_MMSS=3D2, FAB_SYSTEM=3D3 + * Slave ports: EBI_CH0=3D0, SMPSS_L2=3D1, MMSS_FAB=3D2, SYSTEM_FAB=3D3 + * Default target: tiered slave 1 (EBI_CH0) + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + */ +DEFINE_QNODE(mas_ampss_m0, MSM8660_AFAB_MAS_AMPSS_M0, 8, 0, -1, ARB_TIER2, + MSM8660_AFAB_SLV_EBI_CH0, MSM8660_AFAB_TO_MMSS, MSM8660_AFAB_TO_SYST= EM); +DEFINE_QNODE(mas_ampss_m1, MSM8660_AFAB_MAS_AMPSS_M1, 8, 1, -1, ARB_TIER2, + MSM8660_AFAB_SLV_EBI_CH0, MSM8660_AFAB_TO_MMSS, MSM8660_AFAB_TO_SYST= EM); +DEFINE_QNODE(slv_ebi_ch0, MSM8660_AFAB_SLV_EBI_CH0, 8, -1, 0, 0); +DEFINE_QNODE(slv_ampss_l2, MSM8660_AFAB_SLV_AMPSS_L2, 8, -1, 1, 0); +/* + * Gateway nodes need links to both the cross-fabric gateway AND the memory + * slave to enable cross-fabric paths. Without link to EBI_CH0, path_find() + * can't route from MMSS/System fabric masters to main memory. + * + * AFAB_TO_MMSS doubles as AFAB master port 2 (the FAB_MMSS master). MDP + * scanout and GPU traffic enter AFAB through this gateway. Mark it + * ARB_TIER1 so display/multimedia traffic keeps priority over CPU L2 + * misses inside the APPSS fabric =E2=80=94 without this, MDP TIER1 priori= ty + * earned in MMFAB is dropped at the AFAB boundary and MDP fetches lose + * arbitration to CPU traffic, producing PRIMARY_INTF_UDERRUN. + */ +DEFINE_QNODE(afab_to_mmss, MSM8660_AFAB_TO_MMSS, 8, 2, 2, ARB_TIER1, + MSM8660_MMFAB_TO_APPSS, MSM8660_AFAB_SLV_EBI_CH0); +DEFINE_QNODE(afab_to_system, MSM8660_AFAB_TO_SYSTEM, 8, 3, 3, ARB_TIER2, + MSM8660_SFAB_TO_APPSS, MSM8660_AFAB_SLV_EBI_CH0); + +static struct msm8660_icc_node * const msm8660_afab_nodes[] =3D { + [AFAB_MAS_AMPSS_M0] =3D &mas_ampss_m0, + [AFAB_MAS_AMPSS_M1] =3D &mas_ampss_m1, + [AFAB_SLV_EBI_CH0] =3D &slv_ebi_ch0, + [AFAB_SLV_AMPSS_L2] =3D &slv_ampss_l2, + [AFAB_TO_MMSS] =3D &afab_to_mmss, + [AFAB_TO_SYSTEM] =3D &afab_to_system, +}; + +static const struct msm8660_icc_desc msm8660_afab =3D { + .nodes =3D msm8660_afab_nodes, + .num_nodes =3D ARRAY_SIZE(msm8660_afab_nodes), + .bus_clks =3D msm8660_afab_clocks, + .num_clks =3D ARRAY_SIZE(msm8660_afab_clocks), + .rpm_resource =3D QCOM_RPM_APPS_FABRIC_ARB, + .nmasters =3D 4, + .nslaves =3D 4, + .ntieredslaves =3D 2, + .default_tiered_slave =3D 1, /* EBI_CH0 */ + .rpm_buf_size =3D 6, + .bus_width =3D 8, /* 64-bit APPSS fabric datapath */ +}; + +/* + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * System Fabric nodes + * + * 17 masters, 9 slaves, 2 tiered slaves + * Master ports: see enum msm_bus_8660_master_ports_type in webOS + * Slave ports: APPSS_FAB=3D0, SPS=3D1, SYSTEM_IMEM=3D2, SMPSS=3D3, MSS= =3D4, + * LPASS=3D5, CPSS_FPB=3D6, SYSTEM_FPB=3D7, MMSS_FPB=3D8 + * Default target: tiered slave 1 (APPSS gateway) + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + */ +DEFINE_QNODE(sfab_mas_appss, MSM8660_SFAB_MAS_APPSS, 8, 0, -1, ARB_TIER2, + MSM8660_AFAB_TO_SYSTEM); +DEFINE_QNODE(sfab_mas_sps, MSM8660_SFAB_MAS_SPS, 8, 1, -1, ARB_TIER2, + MSM8660_SFAB_SLV_SPS); +/* + * ADM DMA masters - route through SFAB_TO_APPSS to reach EBI memory. + * Path: ADM -> SFAB_TO_APPSS -> AFAB_TO_SYSTEM -> AFAB_SLV_EBI_CH0 + * This enables proper EBI bandwidth voting for DMA operations. + */ +DEFINE_QNODE(sfab_mas_adm0_port0, MSM8660_SFAB_MAS_ADM0_PORT0, 8, 2, -1, A= RB_TIER2, + MSM8660_SFAB_TO_APPSS); +DEFINE_QNODE(sfab_mas_adm0_port1, MSM8660_SFAB_MAS_ADM0_PORT1, 8, 3, -1, A= RB_TIER2, + MSM8660_SFAB_TO_APPSS); +DEFINE_QNODE(sfab_mas_adm1_port0, MSM8660_SFAB_MAS_ADM1_PORT0, 8, 4, -1, A= RB_TIER2, + MSM8660_SFAB_TO_APPSS); +DEFINE_QNODE(sfab_mas_adm1_port1, MSM8660_SFAB_MAS_ADM1_PORT1, 8, 5, -1, A= RB_TIER2, + MSM8660_SFAB_TO_APPSS); +DEFINE_QNODE(sfab_mas_lpass_proc, MSM8660_SFAB_MAS_LPASS_PROC, 8, 6, -1, A= RB_TIER2); +DEFINE_QNODE(sfab_mas_mss_proci, MSM8660_SFAB_MAS_MSS_PROCI, 8, 7, -1, ARB= _TIER2); +DEFINE_QNODE(sfab_mas_mss_procd, MSM8660_SFAB_MAS_MSS_PROCD, 8, 8, -1, ARB= _TIER2); +DEFINE_QNODE(sfab_mas_mss_mdm_port0, MSM8660_SFAB_MAS_MSS_MDM_PORT0, 8, 9,= -1, ARB_TIER2); +DEFINE_QNODE(sfab_mas_lpass, MSM8660_SFAB_MAS_LPASS, 8, 10, -1, ARB_TIER2); +DEFINE_QNODE(sfab_mas_mmss_fpb, MSM8660_SFAB_MAS_MMSS_FPB, 8, 13, -1, ARB_= TIER2); +DEFINE_QNODE(sfab_mas_adm1_ci, MSM8660_SFAB_MAS_ADM1_CI, 8, 14, -1, ARB_TI= ER2); +DEFINE_QNODE(sfab_mas_adm0_ci, MSM8660_SFAB_MAS_ADM0_CI, 8, 15, -1, ARB_TI= ER2); +DEFINE_QNODE(sfab_mas_mss_mdm_port1, MSM8660_SFAB_MAS_MSS_MDM_PORT1, 8, 16= , -1, ARB_TIER2); +/* USB HS has no dedicated master port in webOS SFAB - bandwidth voting on= ly */ +DEFINE_QNODE(sfab_mas_usb_hs, MSM8660_SFAB_MAS_USB_HS, 8, -1, -1, 0, + MSM8660_SFAB_TO_APPSS); +DEFINE_QNODE(sfab_to_appss, MSM8660_SFAB_TO_APPSS, 8, -1, 0, 0, + MSM8660_AFAB_TO_SYSTEM); +DEFINE_QNODE(sfab_to_system_fpb, MSM8660_SFAB_TO_SYSTEM_FPB, 4, -1, 7, 0); +DEFINE_QNODE(sfab_to_cpss_fpb, MSM8660_SFAB_TO_CPSS_FPB, 4, -1, 6, 0); +DEFINE_QNODE(sfab_slv_sps, MSM8660_SFAB_SLV_SPS, 8, -1, 1, 0); +DEFINE_QNODE(sfab_slv_system_imem, MSM8660_SFAB_SLV_SYSTEM_IMEM, 8, -1, 2,= 0); +DEFINE_QNODE(sfab_slv_ampss, MSM8660_SFAB_SLV_AMPSS, 8, -1, 3, 0); +DEFINE_QNODE(sfab_slv_mss, MSM8660_SFAB_SLV_MSS, 8, -1, 4, 0); +DEFINE_QNODE(sfab_slv_lpass, MSM8660_SFAB_SLV_LPASS, 8, -1, 5, 0); +DEFINE_QNODE(sfab_slv_mmss_fpb, MSM8660_SFAB_SLV_MMSS_FPB, 8, -1, 8, 0); +/* + * Gateway to DFAB: links to DFAB_TO_SFAB for path traversal. + * Also links to SFAB_TO_APPSS to enable DFAB->SFAB->AFAB->memory paths. + * No slave port in webOS SFAB config (DFAB is separate fabric). + */ +DEFINE_QNODE(sfab_to_dfab, MSM8660_SFAB_TO_DFAB, 8, -1, -1, 0, + MSM8660_DFAB_TO_SFAB, MSM8660_SFAB_TO_APPSS); + +static struct msm8660_icc_node * const msm8660_sfab_nodes[] =3D { + [SFAB_MAS_APPSS] =3D &sfab_mas_appss, + [SFAB_MAS_SPS] =3D &sfab_mas_sps, + [SFAB_MAS_ADM0_PORT0] =3D &sfab_mas_adm0_port0, + [SFAB_MAS_ADM0_PORT1] =3D &sfab_mas_adm0_port1, + [SFAB_MAS_ADM1_PORT0] =3D &sfab_mas_adm1_port0, + [SFAB_MAS_ADM1_PORT1] =3D &sfab_mas_adm1_port1, + [SFAB_MAS_LPASS_PROC] =3D &sfab_mas_lpass_proc, + [SFAB_MAS_MSS_PROCI] =3D &sfab_mas_mss_proci, + [SFAB_MAS_MSS_PROCD] =3D &sfab_mas_mss_procd, + [SFAB_MAS_MSS_MDM_PORT0] =3D &sfab_mas_mss_mdm_port0, + [SFAB_MAS_LPASS] =3D &sfab_mas_lpass, + [SFAB_MAS_MMSS_FPB] =3D &sfab_mas_mmss_fpb, + [SFAB_MAS_ADM1_CI] =3D &sfab_mas_adm1_ci, + [SFAB_MAS_ADM0_CI] =3D &sfab_mas_adm0_ci, + [SFAB_MAS_MSS_MDM_PORT1] =3D &sfab_mas_mss_mdm_port1, + [SFAB_MAS_USB_HS] =3D &sfab_mas_usb_hs, + [SFAB_TO_APPSS] =3D &sfab_to_appss, + [SFAB_TO_SYSTEM_FPB] =3D &sfab_to_system_fpb, + [SFAB_TO_CPSS_FPB] =3D &sfab_to_cpss_fpb, + [SFAB_SLV_SPS] =3D &sfab_slv_sps, + [SFAB_SLV_SYSTEM_IMEM] =3D &sfab_slv_system_imem, + [SFAB_SLV_AMPSS] =3D &sfab_slv_ampss, + [SFAB_SLV_MSS] =3D &sfab_slv_mss, + [SFAB_SLV_LPASS] =3D &sfab_slv_lpass, + [SFAB_SLV_MMSS_FPB] =3D &sfab_slv_mmss_fpb, + [SFAB_TO_DFAB] =3D &sfab_to_dfab, +}; + +static const struct msm8660_icc_desc msm8660_sfab =3D { + .nodes =3D msm8660_sfab_nodes, + .num_nodes =3D ARRAY_SIZE(msm8660_sfab_nodes), + .bus_clks =3D msm8660_sfab_clocks, + .num_clks =3D ARRAY_SIZE(msm8660_sfab_clocks), + .rpm_resource =3D QCOM_RPM_SYS_FABRIC_ARB, + .nmasters =3D 17, + .nslaves =3D 9, + .ntieredslaves =3D 2, + .default_tiered_slave =3D 1, /* APPSS gateway */ + .rpm_buf_size =3D 22, + .bus_width =3D 8, /* 64-bit System fabric datapath */ +}; + +/* + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * MMSS Fabric nodes - Multimedia subsystem (MDP, camera, video, GPU) + * + * 14 masters, 4 slaves, 3 tiered slaves + * Master ports: MDP0=3D0, MDP1=3D1, ADM1=3D2, ROT=3D3, 3D=3D4, JPEG_DEC= =3D5, + * 2D_CORE0=3D6, VFE=3D7, VPE=3D8, JPEG_ENC=3D9, 2D_CORE1=3D= 10, + * (APPS_FAB=3D11), HD_CODEC0=3D12, HD_CODEC1=3D13 + * Slave ports: SMI=3D0, APPSS_FAB=3D1, (APPSS_FAB_1=3D2), MM_IMEM=3D3 + * Tiered slaves: SMI=3D1, APPSS_FAB=3D2, MM_IMEM=3D3 + * Default target: tiered slave 2 (APPSS gateway -> main memory) + * + * MDP ports get TIER1 (high priority) for guaranteed display refresh. + * All other masters get TIER2 (default priority). + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + */ +DEFINE_QNODE(mmfab_mas_mdp_port0, MSM8660_MMFAB_MAS_MDP_PORT0, 16, 0, -1, = ARB_TIER1, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_mdp_port1, MSM8660_MMFAB_MAS_MDP_PORT1, 16, 1, -1, = ARB_TIER1, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_adm1_port0, MSM8660_MMFAB_MAS_ADM1_PORT0, 8, 2, -1,= ARB_TIER2); +DEFINE_QNODE(mmfab_mas_rotator, MSM8660_MMFAB_MAS_ROTATOR, 16, 3, -1, ARB_= TIER2, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_graphics_3d, MSM8660_MMFAB_MAS_GRAPHICS_3D, 16, 4, = -1, ARB_TIER2, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_jpeg_dec, MSM8660_MMFAB_MAS_JPEG_DEC, 16, 5, -1, AR= B_TIER2, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_graphics_2d_core0, MSM8660_MMFAB_MAS_GRAPHICS_2D_CO= RE0, 16, + 6, -1, ARB_TIER2, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_vfe, MSM8660_MMFAB_MAS_VFE, 16, 7, -1, ARB_TIER2, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_vpe, MSM8660_MMFAB_MAS_VPE, 16, 8, -1, ARB_TIER2, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_jpeg_enc, MSM8660_MMFAB_MAS_JPEG_ENC, 16, 9, -1, AR= B_TIER2, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_graphics_2d_core1, MSM8660_MMFAB_MAS_GRAPHICS_2D_CO= RE1, 16, + 10, -1, ARB_TIER2, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_hd_codec_port0, MSM8660_MMFAB_MAS_HD_CODEC_PORT0, 1= 6, + 12, -1, ARB_TIER2, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +DEFINE_QNODE(mmfab_mas_hd_codec_port1, MSM8660_MMFAB_MAS_HD_CODEC_PORT1, 1= 6, + 13, -1, ARB_TIER2, + MSM8660_MMFAB_SLV_SMI, MSM8660_MMFAB_TO_APPSS); +/* + * Gateway from APPSS into MMSS: slave (port 1) for outbound traffic + * leaving MMSS, AND master (port 2) for inbound traffic arriving from + * APPSS (e.g. CPU memremap_wc accesses to SMI BOs). Without the master + * port and the forward links into MMFAB slaves (SMI / MM_IMEM), the + * ICC path-finder has no route from AMPSS_M0 to MMFAB_SLV_SMI; the + * cross-fabric gateway only worked for outbound traffic (MMSS masters + * reaching APPSS slaves like EBI). + * + * ARB_TIER1 keeps AMPSS->SMI traffic high-priority within MMFAB so + * CPU mmap reads/writes to SMI BOs don't get starved by MDP scanout. + */ +DEFINE_QNODE(mmfab_to_appss, MSM8660_MMFAB_TO_APPSS, 8, 11, 1, ARB_TIER1, + MSM8660_AFAB_TO_MMSS, + MSM8660_MMFAB_SLV_SMI, + MSM8660_MMFAB_SLV_MM_IMEM); +DEFINE_QNODE(mmfab_slv_smi, MSM8660_MMFAB_SLV_SMI, 16, -1, 0, 0); +DEFINE_QNODE(mmfab_slv_mm_imem, MSM8660_MMFAB_SLV_MM_IMEM, 8, -1, 3, 0); + +static struct msm8660_icc_node * const msm8660_mmfab_nodes[] =3D { + [MMFAB_MAS_MDP_PORT0] =3D &mmfab_mas_mdp_port0, + [MMFAB_MAS_MDP_PORT1] =3D &mmfab_mas_mdp_port1, + [MMFAB_MAS_ADM1_PORT0] =3D &mmfab_mas_adm1_port0, + [MMFAB_MAS_ROTATOR] =3D &mmfab_mas_rotator, + [MMFAB_MAS_GRAPHICS_3D] =3D &mmfab_mas_graphics_3d, + [MMFAB_MAS_JPEG_DEC] =3D &mmfab_mas_jpeg_dec, + [MMFAB_MAS_GRAPHICS_2D_CORE0] =3D &mmfab_mas_graphics_2d_core0, + [MMFAB_MAS_VFE] =3D &mmfab_mas_vfe, + [MMFAB_MAS_VPE] =3D &mmfab_mas_vpe, + [MMFAB_MAS_JPEG_ENC] =3D &mmfab_mas_jpeg_enc, + [MMFAB_MAS_GRAPHICS_2D_CORE1] =3D &mmfab_mas_graphics_2d_core1, + [MMFAB_MAS_HD_CODEC_PORT0] =3D &mmfab_mas_hd_codec_port0, + [MMFAB_MAS_HD_CODEC_PORT1] =3D &mmfab_mas_hd_codec_port1, + [MMFAB_TO_APPSS] =3D &mmfab_to_appss, + [MMFAB_SLV_SMI] =3D &mmfab_slv_smi, + [MMFAB_SLV_MM_IMEM] =3D &mmfab_slv_mm_imem, +}; + +static const struct msm8660_icc_desc msm8660_mmfab =3D { + .nodes =3D msm8660_mmfab_nodes, + .num_nodes =3D ARRAY_SIZE(msm8660_mmfab_nodes), + .bus_clks =3D msm8660_mmfab_clocks, + .num_clks =3D ARRAY_SIZE(msm8660_mmfab_clocks), + .rpm_resource =3D QCOM_RPM_MM_FABRIC_ARB, + .nmasters =3D 14, + .nslaves =3D 4, + .ntieredslaves =3D 3, + .default_tiered_slave =3D 2, /* APPSS gateway */ + .rpm_buf_size =3D 23, + .bus_width =3D 16, /* 128-bit Multimedia fabric datapath */ +}; + +/* + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * Daytona Fabric (DFAB) nodes - peripheral bus for SDCC and ADM DMA + * + * DFAB connects slower peripherals to SFAB via the DFAB_TO_SFAB gateway. + * SDCC controllers (eMMC, SD card) connect here. + * + * No RPM ARB for DFAB - it's a simple peripheral bus with clock-only cont= rol. + * + * USB HS is included as a DFAB voter for compatibility with the legacy + * webOS kernel clock voting mechanism. + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + */ +DEFINE_QNODE(dfab_mas_sdc1, MSM8660_DFAB_MAS_SDC1, 8, -1, -1, 0, + MSM8660_DFAB_TO_SFAB); +DEFINE_QNODE(dfab_mas_sdc2, MSM8660_DFAB_MAS_SDC2, 8, -1, -1, 0, + MSM8660_DFAB_TO_SFAB); +DEFINE_QNODE(dfab_mas_sdc3, MSM8660_DFAB_MAS_SDC3, 8, -1, -1, 0, + MSM8660_DFAB_TO_SFAB); +DEFINE_QNODE(dfab_mas_sdc4, MSM8660_DFAB_MAS_SDC4, 8, -1, -1, 0, + MSM8660_DFAB_TO_SFAB); +DEFINE_QNODE(dfab_mas_sdc5, MSM8660_DFAB_MAS_SDC5, 8, -1, -1, 0, + MSM8660_DFAB_TO_SFAB); +DEFINE_QNODE(dfab_mas_adm0_master, MSM8660_DFAB_MAS_ADM0_MASTER, 8, -1, -1= , 0, + MSM8660_DFAB_TO_SFAB); +DEFINE_QNODE(dfab_mas_adm1_master, MSM8660_DFAB_MAS_ADM1_MASTER, 8, -1, -1= , 0, + MSM8660_DFAB_TO_SFAB); +DEFINE_QNODE(dfab_to_sfab, MSM8660_DFAB_TO_SFAB, 8, -1, -1, 0, + MSM8660_SFAB_TO_DFAB); +DEFINE_QNODE(dfab_slv_sdc1, MSM8660_DFAB_SLV_SDC1, 8, -1, -1, 0); +DEFINE_QNODE(dfab_slv_sdc2, MSM8660_DFAB_SLV_SDC2, 8, -1, -1, 0); +DEFINE_QNODE(dfab_slv_sdc3, MSM8660_DFAB_SLV_SDC3, 8, -1, -1, 0); +DEFINE_QNODE(dfab_slv_sdc4, MSM8660_DFAB_SLV_SDC4, 8, -1, -1, 0); +DEFINE_QNODE(dfab_slv_sdc5, MSM8660_DFAB_SLV_SDC5, 8, -1, -1, 0); +/* USB HS DFAB voter - keeps DFAB clock stable during USB activity */ +DEFINE_QNODE(dfab_mas_usb_hs, MSM8660_DFAB_MAS_USB_HS, 8, -1, -1, 0, + MSM8660_DFAB_TO_SFAB); +/* DSPS DFAB voter - keeps DFAB clock stable during sensor activity */ +DEFINE_QNODE(dfab_mas_dsps, MSM8660_DFAB_MAS_DSPS, 8, -1, -1, 0, + MSM8660_DFAB_TO_SFAB); + +static struct msm8660_icc_node * const msm8660_dfab_nodes[] =3D { + [DFAB_MAS_SDC1] =3D &dfab_mas_sdc1, + [DFAB_MAS_SDC2] =3D &dfab_mas_sdc2, + [DFAB_MAS_SDC3] =3D &dfab_mas_sdc3, + [DFAB_MAS_SDC4] =3D &dfab_mas_sdc4, + [DFAB_MAS_SDC5] =3D &dfab_mas_sdc5, + [DFAB_MAS_ADM0_MASTER] =3D &dfab_mas_adm0_master, + [DFAB_MAS_ADM1_MASTER] =3D &dfab_mas_adm1_master, + [DFAB_TO_SFAB] =3D &dfab_to_sfab, + [DFAB_SLV_SDC1] =3D &dfab_slv_sdc1, + [DFAB_SLV_SDC2] =3D &dfab_slv_sdc2, + [DFAB_SLV_SDC3] =3D &dfab_slv_sdc3, + [DFAB_SLV_SDC4] =3D &dfab_slv_sdc4, + [DFAB_SLV_SDC5] =3D &dfab_slv_sdc5, + [DFAB_MAS_USB_HS] =3D &dfab_mas_usb_hs, + [DFAB_MAS_DSPS] =3D &dfab_mas_dsps, +}; + +static const struct msm8660_icc_desc msm8660_dfab =3D { + .nodes =3D msm8660_dfab_nodes, + .num_nodes =3D ARRAY_SIZE(msm8660_dfab_nodes), + .bus_clks =3D msm8660_dfab_clocks, + .num_clks =3D ARRAY_SIZE(msm8660_dfab_clocks), + .rpm_resource =3D -1, /* No RPM ARB for DFAB */ + .bus_width =3D 8, /* 64-bit Daytona fabric datapath */ +}; + +/* + * Pack bwsum[] and arb[] arrays into the u32 RPM buffer. + * + * Two u16 values are packed per u32 word: lower 16 bits first, upper 16 n= ext. + * Layout: [bwsum pairs] then [arb pairs], handling odd boundaries. + * + * This matches the webOS msm_bus_fabric_rpm_commit() packing algorithm. + */ +static void msm8660_pack_rpm_data(const u16 *bwsum, int nslaves, + const u16 *arb, int arb_size, + u32 *buf) +{ + int i, index =3D 0; + + /* Pack bwsum pairs */ + for (i =3D 0; i + 1 < nslaves; i +=3D 2) { + buf[index] =3D ((u32)bwsum[i + 1] << 16) | bwsum[i]; + index++; + } + + /* Handle boundary between bwsum and arb for odd nslaves */ + if (nslaves & 1) { + buf[index] =3D ((u32)arb[0] << 16) | bwsum[i]; + index++; + i =3D 1; /* Start arb from index 1 (index 0 already packed) */ + } else { + i =3D 0; + } + + /* Pack arb pairs */ + for (; i + 1 < arb_size; i +=3D 2) { + buf[index] =3D ((u32)arb[i + 1] << 16) | arb[i]; + index++; + } + + /* Handle odd arb entry at end */ + if (i < arb_size) { + buf[index] =3D arb[i]; + index++; + } +} + +/* + * Send fabric arbitration data to RPM. + * + * Iterates over all ICC nodes in the provider, builds bwsum/arb arrays + * from their aggregated bandwidth, and sends the packed data to RPM. + */ +static void msm8660_rpm_commit(struct msm8660_icc_provider *qp) +{ + const struct msm8660_icc_desc *desc =3D qp->desc; + struct icc_provider *provider =3D &qp->provider; + int nm =3D desc->nmasters; + int ns =3D desc->nslaves; + int nts =3D desc->ntieredslaves; + int arb_size =3D nm * nts; + int def_ts =3D desc->default_tiered_slave; + struct icc_node *n; + int ret; + + memset(qp->bwsum, 0, ns * sizeof(u16)); + memset(qp->arb, 0, arb_size * sizeof(u16)); + memset(qp->rpm_buf, 0, desc->rpm_buf_size * sizeof(u32)); + + list_for_each_entry(n, &provider->nodes, node_list) { + struct msm8660_icc_node *qn =3D n->data; + u64 bw_bytes; + u16 bw_128k; + + /* Use max of avg and peak bandwidth, convert to 128KB units */ + bw_bytes =3D max(icc_units_to_bps(n->avg_bw), + icc_units_to_bps(n->peak_bw)); + bw_128k =3D (u16)min_t(u64, bw_bytes >> 17, ARB_BWMASK); + + /* Set arb entry for masters at their default tiered slave */ + if (qn->mas_port >=3D 0 && qn->mas_port < nm && def_ts > 0) { + int idx =3D (def_ts - 1) * nm + qn->mas_port; + u8 tier; + + if (idx < arb_size) { + tier =3D bw_128k ? qn->mas_tier : ARB_TIER2; + qp->arb[idx] =3D (tier =3D=3D ARB_TIER1 ? ARB_TIERMASK : 0) + | (bw_128k & ARB_BWMASK); + } + } + + /* Set bwsum for slaves */ + if (qn->slv_port >=3D 0 && qn->slv_port < ns) + qp->bwsum[qn->slv_port] =3D bw_128k; + } + + msm8660_pack_rpm_data(qp->bwsum, ns, qp->arb, arb_size, qp->rpm_buf); + + ret =3D qcom_rpm_write(qp->rpm, QCOM_RPM_ACTIVE_STATE, + desc->rpm_resource, qp->rpm_buf, + desc->rpm_buf_size); + if (ret) + dev_err_ratelimited(provider->dev, + "RPM fabric ARB write failed: %d\n", ret); +} + +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 =3D 0, agg_peak =3D 0; + struct icc_provider *provider; + struct icc_node *n; + int ret, i; + + src_qn =3D src->data; + provider =3D src->provider; + qp =3D 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); + + sum_bw =3D icc_units_to_bps(agg_avg); + max_peak_bw =3D icc_units_to_bps(agg_peak); + + /* + * Divide by the *fabric* bus width, not src_qn->buswidth: every + * master on a given fabric shares the same hardware clock, so the + * required clock rate is a single function of total bandwidth and + * the fabric's bus width. Picking the bus width of whichever node + * happened to trigger this update would make the rate oscillate + * depending on which master called icc_set_bw() last. + */ + rate =3D max(sum_bw, max_peak_bw); + do_div(rate, qp->desc->bus_width); + /* Apply minimum floor to prevent bus starvation */ + rate =3D max_t(u64, rate, MSM8660_FABRIC_MIN_RATE); + rate =3D min_t(u32, rate, INT_MAX); + + if (qp->rate !=3D rate) { + for (i =3D 0; i < qp->num_clks; i++) { + ret =3D clk_set_rate(qp->bus_clks[i].clk, rate); + if (ret) { + dev_err(provider->dev, + "%s clk_set_rate error: %d\n", + qp->bus_clks[i].id, ret); + ret =3D 0; + } + } + qp->rate =3D rate; + } + + /* Send RPM fabric arbitration if available */ + if (qp->rpm && qp->desc->rpm_resource >=3D 0) + msm8660_rpm_commit(qp); + + return 0; +} + +static int msm8660_get_bw(struct icc_node *node, u32 *avg, u32 *peak) +{ + *avg =3D 0; + *peak =3D 0; + return 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) +{ + struct device_node *rpm_np; + struct platform_device *rpm_pdev; + struct device_link *link; + struct qcom_rpm *rpm; + + rpm_np =3D 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; + } + + rpm_pdev =3D 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); + } + + rpm =3D dev_get_drvdata(&rpm_pdev->dev); + if (!rpm) { + put_device(&rpm_pdev->dev); + dev_dbg(dev, "RPM not ready, deferring probe\n"); + return ERR_PTR(-EPROBE_DEFER); + } + + /* + * Keep the RPM device alive for as long as we are bound; without + * a device link, the devres-managed qcom_rpm could be released + * out from under us if the RPM driver were unbound at runtime, + * leaving a dangling pointer in qp->rpm. + */ + link =3D 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); + } + + 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 =3D &pdev->dev; + struct icc_onecell_data *data; + struct icc_provider *provider; + struct icc_node *node; + size_t num_nodes, i; + int ret; + + desc =3D of_device_get_match_data(dev); + if (!desc) + return -EINVAL; + + qnodes =3D desc->nodes; + num_nodes =3D desc->num_nodes; + + qp =3D devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL); + if (!qp) + return -ENOMEM; + + data =3D devm_kzalloc(dev, struct_size(data, nodes, num_nodes), + GFP_KERNEL); + if (!data) + return -ENOMEM; + data->num_nodes =3D num_nodes; + + qp->bus_clks =3D devm_kmemdup(dev, desc->bus_clks, + desc->num_clks * sizeof(*desc->bus_clks), + GFP_KERNEL); + if (!qp->bus_clks) + return -ENOMEM; + + qp->num_clks =3D 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". + */ + ret =3D devm_clk_bulk_get_optional(dev, qp->num_clks, qp->bus_clks); + if (ret =3D=3D -EPROBE_DEFER) + return ret; + if (ret) { + dev_warn(dev, "Failed to get bus clocks: %d (continuing without clock sc= aling)\n", + ret); + qp->num_clks =3D 0; + } + + if (qp->num_clks) { + ret =3D 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 =3D 0; + } + } + + /* Set up RPM fabric arbitration */ + qp->desc =3D desc; + if (desc->rpm_resource >=3D 0) { + qp->rpm =3D msm8660_get_rpm(dev); + if (IS_ERR(qp->rpm)) + return PTR_ERR(qp->rpm); + if (qp->rpm) { + int arb_size =3D desc->nmasters * desc->ntieredslaves; + + qp->bwsum =3D devm_kcalloc(dev, desc->nslaves, + sizeof(u16), GFP_KERNEL); + qp->arb =3D devm_kcalloc(dev, arb_size + 1, + sizeof(u16), GFP_KERNEL); + qp->rpm_buf =3D 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 =3D NULL; + } else { + int rc; + + dev_info(dev, "RPM fabric ARB enabled (%d masters, %d slaves, %d tiere= d)\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 =E2=80=94 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 =3D 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 =3D &qp->provider; + provider->dev =3D dev; + provider->set =3D msm8660_icc_set; + provider->aggregate =3D icc_std_aggregate; + provider->xlate =3D of_icc_xlate_onecell; + provider->data =3D data; + provider->get_bw =3D msm8660_get_bw; + + icc_provider_init(provider); + + for (i =3D 0; i < num_nodes; i++) { + size_t j; + + if (!qnodes[i]) + continue; + + node =3D icc_node_create(qnodes[i]->id); + if (IS_ERR(node)) { + ret =3D PTR_ERR(node); + goto err_remove_nodes; + } + + node->name =3D qnodes[i]->name; + node->data =3D qnodes[i]; + icc_node_add(node, provider); + + dev_dbg(dev, "registered node %s\n", node->name); + + /* populate links */ + for (j =3D 0; j < qnodes[i]->num_links; j++) + icc_link_create(node, qnodes[i]->links[j]); + + data->nodes[i] =3D node; + } + + ret =3D icc_provider_register(provider); + if (ret) + goto err_remove_nodes; + + platform_set_drvdata(pdev, qp); + + dev_info(dev, "MSM8660 interconnect provider registered\n"); + + return 0; + +err_remove_nodes: + icc_nodes_remove(provider); + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + + return ret; +} + +static void msm8660_icc_remove(struct platform_device *pdev) +{ + struct msm8660_icc_provider *qp =3D platform_get_drvdata(pdev); + + icc_provider_deregister(&qp->provider); + icc_nodes_remove(&qp->provider); + if (qp->num_clks) + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); +} + +static const struct of_device_id msm8660_noc_of_match[] =3D { + { .compatible =3D "qcom,msm8660-apps-fabric", .data =3D &msm8660_afab }, + { .compatible =3D "qcom,msm8660-system-fabric", .data =3D &msm8660_sfab }, + { .compatible =3D "qcom,msm8660-mmss-fabric", .data =3D &msm8660_mmfab }, + { .compatible =3D "qcom,msm8660-daytona-fabric", .data =3D &msm8660_dfab = }, + { }, +}; +MODULE_DEVICE_TABLE(of, msm8660_noc_of_match); + +static struct platform_driver msm8660_noc_driver =3D { + .probe =3D msm8660_icc_probe, + .remove =3D msm8660_icc_remove, + .driver =3D { + .name =3D "qnoc-msm8660", + .of_match_table =3D msm8660_noc_of_match, + .sync_state =3D icc_sync_state, + }, +}; +/* + * Register the NOC provider at core_initcall, matching the mainline patte= rn + * used by newer Qualcomm SoCs (sm8450, glymur, qdu1000, sc8280xp, sm8750). + * + * Why not module_platform_driver (device_initcall)? drivers/Makefile lis= ts + * drivers/interconnect/ at position 189, *after* every ICC-consumer subdir + * (clk/ @40, soc/ @46, gpu/ @68, base/mfd/ @76, spmi/ @89, usb/ @106, + * i2c/ @116, mmc/ @133, remoteproc/ @158). Within a single initcall level + * execution order =3D link order, so a device_initcall registration here = runs + * *after* every consumer has already tried to probe. Mainline relies on + * deferred-probe retry to recover from that, but in this tree some consum= er + * (apcs-msm8660 + cpufreq cascade suspected) fails to recover within + * deferred_probe_timeout=3D5 and boot dies at the Tux splash with no root= fs. + * Empirically confirmed 2026-05-29 with module_platform_driver (commits + * 99275d8a8ae9 + ca35c591854c, reverted). + * + * icc_provider_register does not require icc_init to have run first -- + * the framework's locks are statically DEFINE_MUTEX'd -- so registering + * the provider at core_initcall (before icc_init at subsys_initcall) is + * safe, same as mainline sm8450 etc. + */ +static int __init msm8660_noc_driver_init(void) +{ + return platform_driver_register(&msm8660_noc_driver); +} +core_initcall(msm8660_noc_driver_init); + +static void __exit msm8660_noc_driver_exit(void) +{ + platform_driver_unregister(&msm8660_noc_driver); +} +module_exit(msm8660_noc_driver_exit); + +MODULE_DESCRIPTION("Qualcomm MSM8x60 interconnect driver"); +MODULE_LICENSE("GPL v2"); --=20 2.43.0 From nobody Mon Jun 8 08:28:04 2026 Received: from outbound8.mail.transip.nl (outbound8.mail.transip.nl [136.144.136.8]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 26D12301474; Sun, 31 May 2026 04:09:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.144.136.8 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780200584; cv=none; b=akw0N7I0VvJCHprJskKy2ftiMVjvJCPdNwCQzjGTNtqr3r9HUrFH3ILmYJiW2QPou5ZTa//AhrdTExJqhUFgbtoxe55Xd20hd/iJSzivDjcmOs1l4rL7MPKD5Q7bCJ2vuizuSawF6dFIShebENPTJFlxkWuMJcjOiI2CMVUsjYA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780200584; c=relaxed/simple; bh=mkFRdKwuUVef8l5jbZHd4TpVbtwCreqS1Vrc2PF1iTk=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RAl8L+tj8vdaE5+Kl7+VuojgNhlyEvJn8W4+flCgPXUfsxfndbnMkyzh7S09CKJiMROID4YNAkQG2XqYspytFMxWfrA+gqSP18/9VWg7X/VJa7dAx8bTgdg8pmK0n4OY3RJ3z3imzqyjEJPeFB6Pss9GcM2K85natVfCrzWoix8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=herrie.org; spf=pass smtp.mailfrom=herrie.org; dkim=pass (2048-bit key) header.d=herrie.org header.i=@herrie.org header.b=j3F/qH3G; arc=none smtp.client-ip=136.144.136.8 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=herrie.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=herrie.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=herrie.org header.i=@herrie.org header.b="j3F/qH3G" Received: from submission4.mail.transip.nl (unknown [10.103.8.155]) by outbound8.mail.transip.nl (Postfix) with ESMTP id 4gSkB84xfdzY75qw; Sun, 31 May 2026 06:09:20 +0200 (CEST) Received: from herrie-desktop.. (180-93-184-31.ftth.glasoperator.nl [31.184.93.180]) by submission4.mail.transip.nl (Postfix) with ESMTPA id 4gSkB74hLfz3R3nyZ; Sun, 31 May 2026 06:09:19 +0200 (CEST) From: Herman van Hazendonk To: Amit Kucheria , Conor Dooley , Daniel Lezcano , devicetree@vger.kernel.org, Krzysztof Kozlowski , Lee Jones , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Lukasz Luba , "Rafael J. Wysocki" , Rob Herring , Satya Priya , Thara Gopinath , van Hazendonk , Zhang Rui Subject: [PATCH v2 2/3] dt-bindings: thermal: qcom: add pm8901-temp-alarm Date: Sun, 31 May 2026 06:09:15 +0200 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: ClueGetter at submission4.mail.transip.nl DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=transip-a; d=herrie.org; t=1780200560; h=from:subject:to:references: in-reply-to:date:mime-version; bh=idL6XwhXReC/2NUZIyb2R5aJeN5I6jIlHbCIEZ5aS2Y=; b=j3F/qH3GILh68AXwuwsdOUBCZcWNCDR3KoPHPg/rPJYAx4zAnX27ZkPCLBcSDbiXY9UZRm Fv7k6p8fM7Mo7rzq8DhzLcrpiEmIkC5JTGjGcAguzKxN3uKpfE87zipVKoDoZTFesVFPyy ZjbmPlhBEEOSFYssHpj1J2co4irXybgu71oFCrxdtbXSBhgKToSgwIX03kRzLLXQPYnQJ1 BvI4m1cxnIO78rkcOhElKPQrYVtOTjVk5nCv29TppZXy9pVwKFzx/xmn5s/XPS+R2qkuuF qb1+/OjHvNGXuaUBTVzmv7DrcrKcxalf17dz50KU5Mr3GwwKmoBevITWrUsd2w== X-Report-Abuse-To: abuse@transip.nl Content-Type: text/plain; charset="utf-8" Add the binding for the temperature-alarm block inside the Qualcomm PM8901 PMIC (companion to the PM8058 on MSM8x60). The block has four selectable thresholds and three escalating stages; the driver maps these to representative millicelsius readings exposed to the thermal-of framework, and a board DT can wire stage 3 as a critical trip so the kernel issues orderly_poweroff() when the part overheats. The binding describes the SSBI sub-node address (CTRL register offset) and the two PMIC-internal interrupts the alarm raises: - TEMP_ALARM (PM8901 IRQ block 6 bit 4 =3D=3D hwirq 52), asserted on every stage transition; - TEMP_HI_ALARM (PM8901 IRQ block 6 bit 5 =3D=3D hwirq 53), asserted when the high-temperature stage is reached. The interrupts are sourced from the parent qcom,pm8901 PMIC's own interrupt-controller (not the SoC GIC); the node references the core /schemas/thermal/thermal-sensor.yaml so that the standard #thermal-sensor-cells handling and other shared thermal-sensor constraints are inherited automatically. Signed-off-by: Herman van Hazendonk --- .../thermal/qcom,pm8901-temp-alarm.yaml | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/qcom,pm8901-t= emp-alarm.yaml diff --git a/Documentation/devicetree/bindings/thermal/qcom,pm8901-temp-ala= rm.yaml b/Documentation/devicetree/bindings/thermal/qcom,pm8901-temp-alarm.= yaml new file mode 100644 index 000000000000..5d9eaeab8326 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/qcom,pm8901-temp-alarm.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/qcom,pm8901-temp-alarm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm PM8901 PMIC Temperature Alarm + +maintainers: + - Herman van Hazendonk + +description: | + PM8901 is a secondary PMIC paired with PM8058 on MSM8x60 family + (MSM8260/MSM8660/APQ8060) platforms. It exposes an over-temperature + alarm block at SSBI offset 0x23 (CTRL) with four selectable + thresholds and three escalating stages. + + Unlike PM8058, there is no raw die-temperature ADC channel - the + driver decodes the stage + threshold pair into a representative + millicelsius value reported via the thermal-of framework. + + Two PMIC-internal interrupts are exposed: + + - TEMP_ALARM (PM8901 IRQ block 6 bit 4 =3D=3D hwirq 52): asserted + on every stage transition; + - TEMP_HI_ALARM (PM8901 IRQ block 6 bit 5 =3D=3D hwirq 53): asserted + when the part enters the high-temperature stage. + + Both line up on the parent qcom,pm8901 interrupt-controller. + +allOf: + - $ref: /schemas/thermal/thermal-sensor.yaml# + +properties: + compatible: + const: qcom,pm8901-temp-alarm + + reg: + description: SSBI offset of the temp-alarm CTRL register. + maxItems: 1 + + interrupts: + items: + - description: Stage-transition alarm interrupt (TEMP_ALARM). + - description: Hi-temperature alarm interrupt (TEMP_HI_ALARM). + + interrupt-names: + items: + - const: alarm + - const: hi-alarm + + "#thermal-sensor-cells": + const: 0 + +required: + - compatible + - reg + - interrupts + - interrupt-names + +additionalProperties: false + +examples: + - | + #include + + ssbi { + #address-cells =3D <1>; + #size-cells =3D <0>; + + pmic@0 { + compatible =3D "qcom,pm8901"; + reg =3D <0>; + #address-cells =3D <1>; + #size-cells =3D <0>; + #interrupt-cells =3D <2>; + interrupt-controller; + interrupt-parent =3D <&tlmm>; + interrupts =3D <31 IRQ_TYPE_EDGE_RISING>; + + temp-alarm@23 { + compatible =3D "qcom,pm8901-temp-alarm"; + reg =3D <0x23>; + interrupts =3D <52 IRQ_TYPE_EDGE_RISING>, + <53 IRQ_TYPE_EDGE_RISING>; + interrupt-names =3D "alarm", "hi-alarm"; + #thermal-sensor-cells =3D <0>; + }; + }; + }; --=20 2.43.0 From nobody Mon Jun 8 08:28:04 2026 Received: from outbound6.mail.transip.nl (outbound6.mail.transip.nl [136.144.136.128]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 82E892D6407; Sun, 31 May 2026 04:09:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.144.136.128 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780200569; cv=none; b=eEAEPrv0SK3/DbtTSI24of50mvMmzU1WqvoBCMv+Qww99k9wqB7Q9ZfMYCVYTuxaayRoTAdH0ySH3SGhvjew+SPDOAHJ1vGCa5U135E00wtawKhRL2+mrZBBM0jt1zbKX8QtIZWEQEgq9zU+diJuMfiJi78QeZH8lMA8gZF9ZAU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780200569; c=relaxed/simple; bh=8Z6YB4Ja9kjIYhaeQZmOhUMbihguecPgoPZiQ0WJQBo=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ag7fD3W26BvvFzwUkd0oFJbiQLBSDOwrGd2q7NWTOdeS+3N9qRT6Ejji5Ib2yuzFBqHHzCEje4+/plZ0Jldy8C3DTgzo993iwfstgPQQmmsx45cay+f+Ylpm9G/fLbDttFjWLi1uYzxoTNbA3ge6xPKFJ1YYcO2qOp119jkahiQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=herrie.org; spf=pass smtp.mailfrom=herrie.org; dkim=pass (2048-bit key) header.d=herrie.org header.i=@herrie.org header.b=U0gTd2OG; arc=none smtp.client-ip=136.144.136.128 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=herrie.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=herrie.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=herrie.org header.i=@herrie.org header.b="U0gTd2OG" Received: from submission4.mail.transip.nl (unknown [10.103.8.155]) by outbound6.mail.transip.nl (Postfix) with ESMTP id 4gSkB95DhfzwLHfW; Sun, 31 May 2026 06:09:21 +0200 (CEST) Received: from herrie-desktop.. (180-93-184-31.ftth.glasoperator.nl [31.184.93.180]) by submission4.mail.transip.nl (Postfix) with ESMTPA id 4gSkB85hjJz3R3nyZ; Sun, 31 May 2026 06:09:20 +0200 (CEST) From: Herman van Hazendonk To: Amit Kucheria , Conor Dooley , Daniel Lezcano , devicetree@vger.kernel.org, Krzysztof Kozlowski , Lee Jones , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Lukasz Luba , "Rafael J. Wysocki" , Rob Herring , Satya Priya , Thara Gopinath , van Hazendonk , Zhang Rui Subject: [PATCH v2 3/3] thermal: qcom: add PM8901 PMIC temperature-alarm driver Date: Sun, 31 May 2026 06:09:16 +0200 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: ClueGetter at submission4.mail.transip.nl DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=transip-a; d=herrie.org; t=1780200561; h=from:subject:to:references: in-reply-to:date:mime-version:content-type; bh=WQ0QwPq9DZzX06ZtQCVj989jT8nDJZsAIoIDgckGPFI=; b=U0gTd2OG23i4sPhhQ7jQW4/b1gjgmaLTJqiiTsaAorpxYuWiy/Q/nq2r2EPb1tunA4hzcX Ikc8XkAxTuOcuJUaL1GtvNaTl9aXhj/H/dKSpxizgen/ji7LuMzWvpRK5hRr3ElZV0KrEG iQU8DUdfhd5tUp1yKU01zWnB3Hiu1t+aoh0dYtU5MR3YFRQLE5yLpKpI/CdbTLybBTf775 EfjFFa+6TSSey6iRAZ/1/rCdLHrBSr3gFH2Lo4VqICUPcWknK4g6z9I5H+kacDT2T0Hoxf aI0AMp8PoGbHJXTuRPi0XkWYMOJiZAzxCiWHDZO5Jw2be4eCM+YQ/gPz20f7AA== X-Report-Abuse-To: abuse@transip.nl Add a thermal-of sensor driver for the temperature-alarm block inside the Qualcomm PM8901 PMIC. PM8901 is a secondary PMIC paired with PM8058 on the MSM8x60 family (MSM8260/MSM8660/APQ8060). It exposes an over-temperature alarm at SSBI offset 0x23/0x24 with three escalating stages (105/125/145 C); the driver decodes the stage + threshold pair into a millicelsius reading and registers two PMIC- internal interrupts (TEMP_ALARM at block 6 bit 4, TEMP_HI_ALARM at block 6 bit 5). Used by board thermal-zones for the orderly_poweroff path on the HP TouchPad. Signed-off-by: Herman van Hazendonk --- drivers/thermal/qcom/Kconfig | 12 + drivers/thermal/qcom/Makefile | 1 + drivers/thermal/qcom/qcom-pm8901-tm.c | 408 ++++++++++++++++++++++++++ 3 files changed, 421 insertions(+) create mode 100644 drivers/thermal/qcom/qcom-pm8901-tm.c diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig index a6bb01082ec6..af099032f1e6 100644 --- a/drivers/thermal/qcom/Kconfig +++ b/drivers/thermal/qcom/Kconfig @@ -32,6 +32,18 @@ config QCOM_SPMI_TEMP_ALARM real time die temperature if an ADC is present or an estimate of the temperature based upon the over temperature stage value. =20 +config QCOM_PM8901_TEMP_ALARM + tristate "Qualcomm PM8901 PMIC Temperature Alarm" + depends on MFD_PM8XXX || COMPILE_TEST + depends on THERMAL_OF + help + This enables the thermal driver for the PM8901 PMIC over-temperature + alarm block. PM8901 exposes a stage-based alarm (no raw ADC) with + four selectable thresholds and three escalating stages. The driver + registers a thermal-of sensor so a board device tree can declare + trip points and a critical-trip action (orderly_poweroff). Used on + HP TouchPad (APQ8060) where PM8901 supplies the secondary PMIC die. + config QCOM_LMH tristate "Qualcomm Limits Management Hardware" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile index 0fa2512042e7..90dc05151e33 100644 --- a/drivers/thermal/qcom/Makefile +++ b/drivers/thermal/qcom/Makefile @@ -5,4 +5,5 @@ qcom_tsens-y +=3D tsens.o tsens-v2.o tsens-v1.o tsens-v0_= 1.o \ tsens-8960.o obj-$(CONFIG_QCOM_SPMI_ADC_TM5) +=3D qcom-spmi-adc-tm5.o obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) +=3D qcom-spmi-temp-alarm.o +obj-$(CONFIG_QCOM_PM8901_TEMP_ALARM) +=3D qcom-pm8901-tm.o obj-$(CONFIG_QCOM_LMH) +=3D lmh.o diff --git a/drivers/thermal/qcom/qcom-pm8901-tm.c b/drivers/thermal/qcom/q= com-pm8901-tm.c new file mode 100644 index 000000000000..b159e9917c2c --- /dev/null +++ b/drivers/thermal/qcom/qcom-pm8901-tm.c @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Qualcomm PM8901 PMIC Thermal-Alarm Driver + * + * Mainline port of the legacy 2.6.35-palm drivers/thermal/pmic8901-tm.c. + * PM8901 exposes a stage-based over-temperature alarm (no raw ADC) with + * four selectable thresholds and three escalating stages. This driver + * mirrors the legacy programming exactly (threshold-set 0, software + * override enabled, PWM gating at 8 Hz) and registers a thermal-of + * sensor so a board DT can declare trip points and a critical action. + * + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2026 Herman van Hazendonk + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SSBI registers (offsets from the per-instance reg base) */ +#define PM8901_TM_REG_CTRL 0x00 /* CTRL/STATUS (base + 0) */ +#define PM8901_TM_REG_PWM 0x01 /* PWM gating (base + 1) */ + +/* CTRL register fields */ +#define CTRL_ST3_SD BIT(7) +#define CTRL_ST2_SD BIT(6) +#define CTRL_STATUS_MASK GENMASK(5, 4) +#define CTRL_THRESH_MASK GENMASK(3, 2) +#define CTRL_OVRD_ST3 BIT(1) +#define CTRL_OVRD_ST2 BIT(0) +#define CTRL_OVRD_MASK GENMASK(1, 0) + +/* PWM register fields */ +#define PWM_EN BIT(7) +#define PWM_PER_PRE_MASK GENMASK(5, 3) +#define PWM_PER_DIV_MASK GENMASK(2, 0) + +/* Temperature math (from legacy pmic8901-tm.c) */ +#define PM8901_TEMP_STAGE_STEP 20000 /* 20 deg C between stages */ +#define PM8901_TEMP_STAGE_HYSTERESIS 2000 /* 2 deg C transition guard */ +#define PM8901_TEMP_THRESH_MIN 105000 /* threshold 0 base =3D 105 C */ +#define PM8901_TEMP_THRESH_STEP 5000 /* 5 deg C per threshold step */ + +/* + * PM8901 has no real die ADC; when stage =3D=3D 0 ("below threshold") we + * report a plausible idle estimate matching the legacy DEFAULT_NO_ADC_TEM= P. + */ +#define PM8901_TEMP_NO_ALARM 37000 + +struct pm8901_tm_chip { + struct device *dev; + struct regmap *map; + struct thermal_zone_device *tz_dev; + struct mutex lock; + unsigned int base; /* SSBI offset, from DT reg */ + unsigned int stage; + unsigned int thresh; + int temp; + bool initialised; +}; + +static int pm8901_tm_read_ctrl(struct pm8901_tm_chip *chip, u8 *val) +{ + unsigned int v; + int ret; + + ret =3D regmap_read(chip->map, chip->base + PM8901_TM_REG_CTRL, &v); + if (!ret) + *val =3D v; + return ret; +} + +static int pm8901_tm_write_ctrl(struct pm8901_tm_chip *chip, u8 val) +{ + return regmap_write(chip->map, chip->base + PM8901_TM_REG_CTRL, val); +} + +static int pm8901_tm_write_pwm(struct pm8901_tm_chip *chip, u8 val) +{ + return regmap_write(chip->map, chip->base + PM8901_TM_REG_PWM, val); +} + +/* + * Decode the (stage, threshold) pair into a single millicelsius value. + * Logic matches the legacy pmic8901-tm.c hysteresis selection: + * - on a rising stage transition, use the lower bound of the new stage + * plus +HYSTERESIS so we don't bounce + * - on a falling stage transition, use the upper bound of the new stage + * minus -HYSTERESIS + * - on the first read after probe (initialised =3D=3D false), report the + * lower bound of the current stage (the most conservative estimate + * given that the hardware only tells us "we crossed this stage's + * threshold"), or PM8901_TEMP_NO_ALARM when stage =3D=3D 0. + */ +static int pm8901_tm_update_temp_locked(struct pm8901_tm_chip *chip) +{ + unsigned int new_stage; + u8 reg; + int ret; + + ret =3D pm8901_tm_read_ctrl(chip, ®); + if (ret) + return ret; + + new_stage =3D FIELD_GET(CTRL_STATUS_MASK, reg); + chip->thresh =3D FIELD_GET(CTRL_THRESH_MASK, reg); + + if (!chip->initialised) { + if (new_stage) + chip->temp =3D PM8901_TEMP_THRESH_MIN + + chip->thresh * PM8901_TEMP_THRESH_STEP + + (new_stage - 1) * PM8901_TEMP_STAGE_STEP; + else + chip->temp =3D PM8901_TEMP_NO_ALARM; + chip->initialised =3D true; + } else if (new_stage > chip->stage) { + chip->temp =3D PM8901_TEMP_THRESH_MIN + + chip->thresh * PM8901_TEMP_THRESH_STEP + + (new_stage - 1) * PM8901_TEMP_STAGE_STEP + + PM8901_TEMP_STAGE_HYSTERESIS; + } else if (new_stage < chip->stage) { + chip->temp =3D PM8901_TEMP_THRESH_MIN + + chip->thresh * PM8901_TEMP_THRESH_STEP + + new_stage * PM8901_TEMP_STAGE_STEP - + PM8901_TEMP_STAGE_HYSTERESIS; + } + + chip->stage =3D new_stage; + return 0; +} + +static int pm8901_tm_get_temp(struct thermal_zone_device *tz, int *temp) +{ + struct pm8901_tm_chip *chip =3D thermal_zone_device_priv(tz); + int ret; + + if (!temp) + return -EINVAL; + + mutex_lock(&chip->lock); + ret =3D pm8901_tm_update_temp_locked(chip); + if (!ret) + *temp =3D chip->temp; + mutex_unlock(&chip->lock); + + return ret; +} + +static const struct thermal_zone_device_ops pm8901_tm_zone_ops =3D { + .get_temp =3D pm8901_tm_get_temp, +}; + +/* + * Shared ISR for both TEMP_ALARM (stage-transition) and TEMP_HI_ALARM + * (hi-temp) interrupts. Updates the cached temperature, clears any + * latched ST2_SD / ST3_SD shutdown bits so the next stage transition + * can be observed, and pokes the thermal core which then re-reads + * temp and walks trips (a critical-trip cross triggers orderly_poweroff + * via the kernel's standard machinery). + */ +static irqreturn_t pm8901_tm_isr(int irq, void *data) +{ + struct pm8901_tm_chip *chip =3D data; + u8 reg; + int ret; + + mutex_lock(&chip->lock); + + ret =3D pm8901_tm_update_temp_locked(chip); + if (ret) { + mutex_unlock(&chip->lock); + return IRQ_HANDLED; + } + + ret =3D pm8901_tm_read_ctrl(chip, ®); + if (!ret && (reg & (CTRL_ST2_SD | CTRL_ST3_SD))) { + reg &=3D ~(CTRL_ST2_SD | CTRL_ST3_SD | CTRL_STATUS_MASK); + pm8901_tm_write_ctrl(chip, reg); + } + + dev_dbg(chip->dev, "alarm irq=3D%d stage=3D%u thresh=3D%u temp=3D%d\n", + irq, chip->stage, chip->thresh, chip->temp); + + mutex_unlock(&chip->lock); + + thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED); + return IRQ_HANDLED; +} + +/* + * Program PM8901 to the legacy default: threshold-set 0 (105 / 125 / 145 = C), + * PWM at 8 Hz (legacy "cut down on unnecessary interrupts" rate), and + * prime the cached temperature. This intentionally does NOT yet flip the + * software-override bits; HW auto-shutdown is left enabled here so the + * PMIC keeps protecting the part if any later probe step fails. The + * SW-override switch happens in pm8901_tm_enable_sw_override() and is + * paired with a devm action that reverts the bits if the driver unbinds. + */ +static int pm8901_tm_init_hw(struct pm8901_tm_chip *chip) +{ + int ret; + u8 reg; + + mutex_lock(&chip->lock); + + ret =3D pm8901_tm_read_ctrl(chip, ®); + if (ret) + goto out; + + /* Clear status + threshold bits, leave OVRD bits as the HW found them. */ + reg =3D reg & ~(CTRL_STATUS_MASK | CTRL_THRESH_MASK); + ret =3D pm8901_tm_write_ctrl(chip, reg); + if (ret) + goto out; + + chip->thresh =3D 0; + + /* PWM @ 8 Hz: PWM_EN | PRE=3D3 | DIV=3D3 =E2=80=94 verbatim from legacy.= */ + reg =3D PWM_EN | FIELD_PREP(PWM_PER_PRE_MASK, 3) | + FIELD_PREP(PWM_PER_DIV_MASK, 3); + ret =3D pm8901_tm_write_pwm(chip, reg); + if (ret) + goto out; + + /* Prime the cached temperature from current hardware state. */ + chip->initialised =3D false; + ret =3D pm8901_tm_update_temp_locked(chip); + +out: + mutex_unlock(&chip->lock); + return ret; +} + +/* + * Re-enable PM8901's hardware auto-cut on the way out, so the PMIC takes + * over thermal protection again once the kernel is no longer the + * shutdown agent. Best-effort: log on failure, do not propagate the + * error (there is nothing the unbind path can do about it). + */ +static void pm8901_tm_restore_hw_shutdown(void *data) +{ + struct pm8901_tm_chip *chip =3D data; + int ret; + u8 reg; + + mutex_lock(&chip->lock); + ret =3D pm8901_tm_read_ctrl(chip, ®); + if (!ret) { + reg &=3D ~CTRL_OVRD_MASK; + ret =3D pm8901_tm_write_ctrl(chip, reg); + } + mutex_unlock(&chip->lock); + + if (ret) + dev_warn(chip->dev, + "failed to restore PMIC HW auto-shutdown: %d\n", ret); +} + +/* + * Hand thermal protection responsibility from the PMIC's hardware + * auto-cut to the kernel thermal core. This is the LAST step of probe + * so that, if any earlier step fails, the PMIC keeps protecting the + * part on its own. Once it succeeds we install a devm action that + * re-enables HW auto-cut if/when the driver is unbound. + */ +static int pm8901_tm_enable_sw_override(struct pm8901_tm_chip *chip) +{ + int ret; + u8 reg; + + mutex_lock(&chip->lock); + ret =3D pm8901_tm_read_ctrl(chip, ®); + if (!ret) { + reg =3D (reg & ~CTRL_OVRD_MASK) | CTRL_OVRD_ST3 | CTRL_OVRD_ST2; + ret =3D pm8901_tm_write_ctrl(chip, reg); + } + mutex_unlock(&chip->lock); + if (ret) + return ret; + + return devm_add_action_or_reset(chip->dev, + pm8901_tm_restore_hw_shutdown, chip); +} + +static int pm8901_tm_probe(struct platform_device *pdev) +{ + struct pm8901_tm_chip *chip; + int ret, irq_alarm, irq_hi_alarm; + u32 res; + + chip =3D devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->dev =3D &pdev->dev; + mutex_init(&chip->lock); + + chip->map =3D dev_get_regmap(pdev->dev.parent, NULL); + if (!chip->map) + return dev_err_probe(&pdev->dev, -ENXIO, + "no regmap on PM8901 parent\n"); + + ret =3D of_property_read_u32(pdev->dev.of_node, "reg", &res); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "missing reg property\n"); + chip->base =3D res; + + irq_alarm =3D platform_get_irq_byname(pdev, "alarm"); + if (irq_alarm < 0) + return irq_alarm; + irq_hi_alarm =3D platform_get_irq_byname(pdev, "hi-alarm"); + if (irq_hi_alarm < 0) + return irq_hi_alarm; + + ret =3D pm8901_tm_init_hw(chip); + if (ret) + return dev_err_probe(&pdev->dev, ret, "hw init failed\n"); + + chip->tz_dev =3D devm_thermal_of_zone_register(&pdev->dev, 0, chip, + &pm8901_tm_zone_ops); + if (IS_ERR(chip->tz_dev)) + return dev_err_probe(&pdev->dev, PTR_ERR(chip->tz_dev), + "thermal zone register failed\n"); + + ret =3D devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL, + pm8901_tm_isr, IRQF_ONESHOT, + "pm8901-tm-alarm", chip); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "alarm IRQ request failed\n"); + + ret =3D devm_request_threaded_irq(&pdev->dev, irq_hi_alarm, NULL, + pm8901_tm_isr, IRQF_ONESHOT, + "pm8901-tm-hi-alarm", chip); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "hi-alarm IRQ request failed\n"); + + platform_set_drvdata(pdev, chip); + + /* + * All resources that we need on the thermal hot path are now in + * place; hand thermal-shutdown responsibility from the PMIC's + * hardware auto-cut to the kernel thermal core. If this fails the + * PMIC is left with its original (post-reset) HW auto-cut intact, + * so we never leave the part unprotected. + */ + ret =3D pm8901_tm_enable_sw_override(chip); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to enable SW thermal override\n"); + + thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED); + + { + unsigned int stage, thresh; + int temp; + + /* + * IRQs and thermal-core polling are live by now, so the + * cached state can be updated under chip->lock at any time. + * Snapshot under the lock so the boot banner is consistent. + */ + mutex_lock(&chip->lock); + stage =3D chip->stage; + thresh =3D chip->thresh; + temp =3D chip->temp; + mutex_unlock(&chip->lock); + + dev_info(&pdev->dev, + "PM8901 thermal alarm: base=3D0x%x stage=3D%u thresh=3D%u temp=3D%d\n", + chip->base, stage, thresh, temp); + } + + return 0; +} + +/* + * No explicit ->remove() needed: pm8901_tm_restore_hw_shutdown() is + * registered as a devm action in probe and re-enables the PMIC's HW + * auto-cut automatically on unbind. + */ + +static const struct of_device_id pm8901_tm_match_table[] =3D { + { .compatible =3D "qcom,pm8901-temp-alarm" }, + { } +}; +MODULE_DEVICE_TABLE(of, pm8901_tm_match_table); + +static struct platform_driver pm8901_tm_driver =3D { + .driver =3D { + .name =3D "pm8901-temp-alarm", + .of_match_table =3D pm8901_tm_match_table, + }, + .probe =3D pm8901_tm_probe, +}; +module_platform_driver(pm8901_tm_driver); + +MODULE_ALIAS("platform:pm8901-temp-alarm"); +MODULE_DESCRIPTION("Qualcomm PM8901 PMIC Thermal Alarm driver"); +MODULE_LICENSE("GPL v2"); --=20 2.43.0