From 13a96342d59f4edbe237245e84c418c045b66188 Mon Sep 17 00:00:00 2001 From: Slawomir Rosek Date: Mon, 3 Nov 2025 16:25:15 +0000 Subject: [PATCH 01/19] thermal: intel: Select INT340X_THERMAL from INTEL_SOC_DTS_THERMAL The IRQ used by the Intel SoC DTS thermal device for critical overheating notification is listed in _CRS of device INT3401 which therefore needs to be enumerated for Intel SoC DTS thermal to work. The enumeration happens by binding the int3401_thermal driver to the INT3401 platform device. Thus CONFIG_INT340X_THERMAL is in fact necessary for enumerating it, so checking CONFIG_INTEL_SOC_DTS_THERMAL in int340x_thermal_handler_attach() is pointless and INT340X_THERMAL may as well be selected by INTEL_SOC_DTS_THERMAL. Signed-off-by: Slawomir Rosek [ rjw: New subject ] Link: https://patch.msgid.link/20251103162516.2606158-2-srosek@google.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dptf/int340x_thermal.c | 7 +------ drivers/thermal/intel/Kconfig | 3 ++- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/dptf/int340x_thermal.c b/drivers/acpi/dptf/int340x_thermal.c index a222df059a16..947fe50c2ef6 100644 --- a/drivers/acpi/dptf/int340x_thermal.c +++ b/drivers/acpi/dptf/int340x_thermal.c @@ -11,10 +11,9 @@ #include "../internal.h" -#define INT3401_DEVICE 0X01 static const struct acpi_device_id int340x_thermal_device_ids[] = { {"INT3400"}, - {"INT3401", INT3401_DEVICE}, + {"INT3401"}, {"INT3402"}, {"INT3403"}, {"INT3404"}, @@ -76,10 +75,6 @@ static int int340x_thermal_handler_attach(struct acpi_device *adev, { if (IS_ENABLED(CONFIG_INT340X_THERMAL)) acpi_create_platform_device(adev, NULL); - /* Intel SoC DTS thermal driver needs INT3401 to set IRQ descriptor */ - else if (IS_ENABLED(CONFIG_INTEL_SOC_DTS_THERMAL) && - id->driver_data == INT3401_DEVICE) - acpi_create_platform_device(adev, NULL); return 1; } diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig index e0268fac7093..347c59bc87d6 100644 --- a/drivers/thermal/intel/Kconfig +++ b/drivers/thermal/intel/Kconfig @@ -44,7 +44,8 @@ config INTEL_SOC_DTS_IOSF_CORE config INTEL_SOC_DTS_THERMAL tristate "Intel SoCs DTS thermal driver" - depends on X86 && PCI && ACPI + depends on X86_64 && PCI && ACPI && NET + select INT340X_THERMAL select INTEL_SOC_DTS_IOSF_CORE help Enable this to register Intel SoCs (e.g. Bay Trail) platform digital From 966c9e65ba5246d5874a9f6ac5f318f7f50aea89 Mon Sep 17 00:00:00 2001 From: Slawomir Rosek Date: Mon, 3 Nov 2025 16:25:16 +0000 Subject: [PATCH 02/19] ACPI: DPTF: Remove int340x thermal scan handler Using the IS_ENABLED() macro in the int340x_thermal_handler_attach() forces the kernel to be recompiled when thermal drivers are enabled or disabled, which is a significant limitation of its modularity. The IS_ENABLED() macro is particularly problematic for the Android Generic Kernel Image (GKI) project which uses unified core kernel while SoC/board support is moved to loadable vendor modules. The Intel Dynamic Platform and Thermal Framework (DPTF) requires thermal drivers to be loaded at runtime, thus ACPI bus scan handler is not needed and acpi_default_enumeration() may create all platform devices, regardless of the actual setting of CONFIG_INT340X_THERMAL. Signed-off-by: Slawomir Rosek Link: https://patch.msgid.link/20251103162516.2606158-3-srosek@google.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dptf/Makefile | 1 - drivers/acpi/dptf/int340x_thermal.c | 89 ----------------------------- drivers/acpi/internal.h | 1 - drivers/acpi/scan.c | 1 - 4 files changed, 92 deletions(-) delete mode 100644 drivers/acpi/dptf/int340x_thermal.c diff --git a/drivers/acpi/dptf/Makefile b/drivers/acpi/dptf/Makefile index 297340682f66..e912a3be1d28 100644 --- a/drivers/acpi/dptf/Makefile +++ b/drivers/acpi/dptf/Makefile @@ -1,4 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_ACPI) += int340x_thermal.o obj-$(CONFIG_DPTF_POWER) += dptf_power.o obj-$(CONFIG_DPTF_PCH_FIVR) += dptf_pch_fivr.o diff --git a/drivers/acpi/dptf/int340x_thermal.c b/drivers/acpi/dptf/int340x_thermal.c deleted file mode 100644 index 947fe50c2ef6..000000000000 --- a/drivers/acpi/dptf/int340x_thermal.c +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * ACPI support for int340x thermal drivers - * - * Copyright (C) 2014, Intel Corporation - * Authors: Zhang Rui - */ - -#include -#include - -#include "../internal.h" - -static const struct acpi_device_id int340x_thermal_device_ids[] = { - {"INT3400"}, - {"INT3401"}, - {"INT3402"}, - {"INT3403"}, - {"INT3404"}, - {"INT3406"}, - {"INT3407"}, - {"INT3408"}, - {"INT3409"}, - {"INT340A"}, - {"INT340B"}, - {"INT3532"}, - {"INTC1040"}, - {"INTC1041"}, - {"INTC1042"}, - {"INTC1043"}, - {"INTC1044"}, - {"INTC1045"}, - {"INTC1046"}, - {"INTC1047"}, - {"INTC1048"}, - {"INTC1049"}, - {"INTC1050"}, - {"INTC1060"}, - {"INTC1061"}, - {"INTC1062"}, - {"INTC1063"}, - {"INTC1064"}, - {"INTC1065"}, - {"INTC1066"}, - {"INTC1068"}, - {"INTC1069"}, - {"INTC106A"}, - {"INTC106B"}, - {"INTC106C"}, - {"INTC106D"}, - {"INTC10A0"}, - {"INTC10A1"}, - {"INTC10A2"}, - {"INTC10A3"}, - {"INTC10A4"}, - {"INTC10A5"}, - {"INTC10D4"}, - {"INTC10D5"}, - {"INTC10D6"}, - {"INTC10D7"}, - {"INTC10D8"}, - {"INTC10D9"}, - {"INTC10FC"}, - {"INTC10FD"}, - {"INTC10FE"}, - {"INTC10FF"}, - {"INTC1100"}, - {"INTC1101"}, - {"INTC1102"}, - {""}, -}; - -static int int340x_thermal_handler_attach(struct acpi_device *adev, - const struct acpi_device_id *id) -{ - if (IS_ENABLED(CONFIG_INT340X_THERMAL)) - acpi_create_platform_device(adev, NULL); - return 1; -} - -static struct acpi_scan_handler int340x_thermal_handler = { - .ids = int340x_thermal_device_ids, - .attach = int340x_thermal_handler_attach, -}; - -void __init acpi_int340x_thermal_init(void) -{ - acpi_scan_add_handler(&int340x_thermal_handler); -} diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 63354972ab0b..40f875b265a9 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -27,7 +27,6 @@ static inline void acpi_pci_link_init(void) {} void acpi_processor_init(void); void acpi_platform_init(void); void acpi_pnp_init(void); -void acpi_int340x_thermal_init(void); int acpi_sysfs_init(void); void acpi_gpe_apply_masked_gpes(void); void acpi_container_init(void); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ef16d58b2949..b74cb80ff587 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2711,7 +2711,6 @@ void __init acpi_scan_init(void) acpi_watchdog_init(); acpi_pnp_init(); acpi_power_resources_init(); - acpi_int340x_thermal_init(); acpi_init_lpit(); acpi_scan_add_handler(&generic_device_handler); From 30183a67a8a0e74adf92e2dc66b5674465d42025 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Mon, 20 Oct 2025 14:31:06 +0000 Subject: [PATCH 03/19] dt-bindings: thermal: r9a09g047-tsu: Document RZ/V2H TSU The Renesas RZ/V2H SoC includes a Thermal Sensor Unit (TSU) block designed to measure the junction temperature. The device provides real-time temperature measurements for thermal management, utilizing two dedicated channels for temperature sensing. The Renesas RZ/V2H SoC is using the same TSU IP found on the RZ/G3E SoC, the only difference being that it has two channels instead of one. Add new compatible string "renesas,r9a09g057-tsu" for RZ/V2H and use "renesas,r9a09g047-tsu" as a fallback compatible to indicate hardware compatibility with the RZ/G3E implementation. Signed-off-by: Ovidiu Panait Signed-off-by: Daniel Lezcano Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251020143107.13974-3-ovidiu.panait.rb@renesas.com --- .../devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml b/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml index 8d3f3c24f0f2..befdc8b7a082 100644 --- a/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml +++ b/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml @@ -16,7 +16,11 @@ description: properties: compatible: - const: renesas,r9a09g047-tsu + oneOf: + - const: renesas,r9a09g047-tsu # RZ/G3E + - items: + - const: renesas,r9a09g057-tsu # RZ/V2H + - const: renesas,r9a09g047-tsu # RZ/G3E reg: maxItems: 1 From e1304efc19ee5c823791a0199e7f4faa6d22bc6b Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Tue, 21 Oct 2025 23:23:59 -0700 Subject: [PATCH 04/19] dt-bindings: thermal: qcom-tsens: document the Kaanapali Temperature Sensor Document the Temperature Sensor (TSENS) on the Kaanapali Platform. Signed-off-by: Manaf Meethalavalappu Pallikunhi Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251021-b4-knp-tsens-v2-1-7b662e2e71b4@oss.qualcomm.com Signed-off-by: Daniel Lezcano --- Documentation/devicetree/bindings/thermal/qcom-tsens.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index 78e2f6573b96..b9f99d109949 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -50,6 +50,7 @@ properties: items: - enum: - qcom,glymur-tsens + - qcom,kaanapali-tsens - qcom,milos-tsens - qcom,msm8953-tsens - qcom,msm8996-tsens From b1c4c05bb0aebbfab10e79c0720c576dfc31409b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 10 Nov 2025 15:30:13 +0100 Subject: [PATCH 05/19] thermal/drivers/rcar_gen3: Document R-Car Gen4 and RZ/G2 support in driver comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The R-Car Gen3 thermal driver supports both R-Car Gen3 and Gen4 SoCs as well as RZ/G2. Update the driver comment. No functional change. Reviewed-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Signed-off-by: Marek Vasut Link: https://patch.msgid.link/20251110143029.10940-1-marek.vasut+renesas@mailbox.org Signed-off-by: Daniel Lezcano --- drivers/thermal/renesas/rcar_gen3_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/renesas/rcar_gen3_thermal.c b/drivers/thermal/renesas/rcar_gen3_thermal.c index 3223de238d01..1f4f02e939ef 100644 --- a/drivers/thermal/renesas/rcar_gen3_thermal.c +++ b/drivers/thermal/renesas/rcar_gen3_thermal.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * R-Car Gen3 THS thermal sensor driver + * R-Car Gen3, Gen4 and RZ/G2 THS thermal sensor driver * Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen. * * Copyright (C) 2016 Renesas Electronics Corporation. From 901990781657660b2621fa7ff86599cf0b98da31 Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Thu, 30 Oct 2025 09:29:55 +0530 Subject: [PATCH 06/19] thermal: intel: int340x: Use symbolic constant for UUID comparison Replace sizeof() with a symbolic constant for UUID matching to maintain existing ABI behavior while improving code clarity. The current behavior of comparing only the first 7 characters is sufficient to distinguish all UUIDs and changing to full string comparison would alter the kernel ABI, potentially breaking existing userspace applications. Use a defined constant to make the truncated comparison explicit and maintainable. Signed-off-by: Kaushlendra Kumar [ rjw: Subject adjustments ] Link: https://patch.msgid.link/20251030035955.62171-1-kaushlendra.kumar@intel.com Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/int340x_thermal/int3400_thermal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index 908cc1bf57f1..128556632685 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -16,6 +16,8 @@ #define INT3400_ODVP_CHANGED 0x88 #define INT3400_KEEP_ALIVE 0xA0 #define INT3400_FAKE_TEMP (20 * 1000) /* faked temp sensor with 20C */ +/* UUID prefix length for comparison - sufficient for all UUIDs */ +#define INT3400_UUID_PREFIX_LEN 7 enum int3400_thermal_uuid { INT3400_THERMAL_ACTIVE = 0, @@ -199,7 +201,7 @@ static ssize_t current_uuid_store(struct device *dev, for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; ++i) { if (!strncmp(buf, int3400_thermal_uuids[i], - sizeof(int3400_thermal_uuids[i]) - 1)) { + INT3400_UUID_PREFIX_LEN)) { /* * If we have a list of supported UUIDs, make sure * this one is supported. From 347d92a79585c6c54be635be9e667384d2685c5c Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Thu, 30 Oct 2025 11:04:10 +0530 Subject: [PATCH 07/19] thermal: intel: int340x: Replace sprintf() with sysfs_emit() Replace sprintf() calls with sysfs_emit() in sysfs "show" functions to follow current kernel coding standards. sysfs_emit() is the preferred method for formatting sysfs output as it provides better bounds checking and is more secure. Signed-off-by: Kaushlendra Kumar [ rjw: Subject adjustments, changelog edits ] Link: https://patch.msgid.link/20251030053410.311656-1-kaushlendra.kumar@intel.com Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/int340x_thermal/int3400_thermal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index 128556632685..1aedc6709229 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -114,7 +114,7 @@ static ssize_t available_uuids_show(struct device *dev, int length = 0; if (!priv->uuid_bitmap) - return sprintf(buf, "UNKNOWN\n"); + return sysfs_emit(buf, "UNKNOWN\n"); for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) { if (priv->uuid_bitmap & (1 << i)) @@ -131,7 +131,7 @@ static ssize_t current_uuid_show(struct device *dev, int i, length = 0; if (priv->current_uuid_index >= 0) - return sprintf(buf, "%s\n", + return sysfs_emit(buf, "%s\n", int3400_thermal_uuids[priv->current_uuid_index]); for (i = 0; i <= INT3400_THERMAL_CRITICAL; i++) { @@ -142,7 +142,7 @@ static ssize_t current_uuid_show(struct device *dev, if (length) return length; - return sprintf(buf, "INVALID\n"); + return sysfs_emit(buf, "INVALID\n"); } static int int3400_thermal_run_osc(acpi_handle handle, char *uuid_str, int *enable) @@ -342,7 +342,7 @@ static ssize_t odvp_show(struct device *dev, struct device_attribute *attr, odvp_attr = container_of(attr, struct odvp_attr, attr); - return sprintf(buf, "%d\n", odvp_attr->priv->odvp[odvp_attr->odvp]); + return sysfs_emit(buf, "%d\n", odvp_attr->priv->odvp[odvp_attr->odvp]); } static void cleanup_odvp(struct int3400_thermal_priv *priv) From af1b80b9412650d96bf9c3ceec19f5d8ea2fe15f Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 10 Nov 2025 16:45:50 -0800 Subject: [PATCH 08/19] thermal: int340x: processor_thermal: Add Nova Lake processor thermal device Add PCI IDs for Nova Lake processor thermal device. Signed-off-by: Srinivas Pandruvada Link: https://patch.msgid.link/20251111004552.137984-1-srinivas.pandruvada@linux.intel.com Signed-off-by: Rafael J. Wysocki --- .../intel/int340x_thermal/processor_thermal_device.h | 2 ++ .../int340x_thermal/processor_thermal_device_pci.c | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h index 30760475102f..b79937a386ec 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h @@ -27,6 +27,8 @@ #define PCI_DEVICE_ID_INTEL_JSL_THERMAL 0x4E03 #define PCI_DEVICE_ID_INTEL_LNLM_THERMAL 0x641D #define PCI_DEVICE_ID_INTEL_MTLP_THERMAL 0x7D03 +#define PCI_DEVICE_ID_INTEL_NVL_H_THERMAL 0xD703 +#define PCI_DEVICE_ID_INTEL_NVL_S_THERMAL 0xAD03 #define PCI_DEVICE_ID_INTEL_RPL_THERMAL 0xA71D #define PCI_DEVICE_ID_INTEL_SKL_THERMAL 0x1903 #define PCI_DEVICE_ID_INTEL_TGL_THERMAL 0x9A03 diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c index e2471768d355..0d4dcc66e097 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c @@ -504,6 +504,16 @@ static const struct pci_device_id proc_thermal_pci_ids[] = { PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC) }, + { PCI_DEVICE_DATA(INTEL, NVL_H_THERMAL, PROC_THERMAL_FEATURE_RAPL | + PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS | + PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT | + PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC | + PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) }, + { PCI_DEVICE_DATA(INTEL, NVL_S_THERMAL, PROC_THERMAL_FEATURE_RAPL | + PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS | + PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT | + PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC | + PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) }, { }, }; From dbd911a07f1448c084e37414b4ebb8367ff13b2f Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 10 Nov 2025 16:45:51 -0800 Subject: [PATCH 09/19] thermal: intel: int340x: Add DLVR support for Nova Lake Add support for DLVR (Digital Linear Voltage Regulator) for Nova Lake. There are no new sysfs attributes or difference in operations compared to prior generations. MMIO offset and bit positions are changed. Also no mapping is required as units are already in MHz. Signed-off-by: Srinivas Pandruvada Link: https://patch.msgid.link/20251111004552.137984-2-srinivas.pandruvada@linux.intel.com Signed-off-by: Rafael J. Wysocki --- .../int340x_thermal/processor_thermal_rfim.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c index 1f3d22b659db..589a3a71f0c4 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c @@ -87,6 +87,17 @@ static const struct mapping_table lnl_dlvr_mapping[] = { {NULL, 0, NULL}, }; +static const struct mmio_reg nvl_dlvr_mmio_regs[] = { + { 0, 0x19208, 5, 0x1F, 0}, /* dlvr_spread_spectrum_pct */ + { 0, 0x19208, 1, 0x1, 5}, /* dlvr_control_mode */ + { 0, 0x19208, 1, 0x1, 6}, /* dlvr_control_lock */ + { 0, 0x19208, 1, 0x1, 7}, /* dlvr_rfim_enable */ + { 0, 0x19208, 12, 0xFFF, 8}, /* dlvr_freq_select */ + { 1, 0x19210, 2, 0x3, 30}, /* dlvr_hardware_rev */ + { 1, 0x19210, 16, 0xFFFF, 0}, /* dlvr_freq_mhz */ + { 1, 0x19210, 1, 0x1, 16}, /* dlvr_pll_busy */ +}; + static int match_mapping_table(const struct mapping_table *table, const char *attr_name, bool match_int_value, const u32 value, const char *value_str, char **result_str, u32 *result_int) @@ -446,6 +457,10 @@ int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc dlvr_mmio_regs_table = lnl_dlvr_mmio_regs; dlvr_mapping = lnl_dlvr_mapping; break; + case PCI_DEVICE_ID_INTEL_NVL_H_THERMAL: + case PCI_DEVICE_ID_INTEL_NVL_S_THERMAL: + dlvr_mmio_regs_table = nvl_dlvr_mmio_regs; + break; default: dlvr_mmio_regs_table = dlvr_mmio_regs; break; From 172880f7c9ea2229b1c71506dfaf95ed3ce69291 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 10 Nov 2025 16:45:52 -0800 Subject: [PATCH 10/19] ACPI: DPTF: Support Nova Lake Add Nova Lake ACPI IDs for DPTF. Signed-off-by: Srinivas Pandruvada Link: https://patch.msgid.link/20251111004552.137984-3-srinivas.pandruvada@linux.intel.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dptf/dptf_power.c | 2 ++ drivers/acpi/fan.h | 1 + drivers/thermal/intel/int340x_thermal/int3400_thermal.c | 1 + drivers/thermal/intel/int340x_thermal/int3403_thermal.c | 1 + 4 files changed, 5 insertions(+) diff --git a/drivers/acpi/dptf/dptf_power.c b/drivers/acpi/dptf/dptf_power.c index 776914f31b9e..55ccbb8ddbe3 100644 --- a/drivers/acpi/dptf/dptf_power.c +++ b/drivers/acpi/dptf/dptf_power.c @@ -240,6 +240,8 @@ static const struct acpi_device_id int3407_device_ids[] = { {"INTC10D9", 0}, {"INTC1100", 0}, {"INTC1101", 0}, + {"INTC10F7", 0}, + {"INTC10F8", 0}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, int3407_device_ids); diff --git a/drivers/acpi/fan.h b/drivers/acpi/fan.h index bedbab0e8e4e..c9583b05d3fb 100644 --- a/drivers/acpi/fan.h +++ b/drivers/acpi/fan.h @@ -21,6 +21,7 @@ {"INTC10A2", }, /* Fan for Raptor Lake generation */ \ {"INTC10D6", }, /* Fan for Panther Lake generation */ \ {"INTC10FE", }, /* Fan for Wildcat Lake generation */ \ + {"INTC10F5", }, /* Fan for Nova Lake generation */ \ {"PNP0C0B", } /* Generic ACPI fan */ #define ACPI_FPS_NAME_LEN 20 diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index 1aedc6709229..41d3bc3ed8a2 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -693,6 +693,7 @@ static const struct acpi_device_id int3400_thermal_match[] = { {"INTC10A0", 0}, {"INTC10D4", 0}, {"INTC10FC", 0}, + {"INTC10F3", 0}, {} }; diff --git a/drivers/thermal/intel/int340x_thermal/int3403_thermal.c b/drivers/thermal/intel/int340x_thermal/int3403_thermal.c index ba63796761eb..264c9bc8e645 100644 --- a/drivers/thermal/intel/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3403_thermal.c @@ -277,6 +277,7 @@ static const struct acpi_device_id int3403_device_ids[] = { {"INTC10A1", 0}, {"INTC10D5", 0}, {"INTC10FD", 0}, + {"INTC10F4", 0}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, int3403_device_ids); From 3402bc010d7630acafde9cbe893e926617f439d8 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 13 Nov 2025 13:21:03 -0800 Subject: [PATCH 11/19] Documentation: thermal: Document thermal throttling on Intel platforms Add documentation for Intel thermal throttling reporting events. Signed-off-by: Srinivas Pandruvada Tested-by: Randy Dunlap [ rjw: Subject adjustment, file name change, minor edits ] Link: https://patch.msgid.link/20251113212104.221632-1-srinivas.pandruvada@linux.intel.com Signed-off-by: Rafael J. Wysocki --- Documentation/admin-guide/thermal/index.rst | 1 + .../thermal/intel_thermal_throttle.rst | 91 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 Documentation/admin-guide/thermal/intel_thermal_throttle.rst diff --git a/Documentation/admin-guide/thermal/index.rst b/Documentation/admin-guide/thermal/index.rst index 193b7b01a87d..e48bc0a1951b 100644 --- a/Documentation/admin-guide/thermal/index.rst +++ b/Documentation/admin-guide/thermal/index.rst @@ -6,3 +6,4 @@ Thermal Subsystem :maxdepth: 1 intel_powerclamp + intel_thermal_throttle diff --git a/Documentation/admin-guide/thermal/intel_thermal_throttle.rst b/Documentation/admin-guide/thermal/intel_thermal_throttle.rst new file mode 100644 index 000000000000..f4fbf9d5a4ec --- /dev/null +++ b/Documentation/admin-guide/thermal/intel_thermal_throttle.rst @@ -0,0 +1,91 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: + +======================================= +Intel thermal throttle events reporting +======================================= + +:Author: Srinivas Pandruvada + +Introduction +------------ + +Intel processors have built in automatic and adaptive thermal monitoring +mechanisms that force the processor to reduce its power consumption in order +to operate within predetermined temperature limits. + +Refer to section "THERMAL MONITORING AND PROTECTION" in the "Intel® 64 and +IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B, 3C, & 3D): +System Programming Guide" for more details. + +In general, there are two mechanisms to control the core temperature of the +processor. They are called "Thermal Monitor 1 (TM1) and Thermal Monitor 2 (TM2)". + +The status of the temperature sensor that triggers the thermal monitor (TM1/TM2) +is indicated through the "thermal status flag" and "thermal status log flag" in +MSR_IA32_THERM_STATUS for core level and MSR_IA32_PACKAGE_THERM_STATUS for +package level. + +Thermal Status flag, bit 0 — When set, indicates that the processor core +temperature is currently at the trip temperature of the thermal monitor and that +the processor power consumption is being reduced via either TM1 or TM2, depending +on which is enabled. When clear, the flag indicates that the core temperature is +below the thermal monitor trip temperature. This flag is read only. + +Thermal Status Log flag, bit 1 — When set, indicates that the thermal sensor has +tripped since the last power-up or reset or since the last time that software +cleared this flag. This flag is a sticky bit; once set it remains set until +cleared by software or until a power-up or reset of the processor. The default +state is clear. + +It is possible that when user reads MSR_IA32_THERM_STATUS or +MSR_IA32_PACKAGE_THERM_STATUS, TM1/TM2 is not active. In this case, +"Thermal Status flag" will read "0" and the "Thermal Status Log flag" will be set +to show any previous "TM1/TM2" activation. But since it needs to be cleared by +the software, it can't show the number of occurrences of "TM1/TM2" activations. + +Hence, Linux provides counters of how many times the "Thermal Status flag" was +set. Also presents how long the "Thermal Status flag" was active in milliseconds. +Using these counters, users can check if the performance was limited because of +thermal events. It is recommended to read from sysfs instead of directly reading +MSRs as the "Thermal Status Log flag" is reset by the driver to implement rate +control. + +Sysfs Interface +--------------- + +Thermal throttling events are presented for each CPU under +"/sys/devices/system/cpu/cpuX/thermal_throttle/", where "X" is the CPU number. + +All these counters are read-only. They can't be reset to 0. So, they can potentially +overflow after reaching the maximum 64 bit unsigned integer. + +``core_throttle_count`` + Shows the number of times "Thermal Status flag" changed from 0 to 1 for this + CPU since OS boot and thermal vector is initialized. This is a 64 bit counter. + +``package_throttle_count`` + Shows the number of times "Thermal Status flag" changed from 0 to 1 for the + package containing this CPU since OS boot and thermal vector is initialized. + Package status is broadcast to all CPUs; all CPUs in the package increment + this count. This is a 64-bit counter. + +``core_throttle_max_time_ms`` + Shows the maximum amount of time for which "Thermal Status flag" has been + set to 1 for this CPU at the core level since OS boot and thermal vector + is initialized. + +``package_throttle_max_time_ms`` + Shows the maximum amount of time for which "Thermal Status flag" has been + set to 1 for the package containing this CPU since OS boot and thermal + vector is initialized. + +``core_throttle_total_time_ms`` + Shows the cumulative time for which "Thermal Status flag" has been + set to 1 for this CPU for core level since OS boot and thermal vector + is initialized. + +``package_throttle_total_time_ms`` + Shows the cumulative time for which "Thermal Status flag" has been set + to 1 for the package containing this CPU since OS boot and thermal vector + is initialized. From 186b5c2726647742bc597c076500c5d83539d9dc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 14 Nov 2025 11:50:35 +0100 Subject: [PATCH 12/19] thermal/drivers/rcar: Convert to DEFINE_SIMPLE_DEV_PM_OPS() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the Renesas R-Car thermal driver from SIMPLE_DEV_PM_OPS() to DEFINE_SIMPLE_DEV_PM_OPS() and pm_sleep_ptr(). This lets us drop the check for CONFIG_PM_SLEEP, and reduces kernel size in case CONFIG_PM or CONFIG_PM_SLEEP is disabled, while increasing build coverage. Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano Reviewed-by: Niklas Söderlund Link: https://patch.msgid.link/ee03ec71d10fd589e7458fa1b0ada3d3c19dbb54.1763117351.git.geert+renesas@glider.be --- drivers/thermal/renesas/rcar_thermal.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/thermal/renesas/rcar_thermal.c b/drivers/thermal/renesas/rcar_thermal.c index fdd7afdc4ff6..6e5dcac5d47a 100644 --- a/drivers/thermal/renesas/rcar_thermal.c +++ b/drivers/thermal/renesas/rcar_thermal.c @@ -534,7 +534,6 @@ static int rcar_thermal_probe(struct platform_device *pdev) return ret; } -#ifdef CONFIG_PM_SLEEP static int rcar_thermal_suspend(struct device *dev) { struct rcar_thermal_common *common = dev_get_drvdata(dev); @@ -567,15 +566,14 @@ static int rcar_thermal_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(rcar_thermal_pm_ops, rcar_thermal_suspend, - rcar_thermal_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(rcar_thermal_pm_ops, rcar_thermal_suspend, + rcar_thermal_resume); static struct platform_driver rcar_thermal_driver = { .driver = { .name = "rcar_thermal", - .pm = &rcar_thermal_pm_ops, + .pm = pm_sleep_ptr(&rcar_thermal_pm_ops), .of_match_table = rcar_thermal_dt_ids, }, .probe = rcar_thermal_probe, From a6eb1771022613f01480c87a15a68939f9823671 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 14 Nov 2025 11:51:29 +0100 Subject: [PATCH 13/19] thermal/drivers/rcar_gen3: Convert to DEFINE_SIMPLE_DEV_PM_OPS() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the Renesas R-Car Gen3 thermal driver from SIMPLE_DEV_PM_OPS() to DEFINE_SIMPLE_DEV_PM_OPS() and pm_sleep_ptr(). This lets us drop the __maybe_unused annotation from its resume callback, and reduces kernel size in case CONFIG_PM or CONFIG_PM_SLEEP is disabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano Reviewed-by: Niklas Söderlund Link: https://patch.msgid.link/813ad36fdc8561cf1c396230436e8ff3ff903a1f.1763117455.git.geert+renesas@glider.be --- drivers/thermal/renesas/rcar_gen3_thermal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/renesas/rcar_gen3_thermal.c b/drivers/thermal/renesas/rcar_gen3_thermal.c index 1f4f02e939ef..94804816e9e1 100644 --- a/drivers/thermal/renesas/rcar_gen3_thermal.c +++ b/drivers/thermal/renesas/rcar_gen3_thermal.c @@ -601,7 +601,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) return ret; } -static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev) +static int rcar_gen3_thermal_resume(struct device *dev) { struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev); unsigned int i; @@ -615,13 +615,13 @@ static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, NULL, - rcar_gen3_thermal_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, NULL, + rcar_gen3_thermal_resume); static struct platform_driver rcar_gen3_thermal_driver = { .driver = { .name = "rcar_gen3_thermal", - .pm = &rcar_gen3_thermal_pm_ops, + .pm = pm_sleep_ptr(&rcar_gen3_thermal_pm_ops), .of_match_table = rcar_gen3_thermal_dt_ids, }, .probe = rcar_gen3_thermal_probe, From 8538e7ee09e2090335a91f43b81cafa4bb39402e Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 18 Nov 2025 14:36:19 -0800 Subject: [PATCH 14/19] docs: driver-api/thermal/intel_dptf: Add new workload type hint Add documentation for longer term classification of workload type for power or performance. Signed-off-by: Srinivas Pandruvada Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Link: https://patch.msgid.link/20251118223620.554798-1-srinivas.pandruvada@linux.intel.com Signed-off-by: Rafael J. Wysocki --- .../driver-api/thermal/intel_dptf.rst | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Documentation/driver-api/thermal/intel_dptf.rst b/Documentation/driver-api/thermal/intel_dptf.rst index c51ac793dc06..916bf0f36a03 100644 --- a/Documentation/driver-api/thermal/intel_dptf.rst +++ b/Documentation/driver-api/thermal/intel_dptf.rst @@ -409,3 +409,26 @@ based on the processor generation. Limit 1 from being exhausted. 4 – Unknown: Can't classify. + + On processors starting from Panther Lake additional hints are provided. + The hardware analyzes workload residencies over an extended period to + determine whether the workload classification tends toward idle/battery + life states or sustained/performance states. Based on this long-term + analysis, it classifies: + + Power Classification: If the workload exhibits more idle or battery life + residencies, it is classified as "power". + + Performance Classification: If the workload exhibits more sustained or + performance residencies, it is classified as "performance". + + This approach enables applications to ignore short-term workload + fluctuations and instead respond to longer-term power vs. performance + trends. + + Residency thresholds for this classification are CPU generation-specific. + Classification is reported via bit 4 of the workload_type_index: + + Bit 4 = 1: Power classification + + Bit 4 = 0: Performance classification From 16e802667ed5c97a668b5eb3efb7615cb5f02832 Mon Sep 17 00:00:00 2001 From: Malaya Kumar Rout Date: Mon, 24 Nov 2025 16:13:58 +0530 Subject: [PATCH 15/19] tools/thermal/thermal-engine: Fix format string bug in thermal-engine The error message in the daemon() failure path uses %p format specifier without providing a corresponding pointer argument, resulting in undefined behavior and printing garbage values. Replace %p with %m to properly print the errno error message, which is the intended behavior when daemon() fails. This fix ensures proper error reporting when daemonization fails. Signed-off-by: Malaya Kumar Rout Signed-off-by: Daniel Lezcano Link: https://patch.msgid.link/20251124104401.374856-1-mrout@redhat.com --- tools/thermal/thermal-engine/thermal-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/thermal/thermal-engine/thermal-engine.c b/tools/thermal/thermal-engine/thermal-engine.c index 0764dc754771..66b0ba1fcd23 100644 --- a/tools/thermal/thermal-engine/thermal-engine.c +++ b/tools/thermal/thermal-engine/thermal-engine.c @@ -374,7 +374,7 @@ int main(int argc, char *argv[]) } if (options.daemonize && daemon(0, 0)) { - ERROR("Failed to daemonize: %p\n"); + ERROR("Failed to daemonize: %m\n"); return THERMAL_ENGINE_DAEMON_ERROR; } From 8d6f8d5c585f02a90a7b0ae4bab83801c1f21262 Mon Sep 17 00:00:00 2001 From: George Moussalem Date: Mon, 18 Aug 2025 15:33:46 +0400 Subject: [PATCH 16/19] dt-bindings: thermal: qcom-tsens: make ipq5018 tsens standalone compatible The tsens IP found in the IPQ5018 SoC should not use qcom,tsens-v1 as fallback since it has no RPM and, as such, must deviate from the standard v1 init routine as this version of tsens needs to be explicitly reset and enabled in the driver. So let's make qcom,ipq5018-tsens a standalone compatible in the bindings. Fixes: 77c6d28192ef ("dt-bindings: thermal: qcom-tsens: Add ipq5018 compatible") Reviewed-by: Krzysztof Kozlowski Reviewed-by: Bjorn Andersson Signed-off-by: George Moussalem Signed-off-by: Daniel Lezcano Link: https://patch.msgid.link/20250818-ipq5018-tsens-fix-v1-1-0f08cf09182d@outlook.com --- Documentation/devicetree/bindings/thermal/qcom-tsens.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index b9f99d109949..e30a48b430a5 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -36,10 +36,15 @@ properties: - qcom,msm8974-tsens - const: qcom,tsens-v0_1 + - description: + v1 of TSENS without RPM which requires to be explicitly reset + and enabled in the driver. + enum: + - qcom,ipq5018-tsens + - description: v1 of TSENS items: - enum: - - qcom,ipq5018-tsens - qcom,msm8937-tsens - qcom,msm8956-tsens - qcom,msm8976-tsens From 1ee90870ce797f314168fb08a5cbb0fba8d4dd65 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Fri, 22 Aug 2025 09:53:15 +0530 Subject: [PATCH 17/19] dt-bindings: thermal: tsens: Add QCS8300 compatible Add compatibility string for the thermal sensors on QCS8300 platform. Signed-off-by: Gaurav Kohli Signed-off-by: Daniel Lezcano Acked-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Akhil P Oommen Link: https://patch.msgid.link/20250822042316.1762153-2-quic_gkohli@quicinc.com --- Documentation/devicetree/bindings/thermal/qcom-tsens.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index e30a48b430a5..921b6172d6f0 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -61,6 +61,7 @@ properties: - qcom,msm8996-tsens - qcom,msm8998-tsens - qcom,qcm2290-tsens + - qcom,qcs8300-tsens - qcom,qcs615-tsens - qcom,sa8255p-tsens - qcom,sa8775p-tsens From f32aedc5753e9045f8697ddbad6e83a4017385a0 Mon Sep 17 00:00:00 2001 From: Pengfei Li Date: Mon, 20 Oct 2025 15:00:40 -0400 Subject: [PATCH 18/19] dt-bindings: thermal: fsl,imx91-tmu: add bindings for NXP i.MX91 thermal module Add bindings documentation for i.MX91 thermal modules. Signed-off-by: Pengfei Li Signed-off-by: Frank Li Signed-off-by: Daniel Lezcano Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251020-imx91tmu-v7-1-48d7d9f25055@nxp.com --- .../bindings/thermal/fsl,imx91-tmu.yaml | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/fsl,imx91-tmu.yaml diff --git a/Documentation/devicetree/bindings/thermal/fsl,imx91-tmu.yaml b/Documentation/devicetree/bindings/thermal/fsl,imx91-tmu.yaml new file mode 100644 index 000000000000..7fd1a86d7287 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/fsl,imx91-tmu.yaml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/fsl,imx91-tmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX91 Thermal + +maintainers: + - Pengfei Li + +description: + i.MX91 features a new temperature sensor. It includes programmable + temperature threshold comparators for both normal and privileged + accesses and allows a programmable measurement frequency for the + Periodic One-Shot Measurement mode. Additionally, it provides + status registers for indicating the end of measurement and threshold + violation events. + +properties: + compatible: + items: + - const: fsl,imx91-tmu + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + items: + - description: Comparator 1 irq + - description: Comparator 2 irq + - description: Data ready irq + + interrupt-names: + items: + - const: thr1 + - const: thr2 + - const: ready + + nvmem-cells: + items: + - description: Phandle to the trim control 1 provided by ocotp + - description: Phandle to the trim control 2 provided by ocotp + + nvmem-cell-names: + items: + - const: trim1 + - const: trim2 + + "#thermal-sensor-cells": + const: 0 + +required: + - compatible + - reg + - clocks + - interrupts + - interrupt-names + +allOf: + - $ref: thermal-sensor.yaml + +unevaluatedProperties: false + +examples: + - | + #include + #include + + thermal-sensor@44482000 { + compatible = "fsl,imx91-tmu"; + reg = <0x44482000 0x1000>; + #thermal-sensor-cells = <0>; + clocks = <&clk IMX93_CLK_TMC_GATE>; + interrupt-parent = <&gic>; + interrupts = , + , + ; + interrupt-names = "thr1", "thr2", "ready"; + nvmem-cells = <&tmu_trim1>, <&tmu_trim2>; + nvmem-cell-names = "trim1", "trim2"; + }; + +... From c411d8bf06992dade7abb88690dc2d467a868cc4 Mon Sep 17 00:00:00 2001 From: Pengfei Li Date: Mon, 20 Oct 2025 15:00:41 -0400 Subject: [PATCH 19/19] thermal/drivers/imx91: Add support for i.MX91 thermal monitoring unit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce support for the i.MX91 thermal monitoring unit, which features a single sensor for the CPU. The register layout differs from other chips, necessitating the creation of a dedicated file for this. This sensor provides a resolution of 1/64°C (6-bit fraction). For actual accuracy, refer to the datasheet, as it varies depending on the chip grade. Provide an interrupt for end of measurement and threshold violation and Contain temperature threshold comparators, in normal and secure address space, with direction and threshold programmability. Datasheet Link: https://www.nxp.com/docs/en/data-sheet/IMX91CEC.pdf Signed-off-by: Pengfei Li Signed-off-by: Peng Fan Signed-off-by: Frank Li Signed-off-by: Daniel Lezcano Link: https://patch.msgid.link/20251020-imx91tmu-v7-2-48d7d9f25055@nxp.com --- drivers/thermal/Kconfig | 10 + drivers/thermal/Makefile | 1 + drivers/thermal/imx91_thermal.c | 384 ++++++++++++++++++++++++++++++++ 3 files changed, 395 insertions(+) create mode 100644 drivers/thermal/imx91_thermal.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index a09c188b9ad1..b10080d61860 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -296,6 +296,16 @@ config IMX8MM_THERMAL cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config IMX91_THERMAL + tristate "Temperature sensor driver for NXP i.MX91 SoC" + depends on ARCH_MXC || COMPILE_TEST + depends on OF + help + Include one sensor and six comparators. Each of them compares the + temperature value (from the sensor) against the programmable + threshold values. The direction of the comparison is configurable + (greater / lesser than). + config K3_THERMAL tristate "Texas Instruments K3 thermal support" depends on ARCH_K3 || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index d7718978db24..bb21e7ea7fc6 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o obj-$(CONFIG_IMX_SC_THERMAL) += imx_sc_thermal.o obj-$(CONFIG_IMX8MM_THERMAL) += imx8mm_thermal.o +obj-$(CONFIG_IMX91_THERMAL) += imx91_thermal.o obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o obj-$(CONFIG_DA9062_THERMAL) += da9062-thermal.o diff --git a/drivers/thermal/imx91_thermal.c b/drivers/thermal/imx91_thermal.c new file mode 100644 index 000000000000..9b20be03d6de --- /dev/null +++ b/drivers/thermal/imx91_thermal.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 NXP. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_SET 0x4 +#define REG_CLR 0x8 +#define REG_TOG 0xc + +#define IMX91_TMU_CTRL0 0x0 +#define IMX91_TMU_CTRL0_THR1_IE BIT(9) +#define IMX91_TMU_CTRL0_THR1_MASK GENMASK(3, 2) +#define IMX91_TMU_CTRL0_CLR_FLT1 BIT(21) + +#define IMX91_TMU_THR_MODE_LE 0 +#define IMX91_TMU_THR_MODE_GE 1 + +#define IMX91_TMU_STAT0 0x10 +#define IMX91_TMU_STAT0_THR1_IF BIT(9) +#define IMX91_TMU_STAT0_THR1_STAT BIT(13) +#define IMX91_TMU_STAT0_DRDY0_IF_MASK BIT(16) + +#define IMX91_TMU_DATA0 0x20 + +#define IMX91_TMU_CTRL1 0x200 +#define IMX91_TMU_CTRL1_EN BIT(31) +#define IMX91_TMU_CTRL1_START BIT(30) +#define IMX91_TMU_CTRL1_STOP BIT(29) +#define IMX91_TMU_CTRL1_RES_MASK GENMASK(19, 18) +#define IMX91_TMU_CTRL1_MEAS_MODE_MASK GENMASK(25, 24) +#define IMX91_TMU_CTRL1_MEAS_MODE_SINGLE 0 +#define IMX91_TMU_CTRL1_MEAS_MODE_CONTINUES 1 +#define IMX91_TMU_CTRL1_MEAS_MODE_PERIODIC 2 + +#define IMX91_TMU_THR_CTRL01 0x30 +#define IMX91_TMU_THR_CTRL01_THR1_MASK GENMASK(31, 16) + +#define IMX91_TMU_REF_DIV 0x280 +#define IMX91_TMU_DIV_EN BIT(31) +#define IMX91_TMU_DIV_MASK GENMASK(23, 16) +#define IMX91_TMU_DIV_MAX 255 + +#define IMX91_TMU_PUD_ST_CTRL 0x2b0 +#define IMX91_TMU_PUDL_MASK GENMASK(23, 16) + +#define IMX91_TMU_TRIM1 0x2e0 +#define IMX91_TMU_TRIM2 0x2f0 + +#define IMX91_TMU_TEMP_LOW_LIMIT -40000 +#define IMX91_TMU_TEMP_HIGH_LIMIT 125000 + +#define IMX91_TMU_DEFAULT_TRIM1_CONFIG 0xb561bc2d +#define IMX91_TMU_DEFAULT_TRIM2_CONFIG 0x65d4 + +#define IMX91_TMU_PERIOD_CTRL 0x270 +#define IMX91_TMU_PERIOD_CTRL_MEAS_MASK GENMASK(23, 0) + +#define IMX91_TMP_FRAC 64 + +struct imx91_tmu { + void __iomem *base; + struct clk *clk; + struct device *dev; + struct thermal_zone_device *tzd; +}; + +static void imx91_tmu_start(struct imx91_tmu *tmu, bool start) +{ + u32 val = start ? IMX91_TMU_CTRL1_START : IMX91_TMU_CTRL1_STOP; + + writel_relaxed(val, tmu->base + IMX91_TMU_CTRL1 + REG_SET); +} + +static void imx91_tmu_enable(struct imx91_tmu *tmu, bool enable) +{ + u32 reg = IMX91_TMU_CTRL1; + + reg += enable ? REG_SET : REG_CLR; + + writel_relaxed(IMX91_TMU_CTRL1_EN, tmu->base + reg); +} + +static int imx91_tmu_to_mcelsius(int x) +{ + return x * MILLIDEGREE_PER_DEGREE / IMX91_TMP_FRAC; +} + +static int imx91_tmu_from_mcelsius(int x) +{ + return x * IMX91_TMP_FRAC / MILLIDEGREE_PER_DEGREE; +} + +static int imx91_tmu_get_temp(struct thermal_zone_device *tz, int *temp) +{ + struct imx91_tmu *tmu = thermal_zone_device_priv(tz); + s16 data; + + /* DATA0 is 16bit signed number */ + data = readw_relaxed(tmu->base + IMX91_TMU_DATA0); + *temp = imx91_tmu_to_mcelsius(data); + + return 0; +} + +static int imx91_tmu_set_trips(struct thermal_zone_device *tz, int low, int high) +{ + struct imx91_tmu *tmu = thermal_zone_device_priv(tz); + int val; + + if (high >= IMX91_TMU_TEMP_HIGH_LIMIT) + return -EINVAL; + + writel_relaxed(IMX91_TMU_CTRL0_THR1_IE, tmu->base + IMX91_TMU_CTRL0 + REG_CLR); + + /* Comparator1 for temperature threshold */ + writel_relaxed(IMX91_TMU_THR_CTRL01_THR1_MASK, tmu->base + IMX91_TMU_THR_CTRL01 + REG_CLR); + val = FIELD_PREP(IMX91_TMU_THR_CTRL01_THR1_MASK, imx91_tmu_from_mcelsius(high)); + + writel_relaxed(val, tmu->base + IMX91_TMU_THR_CTRL01 + REG_SET); + + writel_relaxed(IMX91_TMU_STAT0_THR1_IF, tmu->base + IMX91_TMU_STAT0 + REG_CLR); + + writel_relaxed(IMX91_TMU_CTRL0_THR1_IE, tmu->base + IMX91_TMU_CTRL0 + REG_SET); + + return 0; +} + +static int imx91_init_from_nvmem_cells(struct imx91_tmu *tmu) +{ + struct device *dev = tmu->dev; + u32 trim1, trim2; + int ret; + + ret = nvmem_cell_read_u32(dev, "trim1", &trim1); + if (ret) + return ret; + + ret = nvmem_cell_read_u32(dev, "trim2", &trim2); + if (ret) + return ret; + + if (trim1 == 0 || trim2 == 0) + return -EINVAL; + + writel_relaxed(trim1, tmu->base + IMX91_TMU_TRIM1); + writel_relaxed(trim2, tmu->base + IMX91_TMU_TRIM2); + + return 0; +} + +static void imx91_tmu_action_remove(void *data) +{ + struct imx91_tmu *tmu = data; + + /* disable tmu */ + imx91_tmu_enable(tmu, false); +} + +static irqreturn_t imx91_tmu_alarm_irq(int irq, void *data) +{ + struct imx91_tmu *tmu = data; + u32 val; + + val = readl_relaxed(tmu->base + IMX91_TMU_STAT0); + + /* Check if comparison interrupt occurred */ + if (val & IMX91_TMU_STAT0_THR1_IF) { + /* Clear irq flag and disable interrupt until reconfigured */ + writel(IMX91_TMU_STAT0_THR1_IF, tmu->base + IMX91_TMU_STAT0 + REG_CLR); + writel_relaxed(IMX91_TMU_CTRL0_THR1_IE, tmu->base + IMX91_TMU_CTRL0 + REG_CLR); + + return IRQ_WAKE_THREAD; + } + + return IRQ_NONE; +} + +static irqreturn_t imx91_tmu_alarm_irq_thread(int irq, void *data) +{ + struct imx91_tmu *tmu = data; + + thermal_zone_device_update(tmu->tzd, THERMAL_EVENT_UNSPECIFIED); + + return IRQ_HANDLED; +} + +static int imx91_tmu_change_mode(struct thermal_zone_device *tz, enum thermal_device_mode mode) +{ + struct imx91_tmu *tmu = thermal_zone_device_priv(tz); + int ret; + + if (mode == THERMAL_DEVICE_ENABLED) { + ret = pm_runtime_get(tmu->dev); + if (ret < 0) + return ret; + + writel_relaxed(IMX91_TMU_CTRL0_THR1_IE | IMX91_TMU_CTRL0_THR1_MASK, + tmu->base + IMX91_TMU_CTRL0 + REG_CLR); + + writel_relaxed(FIELD_PREP(IMX91_TMU_CTRL0_THR1_MASK, IMX91_TMU_THR_MODE_GE), + tmu->base + IMX91_TMU_CTRL0 + REG_SET); + imx91_tmu_start(tmu, true); + } else { + writel_relaxed(IMX91_TMU_CTRL0_THR1_IE, tmu->base + IMX91_TMU_CTRL0 + REG_CLR); + imx91_tmu_start(tmu, false); + pm_runtime_put(tmu->dev); + } + + return 0; +} + +static struct thermal_zone_device_ops tmu_tz_ops = { + .get_temp = imx91_tmu_get_temp, + .change_mode = imx91_tmu_change_mode, + .set_trips = imx91_tmu_set_trips, +}; + +static int imx91_tmu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct imx91_tmu *tmu; + unsigned long rate; + int irq, ret; + u32 div; + + tmu = devm_kzalloc(dev, sizeof(struct imx91_tmu), GFP_KERNEL); + if (!tmu) + return -ENOMEM; + + tmu->dev = dev; + + tmu->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(tmu->base)) + return dev_err_probe(dev, PTR_ERR(tmu->base), "failed to get io resource"); + + tmu->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(tmu->clk)) + return dev_err_probe(dev, PTR_ERR(tmu->clk), "failed to get tmu clock\n"); + + platform_set_drvdata(pdev, tmu); + + /* disable the monitor during initialization */ + imx91_tmu_enable(tmu, false); + imx91_tmu_start(tmu, false); + + ret = imx91_init_from_nvmem_cells(tmu); + if (ret) { + dev_warn(dev, "can't get trim value, use default settings\n"); + + writel_relaxed(IMX91_TMU_DEFAULT_TRIM1_CONFIG, tmu->base + IMX91_TMU_TRIM1); + writel_relaxed(IMX91_TMU_DEFAULT_TRIM2_CONFIG, tmu->base + IMX91_TMU_TRIM2); + } + + /* The typical conv clk is 4MHz, the output freq is 'rate / (div + 1)' */ + rate = clk_get_rate(tmu->clk); + div = (rate / (4 * HZ_PER_MHZ)) - 1; + if (div > IMX91_TMU_DIV_MAX) + return dev_err_probe(dev, -EINVAL, "clock divider exceed hardware limitation"); + + /* Set divider value and enable divider */ + writel_relaxed(IMX91_TMU_DIV_EN | FIELD_PREP(IMX91_TMU_DIV_MASK, div), + tmu->base + IMX91_TMU_REF_DIV); + + /* Set max power up delay: 'Tpud(ms) = 0xFF * 1000 / 4000000' */ + writel_relaxed(FIELD_PREP(IMX91_TMU_PUDL_MASK, 100U), tmu->base + IMX91_TMU_PUD_ST_CTRL); + + /* + * Set resolution mode + * 00b - Conversion time = 0.59325 ms + * 01b - Conversion time = 1.10525 ms + * 10b - Conversion time = 2.12925 ms + * 11b - Conversion time = 4.17725 ms + */ + writel_relaxed(FIELD_PREP(IMX91_TMU_CTRL1_RES_MASK, 0x3), + tmu->base + IMX91_TMU_CTRL1 + REG_CLR); + writel_relaxed(FIELD_PREP(IMX91_TMU_CTRL1_RES_MASK, 0x1), + tmu->base + IMX91_TMU_CTRL1 + REG_SET); + + writel_relaxed(IMX91_TMU_CTRL1_MEAS_MODE_MASK, tmu->base + IMX91_TMU_CTRL1 + REG_CLR); + writel_relaxed(FIELD_PREP(IMX91_TMU_CTRL1_MEAS_MODE_MASK, + IMX91_TMU_CTRL1_MEAS_MODE_PERIODIC), + tmu->base + IMX91_TMU_CTRL1 + REG_SET); + + /* + * Set Periodic Measurement Frequency to 25Hz: + * tMEAS_FREQ = tCONV_CLK * PERIOD_CTRL[MEAS_FREQ] + */ + writel_relaxed(FIELD_PREP(IMX91_TMU_PERIOD_CTRL_MEAS_MASK, 4 * HZ_PER_MHZ / 25), + tmu->base + IMX91_TMU_PERIOD_CTRL); + + imx91_tmu_enable(tmu, true); + ret = devm_add_action(dev, imx91_tmu_action_remove, tmu); + if (ret) + return dev_err_probe(dev, ret, "Failure to add action imx91_tmu_action_remove()\n"); + + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + tmu->tzd = devm_thermal_of_zone_register(dev, 0, tmu, &tmu_tz_ops); + if (IS_ERR(tmu->tzd)) + return dev_err_probe(dev, PTR_ERR(tmu->tzd), + "failed to register thermal zone sensor\n"); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, irq, imx91_tmu_alarm_irq, + imx91_tmu_alarm_irq_thread, + IRQF_ONESHOT, "imx91_thermal", tmu); + + if (ret < 0) + return dev_err_probe(dev, ret, "failed to request alarm irq\n"); + + pm_runtime_put(dev); + + return 0; +} + +static int imx91_tmu_runtime_suspend(struct device *dev) +{ + struct imx91_tmu *tmu = dev_get_drvdata(dev); + + /* disable tmu */ + imx91_tmu_enable(tmu, false); + + clk_disable_unprepare(tmu->clk); + + return 0; +} + +static int imx91_tmu_runtime_resume(struct device *dev) +{ + struct imx91_tmu *tmu = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(tmu->clk); + if (ret) + return ret; + + imx91_tmu_enable(tmu, true); + + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(imx91_tmu_pm_ops, imx91_tmu_runtime_suspend, + imx91_tmu_runtime_resume, NULL); + +static const struct of_device_id imx91_tmu_table[] = { + { .compatible = "fsl,imx91-tmu", }, + { }, +}; +MODULE_DEVICE_TABLE(of, imx91_tmu_table); + +static struct platform_driver imx91_tmu = { + .driver = { + .name = "imx91_thermal", + .pm = pm_ptr(&imx91_tmu_pm_ops), + .of_match_table = imx91_tmu_table, + }, + .probe = imx91_tmu_probe, +}; +module_platform_driver(imx91_tmu); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("i.MX91 Thermal Monitor Unit driver"); +MODULE_LICENSE("GPL");