* [PATCH v2 0/8] Add RemoteProc cooling support
@ 2026-01-27 15:57 Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 1/8] thermal: Add Remote Proc cooling driver Gaurav Kohli
` (8 more replies)
0 siblings, 9 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-27 15:57 UTC (permalink / raw)
To: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pm, gaurav.kohli,
manaf.pallikunhi
This series introduces a generic remote proc cooling framework to control
thermal sensors located on remote subsystem like modem, dsp etc.
Communications with these subsystems occurs through various channels, for example,
QMI interface for Qualcomm.
The Framework provides an abstraction layer between thermal subsytem and vendor
specific remote subsystem. Vendor drivers are expected to implement callback
and registration mechanisms with cooling framework to control cooling
devices.
This patchset also revives earlier discussions of QMI based TMD cooling
devices discussion posted on below series by Casey:
https://lore.kernel.org/linux-devicetree/20230905-caleb-qmi_cooling-v1-0-5aa39d4164a7@linaro.org/
That series introduced Qualcomm QMI-based TMD cooling devices which used
to mitigate thermal conditions across multiple remote subsystems. These
devices operate based on junction temperature sensors (TSENS) associated
with thermal zones for each subsystem and registering with remoteproc
cooling framework for cooling registration.
---
Changes in v2:
- Update Remoreproc thermal config to tristate and removed unnecessary NULL checks.
- Fixed dt binding file format and added generic name support for cdsp.
- Fixed memory leak and cleaned up qmi-cooling driver file.
- Corrected DT formatting errors and commit descriptions for all targets.
- Link to v1: https://lore.kernel.org/linux-devicetree/20251223123227.1317244-1-gaurav.kohli@oss.qualcomm.com/
---
Casey Connolly (2):
remoteproc: qcom: probe all child devices
thermal: qcom: add qmi-cooling driver
Gaurav Kohli (6):
thermal: Add Remote Proc cooling driver
dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
arm64: dts: qcom: lemans: Enable CDSP cooling
arm64: dts: qcom: talos: Enable CDSP cooling
arm64: dts: qcom: kodiak: Enable CDSP cooling
arm64: dts: qcom: monaco: Enable CDSP cooling
.../bindings/remoteproc/qcom,pas-common.yaml | 6 +
.../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++
MAINTAINERS | 7 +
arch/arm64/boot/dts/qcom/kodiak.dtsi | 37 ++
arch/arm64/boot/dts/qcom/lemans.dtsi | 138 ++++-
arch/arm64/boot/dts/qcom/monaco.dtsi | 93 ++++
arch/arm64/boot/dts/qcom/talos.dtsi | 24 +
drivers/remoteproc/qcom_q6v5.c | 4 +
drivers/remoteproc/qcom_q6v5_mss.c | 8 -
drivers/soc/qcom/Kconfig | 13 +
drivers/soc/qcom/Makefile | 1 +
drivers/soc/qcom/qmi-cooling.c | 510 ++++++++++++++++++
drivers/soc/qcom/qmi-cooling.h | 429 +++++++++++++++
drivers/thermal/Kconfig | 10 +
drivers/thermal/Makefile | 2 +
drivers/thermal/remoteproc_cooling.c | 143 +++++
include/linux/remoteproc_cooling.h | 52 ++
17 files changed, 1529 insertions(+), 20 deletions(-)
create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
create mode 100644 drivers/soc/qcom/qmi-cooling.c
create mode 100644 drivers/soc/qcom/qmi-cooling.h
create mode 100644 drivers/thermal/remoteproc_cooling.c
create mode 100644 include/linux/remoteproc_cooling.h
--
2.34.1
^ permalink raw reply [flat|nested] 53+ messages in thread
* [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-01-27 15:57 [PATCH v2 0/8] Add RemoteProc cooling support Gaurav Kohli
@ 2026-01-27 15:57 ` Gaurav Kohli
2026-01-28 11:32 ` Krzysztof Kozlowski
` (4 more replies)
2026-01-27 15:57 ` [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings Gaurav Kohli
` (7 subsequent siblings)
8 siblings, 5 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-27 15:57 UTC (permalink / raw)
To: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pm, gaurav.kohli,
manaf.pallikunhi
Add a new generic driver for thermal cooling devices that control
remote processors (modem, DSP, etc.) through various communication
channels.
This driver provides an abstraction layer between the thermal
subsystem and vendor-specific remote processor communication
mechanisms.
Advantage of this to avoid duplicating vendor-specific logic
in the thermal subsystem and make it easier for different vendors
to plug in their own cooling mechanisms via callbacks.
Suggested-by: Amit Kucheria <amit.kucheria@oss.qualcomm.com>
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
MAINTAINERS | 7 ++
drivers/thermal/Kconfig | 10 ++
drivers/thermal/Makefile | 2 +
drivers/thermal/remoteproc_cooling.c | 143 +++++++++++++++++++++++++++
include/linux/remoteproc_cooling.h | 52 ++++++++++
5 files changed, 214 insertions(+)
create mode 100644 drivers/thermal/remoteproc_cooling.c
create mode 100644 include/linux/remoteproc_cooling.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 414f44093269..5ebc7819d2cf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26169,6 +26169,13 @@ F: drivers/thermal/cpufreq_cooling.c
F: drivers/thermal/cpuidle_cooling.c
F: include/linux/cpu_cooling.h
+THERMAL/REMOTEPROC_COOLING
+M: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
+L: linux-pm@vger.kernel.org
+S: Supported
+F: drivers/thermal/remoteproc_cooling.c
+F: include/linux/remoteproc_cooling.h
+
THERMAL/POWER_ALLOCATOR
M: Lukasz Luba <lukasz.luba@arm.com>
L: linux-pm@vger.kernel.org
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index b10080d61860..dfc52eed64de 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -229,6 +229,16 @@ config PCIE_THERMAL
If you want this support, you should say Y here.
+config REMOTEPROC_THERMAL
+ tristate "Remote processor cooling support"
+ help
+ This implements a generic cooling mechanism for remote processors
+ (modem, DSP, etc.) that allows vendor-specific implementations to
+ register thermal cooling devices and provide callbacks for thermal
+ mitigation.
+
+ If you want this support, you should say Y here.
+
config THERMAL_EMULATION
bool "Thermal emulation mode support"
help
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index bb21e7ea7fc6..ae747dde54fe 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -34,6 +34,8 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
thermal_sys-$(CONFIG_PCIE_THERMAL) += pcie_cooling.o
+thermal_sys-$(CONFIG_REMOTEPROC_THERMAL) += remoteproc_cooling.o
+
obj-$(CONFIG_K3_THERMAL) += k3_bandgap.o k3_j72xx_bandgap.o
# platform thermal drivers
obj-y += broadcom/
diff --git a/drivers/thermal/remoteproc_cooling.c b/drivers/thermal/remoteproc_cooling.c
new file mode 100644
index 000000000000..f958efa691b3
--- /dev/null
+++ b/drivers/thermal/remoteproc_cooling.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Remote Processor Cooling Device
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+
+#define REMOTEPROC_PREFIX "rproc_"
+
+struct remoteproc_cooling_ops {
+ int (*get_max_level)(void *devdata, unsigned long *level);
+ int (*get_cur_level)(void *devdata, unsigned long *level);
+ int (*set_cur_level)(void *devdata, unsigned long level);
+};
+
+/**
+ * struct remoteproc_cdev - Remote processor cooling device
+ * @cdev: Thermal cooling device handle
+ * @ops: Vendor-specific operation callbacks
+ * @devdata: Private data for vendor implementation
+ * @np: Device tree node associated with this cooling device
+ * @lock: Mutex to protect cooling device operations
+ */
+struct remoteproc_cdev {
+ struct thermal_cooling_device *cdev;
+ const struct remoteproc_cooling_ops *ops;
+ void *devdata;
+ struct mutex lock;
+};
+
+/* Thermal cooling device callbacks */
+
+static int remoteproc_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct remoteproc_cdev *rproc_cdev = cdev->devdata;
+ int ret;
+
+ mutex_lock(&rproc_cdev->lock);
+ ret = rproc_cdev->ops->get_max_level(rproc_cdev->devdata, state);
+ mutex_unlock(&rproc_cdev->lock);
+
+ return ret;
+}
+
+static int remoteproc_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct remoteproc_cdev *rproc_cdev = cdev->devdata;
+ int ret;
+
+ mutex_lock(&rproc_cdev->lock);
+ ret = rproc_cdev->ops->get_cur_level(rproc_cdev->devdata, state);
+ mutex_unlock(&rproc_cdev->lock);
+
+ return ret;
+}
+
+static int remoteproc_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct remoteproc_cdev *rproc_cdev = cdev->devdata;
+ int ret;
+
+ mutex_lock(&rproc_cdev->lock);
+ ret = rproc_cdev->ops->set_cur_level(rproc_cdev->devdata, state);
+ mutex_unlock(&rproc_cdev->lock);
+
+ return ret;
+}
+
+static const struct thermal_cooling_device_ops remoteproc_cooling_ops = {
+ .get_max_state = remoteproc_get_max_state,
+ .get_cur_state = remoteproc_get_cur_state,
+ .set_cur_state = remoteproc_set_cur_state,
+};
+
+struct remoteproc_cdev *
+remoteproc_cooling_register(struct device_node *np,
+ const char *name, const struct remoteproc_cooling_ops *ops,
+ void *devdata)
+{
+ struct remoteproc_cdev *rproc_cdev;
+ struct thermal_cooling_device *cdev;
+ int ret;
+
+ if (!name || !ops)
+ return ERR_PTR(-EINVAL);
+
+ rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL);
+ if (!rproc_cdev)
+ return ERR_PTR(-ENOMEM);
+
+ rproc_cdev->ops = ops;
+ rproc_cdev->devdata = devdata;
+ mutex_init(&rproc_cdev->lock);
+
+ char *rproc_name __free(kfree) =
+ kasprintf(GFP_KERNEL, REMOTEPROC_PREFIX "%s", name);
+ /* Register with thermal framework */
+ if (np)
+ cdev = thermal_of_cooling_device_register(np, rproc_name, rproc_cdev,
+ &remoteproc_cooling_ops);
+ else
+ cdev = thermal_cooling_device_register(rproc_name, rproc_cdev,
+ &remoteproc_cooling_ops);
+
+ if (IS_ERR(cdev)) {
+ ret = PTR_ERR(cdev);
+ goto free_rproc_cdev;
+ }
+
+ rproc_cdev->cdev = cdev;
+
+ return rproc_cdev;
+
+free_rproc_cdev:
+ kfree(rproc_cdev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(remoteproc_cooling_register);
+
+void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
+{
+ if (!rproc_cdev)
+ return;
+
+ thermal_cooling_device_unregister(rproc_cdev->cdev);
+ mutex_destroy(&rproc_cdev->lock);
+ kfree(rproc_cdev);
+}
+EXPORT_SYMBOL_GPL(remoteproc_cooling_unregister);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Remote Processor Cooling Device");
diff --git a/include/linux/remoteproc_cooling.h b/include/linux/remoteproc_cooling.h
new file mode 100644
index 000000000000..721912d1a5ec
--- /dev/null
+++ b/include/linux/remoteproc_cooling.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Remote Processor Cooling Device
+ *
+ * Copyright (c) 2025, Qualcomm Innovation Center
+ */
+
+#ifndef __REMOTEPROC_COOLING_H__
+#define __REMOTEPROC_COOLING_H__
+
+#include <linux/thermal.h>
+
+struct device;
+struct device_node;
+
+struct remoteproc_cooling_ops {
+ int (*get_max_level)(void *devdata, unsigned long *level);
+ int (*get_cur_level)(void *devdata, unsigned long *level);
+ int (*set_cur_level)(void *devdata, unsigned long level);
+};
+
+struct remoteproc_cdev;
+
+#ifdef CONFIG_REMOTEPROC_THERMAL
+
+struct remoteproc_cdev *
+remoteproc_cooling_register(struct device_node *np,
+ const char *name,
+ const struct remoteproc_cooling_ops *ops,
+ void *devdata);
+
+void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev);
+
+#else /* !CONFIG_REMOTEPROC_THERMAL */
+
+static inline struct remoteproc_cdev *
+remoteproc_cooling_register(struct device_node *np,
+ const char *name,
+ const struct remoteproc_cooling_ops *ops,
+ void *devdata)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline void
+remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
+{
+}
+
+#endif /* CONFIG_REMOTEPROC_THERMAL */
+
+#endif /* __REMOTEPROC_COOLING_H__ */
--
2.34.1
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-01-27 15:57 [PATCH v2 0/8] Add RemoteProc cooling support Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 1/8] thermal: Add Remote Proc cooling driver Gaurav Kohli
@ 2026-01-27 15:57 ` Gaurav Kohli
2026-01-28 11:27 ` Krzysztof Kozlowski
` (2 more replies)
2026-01-27 15:57 ` [PATCH v2 3/8] remoteproc: qcom: probe all child devices Gaurav Kohli
` (6 subsequent siblings)
8 siblings, 3 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-27 15:57 UTC (permalink / raw)
To: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pm, gaurav.kohli,
manaf.pallikunhi
The cooling subnode of a remoteproc represents a client of the Thermal
Mitigation Device QMI service running on it. Each subnode of the cooling
node represents a single control exposed by the service.
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
.../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
.../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
2 files changed, 78 insertions(+)
create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
index 68c17bf18987..6a736161d5ae 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
@@ -80,6 +80,12 @@ properties:
and devices related to the ADSP.
unevaluatedProperties: false
+ cooling:
+ $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
+ description:
+ Cooling subnode which represents the cooling devices exposed by the Modem.
+ unevaluatedProperties: false
+
required:
- clocks
- clock-names
diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
new file mode 100644
index 000000000000..0dd3bd84c176
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMI based thermal mitigation (TMD) cooling devices
+
+maintainers:
+ - Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
+
+description:
+ Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions
+ across multiple remote subsystems. These devices operate based on junction
+ temperature sensors (TSENS) associated with thermal zones for each subsystem.
+
+properties:
+ compatible:
+ enum:
+ - qcom,qmi-cooling-cdsp
+ - qcom,qmi-cooling-cdsp1
+
+patternProperties:
+ "cdsp-tmd[0-9]*$":
+ type: object
+
+ description:
+ Each subnode which represents qmi communication to CDSP.
+
+ properties:
+ label:
+ maxItems: 1
+
+ "#cooling-cells":
+ $ref: /schemas/thermal/thermal-cooling-devices.yaml#/properties/#cooling-cells
+
+ required:
+ - label
+ - "#cooling-cells"
+
+ additionalProperties: false
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ remoteproc-cdsp {
+ cooling {
+ compatible = "qcom,qmi-cooling-cdsp";
+
+ cdsp_tmd0: cdsp-tmd0 {
+ label = "cdsp_sw";
+ #cooling-cells = <2>;
+ };
+ };
+ };
+
+ - |
+ remoteproc-cdsp1 {
+ cooling {
+ compatible = "qcom,qmi-cooling-cdsp1";
+
+ cdsp_tmd1: cdsp-tmd1 {
+ label = "cdsp_sw";
+ #cooling-cells = <2>;
+ };
+ };
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 3/8] remoteproc: qcom: probe all child devices
2026-01-27 15:57 [PATCH v2 0/8] Add RemoteProc cooling support Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 1/8] thermal: Add Remote Proc cooling driver Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings Gaurav Kohli
@ 2026-01-27 15:57 ` Gaurav Kohli
2026-01-27 16:50 ` Dmitry Baryshkov
2026-01-27 15:57 ` [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver Gaurav Kohli
` (5 subsequent siblings)
8 siblings, 1 reply; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-27 15:57 UTC (permalink / raw)
To: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pm, gaurav.kohli,
manaf.pallikunhi
From: Casey Connolly <casey.connolly@linaro.org>
Currently, only qcom,bam-dmux nodes are supported as
remoteproc children with of_platform_populate(). This limits
the other child nodes to probe separately.
Generalise the qcom,bam-dmux child node support by probing all
remoteproc children with of_platform_populate(). This enables
support for devices that represent themselves as subnodes of
the remoteproc, such as QMI clients.
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
drivers/remoteproc/qcom_q6v5.c | 4 ++++
drivers/remoteproc/qcom_q6v5_mss.c | 8 --------
2 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
index 58d5b85e58cd..a02839c7ed8c 100644
--- a/drivers/remoteproc/qcom_q6v5.c
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -6,6 +6,7 @@
* Copyright (C) 2014 Sony Mobile Communications AB
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*/
+#include <linux/of_platform.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/interconnect.h>
@@ -351,6 +352,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->path),
"failed to acquire interconnect path\n");
+ of_platform_populate(q6v5->dev->of_node, NULL, NULL, q6v5->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(qcom_q6v5_init);
@@ -361,6 +364,7 @@ EXPORT_SYMBOL_GPL(qcom_q6v5_init);
*/
void qcom_q6v5_deinit(struct qcom_q6v5 *q6v5)
{
+ of_platform_depopulate(q6v5->dev);
qmp_put(q6v5->qmp);
}
EXPORT_SYMBOL_GPL(qcom_q6v5_deinit);
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index 91940977ca89..d40565c1cc62 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -238,7 +238,6 @@ struct q6v5 {
struct qcom_rproc_pdm pdm_subdev;
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
- struct platform_device *bam_dmux;
bool need_mem_protection;
bool has_alt_reset;
bool has_mba_logs;
@@ -2029,7 +2028,6 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc)
static int q6v5_probe(struct platform_device *pdev)
{
const struct rproc_hexagon_res *desc;
- struct device_node *node;
struct q6v5 *qproc;
struct rproc *rproc;
const char *mba_image;
@@ -2163,10 +2161,6 @@ static int q6v5_probe(struct platform_device *pdev)
if (ret)
goto remove_sysmon_subdev;
- node = of_get_compatible_child(pdev->dev.of_node, "qcom,bam-dmux");
- qproc->bam_dmux = of_platform_device_create(node, NULL, &pdev->dev);
- of_node_put(node);
-
return 0;
remove_sysmon_subdev:
@@ -2186,8 +2180,6 @@ static void q6v5_remove(struct platform_device *pdev)
struct q6v5 *qproc = platform_get_drvdata(pdev);
struct rproc *rproc = qproc->rproc;
- if (qproc->bam_dmux)
- of_platform_device_destroy(&qproc->bam_dmux->dev, NULL);
rproc_del(rproc);
qcom_q6v5_deinit(&qproc->q6v5);
--
2.34.1
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver
2026-01-27 15:57 [PATCH v2 0/8] Add RemoteProc cooling support Gaurav Kohli
` (2 preceding siblings ...)
2026-01-27 15:57 ` [PATCH v2 3/8] remoteproc: qcom: probe all child devices Gaurav Kohli
@ 2026-01-27 15:57 ` Gaurav Kohli
2026-01-30 9:05 ` kernel test robot
` (2 more replies)
2026-01-27 15:57 ` [PATCH v2 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling Gaurav Kohli
` (4 subsequent siblings)
8 siblings, 3 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-27 15:57 UTC (permalink / raw)
To: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pm, gaurav.kohli,
manaf.pallikunhi
From: Casey Connolly <casey.connolly@linaro.org>
The Thermal Mitigation Device (TMD) service exposes various platform
specific thermal mitigations available on remote subsystems (ie the
modem and cdsp). The service is exposed via the QMI messaging
interface, usually over the QRTR transport.
Qualcomm QMI-based TMD cooling devices are used to mitigate thermal
conditions across multiple remote subsystems. These devices operate
based on junction temperature sensors (TSENS) associated with thermal
zones for each subsystem.
Co-developed-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
---
drivers/soc/qcom/Kconfig | 13 +
drivers/soc/qcom/Makefile | 1 +
drivers/soc/qcom/qmi-cooling.c | 510 +++++++++++++++++++++++++++++++++
drivers/soc/qcom/qmi-cooling.h | 429 +++++++++++++++++++++++++++
4 files changed, 953 insertions(+)
create mode 100644 drivers/soc/qcom/qmi-cooling.c
create mode 100644 drivers/soc/qcom/qmi-cooling.h
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 2caadbbcf830..905a24b42fe6 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -124,6 +124,19 @@ config QCOM_PMIC_GLINK
Say yes here to support USB-C and battery status on modern Qualcomm
platforms.
+config QCOM_QMI_COOLING
+ tristate "Qualcomm QMI cooling drivers"
+ depends on QCOM_RPROC_COMMON
+ depends on ARCH_QCOM || COMPILE_TEST
+ select QCOM_QMI_HELPERS
+ help
+ This enables the remote subsystem cooling devices. These cooling
+ devices will be used by Qualcomm chipset to place various remote
+ subsystem mitigations like remote processor passive mitigation,
+ remote subsystem voltage restriction at low temperatures etc.
+ The QMI cooling device will interface with remote subsystem
+ using Qualcomm remoteproc interface.
+
config QCOM_QMI_HELPERS
tristate
depends on NET
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index b7f1d2a57367..b6728f54944b 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o
CFLAGS_pmic_pdcharger_ulog.o := -I$(src)
+obj-$(CONFIG_QCOM_QMI_COOLING) += qmi-cooling.o
obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
qmi_helpers-y += qmi_encdec.o qmi_interface.o
obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o
diff --git a/drivers/soc/qcom/qmi-cooling.c b/drivers/soc/qcom/qmi-cooling.c
new file mode 100644
index 000000000000..463baa47c8b6
--- /dev/null
+++ b/drivers/soc/qcom/qmi-cooling.c
@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017, The Linux Foundation
+ * Copyright (c) 2025, Linaro Limited
+ *
+ * QMI Thermal Mitigation Device (TMD) client driver.
+ * This driver provides an in-kernel client to handle hot and cold thermal
+ * mitigations for remote subsystems (modem and DSPs) running the TMD service.
+ * It doesn't implement any handling of reports from remote subsystems.
+ */
+
+#include <linux/cleanup.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc/qcom_rproc.h>
+#include <linux/remoteproc_cooling.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/qmi.h>
+#include <linux/thermal.h>
+
+#include "qmi-cooling.h"
+
+#define CDSP_INSTANCE_ID 0x43
+#define CDSP1_INSTANCE_ID 0x44
+
+#define QMI_TMD_RESP_TIMEOUT msecs_to_jiffies(100)
+
+/**
+ * struct qmi_tmd_client - TMD client state
+ * @dev: Device associated with this client
+ * @name: Friendly name for the remote TMD service
+ * @handle: QMI connection handle
+ * @mutex: Lock to synchronise QMI communication
+ * @id: The QMI TMD service instance ID
+ * @cdev_list: The list of cooling devices (controls) enabled for this instance
+ * @svc_arrive_work: Work item for initialising the client when the TMD service
+ * starts.
+ * @connection_active: Whether or not we're connected to the QMI TMD service
+ */
+struct qmi_tmd_client {
+ struct device *dev;
+ const char *name;
+ struct qmi_handle handle;
+ struct mutex mutex;
+ u32 id;
+ struct list_head cdev_list;
+ struct work_struct svc_arrive_work;
+ bool connection_active;
+};
+
+/**
+ * struct qmi_tmd - A TMD cooling device
+ * @np: OF node associated with this control
+ * @type: The control type (exposed via sysfs)
+ * @qmi_name: The common name of this control shared by the remote subsystem
+ * @rproc_cdev: Remote processor cooling device handle
+ * @cur_state: The current cooling/warming/mitigation state
+ * @max_state: The maximum state
+ * @client: The TMD client instance this control is associated with
+ */
+struct qmi_tmd {
+ struct device_node *np;
+ const char *type;
+ char qmi_name[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1];
+ struct list_head node;
+ struct remoteproc_cdev *rproc_cdev;
+ unsigned int cur_state;
+ unsigned int max_state;
+ struct qmi_tmd_client *client;
+};
+
+/**
+ * struct qmi_instance_id - QMI instance match data
+ * @id: The QMI instance ID
+ * @name: Friendly name for this instance
+ */
+struct qmi_instance_data {
+ u32 id;
+ const char *name;
+};
+
+/* Notify the remote subsystem of the requested cooling state */
+static int qmi_tmd_send_state_request(struct qmi_tmd *tmd)
+{
+ struct tmd_set_mitigation_level_resp_msg_v01 tmd_resp = { 0 };
+ struct tmd_set_mitigation_level_req_msg_v01 req = { 0 };
+ struct qmi_tmd_client *client;
+ struct qmi_txn txn;
+ int ret = 0;
+
+ client = tmd->client;
+
+ guard(mutex)(&client->mutex);
+
+ /*
+ * This function is called by qmi_set_cur_state() which does not know if
+ * the QMI service is actually online. If it isn't then we noop here.
+ * The state is cached in tmd->cur_state and will be broadcast via
+ * qmi_tmd_init_control() when the service comes up.
+ */
+ if (!client->connection_active)
+ return 0;
+
+ strscpy(req.mitigation_dev_id.mitigation_dev_id, tmd->qmi_name,
+ QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
+ req.mitigation_level = tmd->cur_state;
+
+ ret = qmi_txn_init(&client->handle, &txn,
+ tmd_set_mitigation_level_resp_msg_v01_ei, &tmd_resp);
+ if (ret < 0) {
+ dev_err(client->dev, "qmi set state %d txn init failed for %s ret %d\n",
+ tmd->cur_state, tmd->type, ret);
+ return ret;
+ }
+
+ ret = qmi_send_request(&client->handle, NULL, &txn,
+ QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01,
+ TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN,
+ tmd_set_mitigation_level_req_msg_v01_ei, &req);
+ if (ret < 0) {
+ dev_err(client->dev, "qmi set state %d txn send failed for %s ret %d\n",
+ tmd->cur_state, tmd->type, ret);
+ qmi_txn_cancel(&txn);
+ return ret;
+ }
+
+ ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
+ if (ret < 0) {
+ dev_err(client->dev, "qmi set state %d txn wait failed for %s ret %d\n",
+ tmd->cur_state, tmd->type, ret);
+ return ret;
+ }
+
+ if (tmd_resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ret = -tmd_resp.resp.result;
+ dev_err(client->dev, "qmi set state %d NOT success for %s ret %d\n",
+ tmd->cur_state, tmd->type, ret);
+ return ret;
+ }
+
+ dev_dbg(client->dev, "Requested state %d/%d for %s\n", tmd->cur_state,
+ tmd->max_state, tmd->type);
+
+ return 0;
+}
+
+static int qmi_get_max_level(void *devdata, unsigned long *level)
+{
+ struct qmi_tmd *tmd = devdata;
+
+ if (!tmd)
+ return -EINVAL;
+
+ *level = tmd->max_state;
+
+ return 0;
+}
+
+static int qmi_get_cur_level(void *devdata, unsigned long *level)
+{
+ struct qmi_tmd *tmd = devdata;
+
+ if (!tmd)
+ return -EINVAL;
+
+ *level = tmd->cur_state;
+
+ return 0;
+}
+
+static int qmi_set_cur_level(void *devdata, unsigned long level)
+{
+ struct qmi_tmd *tmd = devdata;
+
+ if (!tmd)
+ return -EINVAL;
+
+ if (level > tmd->max_state)
+ return -EINVAL;
+
+ if (tmd->cur_state == level)
+ return 0;
+
+ tmd->cur_state = level;
+
+ return qmi_tmd_send_state_request(tmd);
+}
+
+static const struct remoteproc_cooling_ops qmi_rproc_ops = {
+ .get_max_level = qmi_get_max_level,
+ .get_cur_level = qmi_get_cur_level,
+ .set_cur_level = qmi_set_cur_level,
+};
+
+static int qmi_register_cooling_device(struct qmi_tmd *tmd)
+{
+ struct remoteproc_cdev *rproc_cdev;
+
+ rproc_cdev = remoteproc_cooling_register(tmd->np,
+ tmd->type,
+ &qmi_rproc_ops,
+ tmd);
+
+ if (IS_ERR(rproc_cdev))
+ return dev_err_probe(tmd->client->dev, PTR_ERR(rproc_cdev),
+ "Failed to register cooling device %s\n",
+ tmd->qmi_name);
+
+ tmd->rproc_cdev = rproc_cdev;
+ return 0;
+}
+
+/*
+ * Init a single TMD control by registering a cooling device for it, or
+ * synchronising state with the remote subsystem if recovering from a service
+ * restart. This is called when the TMD service starts up.
+ */
+static int qmi_tmd_init_control(struct qmi_tmd_client *client, const char *label,
+ u8 max_state)
+{
+ struct qmi_tmd *tmd = NULL;
+
+ list_for_each_entry(tmd, &client->cdev_list, node)
+ if (!strncasecmp(tmd->qmi_name, label,
+ QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1))
+ goto found;
+
+ dev_dbg(client->dev,
+ "TMD '%s' available in firmware but not specified in DT\n",
+ label);
+ return 0;
+
+found:
+ tmd->max_state = max_state;
+ /*
+ * If the cooling device already exists then the QMI service went away and
+ * came back. So just make sure the current cooling device state is
+ * reflected on the remote side and then return.
+ */
+ if (tmd->rproc_cdev)
+ return qmi_tmd_send_state_request(tmd);
+
+ return qmi_register_cooling_device(tmd);
+}
+
+/*
+ * When the QMI service starts up on a remote subsystem this function will fetch
+ * the list of TMDs on the subsystem, match it to the TMDs specified in devicetree
+ * and call qmi_tmd_init_control() for each
+ */
+static void qmi_tmd_svc_arrive(struct work_struct *work)
+{
+ struct qmi_tmd_client *client =
+ container_of(work, struct qmi_tmd_client, svc_arrive_work);
+
+ struct tmd_get_mitigation_device_list_req_msg_v01 req = { 0 };
+ struct tmd_get_mitigation_device_list_resp_msg_v01 *resp __free(kfree) = NULL;
+ int ret = 0, i;
+ struct qmi_txn txn;
+
+ /* resp struct is 1.1kB, allocate it on the heap. */
+ resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+ if (!resp)
+ return;
+
+ /* Get a list of TMDs supported by the remoteproc */
+ scoped_guard(mutex, &client->mutex) {
+ ret = qmi_txn_init(&client->handle, &txn,
+ tmd_get_mitigation_device_list_resp_msg_v01_ei, resp);
+ if (ret < 0) {
+ dev_err(client->dev,
+ "Transaction init error for instance_id: %#x ret %d\n",
+ client->id, ret);
+ return;
+ }
+
+ ret = qmi_send_request(&client->handle, NULL, &txn,
+ QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01,
+ TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN,
+ tmd_get_mitigation_device_list_req_msg_v01_ei, &req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ return;
+ }
+
+ ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
+ if (ret < 0) {
+ dev_err(client->dev, "Transaction wait error for client %#x ret:%d\n",
+ client->id, ret);
+ return;
+ }
+ if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+ ret = resp->resp.result;
+ dev_err(client->dev, "Failed to get device list for client %#x ret:%d\n",
+ client->id, ret);
+ return;
+ }
+
+ client->connection_active = true;
+ }
+
+ for (i = 0; i < resp->mitigation_device_list_len; i++) {
+ struct tmd_mitigation_dev_list_type_v01 *device =
+ &resp->mitigation_device_list[i];
+
+ ret = qmi_tmd_init_control(client,
+ device->mitigation_dev_id.mitigation_dev_id,
+ device->max_mitigation_level);
+ if (ret)
+ break;
+ }
+}
+
+static void thermal_qmi_net_reset(struct qmi_handle *qmi)
+{
+ struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
+ struct qmi_tmd *tmd = NULL;
+
+ list_for_each_entry(tmd, &client->cdev_list, node) {
+ qmi_tmd_send_state_request(tmd);
+ }
+}
+
+static void thermal_qmi_del_server(struct qmi_handle *qmi, struct qmi_service *service)
+{
+ struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
+
+ scoped_guard(mutex, &client->mutex)
+ client->connection_active = false;
+}
+
+static int thermal_qmi_new_server(struct qmi_handle *qmi, struct qmi_service *service)
+{
+ struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
+ struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port };
+
+ scoped_guard(mutex, &client->mutex)
+ kernel_connect(qmi->sock, (struct sockaddr_unsized *)&sq, sizeof(sq), 0);
+
+ queue_work(system_highpri_wq, &client->svc_arrive_work);
+
+ return 0;
+}
+
+static const struct qmi_ops thermal_qmi_event_ops = {
+ .new_server = thermal_qmi_new_server,
+ .del_server = thermal_qmi_del_server,
+ .net_reset = thermal_qmi_net_reset,
+};
+
+static void qmi_tmd_cleanup(struct qmi_tmd_client *client)
+{
+ struct qmi_tmd *tmd, *c_next;
+
+ guard(mutex)(&client->mutex);
+
+ client->connection_active = false;
+
+ qmi_handle_release(&client->handle);
+ cancel_work(&client->svc_arrive_work);
+ list_for_each_entry_safe(tmd, c_next, &client->cdev_list, node) {
+ if (tmd->rproc_cdev)
+ remoteproc_cooling_unregister(tmd->rproc_cdev);
+
+ list_del(&tmd->node);
+ }
+}
+
+/* Parse the controls and allocate a qmi_tmd for each of them */
+static int qmi_tmd_alloc_cdevs(struct qmi_tmd_client *client)
+{
+ struct device *dev = client->dev;
+ struct device_node *node = dev->of_node;
+ struct device_node *subnode;
+ struct qmi_tmd *tmd;
+ int ret;
+
+ for_each_available_child_of_node_scoped(node, subnode) {
+ const char *name;
+
+ tmd = devm_kzalloc(dev, sizeof(*tmd), GFP_KERNEL);
+ if (!tmd)
+ return dev_err_probe(client->dev, -ENOMEM,
+ "Couldn't allocate tmd\n");
+
+ tmd->type = devm_kasprintf(client->dev, GFP_KERNEL, "%s",
+ subnode->name);
+ if (!tmd->type)
+ return dev_err_probe(dev, -ENOMEM,
+ "Couldn't allocate cooling device name\n");
+
+ if (of_property_read_string(subnode, "label", &name))
+ return dev_err_probe(client->dev, -EINVAL,
+ "Failed to parse dev name for %s\n",
+ subnode->name);
+
+ ret = strscpy(tmd->qmi_name, name,
+ QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
+ if (ret == -E2BIG)
+ return dev_err_probe(dev, -EINVAL, "TMD label %s is too long\n",
+ name);
+
+ tmd->client = client;
+ tmd->np = subnode;
+ tmd->cur_state = 0;
+ list_add(&tmd->node, &client->cdev_list);
+ }
+
+ if (list_empty(&client->cdev_list))
+ return dev_err_probe(client->dev, -EINVAL,
+ "No cooling devices specified for client %s (%#x)\n",
+ client->name, client->id);
+
+ return 0;
+}
+
+static int qmi_tmd_client_probe(struct platform_device *pdev)
+{
+ const struct qmi_instance_data *match;
+ struct qmi_tmd_client *client;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ client = devm_kzalloc(dev, sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+
+ client->dev = dev;
+
+ match = of_device_get_match_data(dev);
+ if (!match)
+ return dev_err_probe(dev, -EINVAL, "No match data\n");
+
+ client->id = match->id;
+ client->name = match->name;
+
+ mutex_init(&client->mutex);
+ INIT_LIST_HEAD(&client->cdev_list);
+ INIT_WORK(&client->svc_arrive_work, qmi_tmd_svc_arrive);
+
+ ret = qmi_tmd_alloc_cdevs(client);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, client);
+
+ ret = qmi_handle_init(&client->handle,
+ TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN,
+ &thermal_qmi_event_ops, NULL);
+ if (ret < 0)
+ return dev_err_probe(client->dev, ret, "QMI handle init failed for client %#x\n",
+ client->id);
+
+ ret = qmi_add_lookup(&client->handle, TMD_SERVICE_ID_V01, TMD_SERVICE_VERS_V01,
+ client->id);
+ if (ret < 0) {
+ qmi_handle_release(&client->handle);
+ return dev_err_probe(client->dev, ret, "QMI register failed for client 0x%x\n",
+ client->id);
+ }
+
+ return 0;
+}
+
+static void qmi_tmd_client_remove(struct platform_device *pdev)
+{
+ struct qmi_tmd_client *client = platform_get_drvdata(pdev);
+
+ qmi_tmd_cleanup(client);
+}
+
+static const struct qmi_instance_data qmi_cdsp = {
+ .id = CDSP_INSTANCE_ID,
+ .name = "cdsp",
+};
+
+static const struct qmi_instance_data qmi_cdsp1 = {
+ .id = CDSP1_INSTANCE_ID,
+ .name = "cdsp1",
+};
+
+static const struct of_device_id qmi_tmd_device_table[] = {
+ {
+ .compatible = "qcom,qmi-cooling-cdsp",
+ .data = &qmi_cdsp,
+ },
+ {
+ .compatible = "qcom,qmi-cooling-cdsp1",
+ .data = &qmi_cdsp1,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qmi_tmd_device_table);
+
+static struct platform_driver qmi_tmd_device_driver = {
+ .probe = qmi_tmd_client_probe,
+ .remove = qmi_tmd_client_remove,
+ .driver = {
+ .name = "qcom-qmi-cooling",
+ .of_match_table = qmi_tmd_device_table,
+ },
+};
+
+module_platform_driver(qmi_tmd_device_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm QMI Thermal Mitigation Device driver");
diff --git a/drivers/soc/qcom/qmi-cooling.h b/drivers/soc/qcom/qmi-cooling.h
new file mode 100644
index 000000000000..e33f4c5979e5
--- /dev/null
+++ b/drivers/soc/qcom/qmi-cooling.h
@@ -0,0 +1,429 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2017, The Linux Foundation
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef __QCOM_COOLING_H__
+#define __QCOM_COOLING_H__
+
+#include <linux/soc/qcom/qmi.h>
+
+#define TMD_SERVICE_ID_V01 0x18
+#define TMD_SERVICE_VERS_V01 0x01
+
+#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_RESP_V01 0x0020
+#define QMI_TMD_GET_MITIGATION_LEVEL_REQ_V01 0x0022
+#define QMI_TMD_GET_SUPPORTED_MSGS_REQ_V01 0x001E
+#define QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01 0x0021
+#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0023
+#define QMI_TMD_GET_SUPPORTED_MSGS_RESP_V01 0x001E
+#define QMI_TMD_SET_MITIGATION_LEVEL_RESP_V01 0x0021
+#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0024
+#define QMI_TMD_MITIGATION_LEVEL_REPORT_IND_V01 0x0025
+#define QMI_TMD_GET_MITIGATION_LEVEL_RESP_V01 0x0022
+#define QMI_TMD_GET_SUPPORTED_FIELDS_REQ_V01 0x001F
+#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01 0x0020
+#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0023
+#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0024
+#define QMI_TMD_GET_SUPPORTED_FIELDS_RESP_V01 0x001F
+
+#define QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 32
+#define QMI_TMD_MITIGATION_DEV_LIST_MAX_V01 32
+
+struct tmd_mitigation_dev_id_type_v01 {
+ char mitigation_dev_id[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1];
+};
+
+static const struct qmi_elem_info tmd_mitigation_dev_id_type_v01_ei[] = {
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct tmd_mitigation_dev_id_type_v01,
+ mitigation_dev_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_mitigation_dev_list_type_v01 {
+ struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id;
+ u8 max_mitigation_level;
+};
+
+static const struct qmi_elem_info tmd_mitigation_dev_list_type_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct tmd_mitigation_dev_list_type_v01,
+ mitigation_dev_id),
+ .ei_array = tmd_mitigation_dev_id_type_v01_ei,
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct tmd_mitigation_dev_list_type_v01,
+ max_mitigation_level),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_get_mitigation_device_list_req_msg_v01 {
+ char placeholder;
+};
+
+#define TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN 0
+const struct qmi_elem_info tmd_get_mitigation_device_list_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_get_mitigation_device_list_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 mitigation_device_list_valid;
+ u32 mitigation_device_list_len;
+ struct tmd_mitigation_dev_list_type_v01
+ mitigation_device_list[QMI_TMD_MITIGATION_DEV_LIST_MAX_V01];
+};
+
+#define TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN 1099
+static const struct qmi_elem_info tmd_get_mitigation_device_list_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
+ mitigation_device_list_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
+ mitigation_device_list_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_TMD_MITIGATION_DEV_LIST_MAX_V01,
+ .elem_size = sizeof(struct tmd_mitigation_dev_list_type_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
+ mitigation_device_list),
+ .ei_array = tmd_mitigation_dev_list_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_set_mitigation_level_req_msg_v01 {
+ struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id;
+ u8 mitigation_level;
+};
+
+#define TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 40
+static const struct qmi_elem_info tmd_set_mitigation_level_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01,
+ mitigation_dev_id),
+ .ei_array = tmd_mitigation_dev_id_type_v01_ei,
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01,
+ mitigation_level),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_set_mitigation_level_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define TMD_SET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
+static const struct qmi_elem_info tmd_set_mitigation_level_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct tmd_set_mitigation_level_resp_msg_v01, resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_get_mitigation_level_req_msg_v01 {
+ struct tmd_mitigation_dev_id_type_v01 mitigation_device;
+};
+
+#define TMD_GET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
+
+static const struct qmi_elem_info tmd_get_mitigation_level_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct tmd_get_mitigation_level_req_msg_v01,
+ mitigation_device),
+ .ei_array = tmd_mitigation_dev_id_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_get_mitigation_level_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 current_mitigation_level_valid;
+ u8 current_mitigation_level;
+ u8 requested_mitigation_level_valid;
+ u8 requested_mitigation_level;
+};
+
+#define TMD_GET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 15
+static const struct qmi_elem_info tmd_get_mitigation_level_resp_msg_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01, resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
+ current_mitigation_level_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
+ current_mitigation_level),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
+ requested_mitigation_level_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
+ requested_mitigation_level),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct tmd_register_notification_mitigation_level_req_msg_v01 {
+ struct tmd_mitigation_dev_id_type_v01 mitigation_device;
+};
+
+#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
+static const struct qmi_elem_info
+ tmd_register_notification_mitigation_level_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(
+ struct tmd_register_notification_mitigation_level_req_msg_v01,
+ mitigation_device),
+ .ei_array = tmd_mitigation_dev_id_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+ };
+
+struct tmd_register_notification_mitigation_level_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
+static const struct qmi_elem_info
+ tmd_register_notification_mitigation_level_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct tmd_register_notification_mitigation_level_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+ };
+
+struct tmd_deregister_notification_mitigation_level_req_msg_v01 {
+ struct tmd_mitigation_dev_id_type_v01 mitigation_device;
+};
+
+#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
+static const struct qmi_elem_info
+ tmd_deregister_notification_mitigation_level_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(
+ struct tmd_deregister_notification_mitigation_level_req_msg_v01,
+ mitigation_device),
+ .ei_array = tmd_mitigation_dev_id_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+ };
+
+struct tmd_deregister_notification_mitigation_level_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
+static const struct qmi_elem_info
+ tmd_deregister_notification_mitigation_level_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct tmd_deregister_notification_mitigation_level_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+ };
+
+struct tmd_mitigation_level_report_ind_msg_v01 {
+ struct tmd_mitigation_dev_id_type_v01 mitigation_device;
+ u8 current_mitigation_level;
+};
+
+#define TMD_MITIGATION_LEVEL_REPORT_IND_MSG_V01_MAX_MSG_LEN 40
+static const struct qmi_elem_info tmd_mitigation_level_report_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01,
+ mitigation_device),
+ .ei_array = tmd_mitigation_dev_id_type_v01_ei,
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01,
+ current_mitigation_level),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+#endif /* __QMI_COOLING_INTERNAL_H__ */
--
2.34.1
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling
2026-01-27 15:57 [PATCH v2 0/8] Add RemoteProc cooling support Gaurav Kohli
` (3 preceding siblings ...)
2026-01-27 15:57 ` [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver Gaurav Kohli
@ 2026-01-27 15:57 ` Gaurav Kohli
2026-01-29 0:43 ` Dmitry Baryshkov
2026-01-27 15:57 ` [PATCH v2 6/8] arm64: dts: qcom: talos: " Gaurav Kohli
` (3 subsequent siblings)
8 siblings, 1 reply; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-27 15:57 UTC (permalink / raw)
To: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pm, gaurav.kohli,
manaf.pallikunhi
Unlike the CPU, the CDSP does not throttle its speed automatically
when it reaches high temperatures in Lemans.
Set up CDSP cooling by throttling the cdsp when it reaches 105°C.
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/lemans.dtsi | 138 ++++++++++++++++++++++++---
1 file changed, 126 insertions(+), 12 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index 808827b83553..c747dd534caa 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -7281,6 +7281,15 @@ compute-cb@11 {
};
};
};
+
+ cooling {
+ compatible = "qcom,qmi-cooling-cdsp";
+
+ cdsp_tmd0: cdsp-tmd0 {
+ label = "cdsp_sw";
+ #cooling-cells = <2>;
+ };
+ };
};
nspb_noc: interconnect@2a0c0000 {
@@ -7444,6 +7453,15 @@ compute-cb@13 {
};
};
};
+
+ cooling {
+ compatible = "qcom,qmi-cooling-cdsp1";
+
+ cdsp_tmd1: cdsp-tmd1 {
+ label = "cdsp_sw";
+ #cooling-cells = <2>;
+ };
+ };
};
remoteproc_adsp: remoteproc@30000000 {
@@ -8168,7 +8186,7 @@ nsp-0-0-0-thermal {
thermal-sensors = <&tsens2 5>;
trips {
- trip-point0 {
+ nsp_0_0_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8180,6 +8198,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_0_0_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-1-0-thermal {
@@ -8188,7 +8214,7 @@ nsp-0-1-0-thermal {
thermal-sensors = <&tsens2 6>;
trips {
- trip-point0 {
+ nsp_0_1_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8200,6 +8226,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_1_0_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-2-0-thermal {
@@ -8208,7 +8242,7 @@ nsp-0-2-0-thermal {
thermal-sensors = <&tsens2 7>;
trips {
- trip-point0 {
+ nsp_0_2_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8220,6 +8254,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_2_0_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-0-0-thermal {
@@ -8228,7 +8270,7 @@ nsp-1-0-0-thermal {
thermal-sensors = <&tsens2 8>;
trips {
- trip-point0 {
+ nsp_1_0_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8240,6 +8282,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_0_0_alert0>;
+ cooling-device = <&cdsp_tmd1
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-1-0-thermal {
@@ -8248,7 +8298,7 @@ nsp-1-1-0-thermal {
thermal-sensors = <&tsens2 9>;
trips {
- trip-point0 {
+ nsp_1_1_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8260,6 +8310,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_1_0_alert0>;
+ cooling-device = <&cdsp_tmd1
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-2-0-thermal {
@@ -8268,7 +8326,7 @@ nsp-1-2-0-thermal {
thermal-sensors = <&tsens2 10>;
trips {
- trip-point0 {
+ nsp_1_2_0_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8280,6 +8338,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_2_0_alert0>;
+ cooling-device = <&cdsp_tmd1
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
ddrss-0-thermal {
@@ -8422,7 +8488,7 @@ nsp-0-0-1-thermal {
thermal-sensors = <&tsens3 5>;
trips {
- trip-point0 {
+ nsp_0_0_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8434,6 +8500,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_0_1_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-1-1-thermal {
@@ -8442,7 +8516,7 @@ nsp-0-1-1-thermal {
thermal-sensors = <&tsens3 6>;
trips {
- trip-point0 {
+ nsp_0_1_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8454,6 +8528,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_1_1_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-2-1-thermal {
@@ -8462,7 +8544,7 @@ nsp-0-2-1-thermal {
thermal-sensors = <&tsens3 7>;
trips {
- trip-point0 {
+ nsp_0_2_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8474,6 +8556,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_2_1_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-0-1-thermal {
@@ -8482,7 +8572,7 @@ nsp-1-0-1-thermal {
thermal-sensors = <&tsens3 8>;
trips {
- trip-point0 {
+ nsp_1_0_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8494,6 +8584,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_0_1_alert0>;
+ cooling-device = <&cdsp_tmd1
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-1-1-thermal {
@@ -8502,7 +8600,7 @@ nsp-1-1-1-thermal {
thermal-sensors = <&tsens3 9>;
trips {
- trip-point0 {
+ nsp_1_1_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8514,6 +8612,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_1_1_alert0>;
+ cooling-device = <&cdsp_tmd1
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-1-2-1-thermal {
@@ -8522,7 +8628,7 @@ nsp-1-2-1-thermal {
thermal-sensors = <&tsens3 10>;
trips {
- trip-point0 {
+ nsp_1_2_1_alert0: trip-point0 {
temperature = <105000>;
hysteresis = <5000>;
type = "passive";
@@ -8534,6 +8640,14 @@ trip-point1 {
type = "passive";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_1_2_1_alert0>;
+ cooling-device = <&cdsp_tmd1
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
ddrss-1-thermal {
--
2.34.1
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 6/8] arm64: dts: qcom: talos: Enable CDSP cooling
2026-01-27 15:57 [PATCH v2 0/8] Add RemoteProc cooling support Gaurav Kohli
` (4 preceding siblings ...)
2026-01-27 15:57 ` [PATCH v2 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling Gaurav Kohli
@ 2026-01-27 15:57 ` Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 7/8] arm64: dts: qcom: kodiak: " Gaurav Kohli
` (2 subsequent siblings)
8 siblings, 0 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-27 15:57 UTC (permalink / raw)
To: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pm, gaurav.kohli,
manaf.pallikunhi
Unlike the CPU, the CDSP does not throttle its speed automatically when it
reaches high temperatures in Talos.
Set up CDSP cooling by throttling the CDSP when it reaches 105°C.
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/talos.dtsi | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi
index 75716b4a58d6..4091afd0b6e3 100644
--- a/arch/arm64/boot/dts/qcom/talos.dtsi
+++ b/arch/arm64/boot/dts/qcom/talos.dtsi
@@ -19,6 +19,7 @@
#include <dt-bindings/power/qcom-rpmpd.h>
#include <dt-bindings/power/qcom,rpmhpd.h>
#include <dt-bindings/soc/qcom,rpmh-rsc.h>
+#include <dt-bindings/thermal/thermal.h>
/ {
interrupt-parent = <&intc>;
@@ -3554,6 +3555,15 @@ compute-cb@6 {
};
};
};
+
+ cooling {
+ compatible = "qcom,qmi-cooling-cdsp";
+
+ cdsp_tmd0: cdsp-tmd0 {
+ label = "cdsp_sw";
+ #cooling-cells = <2>;
+ };
+ };
};
pmu@90b6300 {
@@ -4845,12 +4855,26 @@ q6-hvx-thermal {
thermal-sensors = <&tsens0 10>;
trips {
+ q6_hvx_alert0: trip-point0 {
+ temperature = <105000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
q6-hvx-critical {
temperature = <115000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&q6_hvx_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
mdm-core-thermal {
--
2.34.1
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 7/8] arm64: dts: qcom: kodiak: Enable CDSP cooling
2026-01-27 15:57 [PATCH v2 0/8] Add RemoteProc cooling support Gaurav Kohli
` (5 preceding siblings ...)
2026-01-27 15:57 ` [PATCH v2 6/8] arm64: dts: qcom: talos: " Gaurav Kohli
@ 2026-01-27 15:57 ` Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 8/8] arm64: dts: qcom: monaco: " Gaurav Kohli
2026-03-06 9:09 ` [PATCH v2 0/8] Add RemoteProc cooling support Daniel Lezcano
8 siblings, 0 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-27 15:57 UTC (permalink / raw)
To: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pm, gaurav.kohli,
manaf.pallikunhi
Unlike the CPU, the CDSP does not throttle its speed automatically
when it reaches high temperatures in kodiak.
Set up CDSP cooling by throttling the cdsp when it reaches 100°C.
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/kodiak.dtsi | 37 ++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
index 6079e67ea829..3c79572bf55f 100644
--- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
+++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
@@ -4793,6 +4793,15 @@ compute-cb@14 {
};
};
};
+
+ cooling {
+ compatible = "qcom,qmi-cooling-cdsp";
+
+ cdsp_tmd0: cdsp-tmd0 {
+ label = "cdsp_sw";
+ #cooling-cells = <2>;
+ };
+ };
};
usb_1: usb@a600000 {
@@ -7600,12 +7609,26 @@ nspss0_alert0: trip-point0 {
type = "hot";
};
+ nspss0_alert1: trip-point1 {
+ temperature = <100000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nspss0_crit: nspss0-crit {
temperature = <110000>;
hysteresis = <0>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nspss0_alert1>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nspss1-thermal {
@@ -7618,12 +7641,26 @@ nspss1_alert0: trip-point0 {
type = "hot";
};
+ nspss1_alert1: trip-point1 {
+ temperature = <100000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nspss1_crit: nspss1-crit {
temperature = <110000>;
hysteresis = <0>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nspss1_alert1>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
video-thermal {
--
2.34.1
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 8/8] arm64: dts: qcom: monaco: Enable CDSP cooling
2026-01-27 15:57 [PATCH v2 0/8] Add RemoteProc cooling support Gaurav Kohli
` (6 preceding siblings ...)
2026-01-27 15:57 ` [PATCH v2 7/8] arm64: dts: qcom: kodiak: " Gaurav Kohli
@ 2026-01-27 15:57 ` Gaurav Kohli
2026-03-06 9:09 ` [PATCH v2 0/8] Add RemoteProc cooling support Daniel Lezcano
8 siblings, 0 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-27 15:57 UTC (permalink / raw)
To: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pm, gaurav.kohli,
manaf.pallikunhi
Unlike the CPU, the CDSP does not throttle its speed automatically
when it reaches high temperatures in monaco.
Set up CDSP cooling by throttling the cdsp when it reaches 105°C.
Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/monaco.dtsi | 93 ++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 5d2df4305d1c..6d7a269cd98e 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -7194,6 +7194,15 @@ compute-cb@4 {
};
};
};
+
+ cooling {
+ compatible = "qcom,qmi-cooling-cdsp";
+
+ cdsp_tmd0: cdsp-tmd0 {
+ label = "cdsp_sw";
+ #cooling-cells = <2>;
+ };
+ };
};
};
@@ -7528,36 +7537,78 @@ nsp-0-0-0-thermal {
thermal-sensors = <&tsens2 5>;
trips {
+ nsp_0_0_0_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_0_0_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-1-0-thermal {
thermal-sensors = <&tsens2 6>;
trips {
+ nsp_0_1_0_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_1_0_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-2-0-thermal {
thermal-sensors = <&tsens2 7>;
trips {
+ nsp_0_2_0_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_2_0_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
ddrss-0-thermal {
@@ -7648,36 +7699,78 @@ nsp-0-0-1-thermal {
thermal-sensors = <&tsens3 5>;
trips {
+ nsp_0_0_1_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_0_1_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-1-1-thermal {
thermal-sensors = <&tsens3 6>;
trips {
+ nsp_0_1_1_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_1_1_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
nsp-0-2-1-thermal {
thermal-sensors = <&tsens3 7>;
trips {
+ nsp_0_2_1_alert0: trip-point0 {
+ temperature = <115000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+
nsp-critical {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&nsp_0_2_1_alert0>;
+ cooling-device = <&cdsp_tmd0
+ THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
ddrss-1-thermal {
--
2.34.1
^ permalink raw reply related [flat|nested] 53+ messages in thread
* Re: [PATCH v2 3/8] remoteproc: qcom: probe all child devices
2026-01-27 15:57 ` [PATCH v2 3/8] remoteproc: qcom: probe all child devices Gaurav Kohli
@ 2026-01-27 16:50 ` Dmitry Baryshkov
0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Baryshkov @ 2026-01-27 16:50 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Jan 27, 2026 at 09:27:17PM +0530, Gaurav Kohli wrote:
> From: Casey Connolly <casey.connolly@linaro.org>
>
> Currently, only qcom,bam-dmux nodes are supported as
> remoteproc children with of_platform_populate(). This limits
> the other child nodes to probe separately.
>
> Generalise the qcom,bam-dmux child node support by probing all
> remoteproc children with of_platform_populate(). This enables
> support for devices that represent themselves as subnodes of
> the remoteproc, such as QMI clients.
>
> Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> ---
> drivers/remoteproc/qcom_q6v5.c | 4 ++++
> drivers/remoteproc/qcom_q6v5_mss.c | 8 --------
> 2 files changed, 4 insertions(+), 8 deletions(-)
You received a question from the reviewers and then posted the same
patch without concluding the previous discussion. NAK.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-01-27 15:57 ` [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings Gaurav Kohli
@ 2026-01-28 11:27 ` Krzysztof Kozlowski
2026-01-29 12:06 ` Gaurav Kohli
2026-01-28 11:28 ` Krzysztof Kozlowski
2026-01-29 0:45 ` Dmitry Baryshkov
2 siblings, 1 reply; 53+ messages in thread
From: Krzysztof Kozlowski @ 2026-01-28 11:27 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
> The cooling subnode of a remoteproc represents a client of the Thermal
> Mitigation Device QMI service running on it. Each subnode of the cooling
> node represents a single control exposed by the service.
>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> ---
> .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
> 2 files changed, 78 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>
> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> index 68c17bf18987..6a736161d5ae 100644
> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> @@ -80,6 +80,12 @@ properties:
> and devices related to the ADSP.
> unevaluatedProperties: false
>
> + cooling:
> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
> + description:
> + Cooling subnode which represents the cooling devices exposed by the Modem.
I do not see the reason why you need 3 (!!!) children here. Everything
should be folded here.
> + unevaluatedProperties: false
> +
> required:
> - clocks
> - clock-names
> diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
> new file mode 100644
> index 000000000000..0dd3bd84c176
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
> @@ -0,0 +1,72 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices
> +
> +maintainers:
> + - Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> +
> +description:
> + Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions
> + across multiple remote subsystems. These devices operate based on junction
> + temperature sensors (TSENS) associated with thermal zones for each subsystem.
> +
> +properties:
> + compatible:
> + enum:
> + - qcom,qmi-cooling-cdsp
> + - qcom,qmi-cooling-cdsp1
What are the differences between them?
Why these are not SoC specific?
> +
> +patternProperties:
> + "cdsp-tmd[0-9]*$":
> + type: object
No, you do not need childnode. See writing bindings (covers exactly this
case).
> +
> + description:
> + Each subnode which represents qmi communication to CDSP.
> +
> + properties:
> + label:
> + maxItems: 1
> +
> + "#cooling-cells":
> + $ref: /schemas/thermal/thermal-cooling-devices.yaml#/properties/#cooling-cells
> +
> + required:
> + - label
> + - "#cooling-cells"
> +
> + additionalProperties: false
> +
> +required:
> + - compatible
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + remoteproc-cdsp {
> + cooling {
> + compatible = "qcom,qmi-cooling-cdsp";
> +
> + cdsp_tmd0: cdsp-tmd0 {
> + label = "cdsp_sw";
> + #cooling-cells = <2>;
> + };
> + };
> + };
> +
> + - |
> + remoteproc-cdsp1 {
No, don't create unnecessary examples. Please read some slides from
earlier talks so you won't need 10 iterations.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-01-27 15:57 ` [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings Gaurav Kohli
2026-01-28 11:27 ` Krzysztof Kozlowski
@ 2026-01-28 11:28 ` Krzysztof Kozlowski
2026-01-29 12:12 ` Gaurav Kohli
2026-01-29 0:45 ` Dmitry Baryshkov
2 siblings, 1 reply; 53+ messages in thread
From: Krzysztof Kozlowski @ 2026-01-28 11:28 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
> The cooling subnode of a remoteproc represents a client of the Thermal
> Mitigation Device QMI service running on it. Each subnode of the cooling
> node represents a single control exposed by the service.
Subject - almost bingo, you hit two out of three which you should not
use.
A nit, subject: drop second/last, redundant "bindings yaml" and whatever
else is duplicating. The "dt-bindings" prefix is already stating that
these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-01-27 15:57 ` [PATCH v2 1/8] thermal: Add Remote Proc cooling driver Gaurav Kohli
@ 2026-01-28 11:32 ` Krzysztof Kozlowski
2026-01-30 6:39 ` Gaurav Kohli
2026-01-28 11:36 ` Krzysztof Kozlowski
` (3 subsequent siblings)
4 siblings, 1 reply; 53+ messages in thread
From: Krzysztof Kozlowski @ 2026-01-28 11:32 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Jan 27, 2026 at 09:27:15PM +0530, Gaurav Kohli wrote:
> Add a new generic driver for thermal cooling devices that control
There is no driver here. You did not a single driver entry point.
> remote processors (modem, DSP, etc.) through various communication
> channels.
>
> This driver provides an abstraction layer between the thermal
Please read coding style how much we like abstraction layers.
> subsystem and vendor-specific remote processor communication
> mechanisms.
>
> Advantage of this to avoid duplicating vendor-specific logic
> in the thermal subsystem and make it easier for different vendors
> to plug in their own cooling mechanisms via callbacks.
>
> Suggested-by: Amit Kucheria <amit.kucheria@oss.qualcomm.com>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> ---
> MAINTAINERS | 7 ++
> drivers/thermal/Kconfig | 10 ++
> drivers/thermal/Makefile | 2 +
> drivers/thermal/remoteproc_cooling.c | 143 +++++++++++++++++++++++++++
> include/linux/remoteproc_cooling.h | 52 ++++++++++
> 5 files changed, 214 insertions(+)
> create mode 100644 drivers/thermal/remoteproc_cooling.c
> create mode 100644 include/linux/remoteproc_cooling.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 414f44093269..5ebc7819d2cf 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -26169,6 +26169,13 @@ F: drivers/thermal/cpufreq_cooling.c
> F: drivers/thermal/cpuidle_cooling.c
> F: include/linux/cpu_cooling.h
>
> +THERMAL/REMOTEPROC_COOLING
> +M: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> +L: linux-pm@vger.kernel.org
> +S: Supported
> +F: drivers/thermal/remoteproc_cooling.c
> +F: include/linux/remoteproc_cooling.h
> +
> THERMAL/POWER_ALLOCATOR
Please beginning of this file. P < R.
> M: Lukasz Luba <lukasz.luba@arm.com>
> L: linux-pm@vger.kernel.org
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index b10080d61860..dfc52eed64de 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -229,6 +229,16 @@ config PCIE_THERMAL
>
> If you want this support, you should say Y here.
>
> +config REMOTEPROC_THERMAL
> + tristate "Remote processor cooling support"
> + help
> + This implements a generic cooling mechanism for remote processors
> + (modem, DSP, etc.) that allows vendor-specific implementations to
> + register thermal cooling devices and provide callbacks for thermal
> + mitigation.
> +
> + If you want this support, you should say Y here.
> +
> config THERMAL_EMULATION
> bool "Thermal emulation mode support"
> help
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index bb21e7ea7fc6..ae747dde54fe 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -34,6 +34,8 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
>
> thermal_sys-$(CONFIG_PCIE_THERMAL) += pcie_cooling.o
>
> +thermal_sys-$(CONFIG_REMOTEPROC_THERMAL) += remoteproc_cooling.o
> +
> obj-$(CONFIG_K3_THERMAL) += k3_bandgap.o k3_j72xx_bandgap.o
> # platform thermal drivers
> obj-y += broadcom/
> diff --git a/drivers/thermal/remoteproc_cooling.c b/drivers/thermal/remoteproc_cooling.c
> new file mode 100644
> index 000000000000..f958efa691b3
> --- /dev/null
> +++ b/drivers/thermal/remoteproc_cooling.c
> @@ -0,0 +1,143 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Remote Processor Cooling Device
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/export.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
Where do you use it?
> +#include <linux/slab.h>
> +#include <linux/thermal.h>
> +
> +#define REMOTEPROC_PREFIX "rproc_"
> +
> +struct remoteproc_cooling_ops {
> + int (*get_max_level)(void *devdata, unsigned long *level);
> + int (*get_cur_level)(void *devdata, unsigned long *level);
> + int (*set_cur_level)(void *devdata, unsigned long level);
> +};
> +
> +/**
> + * struct remoteproc_cdev - Remote processor cooling device
> + * @cdev: Thermal cooling device handle
> + * @ops: Vendor-specific operation callbacks
> + * @devdata: Private data for vendor implementation
> + * @np: Device tree node associated with this cooling device
> + * @lock: Mutex to protect cooling device operations
> + */
> +struct remoteproc_cdev {
> + struct thermal_cooling_device *cdev;
> + const struct remoteproc_cooling_ops *ops;
> + void *devdata;
> + struct mutex lock;
> +};
> +
> +/* Thermal cooling device callbacks */
> +
> +static int remoteproc_get_max_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
> + int ret;
> +
> + mutex_lock(&rproc_cdev->lock);
> + ret = rproc_cdev->ops->get_max_level(rproc_cdev->devdata, state);
> + mutex_unlock(&rproc_cdev->lock);
> +
> + return ret;
> +}
> +
> +static int remoteproc_get_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
> + int ret;
> +
> + mutex_lock(&rproc_cdev->lock);
> + ret = rproc_cdev->ops->get_cur_level(rproc_cdev->devdata, state);
> + mutex_unlock(&rproc_cdev->lock);
> +
> + return ret;
> +}
> +
> +static int remoteproc_set_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long state)
> +{
> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
> + int ret;
> +
> + mutex_lock(&rproc_cdev->lock);
> + ret = rproc_cdev->ops->set_cur_level(rproc_cdev->devdata, state);
> + mutex_unlock(&rproc_cdev->lock);
> +
> + return ret;
> +}
> +
> +static const struct thermal_cooling_device_ops remoteproc_cooling_ops = {
> + .get_max_state = remoteproc_get_max_state,
> + .get_cur_state = remoteproc_get_cur_state,
> + .set_cur_state = remoteproc_set_cur_state,
> +};
> +
> +struct remoteproc_cdev *
> +remoteproc_cooling_register(struct device_node *np,
> + const char *name, const struct remoteproc_cooling_ops *ops,
> + void *devdata)
> +{
> + struct remoteproc_cdev *rproc_cdev;
> + struct thermal_cooling_device *cdev;
> + int ret;
> +
> + if (!name || !ops)
> + return ERR_PTR(-EINVAL);
> +
> + rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL);
> + if (!rproc_cdev)
> + return ERR_PTR(-ENOMEM);
> +
> + rproc_cdev->ops = ops;
> + rproc_cdev->devdata = devdata;
> + mutex_init(&rproc_cdev->lock);
> +
> + char *rproc_name __free(kfree) =
> + kasprintf(GFP_KERNEL, REMOTEPROC_PREFIX "%s", name);
> + /* Register with thermal framework */
> + if (np)
> + cdev = thermal_of_cooling_device_register(np, rproc_name, rproc_cdev,
> + &remoteproc_cooling_ops);
> + else
> + cdev = thermal_cooling_device_register(rproc_name, rproc_cdev,
> + &remoteproc_cooling_ops);
> +
> + if (IS_ERR(cdev)) {
> + ret = PTR_ERR(cdev);
> + goto free_rproc_cdev;
> + }
> +
> + rproc_cdev->cdev = cdev;
> +
> + return rproc_cdev;
> +
> +free_rproc_cdev:
> + kfree(rproc_cdev);
> + return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(remoteproc_cooling_register);
> +
> +void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
> +{
> + if (!rproc_cdev)
> + return;
> +
> + thermal_cooling_device_unregister(rproc_cdev->cdev);
> + mutex_destroy(&rproc_cdev->lock);
> + kfree(rproc_cdev);
> +}
> +EXPORT_SYMBOL_GPL(remoteproc_cooling_unregister);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Remote Processor Cooling Device");
I do not see any driver here, just bunch of exported functions. I do not
see point in this abstraction/wrapping layer.
Another abstraction layer, NAK.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-01-27 15:57 ` [PATCH v2 1/8] thermal: Add Remote Proc cooling driver Gaurav Kohli
2026-01-28 11:32 ` Krzysztof Kozlowski
@ 2026-01-28 11:36 ` Krzysztof Kozlowski
2026-01-30 6:42 ` Gaurav Kohli
2026-01-30 5:39 ` kernel test robot
` (2 subsequent siblings)
4 siblings, 1 reply; 53+ messages in thread
From: Krzysztof Kozlowski @ 2026-01-28 11:36 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Jan 27, 2026 at 09:27:15PM +0530, Gaurav Kohli wrote:
> + if (!name || !ops)
> + return ERR_PTR(-EINVAL);
> +
> + rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL);
> + if (!rproc_cdev)
> + return ERR_PTR(-ENOMEM);
> +
> + rproc_cdev->ops = ops;
> + rproc_cdev->devdata = devdata;
> + mutex_init(&rproc_cdev->lock);
> +
> + char *rproc_name __free(kfree) =
> + kasprintf(GFP_KERNEL, REMOTEPROC_PREFIX "%s", name);
Ah, you keep ignoring review and sending the same buggy code.
There is no point to spend any time here. It's also fastest way to get
your future contributions ignored or NAKed.
Well, ignoring review is obviously:
NAK
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling
2026-01-27 15:57 ` [PATCH v2 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling Gaurav Kohli
@ 2026-01-29 0:43 ` Dmitry Baryshkov
2026-01-29 12:10 ` Gaurav Kohli
0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2026-01-29 0:43 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Jan 27, 2026 at 09:27:19PM +0530, Gaurav Kohli wrote:
> Unlike the CPU, the CDSP does not throttle its speed automatically
> when it reaches high temperatures in Lemans.
>
> Set up CDSP cooling by throttling the cdsp when it reaches 105°C.
>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/lemans.dtsi | 138 ++++++++++++++++++++++++---
> 1 file changed, 126 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
> index 808827b83553..c747dd534caa 100644
> --- a/arch/arm64/boot/dts/qcom/lemans.dtsi
> +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
> @@ -7281,6 +7281,15 @@ compute-cb@11 {
> };
> };
> };
> +
> + cooling {
> + compatible = "qcom,qmi-cooling-cdsp";
> +
> + cdsp_tmd0: cdsp-tmd0 {
This question was already raised. Are there more than one cooling device
for the DSP? If not, drop the subnodes.
> + label = "cdsp_sw";
> + #cooling-cells = <2>;
> + };
> + };
> };
>
> nspb_noc: interconnect@2a0c0000 {
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-01-27 15:57 ` [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings Gaurav Kohli
2026-01-28 11:27 ` Krzysztof Kozlowski
2026-01-28 11:28 ` Krzysztof Kozlowski
@ 2026-01-29 0:45 ` Dmitry Baryshkov
2026-01-30 7:08 ` Gaurav Kohli
2 siblings, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2026-01-29 0:45 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
> The cooling subnode of a remoteproc represents a client of the Thermal
> Mitigation Device QMI service running on it. Each subnode of the cooling
> node represents a single control exposed by the service.
>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> ---
> .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
> 2 files changed, 78 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>
> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> index 68c17bf18987..6a736161d5ae 100644
> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> @@ -80,6 +80,12 @@ properties:
> and devices related to the ADSP.
> unevaluatedProperties: false
>
> + cooling:
> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
> + description:
> + Cooling subnode which represents the cooling devices exposed by the Modem.
> + unevaluatedProperties: false
> +
> required:
> - clocks
> - clock-names
> diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
> new file mode 100644
> index 000000000000..0dd3bd84c176
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
> @@ -0,0 +1,72 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices
> +
> +maintainers:
> + - Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> +
> +description:
> + Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions
> + across multiple remote subsystems. These devices operate based on junction
> + temperature sensors (TSENS) associated with thermal zones for each subsystem.
> +
> +properties:
> + compatible:
> + enum:
> + - qcom,qmi-cooling-cdsp
> + - qcom,qmi-cooling-cdsp1
If I read your schema as you've it written, then ADSP, SLPI and modem
also can have _CDSP_ cooling device. Seems like an overkill.
Please take care to describe cooling devices for all DSPs at once and
describe them properly.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-01-28 11:27 ` Krzysztof Kozlowski
@ 2026-01-29 12:06 ` Gaurav Kohli
2026-02-08 10:06 ` Krzysztof Kozlowski
0 siblings, 1 reply; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-29 12:06 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 1/28/2026 4:57 PM, Krzysztof Kozlowski wrote:
> On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
>> The cooling subnode of a remoteproc represents a client of the Thermal
>> Mitigation Device QMI service running on it. Each subnode of the cooling
>> node represents a single control exposed by the service.
>>
>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> ---
>> .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
>> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
>> 2 files changed, 78 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>> index 68c17bf18987..6a736161d5ae 100644
>> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>> @@ -80,6 +80,12 @@ properties:
>> and devices related to the ADSP.
>> unevaluatedProperties: false
>>
>> + cooling:
>> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
>> + description:
>> + Cooling subnode which represents the cooling devices exposed by the Modem.
> I do not see the reason why you need 3 (!!!) children here. Everything
> should be folded here.
Thanks Krzysztof for review.
Each subsystem may support multiple thermal mitigation devices through
remote TMD service.
Because of this multiplicity, introduced separate binding file.
>> + unevaluatedProperties: false
>> +
>> required:
>> - clocks
>> - clock-names
>> diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>> new file mode 100644
>> index 000000000000..0dd3bd84c176
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>> @@ -0,0 +1,72 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices
>> +
>> +maintainers:
>> + - Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> +
>> +description:
>> + Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions
>> + across multiple remote subsystems. These devices operate based on junction
>> + temperature sensors (TSENS) associated with thermal zones for each subsystem.
>> +
>> +properties:
>> + compatible:
>> + enum:
>> + - qcom,qmi-cooling-cdsp
>> + - qcom,qmi-cooling-cdsp1
> What are the differences between them?
Some SOcs support multiple CDSP/NSP instances. Each instance requires
it's own
compatible string to distinguish.
> Why these are not SoC specific?
They are not soc specific because the qmi thermal mitigation interface
exposed by CDSP is architecturally
identical across multiple SOCS.
>> +
>> +patternProperties:
>> + "cdsp-tmd[0-9]*$":
>> + type: object
> No, you do not need childnode. See writing bindings (covers exactly this
> case).
Each subsystem may support multiple thermal mitigation devices through
remote TMD service. So
need childnode to distinguish for different mitigations.
>
>> +
>> + description:
>> + Each subnode which represents qmi communication to CDSP.
>> +
>> + properties:
>> + label:
>> + maxItems: 1
>> +
>> + "#cooling-cells":
>> + $ref: /schemas/thermal/thermal-cooling-devices.yaml#/properties/#cooling-cells
>> +
>> + required:
>> + - label
>> + - "#cooling-cells"
>> +
>> + additionalProperties: false
>> +
>> +required:
>> + - compatible
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + remoteproc-cdsp {
>> + cooling {
>> + compatible = "qcom,qmi-cooling-cdsp";
>> +
>> + cdsp_tmd0: cdsp-tmd0 {
>> + label = "cdsp_sw";
>> + #cooling-cells = <2>;
>> + };
>> + };
>> + };
>> +
>> + - |
>> + remoteproc-cdsp1 {
> No, don't create unnecessary examples. Please read some slides from
> earlier talks so you won't need 10 iterations.
Sure, will update this.
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling
2026-01-29 0:43 ` Dmitry Baryshkov
@ 2026-01-29 12:10 ` Gaurav Kohli
2026-01-29 12:29 ` Dmitry Baryshkov
0 siblings, 1 reply; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-29 12:10 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 1/29/2026 6:13 AM, Dmitry Baryshkov wrote:
> On Tue, Jan 27, 2026 at 09:27:19PM +0530, Gaurav Kohli wrote:
>> Unlike the CPU, the CDSP does not throttle its speed automatically
>> when it reaches high temperatures in Lemans.
>>
>> Set up CDSP cooling by throttling the cdsp when it reaches 105°C.
>>
>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> ---
>> arch/arm64/boot/dts/qcom/lemans.dtsi | 138 ++++++++++++++++++++++++---
>> 1 file changed, 126 insertions(+), 12 deletions(-)
>>
>> diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
>> index 808827b83553..c747dd534caa 100644
>> --- a/arch/arm64/boot/dts/qcom/lemans.dtsi
>> +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
>> @@ -7281,6 +7281,15 @@ compute-cb@11 {
>> };
>> };
>> };
>> +
>> + cooling {
>> + compatible = "qcom,qmi-cooling-cdsp";
>> +
>> + cdsp_tmd0: cdsp-tmd0 {
> This question was already raised. Are there more than one cooling device
> for the DSP? If not, drop the subnodes.
Thanks Dmitry for review.
Yes, Each subsystem may support multiple thermal mitigation devices
through remote TMD service.
So, need to define subnodes.
>> + label = "cdsp_sw";
>> + #cooling-cells = <2>;
>> + };
>> + };
>> };
>>
>> nspb_noc: interconnect@2a0c0000 {
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-01-28 11:28 ` Krzysztof Kozlowski
@ 2026-01-29 12:12 ` Gaurav Kohli
0 siblings, 0 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-29 12:12 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 1/28/2026 4:58 PM, Krzysztof Kozlowski wrote:
> On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
>> The cooling subnode of a remoteproc represents a client of the Thermal
>> Mitigation Device QMI service running on it. Each subnode of the cooling
>> node represents a single control exposed by the service.
> Subject - almost bingo, you hit two out of three which you should not
> use.
>
> A nit, subject: drop second/last, redundant "bindings yaml" and whatever
> else is duplicating. The "dt-bindings" prefix is already stating that
> these are bindings.
> See also:
> https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
thanks for review
Will update this.
>
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling
2026-01-29 12:10 ` Gaurav Kohli
@ 2026-01-29 12:29 ` Dmitry Baryshkov
2026-01-29 13:40 ` Gaurav Kohli
0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Baryshkov @ 2026-01-29 12:29 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Thu, Jan 29, 2026 at 05:40:56PM +0530, Gaurav Kohli wrote:
>
> On 1/29/2026 6:13 AM, Dmitry Baryshkov wrote:
> > On Tue, Jan 27, 2026 at 09:27:19PM +0530, Gaurav Kohli wrote:
> > > Unlike the CPU, the CDSP does not throttle its speed automatically
> > > when it reaches high temperatures in Lemans.
> > >
> > > Set up CDSP cooling by throttling the cdsp when it reaches 105°C.
> > >
> > > Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> > > ---
> > > arch/arm64/boot/dts/qcom/lemans.dtsi | 138 ++++++++++++++++++++++++---
> > > 1 file changed, 126 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
> > > index 808827b83553..c747dd534caa 100644
> > > --- a/arch/arm64/boot/dts/qcom/lemans.dtsi
> > > +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
> > > @@ -7281,6 +7281,15 @@ compute-cb@11 {
> > > };
> > > };
> > > };
> > > +
> > > + cooling {
> > > + compatible = "qcom,qmi-cooling-cdsp";
> > > +
> > > + cdsp_tmd0: cdsp-tmd0 {
> > This question was already raised. Are there more than one cooling device
> > for the DSP? If not, drop the subnodes.
>
>
> Thanks Dmitry for review.
>
> Yes, Each subsystem may support multiple thermal mitigation devices through
> remote TMD service.
May or does?
> So, need to define subnodes.
>
>
> > > + label = "cdsp_sw";
> > > + #cooling-cells = <2>;
> > > + };
> > > + };
> > > };
> > > nspb_noc: interconnect@2a0c0000 {
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling
2026-01-29 12:29 ` Dmitry Baryshkov
@ 2026-01-29 13:40 ` Gaurav Kohli
2026-01-30 1:20 ` Dmitry Baryshkov
0 siblings, 1 reply; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-29 13:40 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 1/29/2026 5:59 PM, Dmitry Baryshkov wrote:
> On Thu, Jan 29, 2026 at 05:40:56PM +0530, Gaurav Kohli wrote:
>> On 1/29/2026 6:13 AM, Dmitry Baryshkov wrote:
>>> On Tue, Jan 27, 2026 at 09:27:19PM +0530, Gaurav Kohli wrote:
>>>> Unlike the CPU, the CDSP does not throttle its speed automatically
>>>> when it reaches high temperatures in Lemans.
>>>>
>>>> Set up CDSP cooling by throttling the cdsp when it reaches 105°C.
>>>>
>>>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>>> ---
>>>> arch/arm64/boot/dts/qcom/lemans.dtsi | 138 ++++++++++++++++++++++++---
>>>> 1 file changed, 126 insertions(+), 12 deletions(-)
>>>>
>>>> diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
>>>> index 808827b83553..c747dd534caa 100644
>>>> --- a/arch/arm64/boot/dts/qcom/lemans.dtsi
>>>> +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
>>>> @@ -7281,6 +7281,15 @@ compute-cb@11 {
>>>> };
>>>> };
>>>> };
>>>> +
>>>> + cooling {
>>>> + compatible = "qcom,qmi-cooling-cdsp";
>>>> +
>>>> + cdsp_tmd0: cdsp-tmd0 {
>>> This question was already raised. Are there more than one cooling device
>>> for the DSP? If not, drop the subnodes.
>>
>> Thanks Dmitry for review.
>>
>> Yes, Each subsystem may support multiple thermal mitigation devices through
>> remote TMD service.
> May or does?
It does support. that's why need child node to trigger different mitigation.
>
>> So, need to define subnodes.
>>
>>
>>>> + label = "cdsp_sw";
>>>> + #cooling-cells = <2>;
>>>> + };
>>>> + };
>>>> };
>>>> nspb_noc: interconnect@2a0c0000 {
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling
2026-01-29 13:40 ` Gaurav Kohli
@ 2026-01-30 1:20 ` Dmitry Baryshkov
0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Baryshkov @ 2026-01-30 1:20 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Thu, Jan 29, 2026 at 07:10:49PM +0530, Gaurav Kohli wrote:
>
> On 1/29/2026 5:59 PM, Dmitry Baryshkov wrote:
> > On Thu, Jan 29, 2026 at 05:40:56PM +0530, Gaurav Kohli wrote:
> > > On 1/29/2026 6:13 AM, Dmitry Baryshkov wrote:
> > > > On Tue, Jan 27, 2026 at 09:27:19PM +0530, Gaurav Kohli wrote:
> > > > > Unlike the CPU, the CDSP does not throttle its speed automatically
> > > > > when it reaches high temperatures in Lemans.
> > > > >
> > > > > Set up CDSP cooling by throttling the cdsp when it reaches 105°C.
> > > > >
> > > > > Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> > > > > ---
> > > > > arch/arm64/boot/dts/qcom/lemans.dtsi | 138 ++++++++++++++++++++++++---
> > > > > 1 file changed, 126 insertions(+), 12 deletions(-)
> > > > >
> > > > > diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
> > > > > index 808827b83553..c747dd534caa 100644
> > > > > --- a/arch/arm64/boot/dts/qcom/lemans.dtsi
> > > > > +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
> > > > > @@ -7281,6 +7281,15 @@ compute-cb@11 {
> > > > > };
> > > > > };
> > > > > };
> > > > > +
> > > > > + cooling {
> > > > > + compatible = "qcom,qmi-cooling-cdsp";
> > > > > +
> > > > > + cdsp_tmd0: cdsp-tmd0 {
> > > > This question was already raised. Are there more than one cooling device
> > > > for the DSP? If not, drop the subnodes.
> > >
> > > Thanks Dmitry for review.
> > >
> > > Yes, Each subsystem may support multiple thermal mitigation devices through
> > > remote TMD service.
> > May or does?
>
>
> It does support. that's why need child node to trigger different mitigation.
Then please inside a DT bindings provide a definitive example, demonstrating
that. Otherwise, reviewers can observe only one cooling device per DSP.
>
>
> >
> > > So, need to define subnodes.
> > >
> > >
> > > > > + label = "cdsp_sw";
> > > > > + #cooling-cells = <2>;
> > > > > + };
> > > > > + };
> > > > > };
> > > > > nspb_noc: interconnect@2a0c0000 {
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-01-27 15:57 ` [PATCH v2 1/8] thermal: Add Remote Proc cooling driver Gaurav Kohli
2026-01-28 11:32 ` Krzysztof Kozlowski
2026-01-28 11:36 ` Krzysztof Kozlowski
@ 2026-01-30 5:39 ` kernel test robot
2026-01-30 6:47 ` kernel test robot
2026-03-06 9:19 ` Daniel Lezcano
4 siblings, 0 replies; 53+ messages in thread
From: kernel test robot @ 2026-01-30 5:39 UTC (permalink / raw)
To: Gaurav Kohli, andersson, mathieu.poirier, robh, krzk+dt, conor+dt,
rui.zhang, lukasz.luba, konradybcio, mani, casey.connolly,
amit.kucheria
Cc: oe-kbuild-all, linux-arm-msm, devicetree, linux-kernel, linux-pm,
gaurav.kohli, manaf.pallikunhi
Hi Gaurav,
kernel test robot noticed the following build warnings:
[auto build test WARNING on next-20260126]
[also build test WARNING on v6.19-rc7]
[cannot apply to robh/for-next rafael-pm/thermal remoteproc/rproc-next linus/master v6.19-rc7 v6.19-rc6 v6.19-rc5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Gaurav-Kohli/thermal-Add-Remote-Proc-cooling-driver/20260128-000753
base: next-20260126
patch link: https://lore.kernel.org/r/20260127155722.2797783-2-gaurav.kohli%40oss.qualcomm.com
patch subject: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20260130/202601301354.3ERTn2SC-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260130/202601301354.3ERTn2SC-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601301354.3ERTn2SC-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/thermal/remoteproc_cooling.c:87:1: warning: no previous prototype for 'remoteproc_cooling_register' [-Wmissing-prototypes]
87 | remoteproc_cooling_register(struct device_node *np,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/thermal/remoteproc_cooling.c:131:6: warning: no previous prototype for 'remoteproc_cooling_unregister' [-Wmissing-prototypes]
131 | void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +/remoteproc_cooling_register +87 drivers/thermal/remoteproc_cooling.c
85
86 struct remoteproc_cdev *
> 87 remoteproc_cooling_register(struct device_node *np,
88 const char *name, const struct remoteproc_cooling_ops *ops,
89 void *devdata)
90 {
91 struct remoteproc_cdev *rproc_cdev;
92 struct thermal_cooling_device *cdev;
93 int ret;
94
95 if (!name || !ops)
96 return ERR_PTR(-EINVAL);
97
98 rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL);
99 if (!rproc_cdev)
100 return ERR_PTR(-ENOMEM);
101
102 rproc_cdev->ops = ops;
103 rproc_cdev->devdata = devdata;
104 mutex_init(&rproc_cdev->lock);
105
106 char *rproc_name __free(kfree) =
107 kasprintf(GFP_KERNEL, REMOTEPROC_PREFIX "%s", name);
108 /* Register with thermal framework */
109 if (np)
110 cdev = thermal_of_cooling_device_register(np, rproc_name, rproc_cdev,
111 &remoteproc_cooling_ops);
112 else
113 cdev = thermal_cooling_device_register(rproc_name, rproc_cdev,
114 &remoteproc_cooling_ops);
115
116 if (IS_ERR(cdev)) {
117 ret = PTR_ERR(cdev);
118 goto free_rproc_cdev;
119 }
120
121 rproc_cdev->cdev = cdev;
122
123 return rproc_cdev;
124
125 free_rproc_cdev:
126 kfree(rproc_cdev);
127 return ERR_PTR(ret);
128 }
129 EXPORT_SYMBOL_GPL(remoteproc_cooling_register);
130
> 131 void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
132 {
133 if (!rproc_cdev)
134 return;
135
136 thermal_cooling_device_unregister(rproc_cdev->cdev);
137 mutex_destroy(&rproc_cdev->lock);
138 kfree(rproc_cdev);
139 }
140 EXPORT_SYMBOL_GPL(remoteproc_cooling_unregister);
141
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-01-28 11:32 ` Krzysztof Kozlowski
@ 2026-01-30 6:39 ` Gaurav Kohli
2026-02-08 10:08 ` Krzysztof Kozlowski
0 siblings, 1 reply; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-30 6:39 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 1/28/2026 5:02 PM, Krzysztof Kozlowski wrote:
> On Tue, Jan 27, 2026 at 09:27:15PM +0530, Gaurav Kohli wrote:
>> Add a new generic driver for thermal cooling devices that control
> There is no driver here. You did not a single driver entry point.
>
>> remote processors (modem, DSP, etc.) through various communication
>> channels.
>>
>> This driver provides an abstraction layer between the thermal
> Please read coding style how much we like abstraction layers.
>
>> subsystem and vendor-specific remote processor communication
>> mechanisms.
>>
>> Advantage of this to avoid duplicating vendor-specific logic
>> in the thermal subsystem and make it easier for different vendors
>> to plug in their own cooling mechanisms via callbacks.
>>
>> Suggested-by: Amit Kucheria <amit.kucheria@oss.qualcomm.com>
>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> ---
>> MAINTAINERS | 7 ++
>> drivers/thermal/Kconfig | 10 ++
>> drivers/thermal/Makefile | 2 +
>> drivers/thermal/remoteproc_cooling.c | 143 +++++++++++++++++++++++++++
>> include/linux/remoteproc_cooling.h | 52 ++++++++++
>> 5 files changed, 214 insertions(+)
>> create mode 100644 drivers/thermal/remoteproc_cooling.c
>> create mode 100644 include/linux/remoteproc_cooling.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 414f44093269..5ebc7819d2cf 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -26169,6 +26169,13 @@ F: drivers/thermal/cpufreq_cooling.c
>> F: drivers/thermal/cpuidle_cooling.c
>> F: include/linux/cpu_cooling.h
>>
>> +THERMAL/REMOTEPROC_COOLING
>> +M: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> +L: linux-pm@vger.kernel.org
>> +S: Supported
>> +F: drivers/thermal/remoteproc_cooling.c
>> +F: include/linux/remoteproc_cooling.h
>> +
>> THERMAL/POWER_ALLOCATOR
> Please beginning of this file. P < R.
>
will update this ordering.
>> M: Lukasz Luba <lukasz.luba@arm.com>
>> L: linux-pm@vger.kernel.org
>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>> index b10080d61860..dfc52eed64de 100644
>> --- a/drivers/thermal/Kconfig
>> +++ b/drivers/thermal/Kconfig
>> @@ -229,6 +229,16 @@ config PCIE_THERMAL
>>
>> If you want this support, you should say Y here.
>>
>> +config REMOTEPROC_THERMAL
>> + tristate "Remote processor cooling support"
>> + help
>> + This implements a generic cooling mechanism for remote processors
>> + (modem, DSP, etc.) that allows vendor-specific implementations to
>> + register thermal cooling devices and provide callbacks for thermal
>> + mitigation.
>> +
>> + If you want this support, you should say Y here.
>> +
>> config THERMAL_EMULATION
>> bool "Thermal emulation mode support"
>> help
>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>> index bb21e7ea7fc6..ae747dde54fe 100644
>> --- a/drivers/thermal/Makefile
>> +++ b/drivers/thermal/Makefile
>> @@ -34,6 +34,8 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
>>
>> thermal_sys-$(CONFIG_PCIE_THERMAL) += pcie_cooling.o
>>
>> +thermal_sys-$(CONFIG_REMOTEPROC_THERMAL) += remoteproc_cooling.o
>> +
>> obj-$(CONFIG_K3_THERMAL) += k3_bandgap.o k3_j72xx_bandgap.o
>> # platform thermal drivers
>> obj-y += broadcom/
>> diff --git a/drivers/thermal/remoteproc_cooling.c b/drivers/thermal/remoteproc_cooling.c
>> new file mode 100644
>> index 000000000000..f958efa691b3
>> --- /dev/null
>> +++ b/drivers/thermal/remoteproc_cooling.c
>> @@ -0,0 +1,143 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Remote Processor Cooling Device
>> + *
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/export.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/of.h>
> Where do you use it?
thanks for pointing this, this won't be used anymore.
We had originally plan to parse dt from here, and included was added for
that earlier approach.
Will fix this.
>> +#include <linux/slab.h>
>> +#include <linux/thermal.h>
>> +
>> +#define REMOTEPROC_PREFIX "rproc_"
>> +
>> +struct remoteproc_cooling_ops {
>> + int (*get_max_level)(void *devdata, unsigned long *level);
>> + int (*get_cur_level)(void *devdata, unsigned long *level);
>> + int (*set_cur_level)(void *devdata, unsigned long level);
>> +};
>> +
>> +/**
>> + * struct remoteproc_cdev - Remote processor cooling device
>> + * @cdev: Thermal cooling device handle
>> + * @ops: Vendor-specific operation callbacks
>> + * @devdata: Private data for vendor implementation
>> + * @np: Device tree node associated with this cooling device
>> + * @lock: Mutex to protect cooling device operations
>> + */
>> +struct remoteproc_cdev {
>> + struct thermal_cooling_device *cdev;
>> + const struct remoteproc_cooling_ops *ops;
>> + void *devdata;
>> + struct mutex lock;
>> +};
>> +
>> +/* Thermal cooling device callbacks */
>> +
>> +static int remoteproc_get_max_state(struct thermal_cooling_device *cdev,
>> + unsigned long *state)
>> +{
>> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
>> + int ret;
>> +
>> + mutex_lock(&rproc_cdev->lock);
>> + ret = rproc_cdev->ops->get_max_level(rproc_cdev->devdata, state);
>> + mutex_unlock(&rproc_cdev->lock);
>> +
>> + return ret;
>> +}
>> +
>> +static int remoteproc_get_cur_state(struct thermal_cooling_device *cdev,
>> + unsigned long *state)
>> +{
>> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
>> + int ret;
>> +
>> + mutex_lock(&rproc_cdev->lock);
>> + ret = rproc_cdev->ops->get_cur_level(rproc_cdev->devdata, state);
>> + mutex_unlock(&rproc_cdev->lock);
>> +
>> + return ret;
>> +}
>> +
>> +static int remoteproc_set_cur_state(struct thermal_cooling_device *cdev,
>> + unsigned long state)
>> +{
>> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
>> + int ret;
>> +
>> + mutex_lock(&rproc_cdev->lock);
>> + ret = rproc_cdev->ops->set_cur_level(rproc_cdev->devdata, state);
>> + mutex_unlock(&rproc_cdev->lock);
>> +
>> + return ret;
>> +}
>> +
>> +static const struct thermal_cooling_device_ops remoteproc_cooling_ops = {
>> + .get_max_state = remoteproc_get_max_state,
>> + .get_cur_state = remoteproc_get_cur_state,
>> + .set_cur_state = remoteproc_set_cur_state,
>> +};
>> +
>> +struct remoteproc_cdev *
>> +remoteproc_cooling_register(struct device_node *np,
>> + const char *name, const struct remoteproc_cooling_ops *ops,
>> + void *devdata)
>> +{
>> + struct remoteproc_cdev *rproc_cdev;
>> + struct thermal_cooling_device *cdev;
>> + int ret;
>> +
>> + if (!name || !ops)
>> + return ERR_PTR(-EINVAL);
>> +
>> + rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL);
>> + if (!rproc_cdev)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + rproc_cdev->ops = ops;
>> + rproc_cdev->devdata = devdata;
>> + mutex_init(&rproc_cdev->lock);
>> +
>> + char *rproc_name __free(kfree) =
>> + kasprintf(GFP_KERNEL, REMOTEPROC_PREFIX "%s", name);
>> + /* Register with thermal framework */
>> + if (np)
>> + cdev = thermal_of_cooling_device_register(np, rproc_name, rproc_cdev,
>> + &remoteproc_cooling_ops);
>> + else
>> + cdev = thermal_cooling_device_register(rproc_name, rproc_cdev,
>> + &remoteproc_cooling_ops);
>> +
>> + if (IS_ERR(cdev)) {
>> + ret = PTR_ERR(cdev);
>> + goto free_rproc_cdev;
>> + }
>> +
>> + rproc_cdev->cdev = cdev;
>> +
>> + return rproc_cdev;
>> +
>> +free_rproc_cdev:
>> + kfree(rproc_cdev);
>> + return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(remoteproc_cooling_register);
>> +
>> +void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
>> +{
>> + if (!rproc_cdev)
>> + return;
>> +
>> + thermal_cooling_device_unregister(rproc_cdev->cdev);
>> + mutex_destroy(&rproc_cdev->lock);
>> + kfree(rproc_cdev);
>> +}
>> +EXPORT_SYMBOL_GPL(remoteproc_cooling_unregister);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_DESCRIPTION("Remote Processor Cooling Device");
> I do not see any driver here, just bunch of exported functions. I do not
> see point in this abstraction/wrapping layer.
>
> Another abstraction layer, NAK.
Thanks Krzysztof for review.
We need this abstraction layer to provide a common interface that
multiple vendors can rely on for
their remote processor based cooling communication. If we use
QMI-cooling driver only, then solution will
be qualcomm specific only or other's can not extend that.
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-01-28 11:36 ` Krzysztof Kozlowski
@ 2026-01-30 6:42 ` Gaurav Kohli
0 siblings, 0 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-30 6:42 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 1/28/2026 5:06 PM, Krzysztof Kozlowski wrote:
> On Tue, Jan 27, 2026 at 09:27:15PM +0530, Gaurav Kohli wrote:
>> + if (!name || !ops)
>> + return ERR_PTR(-EINVAL);
>> +
>> + rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL);
>> + if (!rproc_cdev)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + rproc_cdev->ops = ops;
>> + rproc_cdev->devdata = devdata;
>> + mutex_init(&rproc_cdev->lock);
>> +
>> + char *rproc_name __free(kfree) =
>> + kasprintf(GFP_KERNEL, REMOTEPROC_PREFIX "%s", name);
> Ah, you keep ignoring review and sending the same buggy code.
>
> There is no point to spend any time here. It's also fastest way to get
> your future contributions ignored or NAKed.
Apologies for the miss, will make sure not to miss this in future version.
>
> Well, ignoring review is obviously:
> NAK
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-01-27 15:57 ` [PATCH v2 1/8] thermal: Add Remote Proc cooling driver Gaurav Kohli
` (2 preceding siblings ...)
2026-01-30 5:39 ` kernel test robot
@ 2026-01-30 6:47 ` kernel test robot
2026-03-06 9:19 ` Daniel Lezcano
4 siblings, 0 replies; 53+ messages in thread
From: kernel test robot @ 2026-01-30 6:47 UTC (permalink / raw)
To: Gaurav Kohli, andersson, mathieu.poirier, robh, krzk+dt, conor+dt,
rui.zhang, lukasz.luba, konradybcio, mani, casey.connolly,
amit.kucheria
Cc: llvm, oe-kbuild-all, linux-arm-msm, devicetree, linux-kernel,
linux-pm, gaurav.kohli, manaf.pallikunhi
Hi Gaurav,
kernel test robot noticed the following build warnings:
[auto build test WARNING on next-20260126]
[also build test WARNING on v6.19-rc7]
[cannot apply to robh/for-next rafael-pm/thermal remoteproc/rproc-next linus/master v6.19-rc7 v6.19-rc6 v6.19-rc5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Gaurav-Kohli/thermal-Add-Remote-Proc-cooling-driver/20260128-000753
base: next-20260126
patch link: https://lore.kernel.org/r/20260127155722.2797783-2-gaurav.kohli%40oss.qualcomm.com
patch subject: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
config: riscv-allyesconfig (https://download.01.org/0day-ci/archive/20260130/202601301416.z6Jz4P0R-lkp@intel.com/config)
compiler: clang version 16.0.6 (https://github.com/llvm/llvm-project 7cbf1a2591520c2491aa35339f227775f4d3adf6)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260130/202601301416.z6Jz4P0R-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601301416.z6Jz4P0R-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/thermal/remoteproc_cooling.c:87:1: warning: no previous prototype for function 'remoteproc_cooling_register' [-Wmissing-prototypes]
remoteproc_cooling_register(struct device_node *np,
^
drivers/thermal/remoteproc_cooling.c:86:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
struct remoteproc_cdev *
^
static
>> drivers/thermal/remoteproc_cooling.c:131:6: warning: no previous prototype for function 'remoteproc_cooling_unregister' [-Wmissing-prototypes]
void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
^
drivers/thermal/remoteproc_cooling.c:131:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
^
static
2 warnings generated.
vim +/remoteproc_cooling_register +87 drivers/thermal/remoteproc_cooling.c
85
86 struct remoteproc_cdev *
> 87 remoteproc_cooling_register(struct device_node *np,
88 const char *name, const struct remoteproc_cooling_ops *ops,
89 void *devdata)
90 {
91 struct remoteproc_cdev *rproc_cdev;
92 struct thermal_cooling_device *cdev;
93 int ret;
94
95 if (!name || !ops)
96 return ERR_PTR(-EINVAL);
97
98 rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL);
99 if (!rproc_cdev)
100 return ERR_PTR(-ENOMEM);
101
102 rproc_cdev->ops = ops;
103 rproc_cdev->devdata = devdata;
104 mutex_init(&rproc_cdev->lock);
105
106 char *rproc_name __free(kfree) =
107 kasprintf(GFP_KERNEL, REMOTEPROC_PREFIX "%s", name);
108 /* Register with thermal framework */
109 if (np)
110 cdev = thermal_of_cooling_device_register(np, rproc_name, rproc_cdev,
111 &remoteproc_cooling_ops);
112 else
113 cdev = thermal_cooling_device_register(rproc_name, rproc_cdev,
114 &remoteproc_cooling_ops);
115
116 if (IS_ERR(cdev)) {
117 ret = PTR_ERR(cdev);
118 goto free_rproc_cdev;
119 }
120
121 rproc_cdev->cdev = cdev;
122
123 return rproc_cdev;
124
125 free_rproc_cdev:
126 kfree(rproc_cdev);
127 return ERR_PTR(ret);
128 }
129 EXPORT_SYMBOL_GPL(remoteproc_cooling_register);
130
> 131 void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
132 {
133 if (!rproc_cdev)
134 return;
135
136 thermal_cooling_device_unregister(rproc_cdev->cdev);
137 mutex_destroy(&rproc_cdev->lock);
138 kfree(rproc_cdev);
139 }
140 EXPORT_SYMBOL_GPL(remoteproc_cooling_unregister);
141
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-01-29 0:45 ` Dmitry Baryshkov
@ 2026-01-30 7:08 ` Gaurav Kohli
2026-01-30 9:02 ` Dmitry Baryshkov
0 siblings, 1 reply; 53+ messages in thread
From: Gaurav Kohli @ 2026-01-30 7:08 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 1/29/2026 6:15 AM, Dmitry Baryshkov wrote:
> On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
>> The cooling subnode of a remoteproc represents a client of the Thermal
>> Mitigation Device QMI service running on it. Each subnode of the cooling
>> node represents a single control exposed by the service.
>>
>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> ---
>> .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
>> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
>> 2 files changed, 78 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>> index 68c17bf18987..6a736161d5ae 100644
>> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>> @@ -80,6 +80,12 @@ properties:
>> and devices related to the ADSP.
>> unevaluatedProperties: false
>>
>> + cooling:
>> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
>> + description:
>> + Cooling subnode which represents the cooling devices exposed by the Modem.
>> + unevaluatedProperties: false
>> +
>> required:
>> - clocks
>> - clock-names
>> diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>> new file mode 100644
>> index 000000000000..0dd3bd84c176
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>> @@ -0,0 +1,72 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices
>> +
>> +maintainers:
>> + - Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> +
>> +description:
>> + Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions
>> + across multiple remote subsystems. These devices operate based on junction
>> + temperature sensors (TSENS) associated with thermal zones for each subsystem.
>> +
>> +properties:
>> + compatible:
>> + enum:
>> + - qcom,qmi-cooling-cdsp
>> + - qcom,qmi-cooling-cdsp1
> If I read your schema as you've it written, then ADSP, SLPI and modem
> also can have _CDSP_ cooling device. Seems like an overkill.
>
> Please take care to describe cooling devices for all DSPs at once and
> describe them properly.
>
Thanks for review.
All the target supported in this series are limited to CDSP, so i will
update the binding to describe
only the CDSP.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-01-30 7:08 ` Gaurav Kohli
@ 2026-01-30 9:02 ` Dmitry Baryshkov
0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Baryshkov @ 2026-01-30 9:02 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Fri, Jan 30, 2026 at 12:38:52PM +0530, Gaurav Kohli wrote:
>
> On 1/29/2026 6:15 AM, Dmitry Baryshkov wrote:
> > On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
> > > The cooling subnode of a remoteproc represents a client of the Thermal
> > > Mitigation Device QMI service running on it. Each subnode of the cooling
> > > node represents a single control exposed by the service.
> > >
> > > Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> > > ---
> > > .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
> > > .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
> > > 2 files changed, 78 insertions(+)
> > > create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
> > >
> > > diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> > > index 68c17bf18987..6a736161d5ae 100644
> > > --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> > > +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> > > @@ -80,6 +80,12 @@ properties:
> > > and devices related to the ADSP.
> > > unevaluatedProperties: false
> > > + cooling:
> > > + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
> > > + description:
> > > + Cooling subnode which represents the cooling devices exposed by the Modem.
> > > + unevaluatedProperties: false
> > > +
> > > required:
> > > - clocks
> > > - clock-names
> > > diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
> > > new file mode 100644
> > > index 000000000000..0dd3bd84c176
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
> > > @@ -0,0 +1,72 @@
> > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > > +
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices
> > > +
> > > +maintainers:
> > > + - Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> > > +
> > > +description:
> > > + Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions
> > > + across multiple remote subsystems. These devices operate based on junction
> > > + temperature sensors (TSENS) associated with thermal zones for each subsystem.
> > > +
> > > +properties:
> > > + compatible:
> > > + enum:
> > > + - qcom,qmi-cooling-cdsp
> > > + - qcom,qmi-cooling-cdsp1
> > If I read your schema as you've it written, then ADSP, SLPI and modem
> > also can have _CDSP_ cooling device. Seems like an overkill.
> >
> > Please take care to describe cooling devices for all DSPs at once and
> > describe them properly.
> >
>
> Thanks for review.
>
> All the target supported in this series are limited to CDSP, so i will
> update the binding to describe
>
> only the CDSP.
Why are you limiting yourself to just CDSP? I don't think there is a
significant difference between CDSP and other DSPs from the cooling
point of view.
BTW: could you please also fix your email editor, it inserts extra
unneeded newline characters.
>
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver
2026-01-27 15:57 ` [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver Gaurav Kohli
@ 2026-01-30 9:05 ` kernel test robot
2026-03-06 9:31 ` Daniel Lezcano
2026-03-13 14:15 ` Daniel Lezcano
2 siblings, 0 replies; 53+ messages in thread
From: kernel test robot @ 2026-01-30 9:05 UTC (permalink / raw)
To: Gaurav Kohli, andersson, mathieu.poirier, robh, krzk+dt, conor+dt,
rui.zhang, lukasz.luba, konradybcio, mani, casey.connolly,
amit.kucheria
Cc: oe-kbuild-all, linux-arm-msm, devicetree, linux-kernel, linux-pm,
gaurav.kohli, manaf.pallikunhi
Hi Gaurav,
kernel test robot noticed the following build warnings:
[auto build test WARNING on next-20260126]
[also build test WARNING on v6.19-rc7]
[cannot apply to robh/for-next rafael-pm/thermal remoteproc/rproc-next linus/master v6.19-rc7 v6.19-rc6 v6.19-rc5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Gaurav-Kohli/thermal-Add-Remote-Proc-cooling-driver/20260128-000753
base: next-20260126
patch link: https://lore.kernel.org/r/20260127155722.2797783-5-gaurav.kohli%40oss.qualcomm.com
patch subject: [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver
config: arm-allyesconfig (https://download.01.org/0day-ci/archive/20260130/202601301640.GVrYk2iB-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260130/202601301640.GVrYk2iB-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601301640.GVrYk2iB-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/soc/qcom/qmi-cooling.c: In function 'qmi_tmd_alloc_cdevs':
>> drivers/soc/qcom/qmi-cooling.c:377:29: warning: unused variable 'subnode' [-Wunused-variable]
377 | struct device_node *subnode;
| ^~~~~~~
In file included from drivers/soc/qcom/qmi-cooling.c:24:
drivers/soc/qcom/qmi-cooling.h: At top level:
>> drivers/soc/qcom/qmi-cooling.h:402:35: warning: 'tmd_mitigation_level_report_ind_msg_v01_ei' defined but not used [-Wunused-const-variable=]
402 | static const struct qmi_elem_info tmd_mitigation_level_report_ind_msg_v01_ei[] = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/soc/qcom/qmi-cooling.h:377:9: warning: 'tmd_deregister_notification_mitigation_level_resp_msg_v01_ei' defined but not used [-Wunused-const-variable=]
377 | tmd_deregister_notification_mitigation_level_resp_msg_v01_ei[] = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/soc/qcom/qmi-cooling.h:352:9: warning: 'tmd_deregister_notification_mitigation_level_req_msg_v01_ei' defined but not used [-Wunused-const-variable=]
352 | tmd_deregister_notification_mitigation_level_req_msg_v01_ei[] = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/soc/qcom/qmi-cooling.h:327:9: warning: 'tmd_register_notification_mitigation_level_resp_msg_v01_ei' defined but not used [-Wunused-const-variable=]
327 | tmd_register_notification_mitigation_level_resp_msg_v01_ei[] = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/soc/qcom/qmi-cooling.h:302:9: warning: 'tmd_register_notification_mitigation_level_req_msg_v01_ei' defined but not used [-Wunused-const-variable=]
302 | tmd_register_notification_mitigation_level_req_msg_v01_ei[] = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/soc/qcom/qmi-cooling.h:243:35: warning: 'tmd_get_mitigation_level_resp_msg_ei' defined but not used [-Wunused-const-variable=]
243 | static const struct qmi_elem_info tmd_get_mitigation_level_resp_msg_ei[] = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/soc/qcom/qmi-cooling.h:216:35: warning: 'tmd_get_mitigation_level_req_msg_v01_ei' defined but not used [-Wunused-const-variable=]
216 | static const struct qmi_elem_info tmd_get_mitigation_level_req_msg_v01_ei[] = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
>> Warning: drivers/soc/qcom/qmi-cooling.c:72 struct member 'node' not described in 'qmi_tmd'
>> Warning: drivers/soc/qcom/qmi-cooling.c:82 expecting prototype for struct qmi_instance_id. Prototype was for struct qmi_instance_data instead
--
>> Warning: drivers/soc/qcom/qmi-cooling.c:72 struct member 'node' not described in 'qmi_tmd'
vim +/subnode +377 drivers/soc/qcom/qmi-cooling.c
371
372 /* Parse the controls and allocate a qmi_tmd for each of them */
373 static int qmi_tmd_alloc_cdevs(struct qmi_tmd_client *client)
374 {
375 struct device *dev = client->dev;
376 struct device_node *node = dev->of_node;
> 377 struct device_node *subnode;
378 struct qmi_tmd *tmd;
379 int ret;
380
381 for_each_available_child_of_node_scoped(node, subnode) {
382 const char *name;
383
384 tmd = devm_kzalloc(dev, sizeof(*tmd), GFP_KERNEL);
385 if (!tmd)
386 return dev_err_probe(client->dev, -ENOMEM,
387 "Couldn't allocate tmd\n");
388
389 tmd->type = devm_kasprintf(client->dev, GFP_KERNEL, "%s",
390 subnode->name);
391 if (!tmd->type)
392 return dev_err_probe(dev, -ENOMEM,
393 "Couldn't allocate cooling device name\n");
394
395 if (of_property_read_string(subnode, "label", &name))
396 return dev_err_probe(client->dev, -EINVAL,
397 "Failed to parse dev name for %s\n",
398 subnode->name);
399
400 ret = strscpy(tmd->qmi_name, name,
401 QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
402 if (ret == -E2BIG)
403 return dev_err_probe(dev, -EINVAL, "TMD label %s is too long\n",
404 name);
405
406 tmd->client = client;
407 tmd->np = subnode;
408 tmd->cur_state = 0;
409 list_add(&tmd->node, &client->cdev_list);
410 }
411
412 if (list_empty(&client->cdev_list))
413 return dev_err_probe(client->dev, -EINVAL,
414 "No cooling devices specified for client %s (%#x)\n",
415 client->name, client->id);
416
417 return 0;
418 }
419
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-01-29 12:06 ` Gaurav Kohli
@ 2026-02-08 10:06 ` Krzysztof Kozlowski
2026-02-11 7:37 ` Gaurav Kohli
0 siblings, 1 reply; 53+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-08 10:06 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 29/01/2026 13:06, Gaurav Kohli wrote:
>
> On 1/28/2026 4:57 PM, Krzysztof Kozlowski wrote:
>> On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
>>> The cooling subnode of a remoteproc represents a client of the Thermal
>>> Mitigation Device QMI service running on it. Each subnode of the cooling
>>> node represents a single control exposed by the service.
>>>
>>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>> ---
>>> .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
>>> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
>>> 2 files changed, 78 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>> index 68c17bf18987..6a736161d5ae 100644
>>> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>> @@ -80,6 +80,12 @@ properties:
>>> and devices related to the ADSP.
>>> unevaluatedProperties: false
>>>
>>> + cooling:
>>> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
>>> + description:
>>> + Cooling subnode which represents the cooling devices exposed by the Modem.
>> I do not see the reason why you need 3 (!!!) children here. Everything
>> should be folded here.
>
>
> Thanks Krzysztof for review.
>
> Each subsystem may support multiple thermal mitigation devices through
> remote TMD service.
>
> Because of this multiplicity, introduced separate binding file.
This explains nothing. Subsystem does not matter for the binding. My
comment stays.
>
>>> + unevaluatedProperties: false
>>> +
>>> required:
>>> - clocks
>>> - clock-names
>>> diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>> new file mode 100644
>>> index 000000000000..0dd3bd84c176
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>> @@ -0,0 +1,72 @@
>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>> +
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices
>>> +
>>> +maintainers:
>>> + - Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>> +
>>> +description:
>>> + Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions
>>> + across multiple remote subsystems. These devices operate based on junction
>>> + temperature sensors (TSENS) associated with thermal zones for each subsystem.
>>> +
>>> +properties:
>>> + compatible:
>>> + enum:
>>> + - qcom,qmi-cooling-cdsp
>>> + - qcom,qmi-cooling-cdsp1
>> What are the differences between them?
>
>
> Some SOcs support multiple CDSP/NSP instances. Each instance requires
> it's own
>
> compatible string to distinguish.
Why? What are the differences?
I will not ask third time, but just respond with NAK.
>
>
>> Why these are not SoC specific?
>
>
> They are not soc specific because the qmi thermal mitigation interface
> exposed by CDSP is architecturally
>
> identical across multiple SOCS.
I have doubts on that but anyway if you want exception from standard
compatible rules you must come with arguments in terms of hardware and
firmware. Above is not enough. Everyone claims that.
>
>
>>> +
>>> +patternProperties:
>>> + "cdsp-tmd[0-9]*$":
>>> + type: object
>> No, you do not need childnode. See writing bindings (covers exactly this
>> case).
>
>
> Each subsystem may support multiple thermal mitigation devices through
> remote TMD service. So
>
> need childnode to distinguish for different mitigations.
NAK
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-01-30 6:39 ` Gaurav Kohli
@ 2026-02-08 10:08 ` Krzysztof Kozlowski
0 siblings, 0 replies; 53+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-08 10:08 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 30/01/2026 07:39, Gaurav Kohli wrote:
>>> +
>>> +MODULE_LICENSE("GPL");
>>> +MODULE_DESCRIPTION("Remote Processor Cooling Device");
>> I do not see any driver here, just bunch of exported functions. I do not
>> see point in this abstraction/wrapping layer.
>>
>> Another abstraction layer, NAK.
>
>
> Thanks Krzysztof for review.
>
> We need this abstraction layer to provide a common interface that
> multiple vendors can rely on for
Why do you keep inserting blank lines inside sentences?
>
> their remote processor based cooling communication. If we use
> QMI-cooling driver only, then solution will
So you just ignored my comment and repeat the same mantra. You don't
even use any arguments, just push own position. This will get you nowhere.
Read the comment again.
NAK
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-02-08 10:06 ` Krzysztof Kozlowski
@ 2026-02-11 7:37 ` Gaurav Kohli
2026-02-11 8:13 ` Krzysztof Kozlowski
0 siblings, 1 reply; 53+ messages in thread
From: Gaurav Kohli @ 2026-02-11 7:37 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 2/8/2026 3:36 PM, Krzysztof Kozlowski wrote:
> On 29/01/2026 13:06, Gaurav Kohli wrote:
>>
>> On 1/28/2026 4:57 PM, Krzysztof Kozlowski wrote:
>>> On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
>>>> The cooling subnode of a remoteproc represents a client of the Thermal
>>>> Mitigation Device QMI service running on it. Each subnode of the cooling
>>>> node represents a single control exposed by the service.
>>>>
>>>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>>> ---
>>>> .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
>>>> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
>>>> 2 files changed, 78 insertions(+)
>>>> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>> index 68c17bf18987..6a736161d5ae 100644
>>>> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>> @@ -80,6 +80,12 @@ properties:
>>>> and devices related to the ADSP.
>>>> unevaluatedProperties: false
>>>>
>>>> + cooling:
>>>> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
>>>> + description:
>>>> + Cooling subnode which represents the cooling devices exposed by the Modem.
>>> I do not see the reason why you need 3 (!!!) children here. Everything
>>> should be folded here.
>>
>>
>> Thanks Krzysztof for review.
>>
>> Each subsystem may support multiple thermal mitigation devices through
>> remote TMD service.
>>
>> Because of this multiplicity, introduced separate binding file.
>
> This explains nothing. Subsystem does not matter for the binding. My
> comment stays.
>
thanks for this suggestion, we will use qcom,pas-common.yaml to define
bindings and avoid creating new file.
>>
>>>> + unevaluatedProperties: false
>>>> +
>>>> required:
>>>> - clocks
>>>> - clock-names
>>>> diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>> new file mode 100644
>>>> index 000000000000..0dd3bd84c176
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>> @@ -0,0 +1,72 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>>> +
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices
>>>> +
>>>> +maintainers:
>>>> + - Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>>> +
>>>> +description:
>>>> + Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions
>>>> + across multiple remote subsystems. These devices operate based on junction
>>>> + temperature sensors (TSENS) associated with thermal zones for each subsystem.
>>>> +
>>>> +properties:
>>>> + compatible:
>>>> + enum:
>>>> + - qcom,qmi-cooling-cdsp
>>>> + - qcom,qmi-cooling-cdsp1
>>> What are the differences between them?
>>
>>
>> Some SOcs support multiple CDSP/NSP instances. Each instance requires
>> it's own
>>
>> compatible string to distinguish.
>
> Why? What are the differences?
>
> I will not ask third time, but just respond with NAK.
>
For Leman's, we have multiple NSP subsystem to support compute and each
instance has it's own firmware and separate hardware like below for cdsp
Below data is from lemans.dtsi for cdsp subsystem:
-> remoteproc@26300000 {
-> remoteproc@2a300000 {
That's why, we have introduced different compatible to distinguish
multiple instance, but we can also solve this with single compatible
with new dt property for each subsystem instance id. Please let us know
if you are fine, we can use that.
>>
>>
>>> Why these are not SoC specific?
>>
>>
>> They are not soc specific because the qmi thermal mitigation interface
>> exposed by CDSP is architecturally
>>
>> identical across multiple SOCS.
>
> I have doubts on that but anyway if you want exception from standard
> compatible rules you must come with arguments in terms of hardware and
> firmware. Above is not enough. Everyone claims that.
>
>>
>>
>>>> +
>>>> +patternProperties:
>>>> + "cdsp-tmd[0-9]*$":
>>>> + type: object
>>> No, you do not need childnode. See writing bindings (covers exactly this
>>> case).
>>
>>
>> Each subsystem may support multiple thermal mitigation devices through
>> remote TMD service. So
>>
>> need childnode to distinguish for different mitigations.
>
> NAK
>
As each subsystem supports multiple cooling devices, So introduced
multiple child nodes for cooling binding in thermal zone.
>
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-02-11 7:37 ` Gaurav Kohli
@ 2026-02-11 8:13 ` Krzysztof Kozlowski
2026-02-20 7:29 ` Gaurav Kohli
0 siblings, 1 reply; 53+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-11 8:13 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 11/02/2026 08:37, Gaurav Kohli wrote:
>
>
> On 2/8/2026 3:36 PM, Krzysztof Kozlowski wrote:
>> On 29/01/2026 13:06, Gaurav Kohli wrote:
>>>
>>> On 1/28/2026 4:57 PM, Krzysztof Kozlowski wrote:
>>>> On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
>>>>> The cooling subnode of a remoteproc represents a client of the Thermal
>>>>> Mitigation Device QMI service running on it. Each subnode of the cooling
>>>>> node represents a single control exposed by the service.
>>>>>
>>>>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>>>> ---
>>>>> .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
>>>>> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
>>>>> 2 files changed, 78 insertions(+)
>>>>> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>> index 68c17bf18987..6a736161d5ae 100644
>>>>> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>> @@ -80,6 +80,12 @@ properties:
>>>>> and devices related to the ADSP.
>>>>> unevaluatedProperties: false
>>>>>
>>>>> + cooling:
>>>>> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
>>>>> + description:
>>>>> + Cooling subnode which represents the cooling devices exposed by the Modem.
>>>> I do not see the reason why you need 3 (!!!) children here. Everything
>>>> should be folded here.
>>>
>>>
>>> Thanks Krzysztof for review.
>>>
>>> Each subsystem may support multiple thermal mitigation devices through
>>> remote TMD service.
>>>
>>> Because of this multiplicity, introduced separate binding file.
>>
>> This explains nothing. Subsystem does not matter for the binding. My
>> comment stays.
>>
>
> thanks for this suggestion, we will use qcom,pas-common.yaml to define
> bindings and avoid creating new file.
I asked not to create any children nodes.
>
>>>
>>>>> + unevaluatedProperties: false
>>>>> +
>>>>> required:
>>>>> - clocks
>>>>> - clock-names
>>>>> diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>>> new file mode 100644
>>>>> index 000000000000..0dd3bd84c176
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>>> @@ -0,0 +1,72 @@
>>>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>>>> +
>>>>> +%YAML 1.2
>>>>> +---
>>>>> +$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml#
>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>> +
>>>>> +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices
>>>>> +
>>>>> +maintainers:
>>>>> + - Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>>>> +
>>>>> +description:
>>>>> + Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions
>>>>> + across multiple remote subsystems. These devices operate based on junction
>>>>> + temperature sensors (TSENS) associated with thermal zones for each subsystem.
>>>>> +
>>>>> +properties:
>>>>> + compatible:
>>>>> + enum:
>>>>> + - qcom,qmi-cooling-cdsp
>>>>> + - qcom,qmi-cooling-cdsp1
>>>> What are the differences between them?
>>>
>>>
>>> Some SOcs support multiple CDSP/NSP instances. Each instance requires
>>> it's own
>>>
>>> compatible string to distinguish.
>>
>> Why? What are the differences?
>>
>> I will not ask third time, but just respond with NAK.
>>
>
> For Leman's, we have multiple NSP subsystem to support compute and each
> instance has it's own firmware and separate hardware like below for cdsp
>
> Below data is from lemans.dtsi for cdsp subsystem:
> -> remoteproc@26300000 {
> -> remoteproc@2a300000 {
>
> That's why, we have introduced different compatible to distinguish
> multiple instance, but we can also solve this with single compatible
You did not answer the question what are the differences, so I am not
going to ask third time. NAK.
> with new dt property for each subsystem instance id. Please let us know
Instance IDs are not allowed, either. Please read writing bindings doc
or slides from talks.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-02-11 8:13 ` Krzysztof Kozlowski
@ 2026-02-20 7:29 ` Gaurav Kohli
2026-02-20 7:44 ` Krzysztof Kozlowski
0 siblings, 1 reply; 53+ messages in thread
From: Gaurav Kohli @ 2026-02-20 7:29 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 2/11/2026 1:43 PM, Krzysztof Kozlowski wrote:
> On 11/02/2026 08:37, Gaurav Kohli wrote:
>>
>>
>> On 2/8/2026 3:36 PM, Krzysztof Kozlowski wrote:
>>> On 29/01/2026 13:06, Gaurav Kohli wrote:
>>>>
>>>> On 1/28/2026 4:57 PM, Krzysztof Kozlowski wrote:
>>>>> On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
>>>>>> The cooling subnode of a remoteproc represents a client of the Thermal
>>>>>> Mitigation Device QMI service running on it. Each subnode of the cooling
>>>>>> node represents a single control exposed by the service.
>>>>>>
>>>>>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>>>>> ---
>>>>>> .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
>>>>>> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
>>>>>> 2 files changed, 78 insertions(+)
>>>>>> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>>> index 68c17bf18987..6a736161d5ae 100644
>>>>>> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>>> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>>> @@ -80,6 +80,12 @@ properties:
>>>>>> and devices related to the ADSP.
>>>>>> unevaluatedProperties: false
>>>>>>
>>>>>> + cooling:
>>>>>> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
>>>>>> + description:
>>>>>> + Cooling subnode which represents the cooling devices exposed by the Modem.
>>>>> I do not see the reason why you need 3 (!!!) children here. Everything
>>>>> should be folded here.
>>>>
>>>>
>>>> Thanks Krzysztof for review.
>>>>
>>>> Each subsystem may support multiple thermal mitigation devices through
>>>> remote TMD service.
>>>>
>>>> Because of this multiplicity, introduced separate binding file.
>>>
>>> This explains nothing. Subsystem does not matter for the binding. My
>>> comment stays.
>>>
>>
>> thanks for this suggestion, we will use qcom,pas-common.yaml to define
>> bindings and avoid creating new file.
>
> I asked not to create any children nodes.
>
We have multiple cores within a subsystem(cdsp) and each core has its
own independent DCVS. And also we have dedicated TSENS sensor placed on
each core within the subsystem.
As a result, each core requires its own cooling device, which must be
linked to its TSENS thermal zone. Because of this, we introduced
multiple child nodes—one for each cooling device.
------ ----------------------------------------
| | -------> | cdsp |
| | | |
| | | HVX compute(tsens1) HMX NPU(tsens2) | |
| | ----------------------------------------
| SOC |
| |
| |
| | -----------------------------------------
| | -------> | Modem |
| | | |
------ | (modem Lte) (modem nr) (modem pa) |
-----------------------------------------
Unfortunately, we don't have target in this series which supports
multiple cores within the subsystem, but there are targets which
supports multiple cores. We will post patches for those once upstream
dependency aligns. If it make sense, we will add superset node examples
in dt bindings for future targets also.
We can use another approach, we can take this cooling node out of
remoteproc node and use soc node to define child node. This has it's own
drawback, here qmi-tmd will probe and wait for remoteproc subsystem to
be up. For cases where remoteproc won't be up, qmi-tmd will still do
probe and sits indefinitely.
So we need your guidance here.
>>
>>>>
>>>>>> + unevaluatedProperties: false
>>>>>> +
>>>>>> required:
>>>>>> - clocks
>>>>>> - clock-names
>>>>>> diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>>>> new file mode 100644
>>>>>> index 000000000000..0dd3bd84c176
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>>>> @@ -0,0 +1,72 @@
>>>>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>>>>> +
>>>>>> +%YAML 1.2
>>>>>> +---
>>>>>> +$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml#
>>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>>> +
>>>>>> +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices
>>>>>> +
>>>>>> +maintainers:
>>>>>> + - Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>>>>> +
>>>>>> +description:
>>>>>> + Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions
>>>>>> + across multiple remote subsystems. These devices operate based on junction
>>>>>> + temperature sensors (TSENS) associated with thermal zones for each subsystem.
>>>>>> +
>>>>>> +properties:
>>>>>> + compatible:
>>>>>> + enum:
>>>>>> + - qcom,qmi-cooling-cdsp
>>>>>> + - qcom,qmi-cooling-cdsp1
>>>>> What are the differences between them?
>>>>
>>>>
>>>> Some SOcs support multiple CDSP/NSP instances. Each instance requires
>>>> it's own
>>>>
>>>> compatible string to distinguish.
>>>
>>> Why? What are the differences?
>>>
>>> I will not ask third time, but just respond with NAK.
>>>
>>
>> For Leman's, we have multiple NSP subsystem to support compute and each
>> instance has it's own firmware and separate hardware like below for cdsp
>>
>> Below data is from lemans.dtsi for cdsp subsystem:
>> -> remoteproc@26300000 {
>> -> remoteproc@2a300000 {
>>
>> That's why, we have introduced different compatible to distinguish
>> multiple instance, but we can also solve this with single compatible
>
> You did not answer the question what are the differences, so I am not
> going to ask third time. NAK.
For exact hw diff, we are checking internally and will update for this.
Right now we only know that we have two cdsp subsystem in Leman's and
each has it's own firmware/cores.
------ ----------------------------------------
| | -------> | cdsp0 |
| | | |
| | | HVX compute(tsens1) HMX NPU(tsens2) |
| | ----------------------------------------
| SOC |
| |
| |
| | -----------------------------------------
| | -------> | cdsp1 |
| | | |
------ | tsesn3 tsens4 |
-----------------------------------------
>
>> with new dt property for each subsystem instance id. Please let us know
>
> Instance IDs are not allowed, either. Please read writing bindings doc
> or slides from talks.
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-02-20 7:29 ` Gaurav Kohli
@ 2026-02-20 7:44 ` Krzysztof Kozlowski
2026-02-24 12:09 ` Gaurav Kohli
0 siblings, 1 reply; 53+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-20 7:44 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 20/02/2026 08:29, Gaurav Kohli wrote:
>
>
> On 2/11/2026 1:43 PM, Krzysztof Kozlowski wrote:
>> On 11/02/2026 08:37, Gaurav Kohli wrote:
>>>
>>>
>>> On 2/8/2026 3:36 PM, Krzysztof Kozlowski wrote:
>>>> On 29/01/2026 13:06, Gaurav Kohli wrote:
>>>>>
>>>>> On 1/28/2026 4:57 PM, Krzysztof Kozlowski wrote:
>>>>>> On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
>>>>>>> The cooling subnode of a remoteproc represents a client of the Thermal
>>>>>>> Mitigation Device QMI service running on it. Each subnode of the cooling
>>>>>>> node represents a single control exposed by the service.
>>>>>>>
>>>>>>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>>>>>> ---
>>>>>>> .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
>>>>>>> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
>>>>>>> 2 files changed, 78 insertions(+)
>>>>>>> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>>>>>
>>>>>>> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>>>> index 68c17bf18987..6a736161d5ae 100644
>>>>>>> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>>>> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>>>> @@ -80,6 +80,12 @@ properties:
>>>>>>> and devices related to the ADSP.
>>>>>>> unevaluatedProperties: false
>>>>>>>
>>>>>>> + cooling:
>>>>>>> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
>>>>>>> + description:
>>>>>>> + Cooling subnode which represents the cooling devices exposed by the Modem.
>>>>>> I do not see the reason why you need 3 (!!!) children here. Everything
>>>>>> should be folded here.
>>>>>
>>>>>
>>>>> Thanks Krzysztof for review.
>>>>>
>>>>> Each subsystem may support multiple thermal mitigation devices through
>>>>> remote TMD service.
>>>>>
>>>>> Because of this multiplicity, introduced separate binding file.
>>>>
>>>> This explains nothing. Subsystem does not matter for the binding. My
>>>> comment stays.
>>>>
>>>
>>> thanks for this suggestion, we will use qcom,pas-common.yaml to define
>>> bindings and avoid creating new file.
>>
>> I asked not to create any children nodes.
>>
>
> We have multiple cores within a subsystem(cdsp) and each core has its
> own independent DCVS. And also we have dedicated TSENS sensor placed on
> each core within the subsystem.
Your own example in this patch had only one device, so how do you
imagine to convince us with incomplete or half baked code?
> As a result, each core requires its own cooling device, which must be
> linked to its TSENS thermal zone. Because of this, we introduced
> multiple child nodes—one for each cooling device.
So you have one device with cooling cells=1+2, no?
>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-02-20 7:44 ` Krzysztof Kozlowski
@ 2026-02-24 12:09 ` Gaurav Kohli
2026-02-24 12:17 ` Krzysztof Kozlowski
2026-02-24 12:52 ` Dmitry Baryshkov
0 siblings, 2 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-02-24 12:09 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 2/20/2026 1:14 PM, Krzysztof Kozlowski wrote:
> On 20/02/2026 08:29, Gaurav Kohli wrote:
>>
>>
>> On 2/11/2026 1:43 PM, Krzysztof Kozlowski wrote:
>>> On 11/02/2026 08:37, Gaurav Kohli wrote:
>>>>
>>>>
>>>> On 2/8/2026 3:36 PM, Krzysztof Kozlowski wrote:
>>>>> On 29/01/2026 13:06, Gaurav Kohli wrote:
>>>>>>
>>>>>> On 1/28/2026 4:57 PM, Krzysztof Kozlowski wrote:
>>>>>>> On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
>>>>>>>> The cooling subnode of a remoteproc represents a client of the Thermal
>>>>>>>> Mitigation Device QMI service running on it. Each subnode of the cooling
>>>>>>>> node represents a single control exposed by the service.
>>>>>>>>
>>>>>>>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>>>>>>>> ---
>>>>>>>> .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
>>>>>>>> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
>>>>>>>> 2 files changed, 78 insertions(+)
>>>>>>>> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
>>>>>>>>
>>>>>>>> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>>>>> index 68c17bf18987..6a736161d5ae 100644
>>>>>>>> --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>>>>> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
>>>>>>>> @@ -80,6 +80,12 @@ properties:
>>>>>>>> and devices related to the ADSP.
>>>>>>>> unevaluatedProperties: false
>>>>>>>>
>>>>>>>> + cooling:
>>>>>>>> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
>>>>>>>> + description:
>>>>>>>> + Cooling subnode which represents the cooling devices exposed by the Modem.
>>>>>>> I do not see the reason why you need 3 (!!!) children here. Everything
>>>>>>> should be folded here.
>>>>>>
>>>>>>
>>>>>> Thanks Krzysztof for review.
>>>>>>
>>>>>> Each subsystem may support multiple thermal mitigation devices through
>>>>>> remote TMD service.
>>>>>>
>>>>>> Because of this multiplicity, introduced separate binding file.
>>>>>
>>>>> This explains nothing. Subsystem does not matter for the binding. My
>>>>> comment stays.
>>>>>
>>>>
>>>> thanks for this suggestion, we will use qcom,pas-common.yaml to define
>>>> bindings and avoid creating new file.
>>>
>>> I asked not to create any children nodes.
>>>
>>
>> We have multiple cores within a subsystem(cdsp) and each core has its
>> own independent DCVS. And also we have dedicated TSENS sensor placed on
>> each core within the subsystem.
>
> Your own example in this patch had only one device, so how do you
> imagine to convince us with incomplete or half baked code?
>
Target of this series supports one tmd per remoteproc, due to which we
have not posted examples of multiple tmd. Can i use dt binding example
sections to describe all tmd's per remoteproc?
>> As a result, each core requires its own cooling device, which must be
>> linked to its TSENS thermal zone. Because of this, we introduced
>> multiple child nodes—one for each cooling device.
>
> So you have one device with cooling cells=1+2, no?
>
This will be a bigger framework change which is not supported, i can see
other drivers are also using something like this multiple cooling device
under device node, below are few examples :
->Documentation/devicetree/bindings/hwmon/microchip,emc2305.yaml
In this multiple fan child nodes are present.
-> Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.yaml
In this multiple child nodes are present, like heavy and light.
Please suggest if our current approach is fine or you want us to
implement in some other way.
>>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-02-24 12:09 ` Gaurav Kohli
@ 2026-02-24 12:17 ` Krzysztof Kozlowski
2026-03-16 19:57 ` Daniel Lezcano
2026-02-24 12:52 ` Dmitry Baryshkov
1 sibling, 1 reply; 53+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-24 12:17 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 24/02/2026 13:09, Gaurav Kohli wrote:
>>>>>>>>> + cooling:
>>>>>>>>> + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
>>>>>>>>> + description:
>>>>>>>>> + Cooling subnode which represents the cooling devices exposed by the Modem.
>>>>>>>> I do not see the reason why you need 3 (!!!) children here. Everything
>>>>>>>> should be folded here.
>>>>>>>
>>>>>>>
>>>>>>> Thanks Krzysztof for review.
>>>>>>>
>>>>>>> Each subsystem may support multiple thermal mitigation devices through
>>>>>>> remote TMD service.
>>>>>>>
>>>>>>> Because of this multiplicity, introduced separate binding file.
>>>>>>
>>>>>> This explains nothing. Subsystem does not matter for the binding. My
>>>>>> comment stays.
>>>>>>
>>>>>
>>>>> thanks for this suggestion, we will use qcom,pas-common.yaml to define
>>>>> bindings and avoid creating new file.
>>>>
>>>> I asked not to create any children nodes.
>>>>
>>>
>>> We have multiple cores within a subsystem(cdsp) and each core has its
>>> own independent DCVS. And also we have dedicated TSENS sensor placed on
>>> each core within the subsystem.
>>
>> Your own example in this patch had only one device, so how do you
>> imagine to convince us with incomplete or half baked code?
>>
>
> Target of this series supports one tmd per remoteproc, due to which we
> have not posted examples of multiple tmd. Can i use dt binding example
> sections to describe all tmd's per remoteproc?
I don't know but you sent a patch with such rationale. If you post
incomplete patch as rationale, why would we review it in your favor? If
you cannot post complete patch, then what is missing or wrong?
>
>>> As a result, each core requires its own cooling device, which must be
>>> linked to its TSENS thermal zone. Because of this, we introduced
>>> multiple child nodes—one for each cooling device.
>>
>> So you have one device with cooling cells=1+2, no?
>>
>
> This will be a bigger framework change which is not supported, i can see
I don't think that changing open source frameworks is "not supported". I
am pretty sure that changing is not only supported, but actually desired.
> other drivers are also using something like this multiple cooling device
> under device node, below are few examples :
>
> ->Documentation/devicetree/bindings/hwmon/microchip,emc2305.yaml
> In this multiple fan child nodes are present.
So you have a fan there?
>
> -> Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.yaml
> In this multiple child nodes are present, like heavy and light.
This is absolute antipattern, just look at the properties there. Don't
bring ever old legacy, junk as argument that you can do the same junk.
No, you can't. Just like past bugs are not valid reason to add similar
bugs in the future.
Standard writing binding rules apply here - do you have resources there?
No. Then you cannot have children. You should fold the nodes into the
parent and use cooling-cells=3 (or whatever other number makes sense).
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-02-24 12:09 ` Gaurav Kohli
2026-02-24 12:17 ` Krzysztof Kozlowski
@ 2026-02-24 12:52 ` Dmitry Baryshkov
1 sibling, 0 replies; 53+ messages in thread
From: Dmitry Baryshkov @ 2026-02-24 12:52 UTC (permalink / raw)
To: Gaurav Kohli
Cc: Krzysztof Kozlowski, andersson, mathieu.poirier, robh, krzk+dt,
conor+dt, rui.zhang, lukasz.luba, konradybcio, mani,
casey.connolly, amit.kucheria, linux-arm-msm, devicetree,
linux-kernel, linux-pm, manaf.pallikunhi
On Tue, Feb 24, 2026 at 05:39:42PM +0530, Gaurav Kohli wrote:
>
>
> On 2/20/2026 1:14 PM, Krzysztof Kozlowski wrote:
> > On 20/02/2026 08:29, Gaurav Kohli wrote:
> > >
> > >
> > > On 2/11/2026 1:43 PM, Krzysztof Kozlowski wrote:
> > > > On 11/02/2026 08:37, Gaurav Kohli wrote:
> > > > >
> > > > >
> > > > > On 2/8/2026 3:36 PM, Krzysztof Kozlowski wrote:
> > > > > > On 29/01/2026 13:06, Gaurav Kohli wrote:
> > > > > > >
> > > > > > > On 1/28/2026 4:57 PM, Krzysztof Kozlowski wrote:
> > > > > > > > On Tue, Jan 27, 2026 at 09:27:16PM +0530, Gaurav Kohli wrote:
> > > > > > > > > The cooling subnode of a remoteproc represents a client of the Thermal
> > > > > > > > > Mitigation Device QMI service running on it. Each subnode of the cooling
> > > > > > > > > node represents a single control exposed by the service.
> > > > > > > > >
> > > > > > > > > Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> > > > > > > > > ---
> > > > > > > > > .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++
> > > > > > > > > .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++++++++++++++++++
> > > > > > > > > 2 files changed, 78 insertions(+)
> > > > > > > > > create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
> > > > > > > > >
> > > > > > > > > diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> > > > > > > > > index 68c17bf18987..6a736161d5ae 100644
> > > > > > > > > --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> > > > > > > > > +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
> > > > > > > > > @@ -80,6 +80,12 @@ properties:
> > > > > > > > > and devices related to the ADSP.
> > > > > > > > > unevaluatedProperties: false
> > > > > > > > > + cooling:
> > > > > > > > > + $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
> > > > > > > > > + description:
> > > > > > > > > + Cooling subnode which represents the cooling devices exposed by the Modem.
> > > > > > > > I do not see the reason why you need 3 (!!!) children here. Everything
> > > > > > > > should be folded here.
> > > > > > >
> > > > > > >
> > > > > > > Thanks Krzysztof for review.
> > > > > > >
> > > > > > > Each subsystem may support multiple thermal mitigation devices through
> > > > > > > remote TMD service.
> > > > > > >
> > > > > > > Because of this multiplicity, introduced separate binding file.
> > > > > >
> > > > > > This explains nothing. Subsystem does not matter for the binding. My
> > > > > > comment stays.
> > > > > >
> > > > >
> > > > > thanks for this suggestion, we will use qcom,pas-common.yaml to define
> > > > > bindings and avoid creating new file.
> > > >
> > > > I asked not to create any children nodes.
> > > >
> > >
> > > We have multiple cores within a subsystem(cdsp) and each core has its
> > > own independent DCVS. And also we have dedicated TSENS sensor placed on
> > > each core within the subsystem.
> >
> > Your own example in this patch had only one device, so how do you
> > imagine to convince us with incomplete or half baked code?
> >
>
> Target of this series supports one tmd per remoteproc, due to which we have
> not posted examples of multiple tmd. Can i use dt binding example sections
> to describe all tmd's per remoteproc?
I think you have spent more time arguing that you this series is limited
to CDSP than would have been spent on adding ADSP/ SLPI / MDSP support.
>
> > > As a result, each core requires its own cooling device, which must be
> > > linked to its TSENS thermal zone. Because of this, we introduced
> > > multiple child nodes—one for each cooling device.
> >
> > So you have one device with cooling cells=1+2, no?
> >
>
> This will be a bigger framework change which is not supported, i can see
> other drivers are also using something like this multiple cooling device
> under device node, below are few examples :
>
> ->Documentation/devicetree/bindings/hwmon/microchip,emc2305.yaml
> In this multiple fan child nodes are present.
>
> -> Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.yaml
> In this multiple child nodes are present, like heavy and light.
>
> Please suggest if our current approach is fine or you want us to implement
> in some other way.
>
> > >
> > Best regards,
> > Krzysztof
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 0/8] Add RemoteProc cooling support
2026-01-27 15:57 [PATCH v2 0/8] Add RemoteProc cooling support Gaurav Kohli
` (7 preceding siblings ...)
2026-01-27 15:57 ` [PATCH v2 8/8] arm64: dts: qcom: monaco: " Gaurav Kohli
@ 2026-03-06 9:09 ` Daniel Lezcano
8 siblings, 0 replies; 53+ messages in thread
From: Daniel Lezcano @ 2026-03-06 9:09 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
Hi Gaurav,
On Tue, Jan 27, 2026 at 09:27:14PM +0530, Gaurav Kohli wrote:
> This series introduces a generic remote proc cooling framework to control
> thermal sensors located on remote subsystem like modem, dsp etc.
> Communications with these subsystems occurs through various channels, for example,
> QMI interface for Qualcomm.
Can you clarify the semantic of the driver ? It is described as
controlling the thermal sensors, except I'm missing something my
understanding it controls the level of performance of a subsystem
where a thermal sensor is tied to.
> The Framework provides an abstraction layer between thermal subsytem and vendor
> specific remote subsystem. Vendor drivers are expected to implement callback
> and registration mechanisms with cooling framework to control cooling
> devices.
>
> This patchset also revives earlier discussions of QMI based TMD cooling
> devices discussion posted on below series by Casey:
> https://lore.kernel.org/linux-devicetree/20230905-caleb-qmi_cooling-v1-0-5aa39d4164a7@linaro.org/
>
> That series introduced Qualcomm QMI-based TMD cooling devices which used
> to mitigate thermal conditions across multiple remote subsystems. These
> devices operate based on junction temperature sensors (TSENS) associated
> with thermal zones for each subsystem and registering with remoteproc
> cooling framework for cooling registration.
> ---
> Changes in v2:
> - Update Remoreproc thermal config to tristate and removed unnecessary NULL checks.
> - Fixed dt binding file format and added generic name support for cdsp.
> - Fixed memory leak and cleaned up qmi-cooling driver file.
> - Corrected DT formatting errors and commit descriptions for all targets.
> - Link to v1: https://lore.kernel.org/linux-devicetree/20251223123227.1317244-1-gaurav.kohli@oss.qualcomm.com/
> ---
>
> Casey Connolly (2):
> remoteproc: qcom: probe all child devices
> thermal: qcom: add qmi-cooling driver
>
> Gaurav Kohli (6):
> thermal: Add Remote Proc cooling driver
> dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
> arm64: dts: qcom: lemans: Enable CDSP cooling
> arm64: dts: qcom: talos: Enable CDSP cooling
> arm64: dts: qcom: kodiak: Enable CDSP cooling
> arm64: dts: qcom: monaco: Enable CDSP cooling
>
> .../bindings/remoteproc/qcom,pas-common.yaml | 6 +
> .../bindings/thermal/qcom,qmi-cooling.yaml | 72 +++
> MAINTAINERS | 7 +
> arch/arm64/boot/dts/qcom/kodiak.dtsi | 37 ++
> arch/arm64/boot/dts/qcom/lemans.dtsi | 138 ++++-
> arch/arm64/boot/dts/qcom/monaco.dtsi | 93 ++++
> arch/arm64/boot/dts/qcom/talos.dtsi | 24 +
> drivers/remoteproc/qcom_q6v5.c | 4 +
> drivers/remoteproc/qcom_q6v5_mss.c | 8 -
> drivers/soc/qcom/Kconfig | 13 +
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/qmi-cooling.c | 510 ++++++++++++++++++
> drivers/soc/qcom/qmi-cooling.h | 429 +++++++++++++++
> drivers/thermal/Kconfig | 10 +
> drivers/thermal/Makefile | 2 +
> drivers/thermal/remoteproc_cooling.c | 143 +++++
> include/linux/remoteproc_cooling.h | 52 ++
> 17 files changed, 1529 insertions(+), 20 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml
> create mode 100644 drivers/soc/qcom/qmi-cooling.c
> create mode 100644 drivers/soc/qcom/qmi-cooling.h
> create mode 100644 drivers/thermal/remoteproc_cooling.c
> create mode 100644 include/linux/remoteproc_cooling.h
>
> --
> 2.34.1
>
--
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-01-27 15:57 ` [PATCH v2 1/8] thermal: Add Remote Proc cooling driver Gaurav Kohli
` (3 preceding siblings ...)
2026-01-30 6:47 ` kernel test robot
@ 2026-03-06 9:19 ` Daniel Lezcano
2026-03-06 9:27 ` Lukasz Luba
2026-03-09 6:34 ` Gaurav Kohli
4 siblings, 2 replies; 53+ messages in thread
From: Daniel Lezcano @ 2026-03-06 9:19 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Jan 27, 2026 at 09:27:15PM +0530, Gaurav Kohli wrote:
> Add a new generic driver for thermal cooling devices that control
> remote processors (modem, DSP, etc.) through various communication
> channels.
>
> This driver provides an abstraction layer between the thermal
> subsystem and vendor-specific remote processor communication
> mechanisms.
>
> Advantage of this to avoid duplicating vendor-specific logic
> in the thermal subsystem and make it easier for different vendors
> to plug in their own cooling mechanisms via callbacks.
These changes add a layer on top of another existing without bringing
a real benefit. At the first glance, it appears to be an ops calling
an ops with an extra unneeded lock.
IMO, a remote proc cooling device should at least group all common
rproc calls found in the different SoC doing the same thing. Otherwise
it is not worth to add it.
> Suggested-by: Amit Kucheria <amit.kucheria@oss.qualcomm.com>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> ---
> MAINTAINERS | 7 ++
> drivers/thermal/Kconfig | 10 ++
> drivers/thermal/Makefile | 2 +
> drivers/thermal/remoteproc_cooling.c | 143 +++++++++++++++++++++++++++
> include/linux/remoteproc_cooling.h | 52 ++++++++++
> 5 files changed, 214 insertions(+)
> create mode 100644 drivers/thermal/remoteproc_cooling.c
> create mode 100644 include/linux/remoteproc_cooling.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 414f44093269..5ebc7819d2cf 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -26169,6 +26169,13 @@ F: drivers/thermal/cpufreq_cooling.c
> F: drivers/thermal/cpuidle_cooling.c
> F: include/linux/cpu_cooling.h
>
> +THERMAL/REMOTEPROC_COOLING
> +M: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> +L: linux-pm@vger.kernel.org
> +S: Supported
> +F: drivers/thermal/remoteproc_cooling.c
> +F: include/linux/remoteproc_cooling.h
> +
> THERMAL/POWER_ALLOCATOR
> M: Lukasz Luba <lukasz.luba@arm.com>
> L: linux-pm@vger.kernel.org
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index b10080d61860..dfc52eed64de 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -229,6 +229,16 @@ config PCIE_THERMAL
>
> If you want this support, you should say Y here.
>
> +config REMOTEPROC_THERMAL
> + tristate "Remote processor cooling support"
> + help
> + This implements a generic cooling mechanism for remote processors
> + (modem, DSP, etc.) that allows vendor-specific implementations to
> + register thermal cooling devices and provide callbacks for thermal
> + mitigation.
> +
> + If you want this support, you should say Y here.
> +
> config THERMAL_EMULATION
> bool "Thermal emulation mode support"
> help
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index bb21e7ea7fc6..ae747dde54fe 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -34,6 +34,8 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
>
> thermal_sys-$(CONFIG_PCIE_THERMAL) += pcie_cooling.o
>
> +thermal_sys-$(CONFIG_REMOTEPROC_THERMAL) += remoteproc_cooling.o
> +
> obj-$(CONFIG_K3_THERMAL) += k3_bandgap.o k3_j72xx_bandgap.o
> # platform thermal drivers
> obj-y += broadcom/
> diff --git a/drivers/thermal/remoteproc_cooling.c b/drivers/thermal/remoteproc_cooling.c
> new file mode 100644
> index 000000000000..f958efa691b3
> --- /dev/null
> +++ b/drivers/thermal/remoteproc_cooling.c
> @@ -0,0 +1,143 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Remote Processor Cooling Device
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/export.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include <linux/thermal.h>
> +
> +#define REMOTEPROC_PREFIX "rproc_"
> +
> +struct remoteproc_cooling_ops {
> + int (*get_max_level)(void *devdata, unsigned long *level);
> + int (*get_cur_level)(void *devdata, unsigned long *level);
> + int (*set_cur_level)(void *devdata, unsigned long level);
> +};
> +
> +/**
> + * struct remoteproc_cdev - Remote processor cooling device
> + * @cdev: Thermal cooling device handle
> + * @ops: Vendor-specific operation callbacks
> + * @devdata: Private data for vendor implementation
> + * @np: Device tree node associated with this cooling device
> + * @lock: Mutex to protect cooling device operations
> + */
> +struct remoteproc_cdev {
> + struct thermal_cooling_device *cdev;
> + const struct remoteproc_cooling_ops *ops;
> + void *devdata;
> + struct mutex lock;
> +};
> +
> +/* Thermal cooling device callbacks */
> +
> +static int remoteproc_get_max_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
> + int ret;
> +
> + mutex_lock(&rproc_cdev->lock);
> + ret = rproc_cdev->ops->get_max_level(rproc_cdev->devdata, state);
> + mutex_unlock(&rproc_cdev->lock);
> +
> + return ret;
> +}
> +
> +static int remoteproc_get_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
> + int ret;
> +
> + mutex_lock(&rproc_cdev->lock);
> + ret = rproc_cdev->ops->get_cur_level(rproc_cdev->devdata, state);
> + mutex_unlock(&rproc_cdev->lock);
> +
> + return ret;
> +}
> +
> +static int remoteproc_set_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long state)
> +{
> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
> + int ret;
> +
> + mutex_lock(&rproc_cdev->lock);
> + ret = rproc_cdev->ops->set_cur_level(rproc_cdev->devdata, state);
> + mutex_unlock(&rproc_cdev->lock);
> +
> + return ret;
> +}
> +
> +static const struct thermal_cooling_device_ops remoteproc_cooling_ops = {
> + .get_max_state = remoteproc_get_max_state,
> + .get_cur_state = remoteproc_get_cur_state,
> + .set_cur_state = remoteproc_set_cur_state,
> +};
> +
> +struct remoteproc_cdev *
> +remoteproc_cooling_register(struct device_node *np,
> + const char *name, const struct remoteproc_cooling_ops *ops,
> + void *devdata)
> +{
> + struct remoteproc_cdev *rproc_cdev;
> + struct thermal_cooling_device *cdev;
> + int ret;
> +
> + if (!name || !ops)
> + return ERR_PTR(-EINVAL);
> +
> + rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL);
> + if (!rproc_cdev)
> + return ERR_PTR(-ENOMEM);
> +
> + rproc_cdev->ops = ops;
> + rproc_cdev->devdata = devdata;
> + mutex_init(&rproc_cdev->lock);
> +
> + char *rproc_name __free(kfree) =
> + kasprintf(GFP_KERNEL, REMOTEPROC_PREFIX "%s", name);
> + /* Register with thermal framework */
> + if (np)
> + cdev = thermal_of_cooling_device_register(np, rproc_name, rproc_cdev,
> + &remoteproc_cooling_ops);
> + else
> + cdev = thermal_cooling_device_register(rproc_name, rproc_cdev,
> + &remoteproc_cooling_ops);
> +
> + if (IS_ERR(cdev)) {
> + ret = PTR_ERR(cdev);
> + goto free_rproc_cdev;
> + }
> +
> + rproc_cdev->cdev = cdev;
> +
> + return rproc_cdev;
> +
> +free_rproc_cdev:
> + kfree(rproc_cdev);
> + return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(remoteproc_cooling_register);
> +
> +void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
> +{
> + if (!rproc_cdev)
> + return;
> +
> + thermal_cooling_device_unregister(rproc_cdev->cdev);
> + mutex_destroy(&rproc_cdev->lock);
> + kfree(rproc_cdev);
> +}
> +EXPORT_SYMBOL_GPL(remoteproc_cooling_unregister);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Remote Processor Cooling Device");
> diff --git a/include/linux/remoteproc_cooling.h b/include/linux/remoteproc_cooling.h
> new file mode 100644
> index 000000000000..721912d1a5ec
> --- /dev/null
> +++ b/include/linux/remoteproc_cooling.h
> @@ -0,0 +1,52 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Remote Processor Cooling Device
> + *
> + * Copyright (c) 2025, Qualcomm Innovation Center
> + */
> +
> +#ifndef __REMOTEPROC_COOLING_H__
> +#define __REMOTEPROC_COOLING_H__
> +
> +#include <linux/thermal.h>
> +
> +struct device;
> +struct device_node;
> +
> +struct remoteproc_cooling_ops {
> + int (*get_max_level)(void *devdata, unsigned long *level);
> + int (*get_cur_level)(void *devdata, unsigned long *level);
> + int (*set_cur_level)(void *devdata, unsigned long level);
> +};
> +
> +struct remoteproc_cdev;
> +
> +#ifdef CONFIG_REMOTEPROC_THERMAL
> +
> +struct remoteproc_cdev *
> +remoteproc_cooling_register(struct device_node *np,
> + const char *name,
> + const struct remoteproc_cooling_ops *ops,
> + void *devdata);
> +
> +void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev);
> +
> +#else /* !CONFIG_REMOTEPROC_THERMAL */
> +
> +static inline struct remoteproc_cdev *
> +remoteproc_cooling_register(struct device_node *np,
> + const char *name,
> + const struct remoteproc_cooling_ops *ops,
> + void *devdata)
> +{
> + return ERR_PTR(-EINVAL);
> +}
> +
> +static inline void
> +remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
> +{
> +}
> +
> +#endif /* CONFIG_REMOTEPROC_THERMAL */
> +
> +#endif /* __REMOTEPROC_COOLING_H__ */
> --
> 2.34.1
>
--
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-03-06 9:19 ` Daniel Lezcano
@ 2026-03-06 9:27 ` Lukasz Luba
2026-03-09 6:34 ` Gaurav Kohli
1 sibling, 0 replies; 53+ messages in thread
From: Lukasz Luba @ 2026-03-06 9:27 UTC (permalink / raw)
To: Daniel Lezcano, Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
konradybcio, mani, casey.connolly, amit.kucheria, linux-arm-msm,
devicetree, linux-kernel, linux-pm, manaf.pallikunhi
On 3/6/26 09:19, Daniel Lezcano wrote:
> On Tue, Jan 27, 2026 at 09:27:15PM +0530, Gaurav Kohli wrote:
>> Add a new generic driver for thermal cooling devices that control
>> remote processors (modem, DSP, etc.) through various communication
>> channels.
>>
>> This driver provides an abstraction layer between the thermal
>> subsystem and vendor-specific remote processor communication
>> mechanisms.
>>
>> Advantage of this to avoid duplicating vendor-specific logic
>> in the thermal subsystem and make it easier for different vendors
>> to plug in their own cooling mechanisms via callbacks.
>
> These changes add a layer on top of another existing without bringing
> a real benefit. At the first glance, it appears to be an ops calling
> an ops with an extra unneeded lock.
>
> IMO, a remote proc cooling device should at least group all common
> rproc calls found in the different SoC doing the same thing. Otherwise
> it is not worth to add it.
>
I agree with Daniel here. I thought we would have many such SoCs and
a common problem to solve in the fwk layer. When we discussed at LPC25
this needed feature I got an impression this is the case.
Do we have other SoCs which would benefit from this design approach?
If not, then it would be better to put this code next to the SoC's
driver code and not expose it.
Regards,
Lukasz
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver
2026-01-27 15:57 ` [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver Gaurav Kohli
2026-01-30 9:05 ` kernel test robot
@ 2026-03-06 9:31 ` Daniel Lezcano
2026-03-16 10:19 ` Gaurav Kohli
2026-03-13 14:15 ` Daniel Lezcano
2 siblings, 1 reply; 53+ messages in thread
From: Daniel Lezcano @ 2026-03-06 9:31 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Jan 27, 2026 at 09:27:18PM +0530, Gaurav Kohli wrote:
> From: Casey Connolly <casey.connolly@linaro.org>
>
> The Thermal Mitigation Device (TMD) service exposes various platform
> specific thermal mitigations available on remote subsystems (ie the
> modem and cdsp). The service is exposed via the QMI messaging
> interface, usually over the QRTR transport.
>
> Qualcomm QMI-based TMD cooling devices are used to mitigate thermal
> conditions across multiple remote subsystems. These devices operate
> based on junction temperature sensors (TSENS) associated with thermal
> zones for each subsystem.
IIUC, QMI is the messaging mechanism for remote proc. TMD is the cooling device.
If it is correct, I suggest to follow the following organisation:
- tmd_interface.c (qmi <-> tmd)
- tmd_cooling.c (tmd <-> thermal framework)
So we end up with:
qmi_interface -> tmd_interface -> tmd_cooling
AFAICT, it is similar with the pdr_interface, right ?
> Co-developed-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
> ---
> drivers/soc/qcom/Kconfig | 13 +
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/qmi-cooling.c | 510 +++++++++++++++++++++++++++++++++
> drivers/soc/qcom/qmi-cooling.h | 429 +++++++++++++++++++++++++++
> 4 files changed, 953 insertions(+)
> create mode 100644 drivers/soc/qcom/qmi-cooling.c
> create mode 100644 drivers/soc/qcom/qmi-cooling.h
>
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 2caadbbcf830..905a24b42fe6 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -124,6 +124,19 @@ config QCOM_PMIC_GLINK
> Say yes here to support USB-C and battery status on modern Qualcomm
> platforms.
>
> +config QCOM_QMI_COOLING
> + tristate "Qualcomm QMI cooling drivers"
> + depends on QCOM_RPROC_COMMON
> + depends on ARCH_QCOM || COMPILE_TEST
> + select QCOM_QMI_HELPERS
> + help
> + This enables the remote subsystem cooling devices. These cooling
> + devices will be used by Qualcomm chipset to place various remote
> + subsystem mitigations like remote processor passive mitigation,
> + remote subsystem voltage restriction at low temperatures etc.
> + The QMI cooling device will interface with remote subsystem
> + using Qualcomm remoteproc interface.
> +
> config QCOM_QMI_HELPERS
> tristate
> depends on NET
> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
> index b7f1d2a57367..b6728f54944b 100644
> --- a/drivers/soc/qcom/Makefile
> +++ b/drivers/soc/qcom/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
> obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
> obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o
> CFLAGS_pmic_pdcharger_ulog.o := -I$(src)
> +obj-$(CONFIG_QCOM_QMI_COOLING) += qmi-cooling.o
> obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
> qmi_helpers-y += qmi_encdec.o qmi_interface.o
> obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o
> diff --git a/drivers/soc/qcom/qmi-cooling.c b/drivers/soc/qcom/qmi-cooling.c
> new file mode 100644
> index 000000000000..463baa47c8b6
> --- /dev/null
> +++ b/drivers/soc/qcom/qmi-cooling.c
> @@ -0,0 +1,510 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2017, The Linux Foundation
> + * Copyright (c) 2025, Linaro Limited
> + *
> + * QMI Thermal Mitigation Device (TMD) client driver.
> + * This driver provides an in-kernel client to handle hot and cold thermal
> + * mitigations for remote subsystems (modem and DSPs) running the TMD service.
> + * It doesn't implement any handling of reports from remote subsystems.
> + */
> +
> +#include <linux/cleanup.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/net.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/remoteproc/qcom_rproc.h>
> +#include <linux/remoteproc_cooling.h>
> +#include <linux/slab.h>
> +#include <linux/soc/qcom/qmi.h>
> +#include <linux/thermal.h>
> +
> +#include "qmi-cooling.h"
> +
> +#define CDSP_INSTANCE_ID 0x43
> +#define CDSP1_INSTANCE_ID 0x44
> +
> +#define QMI_TMD_RESP_TIMEOUT msecs_to_jiffies(100)
> +
> +/**
> + * struct qmi_tmd_client - TMD client state
> + * @dev: Device associated with this client
> + * @name: Friendly name for the remote TMD service
> + * @handle: QMI connection handle
> + * @mutex: Lock to synchronise QMI communication
> + * @id: The QMI TMD service instance ID
> + * @cdev_list: The list of cooling devices (controls) enabled for this instance
> + * @svc_arrive_work: Work item for initialising the client when the TMD service
> + * starts.
> + * @connection_active: Whether or not we're connected to the QMI TMD service
> + */
> +struct qmi_tmd_client {
> + struct device *dev;
> + const char *name;
> + struct qmi_handle handle;
> + struct mutex mutex;
> + u32 id;
> + struct list_head cdev_list;
> + struct work_struct svc_arrive_work;
> + bool connection_active;
> +};
> +
> +/**
> + * struct qmi_tmd - A TMD cooling device
> + * @np: OF node associated with this control
> + * @type: The control type (exposed via sysfs)
> + * @qmi_name: The common name of this control shared by the remote subsystem
> + * @rproc_cdev: Remote processor cooling device handle
> + * @cur_state: The current cooling/warming/mitigation state
> + * @max_state: The maximum state
> + * @client: The TMD client instance this control is associated with
> + */
> +struct qmi_tmd {
> + struct device_node *np;
> + const char *type;
> + char qmi_name[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1];
> + struct list_head node;
> + struct remoteproc_cdev *rproc_cdev;
> + unsigned int cur_state;
> + unsigned int max_state;
> + struct qmi_tmd_client *client;
> +};
> +
> +/**
> + * struct qmi_instance_id - QMI instance match data
> + * @id: The QMI instance ID
> + * @name: Friendly name for this instance
> + */
> +struct qmi_instance_data {
> + u32 id;
> + const char *name;
> +};
> +
> +/* Notify the remote subsystem of the requested cooling state */
> +static int qmi_tmd_send_state_request(struct qmi_tmd *tmd)
> +{
> + struct tmd_set_mitigation_level_resp_msg_v01 tmd_resp = { 0 };
> + struct tmd_set_mitigation_level_req_msg_v01 req = { 0 };
> + struct qmi_tmd_client *client;
> + struct qmi_txn txn;
> + int ret = 0;
> +
> + client = tmd->client;
> +
> + guard(mutex)(&client->mutex);
> +
> + /*
> + * This function is called by qmi_set_cur_state() which does not know if
> + * the QMI service is actually online. If it isn't then we noop here.
> + * The state is cached in tmd->cur_state and will be broadcast via
> + * qmi_tmd_init_control() when the service comes up.
> + */
> + if (!client->connection_active)
> + return 0;
> +
> + strscpy(req.mitigation_dev_id.mitigation_dev_id, tmd->qmi_name,
> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
> + req.mitigation_level = tmd->cur_state;
> +
> + ret = qmi_txn_init(&client->handle, &txn,
> + tmd_set_mitigation_level_resp_msg_v01_ei, &tmd_resp);
> + if (ret < 0) {
> + dev_err(client->dev, "qmi set state %d txn init failed for %s ret %d\n",
> + tmd->cur_state, tmd->type, ret);
> + return ret;
> + }
> +
> + ret = qmi_send_request(&client->handle, NULL, &txn,
> + QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01,
> + TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN,
> + tmd_set_mitigation_level_req_msg_v01_ei, &req);
> + if (ret < 0) {
> + dev_err(client->dev, "qmi set state %d txn send failed for %s ret %d\n",
> + tmd->cur_state, tmd->type, ret);
> + qmi_txn_cancel(&txn);
> + return ret;
> + }
> +
> + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
> + if (ret < 0) {
> + dev_err(client->dev, "qmi set state %d txn wait failed for %s ret %d\n",
> + tmd->cur_state, tmd->type, ret);
> + return ret;
> + }
> +
> + if (tmd_resp.resp.result != QMI_RESULT_SUCCESS_V01) {
> + ret = -tmd_resp.resp.result;
> + dev_err(client->dev, "qmi set state %d NOT success for %s ret %d\n",
> + tmd->cur_state, tmd->type, ret);
> + return ret;
> + }
> +
> + dev_dbg(client->dev, "Requested state %d/%d for %s\n", tmd->cur_state,
> + tmd->max_state, tmd->type);
> +
> + return 0;
> +}
> +
> +static int qmi_get_max_level(void *devdata, unsigned long *level)
> +{
> + struct qmi_tmd *tmd = devdata;
> +
> + if (!tmd)
> + return -EINVAL;
> +
> + *level = tmd->max_state;
> +
> + return 0;
> +}
> +
> +static int qmi_get_cur_level(void *devdata, unsigned long *level)
> +{
> + struct qmi_tmd *tmd = devdata;
> +
> + if (!tmd)
> + return -EINVAL;
> +
> + *level = tmd->cur_state;
> +
> + return 0;
> +}
> +
> +static int qmi_set_cur_level(void *devdata, unsigned long level)
> +{
> + struct qmi_tmd *tmd = devdata;
> +
> + if (!tmd)
> + return -EINVAL;
> +
> + if (level > tmd->max_state)
> + return -EINVAL;
> +
> + if (tmd->cur_state == level)
> + return 0;
> +
> + tmd->cur_state = level;
> +
> + return qmi_tmd_send_state_request(tmd);
> +}
> +
> +static const struct remoteproc_cooling_ops qmi_rproc_ops = {
> + .get_max_level = qmi_get_max_level,
> + .get_cur_level = qmi_get_cur_level,
> + .set_cur_level = qmi_set_cur_level,
> +};
> +
> +static int qmi_register_cooling_device(struct qmi_tmd *tmd)
> +{
> + struct remoteproc_cdev *rproc_cdev;
> +
> + rproc_cdev = remoteproc_cooling_register(tmd->np,
> + tmd->type,
> + &qmi_rproc_ops,
> + tmd);
> +
> + if (IS_ERR(rproc_cdev))
> + return dev_err_probe(tmd->client->dev, PTR_ERR(rproc_cdev),
> + "Failed to register cooling device %s\n",
> + tmd->qmi_name);
> +
> + tmd->rproc_cdev = rproc_cdev;
> + return 0;
> +}
> +
> +/*
> + * Init a single TMD control by registering a cooling device for it, or
> + * synchronising state with the remote subsystem if recovering from a service
> + * restart. This is called when the TMD service starts up.
> + */
> +static int qmi_tmd_init_control(struct qmi_tmd_client *client, const char *label,
> + u8 max_state)
> +{
> + struct qmi_tmd *tmd = NULL;
> +
> + list_for_each_entry(tmd, &client->cdev_list, node)
> + if (!strncasecmp(tmd->qmi_name, label,
> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1))
> + goto found;
> +
> + dev_dbg(client->dev,
> + "TMD '%s' available in firmware but not specified in DT\n",
> + label);
> + return 0;
> +
> +found:
> + tmd->max_state = max_state;
> + /*
> + * If the cooling device already exists then the QMI service went away and
> + * came back. So just make sure the current cooling device state is
> + * reflected on the remote side and then return.
> + */
> + if (tmd->rproc_cdev)
> + return qmi_tmd_send_state_request(tmd);
> +
> + return qmi_register_cooling_device(tmd);
> +}
> +
> +/*
> + * When the QMI service starts up on a remote subsystem this function will fetch
> + * the list of TMDs on the subsystem, match it to the TMDs specified in devicetree
> + * and call qmi_tmd_init_control() for each
> + */
> +static void qmi_tmd_svc_arrive(struct work_struct *work)
> +{
> + struct qmi_tmd_client *client =
> + container_of(work, struct qmi_tmd_client, svc_arrive_work);
> +
> + struct tmd_get_mitigation_device_list_req_msg_v01 req = { 0 };
> + struct tmd_get_mitigation_device_list_resp_msg_v01 *resp __free(kfree) = NULL;
> + int ret = 0, i;
> + struct qmi_txn txn;
> +
> + /* resp struct is 1.1kB, allocate it on the heap. */
> + resp = kzalloc(sizeof(*resp), GFP_KERNEL);
> + if (!resp)
> + return;
> +
> + /* Get a list of TMDs supported by the remoteproc */
> + scoped_guard(mutex, &client->mutex) {
> + ret = qmi_txn_init(&client->handle, &txn,
> + tmd_get_mitigation_device_list_resp_msg_v01_ei, resp);
> + if (ret < 0) {
> + dev_err(client->dev,
> + "Transaction init error for instance_id: %#x ret %d\n",
> + client->id, ret);
> + return;
> + }
> +
> + ret = qmi_send_request(&client->handle, NULL, &txn,
> + QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01,
> + TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN,
> + tmd_get_mitigation_device_list_req_msg_v01_ei, &req);
> + if (ret < 0) {
> + qmi_txn_cancel(&txn);
> + return;
> + }
> +
> + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
> + if (ret < 0) {
> + dev_err(client->dev, "Transaction wait error for client %#x ret:%d\n",
> + client->id, ret);
> + return;
> + }
> + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
> + ret = resp->resp.result;
> + dev_err(client->dev, "Failed to get device list for client %#x ret:%d\n",
> + client->id, ret);
> + return;
> + }
> +
> + client->connection_active = true;
> + }
> +
> + for (i = 0; i < resp->mitigation_device_list_len; i++) {
> + struct tmd_mitigation_dev_list_type_v01 *device =
> + &resp->mitigation_device_list[i];
> +
> + ret = qmi_tmd_init_control(client,
> + device->mitigation_dev_id.mitigation_dev_id,
> + device->max_mitigation_level);
> + if (ret)
> + break;
> + }
> +}
> +
> +static void thermal_qmi_net_reset(struct qmi_handle *qmi)
> +{
> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
> + struct qmi_tmd *tmd = NULL;
> +
> + list_for_each_entry(tmd, &client->cdev_list, node) {
> + qmi_tmd_send_state_request(tmd);
> + }
> +}
> +
> +static void thermal_qmi_del_server(struct qmi_handle *qmi, struct qmi_service *service)
> +{
> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
> +
> + scoped_guard(mutex, &client->mutex)
> + client->connection_active = false;
> +}
> +
> +static int thermal_qmi_new_server(struct qmi_handle *qmi, struct qmi_service *service)
> +{
> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
> + struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port };
> +
> + scoped_guard(mutex, &client->mutex)
> + kernel_connect(qmi->sock, (struct sockaddr_unsized *)&sq, sizeof(sq), 0);
> +
> + queue_work(system_highpri_wq, &client->svc_arrive_work);
> +
> + return 0;
> +}
> +
> +static const struct qmi_ops thermal_qmi_event_ops = {
> + .new_server = thermal_qmi_new_server,
> + .del_server = thermal_qmi_del_server,
> + .net_reset = thermal_qmi_net_reset,
> +};
> +
> +static void qmi_tmd_cleanup(struct qmi_tmd_client *client)
> +{
> + struct qmi_tmd *tmd, *c_next;
> +
> + guard(mutex)(&client->mutex);
> +
> + client->connection_active = false;
> +
> + qmi_handle_release(&client->handle);
> + cancel_work(&client->svc_arrive_work);
> + list_for_each_entry_safe(tmd, c_next, &client->cdev_list, node) {
> + if (tmd->rproc_cdev)
> + remoteproc_cooling_unregister(tmd->rproc_cdev);
> +
> + list_del(&tmd->node);
> + }
> +}
> +
> +/* Parse the controls and allocate a qmi_tmd for each of them */
> +static int qmi_tmd_alloc_cdevs(struct qmi_tmd_client *client)
> +{
> + struct device *dev = client->dev;
> + struct device_node *node = dev->of_node;
> + struct device_node *subnode;
> + struct qmi_tmd *tmd;
> + int ret;
> +
> + for_each_available_child_of_node_scoped(node, subnode) {
> + const char *name;
> +
> + tmd = devm_kzalloc(dev, sizeof(*tmd), GFP_KERNEL);
> + if (!tmd)
> + return dev_err_probe(client->dev, -ENOMEM,
> + "Couldn't allocate tmd\n");
> +
> + tmd->type = devm_kasprintf(client->dev, GFP_KERNEL, "%s",
> + subnode->name);
> + if (!tmd->type)
> + return dev_err_probe(dev, -ENOMEM,
> + "Couldn't allocate cooling device name\n");
> +
> + if (of_property_read_string(subnode, "label", &name))
> + return dev_err_probe(client->dev, -EINVAL,
> + "Failed to parse dev name for %s\n",
> + subnode->name);
> +
> + ret = strscpy(tmd->qmi_name, name,
> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
> + if (ret == -E2BIG)
> + return dev_err_probe(dev, -EINVAL, "TMD label %s is too long\n",
> + name);
> +
> + tmd->client = client;
> + tmd->np = subnode;
> + tmd->cur_state = 0;
> + list_add(&tmd->node, &client->cdev_list);
> + }
> +
> + if (list_empty(&client->cdev_list))
> + return dev_err_probe(client->dev, -EINVAL,
> + "No cooling devices specified for client %s (%#x)\n",
> + client->name, client->id);
> +
> + return 0;
> +}
> +
> +static int qmi_tmd_client_probe(struct platform_device *pdev)
> +{
> + const struct qmi_instance_data *match;
> + struct qmi_tmd_client *client;
> + struct device *dev = &pdev->dev;
> + int ret;
> +
> + client = devm_kzalloc(dev, sizeof(*client), GFP_KERNEL);
> + if (!client)
> + return -ENOMEM;
> +
> + client->dev = dev;
> +
> + match = of_device_get_match_data(dev);
> + if (!match)
> + return dev_err_probe(dev, -EINVAL, "No match data\n");
> +
> + client->id = match->id;
> + client->name = match->name;
> +
> + mutex_init(&client->mutex);
> + INIT_LIST_HEAD(&client->cdev_list);
> + INIT_WORK(&client->svc_arrive_work, qmi_tmd_svc_arrive);
> +
> + ret = qmi_tmd_alloc_cdevs(client);
> + if (ret)
> + return ret;
> +
> + platform_set_drvdata(pdev, client);
> +
> + ret = qmi_handle_init(&client->handle,
> + TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN,
> + &thermal_qmi_event_ops, NULL);
> + if (ret < 0)
> + return dev_err_probe(client->dev, ret, "QMI handle init failed for client %#x\n",
> + client->id);
> +
> + ret = qmi_add_lookup(&client->handle, TMD_SERVICE_ID_V01, TMD_SERVICE_VERS_V01,
> + client->id);
> + if (ret < 0) {
> + qmi_handle_release(&client->handle);
> + return dev_err_probe(client->dev, ret, "QMI register failed for client 0x%x\n",
> + client->id);
> + }
> +
> + return 0;
> +}
> +
> +static void qmi_tmd_client_remove(struct platform_device *pdev)
> +{
> + struct qmi_tmd_client *client = platform_get_drvdata(pdev);
> +
> + qmi_tmd_cleanup(client);
> +}
> +
> +static const struct qmi_instance_data qmi_cdsp = {
> + .id = CDSP_INSTANCE_ID,
> + .name = "cdsp",
> +};
> +
> +static const struct qmi_instance_data qmi_cdsp1 = {
> + .id = CDSP1_INSTANCE_ID,
> + .name = "cdsp1",
> +};
> +
> +static const struct of_device_id qmi_tmd_device_table[] = {
> + {
> + .compatible = "qcom,qmi-cooling-cdsp",
> + .data = &qmi_cdsp,
> + },
> + {
> + .compatible = "qcom,qmi-cooling-cdsp1",
> + .data = &qmi_cdsp1,
> + },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, qmi_tmd_device_table);
> +
> +static struct platform_driver qmi_tmd_device_driver = {
> + .probe = qmi_tmd_client_probe,
> + .remove = qmi_tmd_client_remove,
> + .driver = {
> + .name = "qcom-qmi-cooling",
> + .of_match_table = qmi_tmd_device_table,
> + },
> +};
> +
> +module_platform_driver(qmi_tmd_device_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Qualcomm QMI Thermal Mitigation Device driver");
> diff --git a/drivers/soc/qcom/qmi-cooling.h b/drivers/soc/qcom/qmi-cooling.h
> new file mode 100644
> index 000000000000..e33f4c5979e5
> --- /dev/null
> +++ b/drivers/soc/qcom/qmi-cooling.h
> @@ -0,0 +1,429 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2017, The Linux Foundation
> + * Copyright (c) 2023, Linaro Limited
> + */
> +
> +#ifndef __QCOM_COOLING_H__
> +#define __QCOM_COOLING_H__
> +
> +#include <linux/soc/qcom/qmi.h>
> +
> +#define TMD_SERVICE_ID_V01 0x18
> +#define TMD_SERVICE_VERS_V01 0x01
> +
> +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_RESP_V01 0x0020
> +#define QMI_TMD_GET_MITIGATION_LEVEL_REQ_V01 0x0022
> +#define QMI_TMD_GET_SUPPORTED_MSGS_REQ_V01 0x001E
> +#define QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01 0x0021
> +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0023
> +#define QMI_TMD_GET_SUPPORTED_MSGS_RESP_V01 0x001E
> +#define QMI_TMD_SET_MITIGATION_LEVEL_RESP_V01 0x0021
> +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0024
> +#define QMI_TMD_MITIGATION_LEVEL_REPORT_IND_V01 0x0025
> +#define QMI_TMD_GET_MITIGATION_LEVEL_RESP_V01 0x0022
> +#define QMI_TMD_GET_SUPPORTED_FIELDS_REQ_V01 0x001F
> +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01 0x0020
> +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0023
> +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0024
> +#define QMI_TMD_GET_SUPPORTED_FIELDS_RESP_V01 0x001F
> +
> +#define QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 32
> +#define QMI_TMD_MITIGATION_DEV_LIST_MAX_V01 32
> +
> +struct tmd_mitigation_dev_id_type_v01 {
> + char mitigation_dev_id[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1];
> +};
> +
> +static const struct qmi_elem_info tmd_mitigation_dev_id_type_v01_ei[] = {
> + {
> + .data_type = QMI_STRING,
> + .elem_len = QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1,
> + .elem_size = sizeof(char),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0,
> + .offset = offsetof(struct tmd_mitigation_dev_id_type_v01,
> + mitigation_dev_id),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_mitigation_dev_list_type_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id;
> + u8 max_mitigation_level;
> +};
> +
> +static const struct qmi_elem_info tmd_mitigation_dev_list_type_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0,
> + .offset = offsetof(struct tmd_mitigation_dev_list_type_v01,
> + mitigation_dev_id),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0,
> + .offset = offsetof(struct tmd_mitigation_dev_list_type_v01,
> + max_mitigation_level),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_get_mitigation_device_list_req_msg_v01 {
> + char placeholder;
> +};
> +
> +#define TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN 0
> +const struct qmi_elem_info tmd_get_mitigation_device_list_req_msg_v01_ei[] = {
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_get_mitigation_device_list_resp_msg_v01 {
> + struct qmi_response_type_v01 resp;
> + u8 mitigation_device_list_valid;
> + u32 mitigation_device_list_len;
> + struct tmd_mitigation_dev_list_type_v01
> + mitigation_device_list[QMI_TMD_MITIGATION_DEV_LIST_MAX_V01];
> +};
> +
> +#define TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN 1099
> +static const struct qmi_elem_info tmd_get_mitigation_device_list_resp_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
> + resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_OPT_FLAG,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
> + mitigation_device_list_valid),
> + },
> + {
> + .data_type = QMI_DATA_LEN,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
> + mitigation_device_list_len),
> + },
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = QMI_TMD_MITIGATION_DEV_LIST_MAX_V01,
> + .elem_size = sizeof(struct tmd_mitigation_dev_list_type_v01),
> + .array_type = VAR_LEN_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
> + mitigation_device_list),
> + .ei_array = tmd_mitigation_dev_list_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_set_mitigation_level_req_msg_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id;
> + u8 mitigation_level;
> +};
> +
> +#define TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 40
> +static const struct qmi_elem_info tmd_set_mitigation_level_req_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01,
> + mitigation_dev_id),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01,
> + mitigation_level),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_set_mitigation_level_resp_msg_v01 {
> + struct qmi_response_type_v01 resp;
> +};
> +
> +#define TMD_SET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
> +static const struct qmi_elem_info tmd_set_mitigation_level_resp_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_set_mitigation_level_resp_msg_v01, resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_get_mitigation_level_req_msg_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
> +};
> +
> +#define TMD_GET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
> +
> +static const struct qmi_elem_info tmd_get_mitigation_level_req_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(struct tmd_get_mitigation_level_req_msg_v01,
> + mitigation_device),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_get_mitigation_level_resp_msg_v01 {
> + struct qmi_response_type_v01 resp;
> + u8 current_mitigation_level_valid;
> + u8 current_mitigation_level;
> + u8 requested_mitigation_level_valid;
> + u8 requested_mitigation_level;
> +};
> +
> +#define TMD_GET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 15
> +static const struct qmi_elem_info tmd_get_mitigation_level_resp_msg_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01, resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_OPT_FLAG,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
> + current_mitigation_level_valid),
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
> + current_mitigation_level),
> + },
> + {
> + .data_type = QMI_OPT_FLAG,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x11,
> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
> + requested_mitigation_level_valid),
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x11,
> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
> + requested_mitigation_level),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_register_notification_mitigation_level_req_msg_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
> +};
> +
> +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
> +static const struct qmi_elem_info
> + tmd_register_notification_mitigation_level_req_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(
> + struct tmd_register_notification_mitigation_level_req_msg_v01,
> + mitigation_device),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> + };
> +
> +struct tmd_register_notification_mitigation_level_resp_msg_v01 {
> + struct qmi_response_type_v01 resp;
> +};
> +
> +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
> +static const struct qmi_elem_info
> + tmd_register_notification_mitigation_level_resp_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(
> + struct tmd_register_notification_mitigation_level_resp_msg_v01,
> + resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> + };
> +
> +struct tmd_deregister_notification_mitigation_level_req_msg_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
> +};
> +
> +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
> +static const struct qmi_elem_info
> + tmd_deregister_notification_mitigation_level_req_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(
> + struct tmd_deregister_notification_mitigation_level_req_msg_v01,
> + mitigation_device),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> + };
> +
> +struct tmd_deregister_notification_mitigation_level_resp_msg_v01 {
> + struct qmi_response_type_v01 resp;
> +};
> +
> +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
> +static const struct qmi_elem_info
> + tmd_deregister_notification_mitigation_level_resp_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(
> + struct tmd_deregister_notification_mitigation_level_resp_msg_v01,
> + resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> + };
> +
> +struct tmd_mitigation_level_report_ind_msg_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
> + u8 current_mitigation_level;
> +};
> +
> +#define TMD_MITIGATION_LEVEL_REPORT_IND_MSG_V01_MAX_MSG_LEN 40
> +static const struct qmi_elem_info tmd_mitigation_level_report_ind_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01,
> + mitigation_device),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01,
> + current_mitigation_level),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +#endif /* __QMI_COOLING_INTERNAL_H__ */
> --
> 2.34.1
>
--
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 1/8] thermal: Add Remote Proc cooling driver
2026-03-06 9:19 ` Daniel Lezcano
2026-03-06 9:27 ` Lukasz Luba
@ 2026-03-09 6:34 ` Gaurav Kohli
1 sibling, 0 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-03-09 6:34 UTC (permalink / raw)
To: Daniel Lezcano
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 3/6/2026 2:49 PM, Daniel Lezcano wrote:
> On Tue, Jan 27, 2026 at 09:27:15PM +0530, Gaurav Kohli wrote:
>> Add a new generic driver for thermal cooling devices that control
>> remote processors (modem, DSP, etc.) through various communication
>> channels.
>>
>> This driver provides an abstraction layer between the thermal
>> subsystem and vendor-specific remote processor communication
>> mechanisms.
>>
>> Advantage of this to avoid duplicating vendor-specific logic
>> in the thermal subsystem and make it easier for different vendors
>> to plug in their own cooling mechanisms via callbacks.
>
> These changes add a layer on top of another existing without bringing
> a real benefit. At the first glance, it appears to be an ops calling
> an ops with an extra unneeded lock.
>
> IMO, a remote proc cooling device should at least group all common
> rproc calls found in the different SoC doing the same thing. Otherwise
> it is not worth to add it.
>
Thanks, Daniel, for the review.
Since this cooling driver is only invoked after the remote processor
(rproc) has started, there are no additional callbacks to consolidate.
The only interaction remaining is the registration with the thermal
cooling framework.
>> Suggested-by: Amit Kucheria <amit.kucheria@oss.qualcomm.com>
>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> ---
>> MAINTAINERS | 7 ++
>> drivers/thermal/Kconfig | 10 ++
>> drivers/thermal/Makefile | 2 +
>> drivers/thermal/remoteproc_cooling.c | 143 +++++++++++++++++++++++++++
>> include/linux/remoteproc_cooling.h | 52 ++++++++++
>> 5 files changed, 214 insertions(+)
>> create mode 100644 drivers/thermal/remoteproc_cooling.c
>> create mode 100644 include/linux/remoteproc_cooling.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 414f44093269..5ebc7819d2cf 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -26169,6 +26169,13 @@ F: drivers/thermal/cpufreq_cooling.c
>> F: drivers/thermal/cpuidle_cooling.c
>> F: include/linux/cpu_cooling.h
>>
>> +THERMAL/REMOTEPROC_COOLING
>> +M: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> +L: linux-pm@vger.kernel.org
>> +S: Supported
>> +F: drivers/thermal/remoteproc_cooling.c
>> +F: include/linux/remoteproc_cooling.h
>> +
>> THERMAL/POWER_ALLOCATOR
>> M: Lukasz Luba <lukasz.luba@arm.com>
>> L: linux-pm@vger.kernel.org
>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>> index b10080d61860..dfc52eed64de 100644
>> --- a/drivers/thermal/Kconfig
>> +++ b/drivers/thermal/Kconfig
>> @@ -229,6 +229,16 @@ config PCIE_THERMAL
>>
>> If you want this support, you should say Y here.
>>
>> +config REMOTEPROC_THERMAL
>> + tristate "Remote processor cooling support"
>> + help
>> + This implements a generic cooling mechanism for remote processors
>> + (modem, DSP, etc.) that allows vendor-specific implementations to
>> + register thermal cooling devices and provide callbacks for thermal
>> + mitigation.
>> +
>> + If you want this support, you should say Y here.
>> +
>> config THERMAL_EMULATION
>> bool "Thermal emulation mode support"
>> help
>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>> index bb21e7ea7fc6..ae747dde54fe 100644
>> --- a/drivers/thermal/Makefile
>> +++ b/drivers/thermal/Makefile
>> @@ -34,6 +34,8 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
>>
>> thermal_sys-$(CONFIG_PCIE_THERMAL) += pcie_cooling.o
>>
>> +thermal_sys-$(CONFIG_REMOTEPROC_THERMAL) += remoteproc_cooling.o
>> +
>> obj-$(CONFIG_K3_THERMAL) += k3_bandgap.o k3_j72xx_bandgap.o
>> # platform thermal drivers
>> obj-y += broadcom/
>> diff --git a/drivers/thermal/remoteproc_cooling.c b/drivers/thermal/remoteproc_cooling.c
>> new file mode 100644
>> index 000000000000..f958efa691b3
>> --- /dev/null
>> +++ b/drivers/thermal/remoteproc_cooling.c
>> @@ -0,0 +1,143 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Remote Processor Cooling Device
>> + *
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/export.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/of.h>
>> +#include <linux/slab.h>
>> +#include <linux/thermal.h>
>> +
>> +#define REMOTEPROC_PREFIX "rproc_"
>> +
>> +struct remoteproc_cooling_ops {
>> + int (*get_max_level)(void *devdata, unsigned long *level);
>> + int (*get_cur_level)(void *devdata, unsigned long *level);
>> + int (*set_cur_level)(void *devdata, unsigned long level);
>> +};
>> +
>> +/**
>> + * struct remoteproc_cdev - Remote processor cooling device
>> + * @cdev: Thermal cooling device handle
>> + * @ops: Vendor-specific operation callbacks
>> + * @devdata: Private data for vendor implementation
>> + * @np: Device tree node associated with this cooling device
>> + * @lock: Mutex to protect cooling device operations
>> + */
>> +struct remoteproc_cdev {
>> + struct thermal_cooling_device *cdev;
>> + const struct remoteproc_cooling_ops *ops;
>> + void *devdata;
>> + struct mutex lock;
>> +};
>> +
>> +/* Thermal cooling device callbacks */
>> +
>> +static int remoteproc_get_max_state(struct thermal_cooling_device *cdev,
>> + unsigned long *state)
>> +{
>> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
>> + int ret;
>> +
>> + mutex_lock(&rproc_cdev->lock);
>> + ret = rproc_cdev->ops->get_max_level(rproc_cdev->devdata, state);
>> + mutex_unlock(&rproc_cdev->lock);
>> +
>> + return ret;
>> +}
>> +
>> +static int remoteproc_get_cur_state(struct thermal_cooling_device *cdev,
>> + unsigned long *state)
>> +{
>> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
>> + int ret;
>> +
>> + mutex_lock(&rproc_cdev->lock);
>> + ret = rproc_cdev->ops->get_cur_level(rproc_cdev->devdata, state);
>> + mutex_unlock(&rproc_cdev->lock);
>> +
>> + return ret;
>> +}
>> +
>> +static int remoteproc_set_cur_state(struct thermal_cooling_device *cdev,
>> + unsigned long state)
>> +{
>> + struct remoteproc_cdev *rproc_cdev = cdev->devdata;
>> + int ret;
>> +
>> + mutex_lock(&rproc_cdev->lock);
>> + ret = rproc_cdev->ops->set_cur_level(rproc_cdev->devdata, state);
>> + mutex_unlock(&rproc_cdev->lock);
>> +
>> + return ret;
>> +}
>> +
>> +static const struct thermal_cooling_device_ops remoteproc_cooling_ops = {
>> + .get_max_state = remoteproc_get_max_state,
>> + .get_cur_state = remoteproc_get_cur_state,
>> + .set_cur_state = remoteproc_set_cur_state,
>> +};
>> +
>> +struct remoteproc_cdev *
>> +remoteproc_cooling_register(struct device_node *np,
>> + const char *name, const struct remoteproc_cooling_ops *ops,
>> + void *devdata)
>> +{
>> + struct remoteproc_cdev *rproc_cdev;
>> + struct thermal_cooling_device *cdev;
>> + int ret;
>> +
>> + if (!name || !ops)
>> + return ERR_PTR(-EINVAL);
>> +
>> + rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL);
>> + if (!rproc_cdev)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + rproc_cdev->ops = ops;
>> + rproc_cdev->devdata = devdata;
>> + mutex_init(&rproc_cdev->lock);
>> +
>> + char *rproc_name __free(kfree) =
>> + kasprintf(GFP_KERNEL, REMOTEPROC_PREFIX "%s", name);
>> + /* Register with thermal framework */
>> + if (np)
>> + cdev = thermal_of_cooling_device_register(np, rproc_name, rproc_cdev,
>> + &remoteproc_cooling_ops);
>> + else
>> + cdev = thermal_cooling_device_register(rproc_name, rproc_cdev,
>> + &remoteproc_cooling_ops);
>> +
>> + if (IS_ERR(cdev)) {
>> + ret = PTR_ERR(cdev);
>> + goto free_rproc_cdev;
>> + }
>> +
>> + rproc_cdev->cdev = cdev;
>> +
>> + return rproc_cdev;
>> +
>> +free_rproc_cdev:
>> + kfree(rproc_cdev);
>> + return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(remoteproc_cooling_register);
>> +
>> +void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
>> +{
>> + if (!rproc_cdev)
>> + return;
>> +
>> + thermal_cooling_device_unregister(rproc_cdev->cdev);
>> + mutex_destroy(&rproc_cdev->lock);
>> + kfree(rproc_cdev);
>> +}
>> +EXPORT_SYMBOL_GPL(remoteproc_cooling_unregister);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_DESCRIPTION("Remote Processor Cooling Device");
>> diff --git a/include/linux/remoteproc_cooling.h b/include/linux/remoteproc_cooling.h
>> new file mode 100644
>> index 000000000000..721912d1a5ec
>> --- /dev/null
>> +++ b/include/linux/remoteproc_cooling.h
>> @@ -0,0 +1,52 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Remote Processor Cooling Device
>> + *
>> + * Copyright (c) 2025, Qualcomm Innovation Center
>> + */
>> +
>> +#ifndef __REMOTEPROC_COOLING_H__
>> +#define __REMOTEPROC_COOLING_H__
>> +
>> +#include <linux/thermal.h>
>> +
>> +struct device;
>> +struct device_node;
>> +
>> +struct remoteproc_cooling_ops {
>> + int (*get_max_level)(void *devdata, unsigned long *level);
>> + int (*get_cur_level)(void *devdata, unsigned long *level);
>> + int (*set_cur_level)(void *devdata, unsigned long level);
>> +};
>> +
>> +struct remoteproc_cdev;
>> +
>> +#ifdef CONFIG_REMOTEPROC_THERMAL
>> +
>> +struct remoteproc_cdev *
>> +remoteproc_cooling_register(struct device_node *np,
>> + const char *name,
>> + const struct remoteproc_cooling_ops *ops,
>> + void *devdata);
>> +
>> +void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev);
>> +
>> +#else /* !CONFIG_REMOTEPROC_THERMAL */
>> +
>> +static inline struct remoteproc_cdev *
>> +remoteproc_cooling_register(struct device_node *np,
>> + const char *name,
>> + const struct remoteproc_cooling_ops *ops,
>> + void *devdata)
>> +{
>> + return ERR_PTR(-EINVAL);
>> +}
>> +
>> +static inline void
>> +remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev)
>> +{
>> +}
>> +
>> +#endif /* CONFIG_REMOTEPROC_THERMAL */
>> +
>> +#endif /* __REMOTEPROC_COOLING_H__ */
>> --
>> 2.34.1
>>
>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver
2026-01-27 15:57 ` [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver Gaurav Kohli
2026-01-30 9:05 ` kernel test robot
2026-03-06 9:31 ` Daniel Lezcano
@ 2026-03-13 14:15 ` Daniel Lezcano
2026-03-17 7:25 ` Gaurav Kohli
2 siblings, 1 reply; 53+ messages in thread
From: Daniel Lezcano @ 2026-03-13 14:15 UTC (permalink / raw)
To: Gaurav Kohli
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Jan 27, 2026 at 09:27:18PM +0530, Gaurav Kohli wrote:
> From: Casey Connolly <casey.connolly@linaro.org>
>
> The Thermal Mitigation Device (TMD) service exposes various platform
> specific thermal mitigations available on remote subsystems (ie the
> modem and cdsp). The service is exposed via the QMI messaging
> interface, usually over the QRTR transport.
>
> Qualcomm QMI-based TMD cooling devices are used to mitigate thermal
> conditions across multiple remote subsystems. These devices operate
> based on junction temperature sensors (TSENS) associated with thermal
> zones for each subsystem.
>
> Co-developed-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
> Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
> ---
> drivers/soc/qcom/Kconfig | 13 +
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/qmi-cooling.c | 510 +++++++++++++++++++++++++++++++++
> drivers/soc/qcom/qmi-cooling.h | 429 +++++++++++++++++++++++++++
> 4 files changed, 953 insertions(+)
> create mode 100644 drivers/soc/qcom/qmi-cooling.c
> create mode 100644 drivers/soc/qcom/qmi-cooling.h
>
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 2caadbbcf830..905a24b42fe6 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -124,6 +124,19 @@ config QCOM_PMIC_GLINK
> Say yes here to support USB-C and battery status on modern Qualcomm
> platforms.
>
> +config QCOM_QMI_COOLING
> + tristate "Qualcomm QMI cooling drivers"
> + depends on QCOM_RPROC_COMMON
> + depends on ARCH_QCOM || COMPILE_TEST
> + select QCOM_QMI_HELPERS
> + help
> + This enables the remote subsystem cooling devices. These cooling
> + devices will be used by Qualcomm chipset to place various remote
> + subsystem mitigations like remote processor passive mitigation,
> + remote subsystem voltage restriction at low temperatures etc.
> + The QMI cooling device will interface with remote subsystem
0> + using Qualcomm remoteproc interface.
> +
> config QCOM_QMI_HELPERS
> tristate
> depends on NET
> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
> index b7f1d2a57367..b6728f54944b 100644
> --- a/drivers/soc/qcom/Makefile
> +++ b/drivers/soc/qcom/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
> obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
> obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o
> CFLAGS_pmic_pdcharger_ulog.o := -I$(src)
> +obj-$(CONFIG_QCOM_QMI_COOLING) += qmi-cooling.o
> obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
> qmi_helpers-y += qmi_encdec.o qmi_interface.o
> obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o
> diff --git a/drivers/soc/qcom/qmi-cooling.c b/drivers/soc/qcom/qmi-cooling.c
> new file mode 100644
> index 000000000000..463baa47c8b6
> --- /dev/null
> +++ b/drivers/soc/qcom/qmi-cooling.c
> @@ -0,0 +1,510 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2017, The Linux Foundation
Why this copyright ? The file is from scratch
> + * Copyright (c) 2025, Linaro Limited
Missing copyright: Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + * QMI Thermal Mitigation Device (TMD) client driver.
> + * This driver provides an in-kernel client to handle hot and cold thermal
> + * mitigations for remote subsystems (modem and DSPs) running the TMD service.
> + * It doesn't implement any handling of reports from remote subsystems.
> + */
> +
> +#include <linux/cleanup.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/net.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/remoteproc/qcom_rproc.h>
> +#include <linux/remoteproc_cooling.h>
> +#include <linux/slab.h>
> +#include <linux/soc/qcom/qmi.h>
> +#include <linux/thermal.h>
> +
> +#include "qmi-cooling.h"
> +
> +#define CDSP_INSTANCE_ID 0x43
> +#define CDSP1_INSTANCE_ID 0x44
> +
> +#define QMI_TMD_RESP_TIMEOUT msecs_to_jiffies(100)
Seems to me a really long duration for a timeout when doing
mitigation. Would it make sense to reduce it ?
> +/**
> + * struct qmi_tmd_client - TMD client state
> + * @dev: Device associated with this client
> + * @name: Friendly name for the remote TMD service
> + * @handle: QMI connection handle
> + * @mutex: Lock to synchronise QMI communication
> + * @id: The QMI TMD service instance ID
> + * @cdev_list: The list of cooling devices (controls) enabled for this instance
> + * @svc_arrive_work: Work item for initialising the client when the TMD service
> + * starts.
> + * @connection_active: Whether or not we're connected to the QMI TMD service
> + */
> +struct qmi_tmd_client {
> + struct device *dev;
> + const char *name;
> + struct qmi_handle handle;
> + struct mutex mutex;
Can you explain why this lock is needed? What race condition is it fixing?
> + u32 id;
So 'dev', 'id' and 'name' are only there to print an error message, right?
IMO, we can get rid of them.
> + struct list_head cdev_list;
> + struct work_struct svc_arrive_work;
> + bool connection_active;
IMO this boolean is not needed.
- connection_active is checked in the function 'set_cur_state'.
If the function is called is because the cooling device is
registered. The only place where it is set to false again is when the
cleanup is called. But if the cooling devices are unregistered before,
there is no reason why 'set_cur_state' to be called in the next steps
of the cleanup.
What remain unclear is in case of a peer reset, if del/new is called
before reset. But in such case, the request through QMI will result in
a error which should be handled in this driver.
> +};
> +
> +/**
> + * struct qmi_tmd - A TMD cooling device
> + * @np: OF node associated with this control
Why needed ?
> + * @type: The control type (exposed via sysfs)
Duplicate with the cooling device name
> + * @qmi_name: The common name of this control shared by the remote subsystem
> + * @rproc_cdev: Remote processor cooling device handle
> + * @cur_state: The current cooling/warming/mitigation state
> + * @max_state: The maximum state
> + * @client: The TMD client instance this control is associated with
> + */
> +struct qmi_tmd {
> + struct device_node *np;
> + const char *type;
> + char qmi_name[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1];
const char * and use devm_kstrdup() instead
> + struct list_head node;
> + struct remoteproc_cdev *rproc_cdev;
> + unsigned int cur_state;
> + unsigned int max_state;
max_state can be removed (see comment below in the get_max_state() ops)
> + struct qmi_tmd_client *client;
> +};
This structure can be simplified (refer to comments below in the code)
> +/**
> + * struct qmi_instance_id - QMI instance match data
> + * @id: The QMI instance ID
> + * @name: Friendly name for this instance
> + */
> +struct qmi_instance_data {
> + u32 id;
> + const char *name;
> +};
If I'm not wrong, this structure is only used to pass information to
print debug information ?
> +
> +/* Notify the remote subsystem of the requested cooling state */
> +static int qmi_tmd_send_state_request(struct qmi_tmd *tmd)
> +{
> + struct tmd_set_mitigation_level_resp_msg_v01 tmd_resp = { 0 };
> + struct tmd_set_mitigation_level_req_msg_v01 req = { 0 };
Please shortened these structure name. It is unreadable. May be you
can do something like:
struct tmd_set_level_msg {
int level;
union {
struct qmi_response_type_v01 resp;
char mitigation_dev_id[...];
};
}
I know the other QMI services are implemented in the same way but it
may be worth to simplify the message format instead of wrapping that
into structures again and again.
> + struct qmi_tmd_client *client;
> + struct qmi_txn txn;
> + int ret = 0;
> +
> + client = tmd->client;
> +
> + guard(mutex)(&client->mutex);
> +
> + /*
> + * This function is called by qmi_set_cur_state() which does not know if
> + * the QMI service is actually online. If it isn't then we noop here.
> + * The state is cached in tmd->cur_state and will be broadcast via
> + * qmi_tmd_init_control() when the service comes up.
> + */
> + if (!client->connection_active)
> + return 0;
> +
> + strscpy(req.mitigation_dev_id.mitigation_dev_id, tmd->qmi_name,
> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
> + req.mitigation_level = tmd->cur_state;
> +
> + ret = qmi_txn_init(&client->handle, &txn,
> + tmd_set_mitigation_level_resp_msg_v01_ei, &tmd_resp);
> + if (ret < 0) {
> + dev_err(client->dev, "qmi set state %d txn init failed for %s ret %d\n",
> + tmd->cur_state, tmd->type, ret);
> + return ret;
> + }
> +
> + ret = qmi_send_request(&client->handle, NULL, &txn,
> + QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01,
> + TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN,
> + tmd_set_mitigation_level_req_msg_v01_ei, &req);
> + if (ret < 0) {
> + dev_err(client->dev, "qmi set state %d txn send failed for %s ret %d\n",
> + tmd->cur_state, tmd->type, ret);
> + qmi_txn_cancel(&txn);
> + return ret;
> + }
> +
> + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
> + if (ret < 0) {
> + dev_err(client->dev, "qmi set state %d txn wait failed for %s ret %d\n",
> + tmd->cur_state, tmd->type, ret);
> + return ret;
> + }
> +
> + if (tmd_resp.resp.result != QMI_RESULT_SUCCESS_V01) {
> + ret = -tmd_resp.resp.result;
Is this result an errno error or a QMI error?
> + dev_err(client->dev, "qmi set state %d NOT success for %s ret %d\n",
> + tmd->cur_state, tmd->type, ret);
> + return ret;
> + }
> +
> + dev_dbg(client->dev, "Requested state %d/%d for %s\n", tmd->cur_state,
> + tmd->max_state, tmd->type);
> +
> + return 0;
> +}
> +
> +static int qmi_get_max_level(void *devdata, unsigned long *level)
> +{
> + struct qmi_tmd *tmd = devdata;
> +
> + if (!tmd)
> + return -EINVAL;
> +
> + *level = tmd->max_state;
> +
> + return 0;
> +}
The get_max_state() is called in two places. When registering the
cooling device and when updating the cooling device. The first one is
called one time and the second one is called when there is an event
like switching the battery mode (ACPI only). Each of them updates the
cdev->max_state field. Otherwise the get_max_state() is not used but
cdev->max_state.
The code above should call the QMI to get the max
level. tmd->max_state could be then removed.
I agree there are other cooling devices doing that but I don't think
it is correct.
> +static int qmi_get_cur_level(void *devdata, unsigned long *level)
> +{
> + struct qmi_tmd *tmd = devdata;
> +
> + if (!tmd)
> + return -EINVAL;
> +
We should assume the core is doing the right thing. So if we
registered the cooling device with the private data, then it should
return it back. If not, then it is a fatal bug crashing the system
which should have been spotted when doing some testing.
> + *level = tmd->cur_state;
> +
> + return 0;
> +}
> +
> +static int qmi_set_cur_level(void *devdata, unsigned long level)
> +{
> + struct qmi_tmd *tmd = devdata;
> +
> + if (!tmd)
> + return -EINVAL;
idem
> + if (level > tmd->max_state)
> + return -EINVAL;
It is already handled in the core code.
> + if (tmd->cur_state == level)
> + return 0;
>
> + tmd->cur_state = level;
> +
> + return qmi_tmd_send_state_request(tmd);
The command should succeed before updating 'cur_state'. So first the
call to qmi_tmd_send_state_request() and if it is ok, then set the
current state. So it means you can pass the state as parameter to
qmi_set_cur_level() which in this case not rely on the caller to set
the tmd->cur_state before calling the function.
> +}
> +
> +static const struct remoteproc_cooling_ops qmi_rproc_ops = {
> + .get_max_level = qmi_get_max_level,
> + .get_cur_level = qmi_get_cur_level,
> + .set_cur_level = qmi_set_cur_level,
> +};
As commented before, the remoteproc cooling device does not really
provide a benefit, so those ops can be converted into cooling device
ops.
[ ... ]
> +/*
> + * Init a single TMD control by registering a cooling device for it, or
> + * synchronising state with the remote subsystem if recovering from a service
> + * restart. This is called when the TMD service starts up.
> + */
> +static int qmi_tmd_init_control(struct qmi_tmd_client *client, const char *label,
> + u8 max_state)
> +{
> + struct qmi_tmd *tmd = NULL;
> +
> + list_for_each_entry(tmd, &client->cdev_list, node)
> + if (!strncasecmp(tmd->qmi_name, label,
> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1))
> + goto found;
> +
> + dev_dbg(client->dev,
> + "TMD '%s' available in firmware but not specified in DT\n",
> + label);
> + return 0;
> +
> +found:
> + tmd->max_state = max_state;
> + /*
> + * If the cooling device already exists then the QMI service went away and
> + * came back. So just make sure the current cooling device state is
> + * reflected on the remote side and then return.
> + */
> + if (tmd->rproc_cdev)
> + return qmi_tmd_send_state_request(tmd);
> +
> + return qmi_register_cooling_device(tmd);
> +}
> +
> +/*
> + * When the QMI service starts up on a remote subsystem this function will fetch
> + * the list of TMDs on the subsystem, match it to the TMDs specified in devicetree
> + * and call qmi_tmd_init_control() for each
> + */
> +static void qmi_tmd_svc_arrive(struct work_struct *work)
> +{
> + struct qmi_tmd_client *client =
> + container_of(work, struct qmi_tmd_client, svc_arrive_work);
> +
> + struct tmd_get_mitigation_device_list_req_msg_v01 req = { 0 };
> + struct tmd_get_mitigation_device_list_resp_msg_v01 *resp __free(kfree) = NULL;
> + int ret = 0, i;
> + struct qmi_txn txn;
> +
> + /* resp struct is 1.1kB, allocate it on the heap. */
> + resp = kzalloc(sizeof(*resp), GFP_KERNEL);
> + if (!resp)
> + return;
> +
> + /* Get a list of TMDs supported by the remoteproc */
> + scoped_guard(mutex, &client->mutex) {
> + ret = qmi_txn_init(&client->handle, &txn,
> + tmd_get_mitigation_device_list_resp_msg_v01_ei, resp);
> + if (ret < 0) {
> + dev_err(client->dev,
> + "Transaction init error for instance_id: %#x ret %d\n",
> + client->id, ret);
> + return;
> + }
> +
> + ret = qmi_send_request(&client->handle, NULL, &txn,
> + QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01,
> + TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN,
> + tmd_get_mitigation_device_list_req_msg_v01_ei, &req);
> + if (ret < 0) {
> + qmi_txn_cancel(&txn);
> + return;
> + }
> +
> + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
> + if (ret < 0) {
> + dev_err(client->dev, "Transaction wait error for client %#x ret:%d\n",
> + client->id, ret);
> + return;
> + }
> + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
> + ret = resp->resp.result;
> + dev_err(client->dev, "Failed to get device list for client %#x ret:%d\n",
> + client->id, ret);
> + return;
> + }
> +
> + client->connection_active = true;
> + }
> +
> + for (i = 0; i < resp->mitigation_device_list_len; i++) {
> + struct tmd_mitigation_dev_list_type_v01 *device =
> + &resp->mitigation_device_list[i];
> +
> + ret = qmi_tmd_init_control(client,
> + device->mitigation_dev_id.mitigation_dev_id,
> + device->max_mitigation_level);
> + if (ret)
> + break;
> + }
> +}
> +
> +static void thermal_qmi_net_reset(struct qmi_handle *qmi)
> +{
> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
> + struct qmi_tmd *tmd = NULL;
> +
> + list_for_each_entry(tmd, &client->cdev_list, node) {
> + qmi_tmd_send_state_request(tmd);
> + }
> +}
> +
> +static void thermal_qmi_del_server(struct qmi_handle *qmi, struct qmi_service *service)
> +{
> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
> +
> + scoped_guard(mutex, &client->mutex)
> + client->connection_active = false;
> +}
> +
> +static int thermal_qmi_new_server(struct qmi_handle *qmi, struct qmi_service *service)
> +{
> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
> + struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port };
> +
> + scoped_guard(mutex, &client->mutex)
> + kernel_connect(qmi->sock, (struct sockaddr_unsized *)&sq, sizeof(sq), 0);
> +
> + queue_work(system_highpri_wq, &client->svc_arrive_work);
> +
> + return 0;
> +}
> +
> +static const struct qmi_ops thermal_qmi_event_ops = {
> + .new_server = thermal_qmi_new_server,
> + .del_server = thermal_qmi_del_server,
> + .net_reset = thermal_qmi_net_reset,
> +};
> +
> +static void qmi_tmd_cleanup(struct qmi_tmd_client *client)
> +{
> + struct qmi_tmd *tmd, *c_next;
> +
> + guard(mutex)(&client->mutex);
> +
> + client->connection_active = false;
> +
> + qmi_handle_release(&client->handle);
> + cancel_work(&client->svc_arrive_work);
> + list_for_each_entry_safe(tmd, c_next, &client->cdev_list, node) {
> + if (tmd->rproc_cdev)
> + remoteproc_cooling_unregister(tmd->rproc_cdev);
> +
> + list_del(&tmd->node);
> + }
> +}
> +
> +/* Parse the controls and allocate a qmi_tmd for each of them */
> +static int qmi_tmd_alloc_cdevs(struct qmi_tmd_client *client)
> +{
> + struct device *dev = client->dev;
> + struct device_node *node = dev->of_node;
> + struct device_node *subnode;
> + struct qmi_tmd *tmd;
> + int ret;
> +
> + for_each_available_child_of_node_scoped(node, subnode) {
> + const char *name;
Ok, I think there are already a lot of comments about the code. I'll
skip the DTpart review in this patch and jump to the DT bindings.
> + tmd = devm_kzalloc(dev, sizeof(*tmd), GFP_KERNEL);
> + if (!tmd)
> + return dev_err_probe(client->dev, -ENOMEM,
> + "Couldn't allocate tmd\n");
Usually we do not return an error message when an allocation fails
because the mem mngt code does already that. So I would replace it
with a simple return -ENOMEM
> +
> + tmd->type = devm_kasprintf(client->dev, GFP_KERNEL, "%s",
> + subnode->name);
devm_kstrdup()
> + if (!tmd->type)
> + return dev_err_probe(dev, -ENOMEM,
> + "Couldn't allocate cooling device name\n");
> +
> + if (of_property_read_string(subnode, "label", &name))
> + return dev_err_probe(client->dev, -EINVAL,
> + "Failed to parse dev name for %s\n",
> + subnode->name);
> +
> + ret = strscpy(tmd->qmi_name, name,
> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
devm_kstrdup()
> + if (ret == -E2BIG)
> + return dev_err_probe(dev, -EINVAL, "TMD label %s is too long\n",
> + name);
> +
> + tmd->client = client;
> + tmd->np = subnode;
Why is it needed? I don't see it used anywhere
> + tmd->cur_state = 0;
> + list_add(&tmd->node, &client->cdev_list);
> + }
> +
> + if (list_empty(&client->cdev_list))
> + return dev_err_probe(client->dev, -EINVAL,
> + "No cooling devices specified for client %s (%#x)\n",
> + client->name, client->id);
> +
> + return 0;
> +}
> +
> +static int qmi_tmd_client_probe(struct platform_device *pdev)
> +{
> + const struct qmi_instance_data *match;
> + struct qmi_tmd_client *client;
> + struct device *dev = &pdev->dev;
> + int ret;
> +
> + client = devm_kzalloc(dev, sizeof(*client), GFP_KERNEL);
> + if (!client)
> + return -ENOMEM;
> +
> + client->dev = dev;
> +
> + match = of_device_get_match_data(dev);
> + if (!match)
> + return dev_err_probe(dev, -EINVAL, "No match data\n");
> +
> + client->id = match->id;
> + client->name = match->name;
> +
> + mutex_init(&client->mutex);
> + INIT_LIST_HEAD(&client->cdev_list);
> + INIT_WORK(&client->svc_arrive_work, qmi_tmd_svc_arrive);
> +
> + ret = qmi_tmd_alloc_cdevs(client);
> + if (ret)
> + return ret;
> +
> + platform_set_drvdata(pdev, client);
> +
> + ret = qmi_handle_init(&client->handle,
> + TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN,
> + &thermal_qmi_event_ops, NULL);
> + if (ret < 0)
> + return dev_err_probe(client->dev, ret, "QMI handle init failed for client %#x\n",
> + client->id);
> +
> + ret = qmi_add_lookup(&client->handle, TMD_SERVICE_ID_V01, TMD_SERVICE_VERS_V01,
> + client->id);
> + if (ret < 0) {
> + qmi_handle_release(&client->handle);
> + return dev_err_probe(client->dev, ret, "QMI register failed for client 0x%x\n",
> + client->id);
> + }
> +
> + return 0;
> +}
> +
> +static void qmi_tmd_client_remove(struct platform_device *pdev)
> +{
> + struct qmi_tmd_client *client = platform_get_drvdata(pdev);
> +
> + qmi_tmd_cleanup(client);
> +}
> +
> +static const struct qmi_instance_data qmi_cdsp = {
> + .id = CDSP_INSTANCE_ID,
> + .name = "cdsp",
> +};
> +
> +static const struct qmi_instance_data qmi_cdsp1 = {
> + .id = CDSP1_INSTANCE_ID,
> + .name = "cdsp1",
> +};
> +
> +static const struct of_device_id qmi_tmd_device_table[] = {
> + {
> + .compatible = "qcom,qmi-cooling-cdsp",
> + .data = &qmi_cdsp,
> + },
> + {
> + .compatible = "qcom,qmi-cooling-cdsp1",
> + .data = &qmi_cdsp1,
> + },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, qmi_tmd_device_table);
> +
> +static struct platform_driver qmi_tmd_device_driver = {
> + .probe = qmi_tmd_client_probe,
> + .remove = qmi_tmd_client_remove,
> + .driver = {
> + .name = "qcom-qmi-cooling",
> + .of_match_table = qmi_tmd_device_table,
> + },
> +};
> +
> +module_platform_driver(qmi_tmd_device_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Qualcomm QMI Thermal Mitigation Device driver");
> diff --git a/drivers/soc/qcom/qmi-cooling.h b/drivers/soc/qcom/qmi-cooling.h
> new file mode 100644
> index 000000000000..e33f4c5979e5
> --- /dev/null
> +++ b/drivers/soc/qcom/qmi-cooling.h
> @@ -0,0 +1,429 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2017, The Linux Foundation
> + * Copyright (c) 2023, Linaro Limited
> + */
> +
> +#ifndef __QCOM_COOLING_H__
> +#define __QCOM_COOLING_H__
I'm not sure we want to export all these macros, structure. It could
be contained into a .c file.
> +#include <linux/soc/qcom/qmi.h>
> +
> +#define TMD_SERVICE_ID_V01 0x18
IMO, this definition should go inside qmi.h
See https://lore.kernel.org/all/20260309230346.3584252-1-daniel.lezcano@oss.qualcomm.com/
> +#define TMD_SERVICE_VERS_V01 0x01
> +
> +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_RESP_V01 0x0020
> +#define QMI_TMD_GET_MITIGATION_LEVEL_REQ_V01 0x0022
> +#define QMI_TMD_GET_SUPPORTED_MSGS_REQ_V01 0x001E
> +#define QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01 0x0021
> +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0023
> +#define QMI_TMD_GET_SUPPORTED_MSGS_RESP_V01 0x001E
> +#define QMI_TMD_SET_MITIGATION_LEVEL_RESP_V01 0x0021
> +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0024
> +#define QMI_TMD_MITIGATION_LEVEL_REPORT_IND_V01 0x0025
> +#define QMI_TMD_GET_MITIGATION_LEVEL_RESP_V01 0x0022
> +#define QMI_TMD_GET_SUPPORTED_FIELDS_REQ_V01 0x001F
> +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01 0x0020
> +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0023
> +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0024
> +#define QMI_TMD_GET_SUPPORTED_FIELDS_RESP_V01 0x001F
> +
> +#define QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 32
> +#define QMI_TMD_MITIGATION_DEV_LIST_MAX_V01 32
Having self explainatory names for the macros is good but somehow
these should be shortened because they are too long and do not help
for the readability when they are used.
Perhaps, add a documentation in the code with the corresponding
structure vs their name.
[ ... ]
> +struct tmd_get_mitigation_device_list_req_msg_v01 {
> + char placeholder;
> +};
> +
> +#define TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN 0.
Where are these macro used ? And why are they needed ?
> +const struct qmi_elem_info tmd_get_mitigation_device_list_req_msg_v01_ei[] = {
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_get_mitigation_device_list_resp_msg_v01 {
> + struct qmi_response_type_v01 resp;
> + u8 mitigation_device_list_valid;
> + u32 mitigation_device_list_len;
> + struct tmd_mitigation_dev_list_type_v01
> + mitigation_device_list[QMI_TMD_MITIGATION_DEV_LIST_MAX_V01];
> +};
> +
> +#define TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN 1099
> +static const struct qmi_elem_info tmd_get_mitigation_device_list_resp_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
> + resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_OPT_FLAG,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
> + mitigation_device_list_valid),
> + },
> + {
> + .data_type = QMI_DATA_LEN,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
> + mitigation_device_list_len),
> + },
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = QMI_TMD_MITIGATION_DEV_LIST_MAX_V01,
> + .elem_size = sizeof(struct tmd_mitigation_dev_list_type_v01),
> + .array_type = VAR_LEN_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
> + mitigation_device_list),
> + .ei_array = tmd_mitigation_dev_list_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_set_mitigation_level_req_msg_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id;
> + u8 mitigation_level;
> +};
> +
> +#define TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 40
> +static const struct qmi_elem_info tmd_set_mitigation_level_req_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01,
> + mitigation_dev_id),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01,
> + mitigation_level),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_set_mitigation_level_resp_msg_v01 {
> + struct qmi_response_type_v01 resp;
> +};
> +
> +#define TMD_SET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
> +static const struct qmi_elem_info tmd_set_mitigation_level_resp_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_set_mitigation_level_resp_msg_v01, resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_get_mitigation_level_req_msg_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
> +};
> +
> +#define TMD_GET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
> +
> +static const struct qmi_elem_info tmd_get_mitigation_level_req_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(struct tmd_get_mitigation_level_req_msg_v01,
> + mitigation_device),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_get_mitigation_level_resp_msg_v01 {
> + struct qmi_response_type_v01 resp;
> + u8 current_mitigation_level_valid;
> + u8 current_mitigation_level;
> + u8 requested_mitigation_level_valid;
> + u8 requested_mitigation_level;
> +};
> +
> +#define TMD_GET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 15
> +static const struct qmi_elem_info tmd_get_mitigation_level_resp_msg_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01, resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_OPT_FLAG,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
> + current_mitigation_level_valid),
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x10,
> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
> + current_mitigation_level),
> + },
> + {
> + .data_type = QMI_OPT_FLAG,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x11,
> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
> + requested_mitigation_level_valid),
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x11,
> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
> + requested_mitigation_level),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +struct tmd_register_notification_mitigation_level_req_msg_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
> +};
> +
> +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
> +static const struct qmi_elem_info
> + tmd_register_notification_mitigation_level_req_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(
> + struct tmd_register_notification_mitigation_level_req_msg_v01,
> + mitigation_device),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> + };
> +
> +struct tmd_register_notification_mitigation_level_resp_msg_v01 {
> + struct qmi_response_type_v01 resp;
> +};
> +
> +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
> +static const struct qmi_elem_info
> + tmd_register_notification_mitigation_level_resp_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(
> + struct tmd_register_notification_mitigation_level_resp_msg_v01,
> + resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> + };
> +
> +struct tmd_deregister_notification_mitigation_level_req_msg_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
> +};
> +
> +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
> +static const struct qmi_elem_info
> + tmd_deregister_notification_mitigation_level_req_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(
> + struct tmd_deregister_notification_mitigation_level_req_msg_v01,
> + mitigation_device),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> + };
> +
> +struct tmd_deregister_notification_mitigation_level_resp_msg_v01 {
> + struct qmi_response_type_v01 resp;
> +};
> +
> +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
> +static const struct qmi_elem_info
> + tmd_deregister_notification_mitigation_level_resp_msg_v01_ei[] = {
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct qmi_response_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(
> + struct tmd_deregister_notification_mitigation_level_resp_msg_v01,
> + resp),
> + .ei_array = qmi_response_type_v01_ei,
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> + };
> +
> +struct tmd_mitigation_level_report_ind_msg_v01 {
> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
> + u8 current_mitigation_level;
> +};
> +
> +#define TMD_MITIGATION_LEVEL_REPORT_IND_MSG_V01_MAX_MSG_LEN 40
> +static const struct qmi_elem_info tmd_mitigation_level_report_ind_msg_v01_ei[] = {
Where is used this variable ?
> + {
> + .data_type = QMI_STRUCT,
> + .elem_len = 1,
> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x01,
> + .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01,
> + mitigation_device),
> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
> + },
> + {
> + .data_type = QMI_UNSIGNED_1_BYTE,
> + .elem_len = 1,
> + .elem_size = sizeof(uint8_t),
> + .array_type = NO_ARRAY,
> + .tlv_type = 0x02,
> + .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01,
> + current_mitigation_level),
> + },
> + {
> + .data_type = QMI_EOTI,
> + .array_type = NO_ARRAY,
> + .tlv_type = QMI_COMMON_TLV_TYPE,
> + },
> +};
> +
> +#endif /* __QMI_COOLING_INTERNAL_H__ */
> --
> 2.34.1
>
--
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver
2026-03-06 9:31 ` Daniel Lezcano
@ 2026-03-16 10:19 ` Gaurav Kohli
0 siblings, 0 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-03-16 10:19 UTC (permalink / raw)
To: Daniel Lezcano
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 3/6/2026 3:01 PM, Daniel Lezcano wrote:
> On Tue, Jan 27, 2026 at 09:27:18PM +0530, Gaurav Kohli wrote:
>> From: Casey Connolly <casey.connolly@linaro.org>
>>
>> The Thermal Mitigation Device (TMD) service exposes various platform
>> specific thermal mitigations available on remote subsystems (ie the
>> modem and cdsp). The service is exposed via the QMI messaging
>> interface, usually over the QRTR transport.
>>
>> Qualcomm QMI-based TMD cooling devices are used to mitigate thermal
>> conditions across multiple remote subsystems. These devices operate
>> based on junction temperature sensors (TSENS) associated with thermal
>> zones for each subsystem.
>
> IIUC, QMI is the messaging mechanism for remote proc. TMD is the cooling device.
>
> If it is correct, I suggest to follow the following organisation:
>
> - tmd_interface.c (qmi <-> tmd)
> - tmd_cooling.c (tmd <-> thermal framework)
>
> So we end up with:
>
> qmi_interface -> tmd_interface -> tmd_cooling
>
Thanks Daniel for review.
As discussed, I will make the changes as per the suggested partitions.
> AFAICT, it is similar with the pdr_interface, right ?
>
>> Co-developed-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
>> ---
>> drivers/soc/qcom/Kconfig | 13 +
>> drivers/soc/qcom/Makefile | 1 +
>> drivers/soc/qcom/qmi-cooling.c | 510 +++++++++++++++++++++++++++++++++
>> drivers/soc/qcom/qmi-cooling.h | 429 +++++++++++++++++++++++++++
>> 4 files changed, 953 insertions(+)
>> create mode 100644 drivers/soc/qcom/qmi-cooling.c
>> create mode 100644 drivers/soc/qcom/qmi-cooling.h
>>
>> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
>> index 2caadbbcf830..905a24b42fe6 100644
>> --- a/drivers/soc/qcom/Kconfig
>> +++ b/drivers/soc/qcom/Kconfig
>> @@ -124,6 +124,19 @@ config QCOM_PMIC_GLINK
>> Say yes here to support USB-C and battery status on modern Qualcomm
>> platforms.
>>
>> +config QCOM_QMI_COOLING
>> + tristate "Qualcomm QMI cooling drivers"
>> + depends on QCOM_RPROC_COMMON
>> + depends on ARCH_QCOM || COMPILE_TEST
>> + select QCOM_QMI_HELPERS
>> + help
>> + This enables the remote subsystem cooling devices. These cooling
>> + devices will be used by Qualcomm chipset to place various remote
>> + subsystem mitigations like remote processor passive mitigation,
>> + remote subsystem voltage restriction at low temperatures etc.
>> + The QMI cooling device will interface with remote subsystem
>> + using Qualcomm remoteproc interface.
>> +
>> config QCOM_QMI_HELPERS
>> tristate
>> depends on NET
>> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
>> index b7f1d2a57367..b6728f54944b 100644
>> --- a/drivers/soc/qcom/Makefile
>> +++ b/drivers/soc/qcom/Makefile
>> @@ -14,6 +14,7 @@ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
>> obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
>> obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o
>> CFLAGS_pmic_pdcharger_ulog.o := -I$(src)
>> +obj-$(CONFIG_QCOM_QMI_COOLING) += qmi-cooling.o
>> obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
>> qmi_helpers-y += qmi_encdec.o qmi_interface.o
>> obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o
>> diff --git a/drivers/soc/qcom/qmi-cooling.c b/drivers/soc/qcom/qmi-cooling.c
>> new file mode 100644
>> index 000000000000..463baa47c8b6
>> --- /dev/null
>> +++ b/drivers/soc/qcom/qmi-cooling.c
>> @@ -0,0 +1,510 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2017, The Linux Foundation
>> + * Copyright (c) 2025, Linaro Limited
>> + *
>> + * QMI Thermal Mitigation Device (TMD) client driver.
>> + * This driver provides an in-kernel client to handle hot and cold thermal
>> + * mitigations for remote subsystems (modem and DSPs) running the TMD service.
>> + * It doesn't implement any handling of reports from remote subsystems.
>> + */
>> +
>> +#include <linux/cleanup.h>
>> +#include <linux/err.h>
>> +#include <linux/module.h>
>> +#include <linux/net.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/remoteproc/qcom_rproc.h>
>> +#include <linux/remoteproc_cooling.h>
>> +#include <linux/slab.h>
>> +#include <linux/soc/qcom/qmi.h>
>> +#include <linux/thermal.h>
>> +
>> +#include "qmi-cooling.h"
>> +
>> +#define CDSP_INSTANCE_ID 0x43
>> +#define CDSP1_INSTANCE_ID 0x44
>> +
>> +#define QMI_TMD_RESP_TIMEOUT msecs_to_jiffies(100)
>> +
>> +/**
>> + * struct qmi_tmd_client - TMD client state
>> + * @dev: Device associated with this client
>> + * @name: Friendly name for the remote TMD service
>> + * @handle: QMI connection handle
>> + * @mutex: Lock to synchronise QMI communication
>> + * @id: The QMI TMD service instance ID
>> + * @cdev_list: The list of cooling devices (controls) enabled for this instance
>> + * @svc_arrive_work: Work item for initialising the client when the TMD service
>> + * starts.
>> + * @connection_active: Whether or not we're connected to the QMI TMD service
>> + */
>> +struct qmi_tmd_client {
>> + struct device *dev;
>> + const char *name;
>> + struct qmi_handle handle;
>> + struct mutex mutex;
>> + u32 id;
>> + struct list_head cdev_list;
>> + struct work_struct svc_arrive_work;
>> + bool connection_active;
>> +};
>> +
>> +/**
>> + * struct qmi_tmd - A TMD cooling device
>> + * @np: OF node associated with this control
>> + * @type: The control type (exposed via sysfs)
>> + * @qmi_name: The common name of this control shared by the remote subsystem
>> + * @rproc_cdev: Remote processor cooling device handle
>> + * @cur_state: The current cooling/warming/mitigation state
>> + * @max_state: The maximum state
>> + * @client: The TMD client instance this control is associated with
>> + */
>> +struct qmi_tmd {
>> + struct device_node *np;
>> + const char *type;
>> + char qmi_name[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1];
>> + struct list_head node;
>> + struct remoteproc_cdev *rproc_cdev;
>> + unsigned int cur_state;
>> + unsigned int max_state;
>> + struct qmi_tmd_client *client;
>> +};
>> +
>> +/**
>> + * struct qmi_instance_id - QMI instance match data
>> + * @id: The QMI instance ID
>> + * @name: Friendly name for this instance
>> + */
>> +struct qmi_instance_data {
>> + u32 id;
>> + const char *name;
>> +};
>> +
>> +/* Notify the remote subsystem of the requested cooling state */
>> +static int qmi_tmd_send_state_request(struct qmi_tmd *tmd)
>> +{
>> + struct tmd_set_mitigation_level_resp_msg_v01 tmd_resp = { 0 };
>> + struct tmd_set_mitigation_level_req_msg_v01 req = { 0 };
>> + struct qmi_tmd_client *client;
>> + struct qmi_txn txn;
>> + int ret = 0;
>> +
>> + client = tmd->client;
>> +
>> + guard(mutex)(&client->mutex);
>> +
>> + /*
>> + * This function is called by qmi_set_cur_state() which does not know if
>> + * the QMI service is actually online. If it isn't then we noop here.
>> + * The state is cached in tmd->cur_state and will be broadcast via
>> + * qmi_tmd_init_control() when the service comes up.
>> + */
>> + if (!client->connection_active)
>> + return 0;
>> +
>> + strscpy(req.mitigation_dev_id.mitigation_dev_id, tmd->qmi_name,
>> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
>> + req.mitigation_level = tmd->cur_state;
>> +
>> + ret = qmi_txn_init(&client->handle, &txn,
>> + tmd_set_mitigation_level_resp_msg_v01_ei, &tmd_resp);
>> + if (ret < 0) {
>> + dev_err(client->dev, "qmi set state %d txn init failed for %s ret %d\n",
>> + tmd->cur_state, tmd->type, ret);
>> + return ret;
>> + }
>> +
>> + ret = qmi_send_request(&client->handle, NULL, &txn,
>> + QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01,
>> + TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN,
>> + tmd_set_mitigation_level_req_msg_v01_ei, &req);
>> + if (ret < 0) {
>> + dev_err(client->dev, "qmi set state %d txn send failed for %s ret %d\n",
>> + tmd->cur_state, tmd->type, ret);
>> + qmi_txn_cancel(&txn);
>> + return ret;
>> + }
>> +
>> + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
>> + if (ret < 0) {
>> + dev_err(client->dev, "qmi set state %d txn wait failed for %s ret %d\n",
>> + tmd->cur_state, tmd->type, ret);
>> + return ret;
>> + }
>> +
>> + if (tmd_resp.resp.result != QMI_RESULT_SUCCESS_V01) {
>> + ret = -tmd_resp.resp.result;
>> + dev_err(client->dev, "qmi set state %d NOT success for %s ret %d\n",
>> + tmd->cur_state, tmd->type, ret);
>> + return ret;
>> + }
>> +
>> + dev_dbg(client->dev, "Requested state %d/%d for %s\n", tmd->cur_state,
>> + tmd->max_state, tmd->type);
>> +
>> + return 0;
>> +}
>> +
>> +static int qmi_get_max_level(void *devdata, unsigned long *level)
>> +{
>> + struct qmi_tmd *tmd = devdata;
>> +
>> + if (!tmd)
>> + return -EINVAL;
>> +
>> + *level = tmd->max_state;
>> +
>> + return 0;
>> +}
>> +
>> +static int qmi_get_cur_level(void *devdata, unsigned long *level)
>> +{
>> + struct qmi_tmd *tmd = devdata;
>> +
>> + if (!tmd)
>> + return -EINVAL;
>> +
>> + *level = tmd->cur_state;
>> +
>> + return 0;
>> +}
>> +
>> +static int qmi_set_cur_level(void *devdata, unsigned long level)
>> +{
>> + struct qmi_tmd *tmd = devdata;
>> +
>> + if (!tmd)
>> + return -EINVAL;
>> +
>> + if (level > tmd->max_state)
>> + return -EINVAL;
>> +
>> + if (tmd->cur_state == level)
>> + return 0;
>> +
>> + tmd->cur_state = level;
>> +
>> + return qmi_tmd_send_state_request(tmd);
>> +}
>> +
>> +static const struct remoteproc_cooling_ops qmi_rproc_ops = {
>> + .get_max_level = qmi_get_max_level,
>> + .get_cur_level = qmi_get_cur_level,
>> + .set_cur_level = qmi_set_cur_level,
>> +};
>> +
>> +static int qmi_register_cooling_device(struct qmi_tmd *tmd)
>> +{
>> + struct remoteproc_cdev *rproc_cdev;
>> +
>> + rproc_cdev = remoteproc_cooling_register(tmd->np,
>> + tmd->type,
>> + &qmi_rproc_ops,
>> + tmd);
>> +
>> + if (IS_ERR(rproc_cdev))
>> + return dev_err_probe(tmd->client->dev, PTR_ERR(rproc_cdev),
>> + "Failed to register cooling device %s\n",
>> + tmd->qmi_name);
>> +
>> + tmd->rproc_cdev = rproc_cdev;
>> + return 0;
>> +}
>> +
>> +/*
>> + * Init a single TMD control by registering a cooling device for it, or
>> + * synchronising state with the remote subsystem if recovering from a service
>> + * restart. This is called when the TMD service starts up.
>> + */
>> +static int qmi_tmd_init_control(struct qmi_tmd_client *client, const char *label,
>> + u8 max_state)
>> +{
>> + struct qmi_tmd *tmd = NULL;
>> +
>> + list_for_each_entry(tmd, &client->cdev_list, node)
>> + if (!strncasecmp(tmd->qmi_name, label,
>> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1))
>> + goto found;
>> +
>> + dev_dbg(client->dev,
>> + "TMD '%s' available in firmware but not specified in DT\n",
>> + label);
>> + return 0;
>> +
>> +found:
>> + tmd->max_state = max_state;
>> + /*
>> + * If the cooling device already exists then the QMI service went away and
>> + * came back. So just make sure the current cooling device state is
>> + * reflected on the remote side and then return.
>> + */
>> + if (tmd->rproc_cdev)
>> + return qmi_tmd_send_state_request(tmd);
>> +
>> + return qmi_register_cooling_device(tmd);
>> +}
>> +
>> +/*
>> + * When the QMI service starts up on a remote subsystem this function will fetch
>> + * the list of TMDs on the subsystem, match it to the TMDs specified in devicetree
>> + * and call qmi_tmd_init_control() for each
>> + */
>> +static void qmi_tmd_svc_arrive(struct work_struct *work)
>> +{
>> + struct qmi_tmd_client *client =
>> + container_of(work, struct qmi_tmd_client, svc_arrive_work);
>> +
>> + struct tmd_get_mitigation_device_list_req_msg_v01 req = { 0 };
>> + struct tmd_get_mitigation_device_list_resp_msg_v01 *resp __free(kfree) = NULL;
>> + int ret = 0, i;
>> + struct qmi_txn txn;
>> +
>> + /* resp struct is 1.1kB, allocate it on the heap. */
>> + resp = kzalloc(sizeof(*resp), GFP_KERNEL);
>> + if (!resp)
>> + return;
>> +
>> + /* Get a list of TMDs supported by the remoteproc */
>> + scoped_guard(mutex, &client->mutex) {
>> + ret = qmi_txn_init(&client->handle, &txn,
>> + tmd_get_mitigation_device_list_resp_msg_v01_ei, resp);
>> + if (ret < 0) {
>> + dev_err(client->dev,
>> + "Transaction init error for instance_id: %#x ret %d\n",
>> + client->id, ret);
>> + return;
>> + }
>> +
>> + ret = qmi_send_request(&client->handle, NULL, &txn,
>> + QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01,
>> + TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN,
>> + tmd_get_mitigation_device_list_req_msg_v01_ei, &req);
>> + if (ret < 0) {
>> + qmi_txn_cancel(&txn);
>> + return;
>> + }
>> +
>> + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
>> + if (ret < 0) {
>> + dev_err(client->dev, "Transaction wait error for client %#x ret:%d\n",
>> + client->id, ret);
>> + return;
>> + }
>> + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
>> + ret = resp->resp.result;
>> + dev_err(client->dev, "Failed to get device list for client %#x ret:%d\n",
>> + client->id, ret);
>> + return;
>> + }
>> +
>> + client->connection_active = true;
>> + }
>> +
>> + for (i = 0; i < resp->mitigation_device_list_len; i++) {
>> + struct tmd_mitigation_dev_list_type_v01 *device =
>> + &resp->mitigation_device_list[i];
>> +
>> + ret = qmi_tmd_init_control(client,
>> + device->mitigation_dev_id.mitigation_dev_id,
>> + device->max_mitigation_level);
>> + if (ret)
>> + break;
>> + }
>> +}
>> +
>> +static void thermal_qmi_net_reset(struct qmi_handle *qmi)
>> +{
>> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
>> + struct qmi_tmd *tmd = NULL;
>> +
>> + list_for_each_entry(tmd, &client->cdev_list, node) {
>> + qmi_tmd_send_state_request(tmd);
>> + }
>> +}
>> +
>> +static void thermal_qmi_del_server(struct qmi_handle *qmi, struct qmi_service *service)
>> +{
>> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
>> +
>> + scoped_guard(mutex, &client->mutex)
>> + client->connection_active = false;
>> +}
>> +
>> +static int thermal_qmi_new_server(struct qmi_handle *qmi, struct qmi_service *service)
>> +{
>> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
>> + struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port };
>> +
>> + scoped_guard(mutex, &client->mutex)
>> + kernel_connect(qmi->sock, (struct sockaddr_unsized *)&sq, sizeof(sq), 0);
>> +
>> + queue_work(system_highpri_wq, &client->svc_arrive_work);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct qmi_ops thermal_qmi_event_ops = {
>> + .new_server = thermal_qmi_new_server,
>> + .del_server = thermal_qmi_del_server,
>> + .net_reset = thermal_qmi_net_reset,
>> +};
>> +
>> +static void qmi_tmd_cleanup(struct qmi_tmd_client *client)
>> +{
>> + struct qmi_tmd *tmd, *c_next;
>> +
>> + guard(mutex)(&client->mutex);
>> +
>> + client->connection_active = false;
>> +
>> + qmi_handle_release(&client->handle);
>> + cancel_work(&client->svc_arrive_work);
>> + list_for_each_entry_safe(tmd, c_next, &client->cdev_list, node) {
>> + if (tmd->rproc_cdev)
>> + remoteproc_cooling_unregister(tmd->rproc_cdev);
>> +
>> + list_del(&tmd->node);
>> + }
>> +}
>> +
>> +/* Parse the controls and allocate a qmi_tmd for each of them */
>> +static int qmi_tmd_alloc_cdevs(struct qmi_tmd_client *client)
>> +{
>> + struct device *dev = client->dev;
>> + struct device_node *node = dev->of_node;
>> + struct device_node *subnode;
>> + struct qmi_tmd *tmd;
>> + int ret;
>> +
>> + for_each_available_child_of_node_scoped(node, subnode) {
>> + const char *name;
>> +
>> + tmd = devm_kzalloc(dev, sizeof(*tmd), GFP_KERNEL);
>> + if (!tmd)
>> + return dev_err_probe(client->dev, -ENOMEM,
>> + "Couldn't allocate tmd\n");
>> +
>> + tmd->type = devm_kasprintf(client->dev, GFP_KERNEL, "%s",
>> + subnode->name);
>> + if (!tmd->type)
>> + return dev_err_probe(dev, -ENOMEM,
>> + "Couldn't allocate cooling device name\n");
>> +
>> + if (of_property_read_string(subnode, "label", &name))
>> + return dev_err_probe(client->dev, -EINVAL,
>> + "Failed to parse dev name for %s\n",
>> + subnode->name);
>> +
>> + ret = strscpy(tmd->qmi_name, name,
>> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
>> + if (ret == -E2BIG)
>> + return dev_err_probe(dev, -EINVAL, "TMD label %s is too long\n",
>> + name);
>> +
>> + tmd->client = client;
>> + tmd->np = subnode;
>> + tmd->cur_state = 0;
>> + list_add(&tmd->node, &client->cdev_list);
>> + }
>> +
>> + if (list_empty(&client->cdev_list))
>> + return dev_err_probe(client->dev, -EINVAL,
>> + "No cooling devices specified for client %s (%#x)\n",
>> + client->name, client->id);
>> +
>> + return 0;
>> +}
>> +
>> +static int qmi_tmd_client_probe(struct platform_device *pdev)
>> +{
>> + const struct qmi_instance_data *match;
>> + struct qmi_tmd_client *client;
>> + struct device *dev = &pdev->dev;
>> + int ret;
>> +
>> + client = devm_kzalloc(dev, sizeof(*client), GFP_KERNEL);
>> + if (!client)
>> + return -ENOMEM;
>> +
>> + client->dev = dev;
>> +
>> + match = of_device_get_match_data(dev);
>> + if (!match)
>> + return dev_err_probe(dev, -EINVAL, "No match data\n");
>> +
>> + client->id = match->id;
>> + client->name = match->name;
>> +
>> + mutex_init(&client->mutex);
>> + INIT_LIST_HEAD(&client->cdev_list);
>> + INIT_WORK(&client->svc_arrive_work, qmi_tmd_svc_arrive);
>> +
>> + ret = qmi_tmd_alloc_cdevs(client);
>> + if (ret)
>> + return ret;
>> +
>> + platform_set_drvdata(pdev, client);
>> +
>> + ret = qmi_handle_init(&client->handle,
>> + TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN,
>> + &thermal_qmi_event_ops, NULL);
>> + if (ret < 0)
>> + return dev_err_probe(client->dev, ret, "QMI handle init failed for client %#x\n",
>> + client->id);
>> +
>> + ret = qmi_add_lookup(&client->handle, TMD_SERVICE_ID_V01, TMD_SERVICE_VERS_V01,
>> + client->id);
>> + if (ret < 0) {
>> + qmi_handle_release(&client->handle);
>> + return dev_err_probe(client->dev, ret, "QMI register failed for client 0x%x\n",
>> + client->id);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void qmi_tmd_client_remove(struct platform_device *pdev)
>> +{
>> + struct qmi_tmd_client *client = platform_get_drvdata(pdev);
>> +
>> + qmi_tmd_cleanup(client);
>> +}
>> +
>> +static const struct qmi_instance_data qmi_cdsp = {
>> + .id = CDSP_INSTANCE_ID,
>> + .name = "cdsp",
>> +};
>> +
>> +static const struct qmi_instance_data qmi_cdsp1 = {
>> + .id = CDSP1_INSTANCE_ID,
>> + .name = "cdsp1",
>> +};
>> +
>> +static const struct of_device_id qmi_tmd_device_table[] = {
>> + {
>> + .compatible = "qcom,qmi-cooling-cdsp",
>> + .data = &qmi_cdsp,
>> + },
>> + {
>> + .compatible = "qcom,qmi-cooling-cdsp1",
>> + .data = &qmi_cdsp1,
>> + },
>> + {}
>> +};
>> +MODULE_DEVICE_TABLE(of, qmi_tmd_device_table);
>> +
>> +static struct platform_driver qmi_tmd_device_driver = {
>> + .probe = qmi_tmd_client_probe,
>> + .remove = qmi_tmd_client_remove,
>> + .driver = {
>> + .name = "qcom-qmi-cooling",
>> + .of_match_table = qmi_tmd_device_table,
>> + },
>> +};
>> +
>> +module_platform_driver(qmi_tmd_device_driver);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_DESCRIPTION("Qualcomm QMI Thermal Mitigation Device driver");
>> diff --git a/drivers/soc/qcom/qmi-cooling.h b/drivers/soc/qcom/qmi-cooling.h
>> new file mode 100644
>> index 000000000000..e33f4c5979e5
>> --- /dev/null
>> +++ b/drivers/soc/qcom/qmi-cooling.h
>> @@ -0,0 +1,429 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2017, The Linux Foundation
>> + * Copyright (c) 2023, Linaro Limited
>> + */
>> +
>> +#ifndef __QCOM_COOLING_H__
>> +#define __QCOM_COOLING_H__
>> +
>> +#include <linux/soc/qcom/qmi.h>
>> +
>> +#define TMD_SERVICE_ID_V01 0x18
>> +#define TMD_SERVICE_VERS_V01 0x01
>> +
>> +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_RESP_V01 0x0020
>> +#define QMI_TMD_GET_MITIGATION_LEVEL_REQ_V01 0x0022
>> +#define QMI_TMD_GET_SUPPORTED_MSGS_REQ_V01 0x001E
>> +#define QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01 0x0021
>> +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0023
>> +#define QMI_TMD_GET_SUPPORTED_MSGS_RESP_V01 0x001E
>> +#define QMI_TMD_SET_MITIGATION_LEVEL_RESP_V01 0x0021
>> +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0024
>> +#define QMI_TMD_MITIGATION_LEVEL_REPORT_IND_V01 0x0025
>> +#define QMI_TMD_GET_MITIGATION_LEVEL_RESP_V01 0x0022
>> +#define QMI_TMD_GET_SUPPORTED_FIELDS_REQ_V01 0x001F
>> +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01 0x0020
>> +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0023
>> +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0024
>> +#define QMI_TMD_GET_SUPPORTED_FIELDS_RESP_V01 0x001F
>> +
>> +#define QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 32
>> +#define QMI_TMD_MITIGATION_DEV_LIST_MAX_V01 32
>> +
>> +struct tmd_mitigation_dev_id_type_v01 {
>> + char mitigation_dev_id[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1];
>> +};
>> +
>> +static const struct qmi_elem_info tmd_mitigation_dev_id_type_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRING,
>> + .elem_len = QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1,
>> + .elem_size = sizeof(char),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0,
>> + .offset = offsetof(struct tmd_mitigation_dev_id_type_v01,
>> + mitigation_dev_id),
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_mitigation_dev_list_type_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id;
>> + u8 max_mitigation_level;
>> +};
>> +
>> +static const struct qmi_elem_info tmd_mitigation_dev_list_type_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0,
>> + .offset = offsetof(struct tmd_mitigation_dev_list_type_v01,
>> + mitigation_dev_id),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_UNSIGNED_1_BYTE,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0,
>> + .offset = offsetof(struct tmd_mitigation_dev_list_type_v01,
>> + max_mitigation_level),
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_get_mitigation_device_list_req_msg_v01 {
>> + char placeholder;
>> +};
>> +
>> +#define TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN 0
>> +const struct qmi_elem_info tmd_get_mitigation_device_list_req_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_get_mitigation_device_list_resp_msg_v01 {
>> + struct qmi_response_type_v01 resp;
>> + u8 mitigation_device_list_valid;
>> + u32 mitigation_device_list_len;
>> + struct tmd_mitigation_dev_list_type_v01
>> + mitigation_device_list[QMI_TMD_MITIGATION_DEV_LIST_MAX_V01];
>> +};
>> +
>> +#define TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN 1099
>> +static const struct qmi_elem_info tmd_get_mitigation_device_list_resp_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct qmi_response_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
>> + resp),
>> + .ei_array = qmi_response_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_OPT_FLAG,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x10,
>> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
>> + mitigation_device_list_valid),
>> + },
>> + {
>> + .data_type = QMI_DATA_LEN,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x10,
>> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
>> + mitigation_device_list_len),
>> + },
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = QMI_TMD_MITIGATION_DEV_LIST_MAX_V01,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_list_type_v01),
>> + .array_type = VAR_LEN_ARRAY,
>> + .tlv_type = 0x10,
>> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
>> + mitigation_device_list),
>> + .ei_array = tmd_mitigation_dev_list_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_set_mitigation_level_req_msg_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id;
>> + u8 mitigation_level;
>> +};
>> +
>> +#define TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 40
>> +static const struct qmi_elem_info tmd_set_mitigation_level_req_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x01,
>> + .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01,
>> + mitigation_dev_id),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_UNSIGNED_1_BYTE,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01,
>> + mitigation_level),
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_set_mitigation_level_resp_msg_v01 {
>> + struct qmi_response_type_v01 resp;
>> +};
>> +
>> +#define TMD_SET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
>> +static const struct qmi_elem_info tmd_set_mitigation_level_resp_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct qmi_response_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(struct tmd_set_mitigation_level_resp_msg_v01, resp),
>> + .ei_array = qmi_response_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_get_mitigation_level_req_msg_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
>> +};
>> +
>> +#define TMD_GET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
>> +
>> +static const struct qmi_elem_info tmd_get_mitigation_level_req_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x01,
>> + .offset = offsetof(struct tmd_get_mitigation_level_req_msg_v01,
>> + mitigation_device),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_get_mitigation_level_resp_msg_v01 {
>> + struct qmi_response_type_v01 resp;
>> + u8 current_mitigation_level_valid;
>> + u8 current_mitigation_level;
>> + u8 requested_mitigation_level_valid;
>> + u8 requested_mitigation_level;
>> +};
>> +
>> +#define TMD_GET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 15
>> +static const struct qmi_elem_info tmd_get_mitigation_level_resp_msg_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct qmi_response_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01, resp),
>> + .ei_array = qmi_response_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_OPT_FLAG,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x10,
>> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
>> + current_mitigation_level_valid),
>> + },
>> + {
>> + .data_type = QMI_UNSIGNED_1_BYTE,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x10,
>> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
>> + current_mitigation_level),
>> + },
>> + {
>> + .data_type = QMI_OPT_FLAG,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x11,
>> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
>> + requested_mitigation_level_valid),
>> + },
>> + {
>> + .data_type = QMI_UNSIGNED_1_BYTE,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x11,
>> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
>> + requested_mitigation_level),
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_register_notification_mitigation_level_req_msg_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
>> +};
>> +
>> +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
>> +static const struct qmi_elem_info
>> + tmd_register_notification_mitigation_level_req_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x01,
>> + .offset = offsetof(
>> + struct tmd_register_notification_mitigation_level_req_msg_v01,
>> + mitigation_device),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> + };
>> +
>> +struct tmd_register_notification_mitigation_level_resp_msg_v01 {
>> + struct qmi_response_type_v01 resp;
>> +};
>> +
>> +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
>> +static const struct qmi_elem_info
>> + tmd_register_notification_mitigation_level_resp_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct qmi_response_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(
>> + struct tmd_register_notification_mitigation_level_resp_msg_v01,
>> + resp),
>> + .ei_array = qmi_response_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> + };
>> +
>> +struct tmd_deregister_notification_mitigation_level_req_msg_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
>> +};
>> +
>> +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
>> +static const struct qmi_elem_info
>> + tmd_deregister_notification_mitigation_level_req_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x01,
>> + .offset = offsetof(
>> + struct tmd_deregister_notification_mitigation_level_req_msg_v01,
>> + mitigation_device),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> + };
>> +
>> +struct tmd_deregister_notification_mitigation_level_resp_msg_v01 {
>> + struct qmi_response_type_v01 resp;
>> +};
>> +
>> +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
>> +static const struct qmi_elem_info
>> + tmd_deregister_notification_mitigation_level_resp_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct qmi_response_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(
>> + struct tmd_deregister_notification_mitigation_level_resp_msg_v01,
>> + resp),
>> + .ei_array = qmi_response_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> + };
>> +
>> +struct tmd_mitigation_level_report_ind_msg_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
>> + u8 current_mitigation_level;
>> +};
>> +
>> +#define TMD_MITIGATION_LEVEL_REPORT_IND_MSG_V01_MAX_MSG_LEN 40
>> +static const struct qmi_elem_info tmd_mitigation_level_report_ind_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x01,
>> + .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01,
>> + mitigation_device),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_UNSIGNED_1_BYTE,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01,
>> + current_mitigation_level),
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +#endif /* __QMI_COOLING_INTERNAL_H__ */
>> --
>> 2.34.1
>>
>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-02-24 12:17 ` Krzysztof Kozlowski
@ 2026-03-16 19:57 ` Daniel Lezcano
2026-03-18 10:17 ` Gaurav Kohli
0 siblings, 1 reply; 53+ messages in thread
From: Daniel Lezcano @ 2026-03-16 19:57 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Gaurav Kohli, andersson, mathieu.poirier, robh, krzk+dt, conor+dt,
rui.zhang, lukasz.luba, konradybcio, mani, casey.connolly,
amit.kucheria, linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On Tue, Feb 24, 2026 at 01:17:22PM +0100, Krzysztof Kozlowski wrote:
> On 24/02/2026 13:09, Gaurav Kohli wrote:
[ ... ]
> >>> As a result, each core requires its own cooling device, which must be
> >>> linked to its TSENS thermal zone. Because of this, we introduced
> >>> multiple child nodes—one for each cooling device.
> >>
> >> So you have one device with cooling cells=1+2, no?
> >>
> >
> > This will be a bigger framework change which is not supported, i can see
>
> I don't think that changing open source frameworks is "not supported". I
> am pretty sure that changing is not only supported, but actually desired.
Yes, IMO it could make sense. There are the thermal zones with phandle
to a sensor and a sensor id. We can have the same with a phandle to a
cooling device and a cooling device id.
(... or several ids because the thermal sensor can also have multiple
ids ?)
May be an array of names corresponding to the TMD names at the 'id'
position ?
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver
2026-03-13 14:15 ` Daniel Lezcano
@ 2026-03-17 7:25 ` Gaurav Kohli
0 siblings, 0 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-03-17 7:25 UTC (permalink / raw)
To: Daniel Lezcano
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 3/13/2026 7:45 PM, Daniel Lezcano wrote:
> On Tue, Jan 27, 2026 at 09:27:18PM +0530, Gaurav Kohli wrote:
>> From: Casey Connolly <casey.connolly@linaro.org>
>>
>> The Thermal Mitigation Device (TMD) service exposes various platform
>> specific thermal mitigations available on remote subsystems (ie the
>> modem and cdsp). The service is exposed via the QMI messaging
>> interface, usually over the QRTR transport.
>>
>> Qualcomm QMI-based TMD cooling devices are used to mitigate thermal
>> conditions across multiple remote subsystems. These devices operate
>> based on junction temperature sensors (TSENS) associated with thermal
>> zones for each subsystem.
>>
>> Co-developed-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> Signed-off-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>
>> Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
>> ---
>> drivers/soc/qcom/Kconfig | 13 +
>> drivers/soc/qcom/Makefile | 1 +
>> drivers/soc/qcom/qmi-cooling.c | 510 +++++++++++++++++++++++++++++++++
>> drivers/soc/qcom/qmi-cooling.h | 429 +++++++++++++++++++++++++++
>> 4 files changed, 953 insertions(+)
>> create mode 100644 drivers/soc/qcom/qmi-cooling.c
>> create mode 100644 drivers/soc/qcom/qmi-cooling.h
>>
>> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
>> index 2caadbbcf830..905a24b42fe6 100644
>> --- a/drivers/soc/qcom/Kconfig
>> +++ b/drivers/soc/qcom/Kconfig
>> @@ -124,6 +124,19 @@ config QCOM_PMIC_GLINK
>> Say yes here to support USB-C and battery status on modern Qualcomm
>> platforms.
>>
>> +config QCOM_QMI_COOLING
>> + tristate "Qualcomm QMI cooling drivers"
>> + depends on QCOM_RPROC_COMMON
>> + depends on ARCH_QCOM || COMPILE_TEST
>> + select QCOM_QMI_HELPERS
>> + help
>> + This enables the remote subsystem cooling devices. These cooling
>> + devices will be used by Qualcomm chipset to place various remote
>> + subsystem mitigations like remote processor passive mitigation,
>> + remote subsystem voltage restriction at low temperatures etc.
>> + The QMI cooling device will interface with remote subsystem
> 0> + using Qualcomm remoteproc interface.
Thanks Daniel for review.
will update this.
>> +
>> config QCOM_QMI_HELPERS
>> tristate
>> depends on NET
>> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
>> index b7f1d2a57367..b6728f54944b 100644
>> --- a/drivers/soc/qcom/Makefile
>> +++ b/drivers/soc/qcom/Makefile
>> @@ -14,6 +14,7 @@ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
>> obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
>> obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o
>> CFLAGS_pmic_pdcharger_ulog.o := -I$(src)
>> +obj-$(CONFIG_QCOM_QMI_COOLING) += qmi-cooling.o
>> obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
>> qmi_helpers-y += qmi_encdec.o qmi_interface.o
>> obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o
>> diff --git a/drivers/soc/qcom/qmi-cooling.c b/drivers/soc/qcom/qmi-cooling.c
>> new file mode 100644
>> index 000000000000..463baa47c8b6
>> --- /dev/null
>> +++ b/drivers/soc/qcom/qmi-cooling.c
>> @@ -0,0 +1,510 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2017, The Linux Foundation
>
> Why this copyright ? The file is from scratch
>
>> + * Copyright (c) 2025, Linaro Limited
will update this.
>
> Missing copyright: Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>
will add QC copyright also.
>> + * QMI Thermal Mitigation Device (TMD) client driver.
>> + * This driver provides an in-kernel client to handle hot and cold thermal
>> + * mitigations for remote subsystems (modem and DSPs) running the TMD service.
>> + * It doesn't implement any handling of reports from remote subsystems.
>> + */
>> +
>> +#include <linux/cleanup.h>
>> +#include <linux/err.h>
>> +#include <linux/module.h>
>> +#include <linux/net.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/remoteproc/qcom_rproc.h>
>> +#include <linux/remoteproc_cooling.h>
>> +#include <linux/slab.h>
>> +#include <linux/soc/qcom/qmi.h>
>> +#include <linux/thermal.h>
>> +
>> +#include "qmi-cooling.h"
>> +
>> +#define CDSP_INSTANCE_ID 0x43
>> +#define CDSP1_INSTANCE_ID 0x44
>> +
>> +#define QMI_TMD_RESP_TIMEOUT msecs_to_jiffies(100)
>
> Seems to me a really long duration for a timeout when doing
> mitigation. Would it make sense to reduce it ?
Let me come back on this, as we have to run lot of stability testing for
this.
>
>> +/**
>> + * struct qmi_tmd_client - TMD client state
>> + * @dev: Device associated with this client
>> + * @name: Friendly name for the remote TMD service
>> + * @handle: QMI connection handle
>> + * @mutex: Lock to synchronise QMI communication
>> + * @id: The QMI TMD service instance ID
>> + * @cdev_list: The list of cooling devices (controls) enabled for this instance
>> + * @svc_arrive_work: Work item for initialising the client when the TMD service
>> + * starts.
>> + * @connection_active: Whether or not we're connected to the QMI TMD service
>> + */
>> +struct qmi_tmd_client {
>> + struct device *dev;
>> + const char *name;
>> + struct qmi_handle handle;
>> + struct mutex mutex;
>
> Can you explain why this lock is needed? What race condition is it fixing?
>
>> + u32 id;
>
It is unique instance id used by remote qmi service per subsystem and
needed for qmi connection, may be i can change this to instance id ?
> So 'dev', 'id' and 'name' are only there to print an error message, right?
>
> IMO, we can get rid of them.
>
>> + struct list_head cdev_list;
>> + struct work_struct svc_arrive_work;
>> + bool connection_active;
>
> IMO this boolean is not needed.
No, this connection_active is setting false during subsystem
shutdown(SSR cases also), at that time to prevent setting current state
this state machine is needed.
>
> - connection_active is checked in the function 'set_cur_state'.
>
> If the function is called is because the cooling device is
> registered. The only place where it is set to false again is when the
> cleanup is called. But if the cooling devices are unregistered before,
> there is no reason why 'set_cur_state' to be called in the next steps
> of the cleanup.
>
> What remain unclear is in case of a peer reset, if del/new is called
> before reset. But in such case, the request through QMI will result in
> a error which should be handled in this driver.
>
>> +};
>> +
>> +/**
>> + * struct qmi_tmd - A TMD cooling device
>> + * @np: OF node associated with this control
>
> Why needed ?
>
As we are using thermal_of_cooling_device_register for each tmd, that's
why we are using np. But if we change to cooling-cells=3 then we can use
parent device node.
>> + * @type: The control type (exposed via sysfs)
>
> Duplicate with the cooling device name
>
>> + * @qmi_name: The common name of this control shared by the remote subsystem
>> + * @rproc_cdev: Remote processor cooling device handle
>> + * @cur_state: The current cooling/warming/mitigation state
>> + * @max_state: The maximum state
>> + * @client: The TMD client instance this control is associated with
>> + */
>> +struct qmi_tmd {
>> + struct device_node *np;
>> + const char *type;
>> + char qmi_name[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1];
>
> const char * and use devm_kstrdup() instead
>
will update this.
>> + struct list_head node;
>> + struct remoteproc_cdev *rproc_cdev;
>> + unsigned int cur_state;
>> + unsigned int max_state;
>
> max_state can be removed (see comment below in the get_max_state() ops)
>
>> + struct qmi_tmd_client *client;
>> +};
>
> This structure can be simplified (refer to comments below in the code)
>
>> +/**
>> + * struct qmi_instance_id - QMI instance match data
>> + * @id: The QMI instance ID
>> + * @name: Friendly name for this instance
>> + */
>> +struct qmi_instance_data {
>> + u32 id;
>> + const char *name;
>> +};
>
> If I'm not wrong, this structure is only used to pass information to
> print debug information ?
>
this is same as mentioned above, using this instance id for qmi
connection with subsystem.
>> +
>> +/* Notify the remote subsystem of the requested cooling state */
>> +static int qmi_tmd_send_state_request(struct qmi_tmd *tmd)
>> +{
>> + struct tmd_set_mitigation_level_resp_msg_v01 tmd_resp = { 0 };
>> + struct tmd_set_mitigation_level_req_msg_v01 req = { 0 };
>
> Please shortened these structure name. It is unreadable. May be you
> can do something like:
>
> struct tmd_set_level_msg {
> int level;
> union {
> struct qmi_response_type_v01 resp;
> char mitigation_dev_id[...];
> };
> }
>
> I know the other QMI services are implemented in the same way but it
> may be worth to simplify the message format instead of wrapping that
> into structures again and again.
>
Sure, let me update and come back on this.
>> + struct qmi_tmd_client *client;
>> + struct qmi_txn txn;
>> + int ret = 0;
>> +
>> + client = tmd->client;
>> +
>> + guard(mutex)(&client->mutex);
>> +
>> + /*
>> + * This function is called by qmi_set_cur_state() which does not know if
>> + * the QMI service is actually online. If it isn't then we noop here.
>> + * The state is cached in tmd->cur_state and will be broadcast via
>> + * qmi_tmd_init_control() when the service comes up.
>> + */
>> + if (!client->connection_active)
>> + return 0;
>> +
>> + strscpy(req.mitigation_dev_id.mitigation_dev_id, tmd->qmi_name,
>> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
>> + req.mitigation_level = tmd->cur_state;
>> +
>> + ret = qmi_txn_init(&client->handle, &txn,
>> + tmd_set_mitigation_level_resp_msg_v01_ei, &tmd_resp);
>> + if (ret < 0) {
>> + dev_err(client->dev, "qmi set state %d txn init failed for %s ret %d\n",
>> + tmd->cur_state, tmd->type, ret);
>> + return ret;
>> + }
>> +
>> + ret = qmi_send_request(&client->handle, NULL, &txn,
>> + QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01,
>> + TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN,
>> + tmd_set_mitigation_level_req_msg_v01_ei, &req);
>> + if (ret < 0) {
>> + dev_err(client->dev, "qmi set state %d txn send failed for %s ret %d\n",
>> + tmd->cur_state, tmd->type, ret);
>> + qmi_txn_cancel(&txn);
>> + return ret;
>> + }
>> +
>> + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
>> + if (ret < 0) {
>> + dev_err(client->dev, "qmi set state %d txn wait failed for %s ret %d\n",
>> + tmd->cur_state, tmd->type, ret);
>> + return ret;
>> + }
>> +
>> + if (tmd_resp.resp.result != QMI_RESULT_SUCCESS_V01) {
>> + ret = -tmd_resp.resp.result;
>
> Is this result an errno error or a QMI error?
>
>> + dev_err(client->dev, "qmi set state %d NOT success for %s ret %d\n",
>> + tmd->cur_state, tmd->type, ret);
>> + return ret;
>> + }
>> +
>> + dev_dbg(client->dev, "Requested state %d/%d for %s\n", tmd->cur_state,
>> + tmd->max_state, tmd->type);
>> +
>> + return 0;
>> +}
>> +
>> +static int qmi_get_max_level(void *devdata, unsigned long *level)
>> +{
>> + struct qmi_tmd *tmd = devdata;
>> +
>> + if (!tmd)
>> + return -EINVAL;
>> +
>> + *level = tmd->max_state;
>> +
>> + return 0;
>> +}
>
> The get_max_state() is called in two places. When registering the
> cooling device and when updating the cooling device. The first one is
> called one time and the second one is called when there is an event
> like switching the battery mode (ACPI only). Each of them updates the
> cdev->max_state field. Otherwise the get_max_state() is not used but
> cdev->max_state.
>
> The code above should call the QMI to get the max
> level. tmd->max_state could be then removed.
>
For first time registration also, framework is reading max_state
callback only to update cdev->max_state, so to maintain that we need
this variable.
> I agree there are other cooling devices doing that but I don't think
> it is correct.
>
>> +static int qmi_get_cur_level(void *devdata, unsigned long *level)
>> +{
>> + struct qmi_tmd *tmd = devdata;
>> +
>> + if (!tmd)
>> + return -EINVAL;
>> +
>
> We should assume the core is doing the right thing. So if we
> registered the cooling device with the private data, then it should
> return it back. If not, then it is a fatal bug crashing the system
> which should have been spotted when doing some testing.
>
Sure, will remove the check.
>> + *level = tmd->cur_state;
>> +
>> + return 0;
>> +}
>> +
>> +static int qmi_set_cur_level(void *devdata, unsigned long level)
>> +{
>> + struct qmi_tmd *tmd = devdata;
>> +
>> + if (!tmd)
>> + return -EINVAL;
>
> idem
>
>> + if (level > tmd->max_state)
>> + return -EINVAL;
>
> It is already handled in the core code.
>
In older kernel, i think it is not taking care for sysfs path, but now
we can remove.
>> + if (tmd->cur_state == level)
>> + return 0;
>>
>> + tmd->cur_state = level;
>> +
>> + return qmi_tmd_send_state_request(tmd);
>
> The command should succeed before updating 'cur_state'. So first the
> call to qmi_tmd_send_state_request() and if it is ok, then set the
> current state. So it means you can pass the state as parameter to
> qmi_set_cur_level() which in this case not rely on the caller to set
> the tmd->cur_state before calling the function.
>
Thanks for catching this, will check error case and then only update.
>> +}
>> +
>> +static const struct remoteproc_cooling_ops qmi_rproc_ops = {
>> + .get_max_level = qmi_get_max_level,
>> + .get_cur_level = qmi_get_cur_level,
>> + .set_cur_level = qmi_set_cur_level,
>> +};
>
> As commented before, the remoteproc cooling device does not really
> provide a benefit, so those ops can be converted into cooling device
> ops.
>
Yes, in next post will remove remoteproc cooling device.
> [ ... ]
>
>> +/*
>> + * Init a single TMD control by registering a cooling device for it, or
>> + * synchronising state with the remote subsystem if recovering from a service
>> + * restart. This is called when the TMD service starts up.
>> + */
>> +static int qmi_tmd_init_control(struct qmi_tmd_client *client, const char *label,
>> + u8 max_state)
>> +{
>> + struct qmi_tmd *tmd = NULL;
>> +
>> + list_for_each_entry(tmd, &client->cdev_list, node)
>> + if (!strncasecmp(tmd->qmi_name, label,
>> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1))
>> + goto found;
>> +
>> + dev_dbg(client->dev,
>> + "TMD '%s' available in firmware but not specified in DT\n",
>> + label);
>> + return 0;
>> +
>> +found:
>> + tmd->max_state = max_state;
>> + /*
>> + * If the cooling device already exists then the QMI service went away and
>> + * came back. So just make sure the current cooling device state is
>> + * reflected on the remote side and then return.
>> + */
>> + if (tmd->rproc_cdev)
>> + return qmi_tmd_send_state_request(tmd);
>> +
>> + return qmi_register_cooling_device(tmd);
>> +}
>> +
>> +/*
>> + * When the QMI service starts up on a remote subsystem this function will fetch
>> + * the list of TMDs on the subsystem, match it to the TMDs specified in devicetree
>> + * and call qmi_tmd_init_control() for each
>> + */
>> +static void qmi_tmd_svc_arrive(struct work_struct *work)
>> +{
>> + struct qmi_tmd_client *client =
>> + container_of(work, struct qmi_tmd_client, svc_arrive_work);
>> +
>> + struct tmd_get_mitigation_device_list_req_msg_v01 req = { 0 };
>> + struct tmd_get_mitigation_device_list_resp_msg_v01 *resp __free(kfree) = NULL;
>> + int ret = 0, i;
>> + struct qmi_txn txn;
>> +
>> + /* resp struct is 1.1kB, allocate it on the heap. */
>> + resp = kzalloc(sizeof(*resp), GFP_KERNEL);
>> + if (!resp)
>> + return;
>> +
>> + /* Get a list of TMDs supported by the remoteproc */
>> + scoped_guard(mutex, &client->mutex) {
>> + ret = qmi_txn_init(&client->handle, &txn,
>> + tmd_get_mitigation_device_list_resp_msg_v01_ei, resp);
>> + if (ret < 0) {
>> + dev_err(client->dev,
>> + "Transaction init error for instance_id: %#x ret %d\n",
>> + client->id, ret);
>> + return;
>> + }
>> +
>> + ret = qmi_send_request(&client->handle, NULL, &txn,
>> + QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01,
>> + TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN,
>> + tmd_get_mitigation_device_list_req_msg_v01_ei, &req);
>> + if (ret < 0) {
>> + qmi_txn_cancel(&txn);
>> + return;
>> + }
>> +
>> + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT);
>> + if (ret < 0) {
>> + dev_err(client->dev, "Transaction wait error for client %#x ret:%d\n",
>> + client->id, ret);
>> + return;
>> + }
>> + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
>> + ret = resp->resp.result;
>> + dev_err(client->dev, "Failed to get device list for client %#x ret:%d\n",
>> + client->id, ret);
>> + return;
>> + }
>> +
>> + client->connection_active = true;
>> + }
>> +
>> + for (i = 0; i < resp->mitigation_device_list_len; i++) {
>> + struct tmd_mitigation_dev_list_type_v01 *device =
>> + &resp->mitigation_device_list[i];
>> +
>> + ret = qmi_tmd_init_control(client,
>> + device->mitigation_dev_id.mitigation_dev_id,
>> + device->max_mitigation_level);
>> + if (ret)
>> + break;
>> + }
>> +}
>> +
>> +static void thermal_qmi_net_reset(struct qmi_handle *qmi)
>> +{
>> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
>> + struct qmi_tmd *tmd = NULL;
>> +
>> + list_for_each_entry(tmd, &client->cdev_list, node) {
>> + qmi_tmd_send_state_request(tmd);
>> + }
>> +}
>> +
>> +static void thermal_qmi_del_server(struct qmi_handle *qmi, struct qmi_service *service)
>> +{
>> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
>> +
>> + scoped_guard(mutex, &client->mutex)
>> + client->connection_active = false;
>> +}
>> +
>> +static int thermal_qmi_new_server(struct qmi_handle *qmi, struct qmi_service *service)
>> +{
>> + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle);
>> + struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port };
>> +
>> + scoped_guard(mutex, &client->mutex)
>> + kernel_connect(qmi->sock, (struct sockaddr_unsized *)&sq, sizeof(sq), 0);
>> +
>> + queue_work(system_highpri_wq, &client->svc_arrive_work);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct qmi_ops thermal_qmi_event_ops = {
>> + .new_server = thermal_qmi_new_server,
>> + .del_server = thermal_qmi_del_server,
>> + .net_reset = thermal_qmi_net_reset,
>> +};
>> +
>> +static void qmi_tmd_cleanup(struct qmi_tmd_client *client)
>> +{
>> + struct qmi_tmd *tmd, *c_next;
>> +
>> + guard(mutex)(&client->mutex);
>> +
>> + client->connection_active = false;
>> +
>> + qmi_handle_release(&client->handle);
>> + cancel_work(&client->svc_arrive_work);
>> + list_for_each_entry_safe(tmd, c_next, &client->cdev_list, node) {
>> + if (tmd->rproc_cdev)
>> + remoteproc_cooling_unregister(tmd->rproc_cdev);
>> +
>> + list_del(&tmd->node);
>> + }
>> +}
>> +
>> +/* Parse the controls and allocate a qmi_tmd for each of them */
>> +static int qmi_tmd_alloc_cdevs(struct qmi_tmd_client *client)
>> +{
>> + struct device *dev = client->dev;
>> + struct device_node *node = dev->of_node;
>> + struct device_node *subnode;
>> + struct qmi_tmd *tmd;
>> + int ret;
>> +
>> + for_each_available_child_of_node_scoped(node, subnode) {
>> + const char *name;
>
> Ok, I think there are already a lot of comments about the code. I'll
> skip the DTpart review in this patch and jump to the DT bindings.
>
>> + tmd = devm_kzalloc(dev, sizeof(*tmd), GFP_KERNEL);
>> + if (!tmd)
>> + return dev_err_probe(client->dev, -ENOMEM,
>> + "Couldn't allocate tmd\n");
>
> Usually we do not return an error message when an allocation fails
> because the mem mngt code does already that. So I would replace it
> with a simple return -ENOMEM
>
Sure, will update this.
>> +
>> + tmd->type = devm_kasprintf(client->dev, GFP_KERNEL, "%s",
>> + subnode->name);
>
> devm_kstrdup()
>
>> + if (!tmd->type)
>> + return dev_err_probe(dev, -ENOMEM,
>> + "Couldn't allocate cooling device name\n");
>> +
>> + if (of_property_read_string(subnode, "label", &name))
>> + return dev_err_probe(client->dev, -EINVAL,
>> + "Failed to parse dev name for %s\n",
>> + subnode->name);
>> +
>> + ret = strscpy(tmd->qmi_name, name,
>> + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1);
>
> devm_kstrdup()
>
>> + if (ret == -E2BIG)
>> + return dev_err_probe(dev, -EINVAL, "TMD label %s is too long\n",
>> + name);
>> +
>> + tmd->client = client;
>> + tmd->np = subnode;
>
> Why is it needed? I don't see it used anywhere
>
As mentioned earlier, we are using this during cooling registration call.
>> + tmd->cur_state = 0;
>> + list_add(&tmd->node, &client->cdev_list);
>> + }
>> +
>> + if (list_empty(&client->cdev_list))
>> + return dev_err_probe(client->dev, -EINVAL,
>> + "No cooling devices specified for client %s (%#x)\n",
>> + client->name, client->id);
>> +
>> + return 0;
>> +}
>> +
>> +static int qmi_tmd_client_probe(struct platform_device *pdev)
>> +{
>> + const struct qmi_instance_data *match;
>> + struct qmi_tmd_client *client;
>> + struct device *dev = &pdev->dev;
>> + int ret;
>> +
>> + client = devm_kzalloc(dev, sizeof(*client), GFP_KERNEL);
>> + if (!client)
>> + return -ENOMEM;
>> +
>> + client->dev = dev;
>> +
>> + match = of_device_get_match_data(dev);
>> + if (!match)
>> + return dev_err_probe(dev, -EINVAL, "No match data\n");
>> +
>> + client->id = match->id;
>> + client->name = match->name;
>> +
>> + mutex_init(&client->mutex);
>> + INIT_LIST_HEAD(&client->cdev_list);
>> + INIT_WORK(&client->svc_arrive_work, qmi_tmd_svc_arrive);
>> +
>> + ret = qmi_tmd_alloc_cdevs(client);
>> + if (ret)
>> + return ret;
>> +
>> + platform_set_drvdata(pdev, client);
>> +
>> + ret = qmi_handle_init(&client->handle,
>> + TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN,
>> + &thermal_qmi_event_ops, NULL);
>> + if (ret < 0)
>> + return dev_err_probe(client->dev, ret, "QMI handle init failed for client %#x\n",
>> + client->id);
>> +
>> + ret = qmi_add_lookup(&client->handle, TMD_SERVICE_ID_V01, TMD_SERVICE_VERS_V01,
>> + client->id);
>> + if (ret < 0) {
>> + qmi_handle_release(&client->handle);
>> + return dev_err_probe(client->dev, ret, "QMI register failed for client 0x%x\n",
>> + client->id);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void qmi_tmd_client_remove(struct platform_device *pdev)
>> +{
>> + struct qmi_tmd_client *client = platform_get_drvdata(pdev);
>> +
>> + qmi_tmd_cleanup(client);
>> +}
>> +
>> +static const struct qmi_instance_data qmi_cdsp = {
>> + .id = CDSP_INSTANCE_ID,
>> + .name = "cdsp",
>> +};
>> +
>> +static const struct qmi_instance_data qmi_cdsp1 = {
>> + .id = CDSP1_INSTANCE_ID,
>> + .name = "cdsp1",
>> +};
>> +
>> +static const struct of_device_id qmi_tmd_device_table[] = {
>> + {
>> + .compatible = "qcom,qmi-cooling-cdsp",
>> + .data = &qmi_cdsp,
>> + },
>> + {
>> + .compatible = "qcom,qmi-cooling-cdsp1",
>> + .data = &qmi_cdsp1,
>> + },
>> + {}
>> +};
>> +MODULE_DEVICE_TABLE(of, qmi_tmd_device_table);
>> +
>> +static struct platform_driver qmi_tmd_device_driver = {
>> + .probe = qmi_tmd_client_probe,
>> + .remove = qmi_tmd_client_remove,
>> + .driver = {
>> + .name = "qcom-qmi-cooling",
>> + .of_match_table = qmi_tmd_device_table,
>> + },
>> +};
>> +
>> +module_platform_driver(qmi_tmd_device_driver);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_DESCRIPTION("Qualcomm QMI Thermal Mitigation Device driver");
>> diff --git a/drivers/soc/qcom/qmi-cooling.h b/drivers/soc/qcom/qmi-cooling.h
>> new file mode 100644
>> index 000000000000..e33f4c5979e5
>> --- /dev/null
>> +++ b/drivers/soc/qcom/qmi-cooling.h
>> @@ -0,0 +1,429 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2017, The Linux Foundation
>> + * Copyright (c) 2023, Linaro Limited
>> + */
>> +
>> +#ifndef __QCOM_COOLING_H__
>> +#define __QCOM_COOLING_H__
>
> I'm not sure we want to export all these macros, structure. It could
> be contained into a .c file.
>
>> +#include <linux/soc/qcom/qmi.h>
>> +
>> +#define TMD_SERVICE_ID_V01 0x18
>
will update this.
> IMO, this definition should go inside qmi.h
>
> See https://lore.kernel.org/all/20260309230346.3584252-1-daniel.lezcano@oss.qualcomm.com/
>
>> +#define TMD_SERVICE_VERS_V01 0x01
>> +
>> +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_RESP_V01 0x0020
>> +#define QMI_TMD_GET_MITIGATION_LEVEL_REQ_V01 0x0022
>> +#define QMI_TMD_GET_SUPPORTED_MSGS_REQ_V01 0x001E
>> +#define QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01 0x0021
>> +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0023
>> +#define QMI_TMD_GET_SUPPORTED_MSGS_RESP_V01 0x001E
>> +#define QMI_TMD_SET_MITIGATION_LEVEL_RESP_V01 0x0021
>> +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0024
>> +#define QMI_TMD_MITIGATION_LEVEL_REPORT_IND_V01 0x0025
>> +#define QMI_TMD_GET_MITIGATION_LEVEL_RESP_V01 0x0022
>> +#define QMI_TMD_GET_SUPPORTED_FIELDS_REQ_V01 0x001F
>> +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01 0x0020
>> +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0023
>> +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0024
>> +#define QMI_TMD_GET_SUPPORTED_FIELDS_RESP_V01 0x001F
>> +
>> +#define QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 32
>> +#define QMI_TMD_MITIGATION_DEV_LIST_MAX_V01 32
>
> Having self explainatory names for the macros is good but somehow
> these should be shortened because they are too long and do not help
> for the readability when they are used.
>
> Perhaps, add a documentation in the code with the corresponding
> structure vs their name.
>
> [ ... ]
>
>> +struct tmd_get_mitigation_device_list_req_msg_v01 {
>> + char placeholder;
>> +};
>> +
>> +#define TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN 0.
>
> Where are these macro used ? And why are they needed ?
>
will cleanup the unused macro.
>> +const struct qmi_elem_info tmd_get_mitigation_device_list_req_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_get_mitigation_device_list_resp_msg_v01 {
>> + struct qmi_response_type_v01 resp;
>> + u8 mitigation_device_list_valid;
>> + u32 mitigation_device_list_len;
>> + struct tmd_mitigation_dev_list_type_v01
>> + mitigation_device_list[QMI_TMD_MITIGATION_DEV_LIST_MAX_V01];
>> +};
>> +
>> +#define TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN 1099
>> +static const struct qmi_elem_info tmd_get_mitigation_device_list_resp_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct qmi_response_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
>> + resp),
>> + .ei_array = qmi_response_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_OPT_FLAG,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x10,
>> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
>> + mitigation_device_list_valid),
>> + },
>> + {
>> + .data_type = QMI_DATA_LEN,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x10,
>> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
>> + mitigation_device_list_len),
>> + },
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = QMI_TMD_MITIGATION_DEV_LIST_MAX_V01,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_list_type_v01),
>> + .array_type = VAR_LEN_ARRAY,
>> + .tlv_type = 0x10,
>> + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01,
>> + mitigation_device_list),
>> + .ei_array = tmd_mitigation_dev_list_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_set_mitigation_level_req_msg_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id;
>> + u8 mitigation_level;
>> +};
>> +
>> +#define TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 40
>> +static const struct qmi_elem_info tmd_set_mitigation_level_req_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x01,
>> + .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01,
>> + mitigation_dev_id),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_UNSIGNED_1_BYTE,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01,
>> + mitigation_level),
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_set_mitigation_level_resp_msg_v01 {
>> + struct qmi_response_type_v01 resp;
>> +};
>> +
>> +#define TMD_SET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
>> +static const struct qmi_elem_info tmd_set_mitigation_level_resp_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct qmi_response_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(struct tmd_set_mitigation_level_resp_msg_v01, resp),
>> + .ei_array = qmi_response_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_get_mitigation_level_req_msg_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
>> +};
>> +
>> +#define TMD_GET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
>> +
>> +static const struct qmi_elem_info tmd_get_mitigation_level_req_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x01,
>> + .offset = offsetof(struct tmd_get_mitigation_level_req_msg_v01,
>> + mitigation_device),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_get_mitigation_level_resp_msg_v01 {
>> + struct qmi_response_type_v01 resp;
>> + u8 current_mitigation_level_valid;
>> + u8 current_mitigation_level;
>> + u8 requested_mitigation_level_valid;
>> + u8 requested_mitigation_level;
>> +};
>> +
>> +#define TMD_GET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 15
>> +static const struct qmi_elem_info tmd_get_mitigation_level_resp_msg_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct qmi_response_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01, resp),
>> + .ei_array = qmi_response_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_OPT_FLAG,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x10,
>> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
>> + current_mitigation_level_valid),
>> + },
>> + {
>> + .data_type = QMI_UNSIGNED_1_BYTE,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x10,
>> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
>> + current_mitigation_level),
>> + },
>> + {
>> + .data_type = QMI_OPT_FLAG,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x11,
>> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
>> + requested_mitigation_level_valid),
>> + },
>> + {
>> + .data_type = QMI_UNSIGNED_1_BYTE,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x11,
>> + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01,
>> + requested_mitigation_level),
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +struct tmd_register_notification_mitigation_level_req_msg_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
>> +};
>> +
>> +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
>> +static const struct qmi_elem_info
>> + tmd_register_notification_mitigation_level_req_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x01,
>> + .offset = offsetof(
>> + struct tmd_register_notification_mitigation_level_req_msg_v01,
>> + mitigation_device),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> + };
>> +
>> +struct tmd_register_notification_mitigation_level_resp_msg_v01 {
>> + struct qmi_response_type_v01 resp;
>> +};
>> +
>> +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
>> +static const struct qmi_elem_info
>> + tmd_register_notification_mitigation_level_resp_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct qmi_response_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(
>> + struct tmd_register_notification_mitigation_level_resp_msg_v01,
>> + resp),
>> + .ei_array = qmi_response_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> + };
>> +
>> +struct tmd_deregister_notification_mitigation_level_req_msg_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
>> +};
>> +
>> +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36
>> +static const struct qmi_elem_info
>> + tmd_deregister_notification_mitigation_level_req_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x01,
>> + .offset = offsetof(
>> + struct tmd_deregister_notification_mitigation_level_req_msg_v01,
>> + mitigation_device),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> + };
>> +
>> +struct tmd_deregister_notification_mitigation_level_resp_msg_v01 {
>> + struct qmi_response_type_v01 resp;
>> +};
>> +
>> +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
>> +static const struct qmi_elem_info
>> + tmd_deregister_notification_mitigation_level_resp_msg_v01_ei[] = {
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct qmi_response_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(
>> + struct tmd_deregister_notification_mitigation_level_resp_msg_v01,
>> + resp),
>> + .ei_array = qmi_response_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> + };
>> +
>> +struct tmd_mitigation_level_report_ind_msg_v01 {
>> + struct tmd_mitigation_dev_id_type_v01 mitigation_device;
>> + u8 current_mitigation_level;
>> +};
>> +
>> +#define TMD_MITIGATION_LEVEL_REPORT_IND_MSG_V01_MAX_MSG_LEN 40
>> +static const struct qmi_elem_info tmd_mitigation_level_report_ind_msg_v01_ei[] = {
>
> Where is used this variable ?
>
>> + {
>> + .data_type = QMI_STRUCT,
>> + .elem_len = 1,
>> + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x01,
>> + .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01,
>> + mitigation_device),
>> + .ei_array = tmd_mitigation_dev_id_type_v01_ei,
>> + },
>> + {
>> + .data_type = QMI_UNSIGNED_1_BYTE,
>> + .elem_len = 1,
>> + .elem_size = sizeof(uint8_t),
>> + .array_type = NO_ARRAY,
>> + .tlv_type = 0x02,
>> + .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01,
>> + current_mitigation_level),
>> + },
>> + {
>> + .data_type = QMI_EOTI,
>> + .array_type = NO_ARRAY,
>> + .tlv_type = QMI_COMMON_TLV_TYPE,
>> + },
>> +};
>> +
>> +#endif /* __QMI_COOLING_INTERNAL_H__ */
>> --
>> 2.34.1
>>
>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-03-16 19:57 ` Daniel Lezcano
@ 2026-03-18 10:17 ` Gaurav Kohli
2026-03-19 9:51 ` Konrad Dybcio
0 siblings, 1 reply; 53+ messages in thread
From: Gaurav Kohli @ 2026-03-18 10:17 UTC (permalink / raw)
To: Daniel Lezcano, Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 3/17/2026 1:27 AM, Daniel Lezcano wrote:
> On Tue, Feb 24, 2026 at 01:17:22PM +0100, Krzysztof Kozlowski wrote:
>> On 24/02/2026 13:09, Gaurav Kohli wrote:
>
> [ ... ]
>
>>>>> As a result, each core requires its own cooling device, which must be
>>>>> linked to its TSENS thermal zone. Because of this, we introduced
>>>>> multiple child nodes—one for each cooling device.
>>>>
>>>> So you have one device with cooling cells=1+2, no?
>>>>
>>>
>>> This will be a bigger framework change which is not supported, i can see
>>
>> I don't think that changing open source frameworks is "not supported". I
>> am pretty sure that changing is not only supported, but actually desired.
>
> Yes, IMO it could make sense. There are the thermal zones with phandle
> to a sensor and a sensor id. We can have the same with a phandle to a
> cooling device and a cooling device id.
>
> (... or several ids because the thermal sensor can also have multiple
> ids ?)
>
> May be an array of names corresponding to the TMD names at the 'id'
> position ?
>
I am using dt node like below to use with cooling-cells = <3> approach,
will post new patches with that.
cdsp_tmd: cdsp-tmd {
compatible = "qcom,qmi-cooling-cdsp";
tmd-names = "cdsp_sw", "cdsp_hw";
#cooling-cells = <3>;
};
please let me know, if you are expecting something like this only.
thanks
Gaurav
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-03-18 10:17 ` Gaurav Kohli
@ 2026-03-19 9:51 ` Konrad Dybcio
2026-03-21 9:00 ` Daniel Lezcano
0 siblings, 1 reply; 53+ messages in thread
From: Konrad Dybcio @ 2026-03-19 9:51 UTC (permalink / raw)
To: Gaurav Kohli, Daniel Lezcano, Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 3/18/26 11:17 AM, Gaurav Kohli wrote:
>
>
> On 3/17/2026 1:27 AM, Daniel Lezcano wrote:
>> On Tue, Feb 24, 2026 at 01:17:22PM +0100, Krzysztof Kozlowski wrote:
>>> On 24/02/2026 13:09, Gaurav Kohli wrote:
>>
>> [ ... ]
>>
>>>>>> As a result, each core requires its own cooling device, which must be
>>>>>> linked to its TSENS thermal zone. Because of this, we introduced
>>>>>> multiple child nodes—one for each cooling device.
>>>>>
>>>>> So you have one device with cooling cells=1+2, no?
>>>>>
>>>>
>>>> This will be a bigger framework change which is not supported, i can see
>>>
>>> I don't think that changing open source frameworks is "not supported". I
>>> am pretty sure that changing is not only supported, but actually desired.
>>
>> Yes, IMO it could make sense. There are the thermal zones with phandle
>> to a sensor and a sensor id. We can have the same with a phandle to a
>> cooling device and a cooling device id.
>>
>> (... or several ids because the thermal sensor can also have multiple
>> ids ?)
>>
>> May be an array of names corresponding to the TMD names at the 'id'
>> position ?
>>
>
> I am using dt node like below to use with cooling-cells = <3> approach, will post new patches with that.
>
> cdsp_tmd: cdsp-tmd {
> compatible = "qcom,qmi-cooling-cdsp";
> tmd-names = "cdsp_sw", "cdsp_hw";
> #cooling-cells = <3>;
> };
>
> please let me know, if you are expecting something like this only.
My question about the need of a separate node still remains, i.e.
why can't this be:
remoteproc_cdsp: remoteproc@cafebabe {
compatible = "qcom,foo-cdsp"
...
tmd-names = "abc", "xyz";
#cooling-cells = <3>;
};
foo-thermal {
cooling-maps {
map0 {
cooling-device = <&remoteproc_cdsp CDSP_COOLING_XYZ
THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
};
};
};
where you'd presumably call something like qmi_cooling_register(...) from
the remoteproc driver, making your added code essentially a library, not a
separate platform device
Konrad
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-03-19 9:51 ` Konrad Dybcio
@ 2026-03-21 9:00 ` Daniel Lezcano
2026-03-23 12:29 ` Konrad Dybcio
0 siblings, 1 reply; 53+ messages in thread
From: Daniel Lezcano @ 2026-03-21 9:00 UTC (permalink / raw)
To: Konrad Dybcio, Gaurav Kohli, Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
Hi Konrad,
On 3/19/26 10:51, Konrad Dybcio wrote:
> On 3/18/26 11:17 AM, Gaurav Kohli wrote:
>>
>>
>> On 3/17/2026 1:27 AM, Daniel Lezcano wrote:
>>> On Tue, Feb 24, 2026 at 01:17:22PM +0100, Krzysztof Kozlowski wrote:
>>>> On 24/02/2026 13:09, Gaurav Kohli wrote:
>>>
>>> [ ... ]
>>>
>>>>>>> As a result, each core requires its own cooling device, which must be
>>>>>>> linked to its TSENS thermal zone. Because of this, we introduced
>>>>>>> multiple child nodes—one for each cooling device.
>>>>>>
>>>>>> So you have one device with cooling cells=1+2, no?
>>>>>>
>>>>>
>>>>> This will be a bigger framework change which is not supported, i can see
>>>>
>>>> I don't think that changing open source frameworks is "not supported". I
>>>> am pretty sure that changing is not only supported, but actually desired.
>>>
>>> Yes, IMO it could make sense. There are the thermal zones with phandle
>>> to a sensor and a sensor id. We can have the same with a phandle to a
>>> cooling device and a cooling device id.
>>>
>>> (... or several ids because the thermal sensor can also have multiple
>>> ids ?)
>>>
>>> May be an array of names corresponding to the TMD names at the 'id'
>>> position ?
>>>
>>
>> I am using dt node like below to use with cooling-cells = <3> approach, will post new patches with that.
>>
>> cdsp_tmd: cdsp-tmd {
>> compatible = "qcom,qmi-cooling-cdsp";
>> tmd-names = "cdsp_sw", "cdsp_hw";
>> #cooling-cells = <3>;
>> };
>>
>> please let me know, if you are expecting something like this only.
>
> My question about the need of a separate node still remains, i.e.
> why can't this be:
>
> remoteproc_cdsp: remoteproc@cafebabe {
> compatible = "qcom,foo-cdsp"
>
> ...
>
> tmd-names = "abc", "xyz";
> #cooling-cells = <3>;
> };
>
>
>
> foo-thermal {
> cooling-maps {
> map0 {
> cooling-device = <&remoteproc_cdsp CDSP_COOLING_XYZ
> THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
> };
> };
> };
>
> where you'd presumably call something like qmi_cooling_register(...) from
> the remoteproc driver, making your added code essentially a library, not a
> separate platform device
I'm not sure to get your question. My understanding of the 3
cooling-cells is exactly what you described. The second argument of the
cooling-device map is an index corresponding to the id of the TMD. BTW I
prefer also the compatible name like 'qcom,foo-cdsp'
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-03-21 9:00 ` Daniel Lezcano
@ 2026-03-23 12:29 ` Konrad Dybcio
2026-03-23 14:19 ` Daniel Lezcano
0 siblings, 1 reply; 53+ messages in thread
From: Konrad Dybcio @ 2026-03-23 12:29 UTC (permalink / raw)
To: Daniel Lezcano, Gaurav Kohli, Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 3/21/26 10:00 AM, Daniel Lezcano wrote:
>
> Hi Konrad,
>
> On 3/19/26 10:51, Konrad Dybcio wrote:
>> On 3/18/26 11:17 AM, Gaurav Kohli wrote:
>>>
>>>
>>> On 3/17/2026 1:27 AM, Daniel Lezcano wrote:
>>>> On Tue, Feb 24, 2026 at 01:17:22PM +0100, Krzysztof Kozlowski wrote:
>>>>> On 24/02/2026 13:09, Gaurav Kohli wrote:
>>>>
>>>> [ ... ]
>>>>
>>>>>>>> As a result, each core requires its own cooling device, which must be
>>>>>>>> linked to its TSENS thermal zone. Because of this, we introduced
>>>>>>>> multiple child nodes—one for each cooling device.
>>>>>>>
>>>>>>> So you have one device with cooling cells=1+2, no?
>>>>>>>
>>>>>>
>>>>>> This will be a bigger framework change which is not supported, i can see
>>>>>
>>>>> I don't think that changing open source frameworks is "not supported". I
>>>>> am pretty sure that changing is not only supported, but actually desired.
>>>>
>>>> Yes, IMO it could make sense. There are the thermal zones with phandle
>>>> to a sensor and a sensor id. We can have the same with a phandle to a
>>>> cooling device and a cooling device id.
>>>>
>>>> (... or several ids because the thermal sensor can also have multiple
>>>> ids ?)
>>>>
>>>> May be an array of names corresponding to the TMD names at the 'id'
>>>> position ?
>>>>
>>>
>>> I am using dt node like below to use with cooling-cells = <3> approach, will post new patches with that.
>>>
>>> cdsp_tmd: cdsp-tmd {
>>> compatible = "qcom,qmi-cooling-cdsp";
>>> tmd-names = "cdsp_sw", "cdsp_hw";
>>> #cooling-cells = <3>;
>>> };
>>>
>>> please let me know, if you are expecting something like this only.
>>
>> My question about the need of a separate node still remains, i.e.
>> why can't this be:
>>
>> remoteproc_cdsp: remoteproc@cafebabe {
>> compatible = "qcom,foo-cdsp"
>>
>> ...
>>
>> tmd-names = "abc", "xyz";
>> #cooling-cells = <3>;
>> };
>>
>>
>>
>> foo-thermal {
>> cooling-maps {
>> map0 {
>> cooling-device = <&remoteproc_cdsp CDSP_COOLING_XYZ
>> THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
>> };
>> };
>> };
>>
>> where you'd presumably call something like qmi_cooling_register(...) from
>> the remoteproc driver, making your added code essentially a library, not a
>> separate platform device
>
> I'm not sure to get your question. My understanding of the 3 cooling-cells is exactly what you described. The second argument of the cooling-device map is an index corresponding to the id of the TMD. BTW I prefer also the compatible name like 'qcom,foo-cdsp'
My specific suggestion is to _not_ spawn an additional node, since all
of this logic relates to the behavior of the (e.g.) CDSP, which already
has its own node
Konrad
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-03-23 12:29 ` Konrad Dybcio
@ 2026-03-23 14:19 ` Daniel Lezcano
2026-03-23 14:25 ` Gaurav Kohli
0 siblings, 1 reply; 53+ messages in thread
From: Daniel Lezcano @ 2026-03-23 14:19 UTC (permalink / raw)
To: Konrad Dybcio, Gaurav Kohli, Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 3/23/26 13:29, Konrad Dybcio wrote:
> On 3/21/26 10:00 AM, Daniel Lezcano wrote:
>>
>> Hi Konrad,
[ ... ]
> My specific suggestion is to _not_ spawn an additional node, since
> all of this logic relates to the behavior of the (e.g.) CDSP, which
> already has its own node
Got it thanks !
+1
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings
2026-03-23 14:19 ` Daniel Lezcano
@ 2026-03-23 14:25 ` Gaurav Kohli
0 siblings, 0 replies; 53+ messages in thread
From: Gaurav Kohli @ 2026-03-23 14:25 UTC (permalink / raw)
To: Daniel Lezcano, Konrad Dybcio, Krzysztof Kozlowski
Cc: andersson, mathieu.poirier, robh, krzk+dt, conor+dt, rui.zhang,
lukasz.luba, konradybcio, mani, casey.connolly, amit.kucheria,
linux-arm-msm, devicetree, linux-kernel, linux-pm,
manaf.pallikunhi
On 3/23/2026 7:49 PM, Daniel Lezcano wrote:
> On 3/23/26 13:29, Konrad Dybcio wrote:
>> On 3/21/26 10:00 AM, Daniel Lezcano wrote:
>>>
>>> Hi Konrad,
>
> [ ... ]
>
>> My specific suggestion is to _not_ spawn an additional node, since
>> all of this logic relates to the behavior of the (e.g.) CDSP, which
>> already has its own node
>
> Got it thanks !
>
> +1
thanks for the review & guidance for the design.
working on it, will come back with a new version.
^ permalink raw reply [flat|nested] 53+ messages in thread
end of thread, other threads:[~2026-03-23 14:25 UTC | newest]
Thread overview: 53+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-27 15:57 [PATCH v2 0/8] Add RemoteProc cooling support Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 1/8] thermal: Add Remote Proc cooling driver Gaurav Kohli
2026-01-28 11:32 ` Krzysztof Kozlowski
2026-01-30 6:39 ` Gaurav Kohli
2026-02-08 10:08 ` Krzysztof Kozlowski
2026-01-28 11:36 ` Krzysztof Kozlowski
2026-01-30 6:42 ` Gaurav Kohli
2026-01-30 5:39 ` kernel test robot
2026-01-30 6:47 ` kernel test robot
2026-03-06 9:19 ` Daniel Lezcano
2026-03-06 9:27 ` Lukasz Luba
2026-03-09 6:34 ` Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 2/8] dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings Gaurav Kohli
2026-01-28 11:27 ` Krzysztof Kozlowski
2026-01-29 12:06 ` Gaurav Kohli
2026-02-08 10:06 ` Krzysztof Kozlowski
2026-02-11 7:37 ` Gaurav Kohli
2026-02-11 8:13 ` Krzysztof Kozlowski
2026-02-20 7:29 ` Gaurav Kohli
2026-02-20 7:44 ` Krzysztof Kozlowski
2026-02-24 12:09 ` Gaurav Kohli
2026-02-24 12:17 ` Krzysztof Kozlowski
2026-03-16 19:57 ` Daniel Lezcano
2026-03-18 10:17 ` Gaurav Kohli
2026-03-19 9:51 ` Konrad Dybcio
2026-03-21 9:00 ` Daniel Lezcano
2026-03-23 12:29 ` Konrad Dybcio
2026-03-23 14:19 ` Daniel Lezcano
2026-03-23 14:25 ` Gaurav Kohli
2026-02-24 12:52 ` Dmitry Baryshkov
2026-01-28 11:28 ` Krzysztof Kozlowski
2026-01-29 12:12 ` Gaurav Kohli
2026-01-29 0:45 ` Dmitry Baryshkov
2026-01-30 7:08 ` Gaurav Kohli
2026-01-30 9:02 ` Dmitry Baryshkov
2026-01-27 15:57 ` [PATCH v2 3/8] remoteproc: qcom: probe all child devices Gaurav Kohli
2026-01-27 16:50 ` Dmitry Baryshkov
2026-01-27 15:57 ` [PATCH v2 4/8] thermal: qcom: add qmi-cooling driver Gaurav Kohli
2026-01-30 9:05 ` kernel test robot
2026-03-06 9:31 ` Daniel Lezcano
2026-03-16 10:19 ` Gaurav Kohli
2026-03-13 14:15 ` Daniel Lezcano
2026-03-17 7:25 ` Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 5/8] arm64: dts: qcom: lemans: Enable CDSP cooling Gaurav Kohli
2026-01-29 0:43 ` Dmitry Baryshkov
2026-01-29 12:10 ` Gaurav Kohli
2026-01-29 12:29 ` Dmitry Baryshkov
2026-01-29 13:40 ` Gaurav Kohli
2026-01-30 1:20 ` Dmitry Baryshkov
2026-01-27 15:57 ` [PATCH v2 6/8] arm64: dts: qcom: talos: " Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 7/8] arm64: dts: qcom: kodiak: " Gaurav Kohli
2026-01-27 15:57 ` [PATCH v2 8/8] arm64: dts: qcom: monaco: " Gaurav Kohli
2026-03-06 9:09 ` [PATCH v2 0/8] Add RemoteProc cooling support Daniel Lezcano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox