Merge branch 'thermal' into linux-next * thermal: (34 commits) drivers: thermal: intel: tcc_cooling: Drop redundant local variable thermal/of: Fix reference leak in thermal_of_cm_lookup() thermal: core: thermal_core.h: fix all kernel-doc warnings thermal: intel: x86_pkg_temp_thermal: Handle invalid temperature thermal: renesas: rzg3e: add support for RZ/T2H and RZ/N2H dt-bindings: thermal: r9a09g047-tsu: document RZ/T2H and RZ/N2H thermal: renesas: rzg3e: make calibration value retrieval per-chip thermal: renesas: rzg3e: make min and max temperature per-chip thermal: renesas: rzg3e: make reset optional dt-bindings: thermal: r9a09g047-tsu: Document RZ/V2N TSU thermal/drivers/broadcom: Use clamp to simplify bcm2835_thermal_temp2adc thermal/drivers/stm32: Use predefined HZ_PER_MHZ instead of a custom one thermal/drivers/mediatek/lvts_thermal: Add mt7987 support dt-bindings: thermal: mediatek: Add LVTS thermal controller definition for MT7987 dt-bindings: nvmem: mediatek: efuse: Add support for MT8196 thermal/drivers/mediatek/lvts_thermal: Add MT8196 support thermal/drivers/mediatek/lvts: Support MSR offset for 16-bit calibration data thermal/drivers/mediatek/lvts: Add support for ATP mode thermal/drivers/mediatek/lvts: Add lvts_temp_to_raw variant thermal/drivers/mediatek/lvts: Add platform ops to support alternative conversion logic ...
diff --git a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml index c9bf34e..f9323b3 100644 --- a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml
@@ -28,6 +28,7 @@ - enum: - mediatek,mt8188-efuse - mediatek,mt8189-efuse + - mediatek,mt8196-efuse - const: mediatek,mt8186-efuse - const: mediatek,mt8186-efuse
diff --git a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml index 0259cd3..9752351 100644 --- a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
@@ -18,6 +18,7 @@ properties: compatible: enum: + - mediatek,mt7987-lvts-ap - mediatek,mt7988-lvts-ap - mediatek,mt8186-lvts - mediatek,mt8188-lvts-ap @@ -26,6 +27,8 @@ - mediatek,mt8192-lvts-mcu - mediatek,mt8195-lvts-ap - mediatek,mt8195-lvts-mcu + - mediatek,mt8196-lvts-ap + - mediatek,mt8196-lvts-mcu reg: maxItems: 1
diff --git a/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml b/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml index befdc8b..d560c58b 100644 --- a/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml +++ b/Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml
@@ -17,10 +17,17 @@ properties: compatible: oneOf: - - const: renesas,r9a09g047-tsu # RZ/G3E + - enum: + - renesas,r9a09g047-tsu # RZ/G3E + - renesas,r9a09g077-tsu # RZ/T2H - items: - - const: renesas,r9a09g057-tsu # RZ/V2H + - enum: + - renesas,r9a09g056-tsu # RZ/V2N + - renesas,r9a09g057-tsu # RZ/V2H - const: renesas,r9a09g047-tsu # RZ/G3E + - items: + - const: renesas,r9a09g087-tsu # RZ/N2H + - const: renesas,r9a09g077-tsu # RZ/T2H reg: maxItems: 1 @@ -63,12 +70,31 @@ - compatible - reg - clocks - - resets - power-domains - interrupts - interrupt-names - "#thermal-sensor-cells" - - renesas,tsu-trim + +allOf: + - if: + properties: + compatible: + contains: + const: renesas,r9a09g047-tsu + then: + required: + - resets + - renesas,tsu-trim + + - if: + properties: + compatible: + contains: + const: renesas,r9a09g077-tsu + then: + properties: + resets: false + renesas,tsu-trim: false additionalProperties: false
diff --git a/Documentation/driver-api/thermal/intel_dptf.rst b/Documentation/driver-api/thermal/intel_dptf.rst index 916bf0f..4adfa1e 100644 --- a/Documentation/driver-api/thermal/intel_dptf.rst +++ b/Documentation/driver-api/thermal/intel_dptf.rst
@@ -375,6 +375,9 @@ ``workload_hint_enable`` (RW) Enable firmware to send workload type hints to user space. +``workload_slow_hint_enable`` (RW) + Enable firmware to send slow workload type hints to user space. + ``notification_delay_ms`` (RW) Minimum delay in milliseconds before firmware will notify OS. This is for the rate control of notifications. This delay is between changing
diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c index 685a5ae..c5105df 100644 --- a/drivers/thermal/broadcom/bcm2835_thermal.c +++ b/drivers/thermal/broadcom/bcm2835_thermal.c
@@ -11,6 +11,7 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/minmax.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> @@ -80,12 +81,7 @@ static int bcm2835_thermal_temp2adc(int temp, int offset, int slope) temp -= offset; temp /= slope; - if (temp < 0) - temp = 0; - if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS)) - temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1; - - return temp; + return clamp(temp, 0, (int)BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1); } static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 48e7849..f80dbe2 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -8,6 +8,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/sysfs.h> #include <linux/thermal.h> #include <asm/msr.h> #include "int340x_thermal_zone.h" @@ -23,7 +24,7 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ { \ struct proc_thermal_device *proc_dev = dev_get_drvdata(dev); \ \ - return sprintf(buf, "%lu\n",\ + return sysfs_emit(buf, "%lu\n",\ (unsigned long)proc_dev->power_limits[index].suffix * 1000); \ } @@ -143,7 +144,7 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev, if (offset < 0) return offset; - return sprintf(buf, "%d\n", offset); + return sysfs_emit(buf, "%d\n", offset); } static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c index 589a3a7..bb9398d 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
@@ -7,6 +7,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/sysfs.h> #include "processor_thermal_device.h" MODULE_IMPORT_NS("INT340X_THERMAL"); @@ -211,9 +212,9 @@ static ssize_t suffix##_show(struct device *dev,\ ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\ err = get_mapped_string(mapping, attr->attr.name, ret, &str);\ if (!err)\ - return sprintf(buf, "%s\n", str);\ + return sysfs_emit(buf, "%s\n", str);\ if (err == -EOPNOTSUPP)\ - return sprintf(buf, "%u\n", ret);\ + return sysfs_emit(buf, "%u\n", ret);\ return err;\ } @@ -398,7 +399,7 @@ static ssize_t rfi_restriction_show(struct device *dev, if (ret) return ret; - return sprintf(buf, "%llu\n", resp); + return sysfs_emit(buf, "%llu\n", resp); } static ssize_t ddr_data_rate_show(struct device *dev, @@ -413,7 +414,7 @@ static ssize_t ddr_data_rate_show(struct device *dev, if (ret) return ret; - return sprintf(buf, "%llu\n", resp); + return sysfs_emit(buf, "%llu\n", resp); } static DEVICE_ATTR_RW(rfi_restriction);
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c index 68e8391..f8c33e8 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c
@@ -34,6 +34,7 @@ #define SOC_WT GENMASK_ULL(47, 40) +#define SOC_WT_SLOW_PREDICTION_INT_ENABLE_BIT 22 #define SOC_WT_PREDICTION_INT_ENABLE_BIT 23 #define SOC_WT_PREDICTION_INT_ACTIVE BIT(2) @@ -47,6 +48,7 @@ static u16 notify_delay_ms = 1024; static DEFINE_MUTEX(wt_lock); static u8 wt_enable; +static u8 wt_slow_enable; /* Show current predicted workload type index */ static ssize_t workload_type_index_show(struct device *dev, @@ -59,7 +61,7 @@ static ssize_t workload_type_index_show(struct device *dev, int wt; mutex_lock(&wt_lock); - if (!wt_enable) { + if (!wt_enable && !wt_slow_enable) { mutex_unlock(&wt_lock); return -ENODATA; } @@ -84,9 +86,9 @@ static ssize_t workload_hint_enable_show(struct device *dev, return sysfs_emit(buf, "%d\n", wt_enable); } -static ssize_t workload_hint_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) +static ssize_t workload_hint_enable(struct device *dev, u8 enable_bit, u8 *status, + struct device_attribute *attr, + const char *buf, size_t size) { struct pci_dev *pdev = to_pci_dev(dev); u8 mode; @@ -99,17 +101,17 @@ static ssize_t workload_hint_enable_store(struct device *dev, if (mode) ret = processor_thermal_mbox_interrupt_config(pdev, true, - SOC_WT_PREDICTION_INT_ENABLE_BIT, + enable_bit, notify_delay); else ret = processor_thermal_mbox_interrupt_config(pdev, false, - SOC_WT_PREDICTION_INT_ENABLE_BIT, 0); + enable_bit, 0); if (ret) goto ret_enable_store; ret = size; - wt_enable = mode; + *status = mode; ret_enable_store: mutex_unlock(&wt_lock); @@ -117,8 +119,28 @@ static ssize_t workload_hint_enable_store(struct device *dev, return ret; } +static ssize_t workload_hint_enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + return workload_hint_enable(dev, SOC_WT_PREDICTION_INT_ENABLE_BIT, &wt_enable, + attr, buf, size); +} static DEVICE_ATTR_RW(workload_hint_enable); +static ssize_t workload_slow_hint_enable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%d\n", wt_slow_enable); +} + +static ssize_t workload_slow_hint_enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + return workload_hint_enable(dev, SOC_WT_SLOW_PREDICTION_INT_ENABLE_BIT, &wt_slow_enable, + attr, buf, size); +} +static DEVICE_ATTR_RW(workload_slow_hint_enable); + static ssize_t notification_delay_ms_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -178,16 +200,35 @@ static ssize_t notification_delay_ms_store(struct device *dev, static DEVICE_ATTR_RW(notification_delay_ms); +static umode_t workload_hint_attr_visible(struct kobject *kobj, struct attribute *attr, int unused) +{ + if (attr != &dev_attr_workload_slow_hint_enable.attr) + return attr->mode; + + switch (to_pci_dev(kobj_to_dev(kobj))->device) { + case PCI_DEVICE_ID_INTEL_LNLM_THERMAL: + case PCI_DEVICE_ID_INTEL_MTLP_THERMAL: + case PCI_DEVICE_ID_INTEL_ARL_S_THERMAL: + return 0; + default: + break; + } + + return attr->mode; +} + static struct attribute *workload_hint_attrs[] = { &dev_attr_workload_type_index.attr, &dev_attr_workload_hint_enable.attr, + &dev_attr_workload_slow_hint_enable.attr, &dev_attr_notification_delay_ms.attr, NULL }; static const struct attribute_group workload_hint_attribute_group = { .attrs = workload_hint_attrs, - .name = "workload_hint" + .name = "workload_hint", + .is_visible = workload_hint_attr_visible }; /*
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c index b95810f..2372f52 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c
@@ -7,6 +7,7 @@ */ #include <linux/pci.h> +#include <linux/sysfs.h> #include "processor_thermal_device.h" /* List of workload types */ @@ -28,9 +29,9 @@ static ssize_t workload_available_types_show(struct device *dev, int ret = 0; while (workload_types[i] != NULL) - ret += sprintf(&buf[ret], "%s ", workload_types[i++]); + ret += sysfs_emit_at(buf, ret, "%s ", workload_types[i++]); - ret += sprintf(&buf[ret], "\n"); + ret += sysfs_emit_at(buf, ret, "\n"); return ret; } @@ -85,7 +86,7 @@ static ssize_t workload_type_show(struct device *dev, if (cmd_resp > ARRAY_SIZE(workload_types) - 1) return -EINVAL; - return sprintf(buf, "%s\n", workload_types[cmd_resp]); + return sysfs_emit(buf, "%s\n", workload_types[cmd_resp]); } static DEVICE_ATTR_RW(workload_type);
diff --git a/drivers/thermal/intel/intel_pch_thermal.c b/drivers/thermal/intel/intel_pch_thermal.c index fc32698..52e71af 100644 --- a/drivers/thermal/intel/intel_pch_thermal.c +++ b/drivers/thermal/intel/intel_pch_thermal.c
@@ -269,7 +269,6 @@ static void intel_pch_thermal_remove(struct pci_dev *pdev) thermal_zone_device_unregister(ptd->tzd); iounmap(ptd->hw_base); - pci_set_drvdata(pdev, NULL); pci_release_regions(pdev); pci_disable_device(pdev); }
diff --git a/drivers/thermal/intel/intel_tcc.c b/drivers/thermal/intel/intel_tcc.c index b2a615a..ab61fb1 100644 --- a/drivers/thermal/intel/intel_tcc.c +++ b/drivers/thermal/intel/intel_tcc.c
@@ -172,7 +172,7 @@ static u32 get_temp_mask(bool pkg) /** * intel_tcc_get_tjmax() - returns the default TCC activation Temperature - * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * @cpu: cpu that the MSR should be run on, negative value means any cpu. * * Get the TjMax value, which is the default thermal throttling or TCC * activation temperature in degrees C. @@ -199,7 +199,7 @@ EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, "INTEL_TCC"); /** * intel_tcc_get_offset() - returns the TCC Offset value to Tjmax - * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * @cpu: cpu that the MSR should be run on, negative value means any cpu. * * Get the TCC offset value to Tjmax. The effective thermal throttling or TCC * activation temperature equals "Tjmax" - "TCC Offset", in degrees C. @@ -224,7 +224,7 @@ EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, "INTEL_TCC"); /** * intel_tcc_set_offset() - set the TCC offset value to Tjmax - * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * @cpu: cpu that the MSR should be run on, negative value means any cpu. * @offset: TCC offset value in degree C * * Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC @@ -267,7 +267,7 @@ EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, "INTEL_TCC"); /** * intel_tcc_get_temp() - returns the current temperature - * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * @cpu: cpu that the MSR should be run on, negative value means any cpu. * @temp: pointer to the memory for saving cpu temperature. * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor. *
diff --git a/drivers/thermal/intel/intel_tcc_cooling.c b/drivers/thermal/intel/intel_tcc_cooling.c index f352eca..6c2ba0b 100644 --- a/drivers/thermal/intel/intel_tcc_cooling.c +++ b/drivers/thermal/intel/intel_tcc_cooling.c
@@ -65,6 +65,10 @@ static const struct x86_cpu_id tcc_ids[] __initconst = { X86_MATCH_VFM(INTEL_RAPTORLAKE, NULL), X86_MATCH_VFM(INTEL_RAPTORLAKE_P, NULL), X86_MATCH_VFM(INTEL_RAPTORLAKE_S, NULL), + X86_MATCH_VFM(INTEL_PANTHERLAKE_L, NULL), + X86_MATCH_VFM(INTEL_WILDCATLAKE_L, NULL), + X86_MATCH_VFM(INTEL_NOVALAKE, NULL), + X86_MATCH_VFM(INTEL_NOVALAKE_L, NULL), {} }; @@ -72,10 +76,8 @@ MODULE_DEVICE_TABLE(x86cpu, tcc_ids); static int __init tcc_cooling_init(void) { - int ret; u64 val; const struct x86_cpu_id *id; - int err; id = x86_match_cpu(tcc_ids); @@ -103,10 +105,9 @@ static int __init tcc_cooling_init(void) tcc_cdev = thermal_cooling_device_register("TCC Offset", NULL, &tcc_cooling_ops); - if (IS_ERR(tcc_cdev)) { - ret = PTR_ERR(tcc_cdev); - return ret; - } + if (IS_ERR(tcc_cdev)) + return PTR_ERR(tcc_cdev); + return 0; }
diff --git a/drivers/thermal/intel/therm_throt.c b/drivers/thermal/intel/therm_throt.c index debc94e..44fa4dd 100644 --- a/drivers/thermal/intel/therm_throt.c +++ b/drivers/thermal/intel/therm_throt.c
@@ -23,6 +23,7 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/smp.h> +#include <linux/sysfs.h> #include <linux/cpu.h> #include <asm/processor.h> @@ -144,8 +145,8 @@ static ssize_t therm_throt_device_show_##event##_##name( \ \ preempt_disable(); /* CPU hotplug */ \ if (cpu_online(cpu)) { \ - ret = sprintf(buf, "%lu\n", \ - per_cpu(thermal_state, cpu).event.name); \ + ret = sysfs_emit(buf, "%lu\n", \ + per_cpu(thermal_state, cpu).event.name); \ } else \ ret = 0; \ preempt_enable(); \
diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c index 3fc679b..aab5f9f 100644 --- a/drivers/thermal/intel/x86_pkg_temp_thermal.c +++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c
@@ -128,6 +128,9 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, u32 l, h, mask, shift, intr; int tj_max, val, ret; + if (temp == THERMAL_TEMP_INVALID) + temp = 0; + tj_max = intel_tcc_get_tjmax(zonedev->cpu); if (tj_max < 0) return tj_max;
diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index ab55b20c..a9617d5 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c
@@ -44,6 +44,11 @@ #define LVTS_EDATA01(__base) (__base + 0x0058) #define LVTS_EDATA02(__base) (__base + 0x005C) #define LVTS_EDATA03(__base) (__base + 0x0060) +#define LVTS_MSROFT(__base) (__base + 0x006C) +#define LVTS_ATP0(__base) (__base + 0x0070) +#define LVTS_ATP1(__base) (__base + 0x0074) +#define LVTS_ATP2(__base) (__base + 0x0078) +#define LVTS_ATP3(__base) (__base + 0x007C) #define LVTS_MSR0(__base) (__base + 0x0090) #define LVTS_MSR1(__base) (__base + 0x0094) #define LVTS_MSR2(__base) (__base + 0x0098) @@ -85,30 +90,43 @@ #define LVTS_GOLDEN_TEMP_DEFAULT 50 #define LVTS_COEFF_A_MT8195 -250460 #define LVTS_COEFF_B_MT8195 250460 +#define LVTS_COEFF_A_MT7987 -204650 +#define LVTS_COEFF_B_MT7987 204650 #define LVTS_COEFF_A_MT7988 -204650 #define LVTS_COEFF_B_MT7988 204650 +#define LVTS_COEFF_A_MT8196 391460 +#define LVTS_COEFF_B_MT8196 -391460 -#define LVTS_MSR_IMMEDIATE_MODE 0 -#define LVTS_MSR_FILTERED_MODE 1 +#define LVTS_MSR_OFFSET_MT8196 -984 #define LVTS_MSR_READ_TIMEOUT_US 400 #define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2) #define LVTS_MINIMUM_THRESHOLD 20000 +#define LVTS_MAX_CAL_OFFSETS 3 +#define LVTS_NUM_CAL_OFFSETS_MT7988 3 +#define LVTS_NUM_CAL_OFFSETS_MT8196 2 + static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT; static int golden_temp_offset; +enum lvts_msr_mode { + LVTS_MSR_IMMEDIATE_MODE, + LVTS_MSR_FILTERED_MODE, + LVTS_MSR_ATP_MODE, +}; + struct lvts_sensor_data { int dt_id; - u8 cal_offsets[3]; + u8 cal_offsets[LVTS_MAX_CAL_OFFSETS]; }; struct lvts_ctrl_data { struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX]; u8 valid_sensor_mask; int offset; - int mode; + enum lvts_msr_mode mode; }; #define VALID_SENSOR_MAP(s0, s1, s2, s3) \ @@ -123,10 +141,17 @@ struct lvts_ctrl_data { continue; \ else +struct lvts_platform_ops { + int (*lvts_raw_to_temp)(u32 raw_temp, int temp_factor); + u32 (*lvts_temp_to_raw)(int temperature, int temp_factor); +}; + struct lvts_data { const struct lvts_ctrl_data *lvts_ctrl; + const struct lvts_platform_ops *ops; const u32 *conn_cmd; const u32 *init_cmd; + int num_cal_offsets; int num_lvts_ctrl; int num_conn_cmd; int num_init_cmd; @@ -134,6 +159,7 @@ struct lvts_data { int temp_offset; int gt_calib_bit_offset; unsigned int def_calibration; + u16 msr_offset; }; struct lvts_sensor { @@ -202,6 +228,11 @@ static const struct debugfs_reg32 lvts_regs[] = { LVTS_DEBUG_FS_REGS(LVTS_EDATA01), LVTS_DEBUG_FS_REGS(LVTS_EDATA02), LVTS_DEBUG_FS_REGS(LVTS_EDATA03), + LVTS_DEBUG_FS_REGS(LVTS_MSROFT), + LVTS_DEBUG_FS_REGS(LVTS_ATP0), + LVTS_DEBUG_FS_REGS(LVTS_ATP1), + LVTS_DEBUG_FS_REGS(LVTS_ATP2), + LVTS_DEBUG_FS_REGS(LVTS_ATP3), LVTS_DEBUG_FS_REGS(LVTS_MSR0), LVTS_DEBUG_FS_REGS(LVTS_MSR1), LVTS_DEBUG_FS_REGS(LVTS_MSR2), @@ -269,7 +300,17 @@ static inline int lvts_debugfs_init(struct device *dev, #endif -static int lvts_raw_to_temp(u32 raw_temp, int temp_factor) +static int lvts_raw_to_temp(u32 raw_temp, const struct lvts_data *lvts_data) +{ + return lvts_data->ops->lvts_raw_to_temp(raw_temp & 0xFFFF, lvts_data->temp_factor); +} + +static u32 lvts_temp_to_raw(int temperature, const struct lvts_data *lvts_data) +{ + return lvts_data->ops->lvts_temp_to_raw(temperature, lvts_data->temp_factor); +} + +static int lvts_raw_to_temp_mt7988(u32 raw_temp, int temp_factor) { int temperature; @@ -279,7 +320,7 @@ static int lvts_raw_to_temp(u32 raw_temp, int temp_factor) return temperature; } -static u32 lvts_temp_to_raw(int temperature, int temp_factor) +static u32 lvts_temp_to_raw_mt7988(int temperature, int temp_factor) { u32 raw_temp = ((s64)(golden_temp_offset - temperature)) << 14; @@ -288,6 +329,15 @@ static u32 lvts_temp_to_raw(int temperature, int temp_factor) return raw_temp; } +static u32 lvts_temp_to_raw_mt8196(int temperature, int temp_factor) +{ + u32 raw_temp; + + raw_temp = temperature - golden_temp_offset; + + return div_s64((s64)temp_factor << 14, raw_temp); +} + static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) { struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); @@ -326,7 +376,7 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) if (rc) return -EAGAIN; - *temp = lvts_raw_to_temp(value & 0xFFFF, lvts_data->temp_factor); + *temp = lvts_raw_to_temp(value, lvts_data); return 0; } @@ -396,8 +446,8 @@ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) const struct lvts_data *lvts_data = lvts_ctrl->lvts_data; void __iomem *base = lvts_sensor->base; u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD, - lvts_data->temp_factor); - u32 raw_high = lvts_temp_to_raw(high, lvts_data->temp_factor); + lvts_data); + u32 raw_high = lvts_temp_to_raw(high, lvts_data); bool should_update_thresh; lvts_sensor->low_thresh = low; @@ -599,6 +649,13 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, LVTS_IMMD3(lvts_ctrl->base) }; + void __iomem *atp_regs[] = { + LVTS_ATP0(lvts_ctrl->base), + LVTS_ATP1(lvts_ctrl->base), + LVTS_ATP2(lvts_ctrl->base), + LVTS_ATP3(lvts_ctrl->base) + }; + int i; lvts_for_each_valid_sensor(i, lvts_ctrl_data) { @@ -634,8 +691,20 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, /* * Each sensor has its own register address to read from. */ - lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ? - imm_regs[i] : msr_regs[i]; + switch (lvts_ctrl_data->mode) { + case LVTS_MSR_IMMEDIATE_MODE: + lvts_sensor[i].msr = imm_regs[i]; + break; + case LVTS_MSR_FILTERED_MODE: + lvts_sensor[i].msr = msr_regs[i]; + break; + case LVTS_MSR_ATP_MODE: + lvts_sensor[i].msr = atp_regs[i]; + break; + default: + lvts_sensor[i].msr = imm_regs[i]; + break; + } lvts_sensor[i].low_thresh = INT_MIN; lvts_sensor[i].high_thresh = INT_MIN; @@ -646,6 +715,26 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, return 0; } +static int lvts_decode_sensor_calibration(const struct lvts_sensor_data *sensor, + const u8 *efuse_calibration, u32 calib_len, + u8 num_offsets, u32 *calib) +{ + int i; + u32 calib_val = 0; + + for (i = 0; i < num_offsets; i++) { + u8 offset = sensor->cal_offsets[i]; + + if (offset >= calib_len) + return -EINVAL; + // Pack each calibration byte into the correct position + calib_val |= efuse_calibration[offset] << (8 * i); + } + + *calib = calib_val; + return 0; +} + /* * The efuse blob values follows the sensor enumeration per thermal * controller. The decoding of the stream is as follow: @@ -702,6 +791,39 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, * <-----ap--tc#3-----> <-----sensor#7-----> <-----sensor#8-----> * 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48 * + * MT8196 : + * Stream index map for MCU Domain mt8196 : + * + * <-sensor#1--> <-sensor#0--> <-sensor#3--> <-sensor#2--> + * 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0A | 0x0B + * + * <-sensor#5--> <-sensor#4--> <-sensor#7--> <-sensor#6--> + * 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12 | 0x13 + * + * <-sensor#9--> <-sensor#8--> <-sensor#11-> <-sensor#10-> + * 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0X1B + * + * <-sensor#13-> <-sensor#12-> <-sensor#15-> <-sensor#14-> + * 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21 | 0x22 | 0x23 + * + * Stream index map for APU Domain mt8196 : + * + * <-sensor#1--> <-sensor#0--> <-sensor#3--> <-sensor#2--> + * 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A | 0x2B + * + * Stream index map for GPU Domain mt8196 : + * + * <-sensor#1--> <-sensor#0--> + * 0x2C | 0x2D | 0x2E | 0x2F + * + * Stream index map for AP Domain mt8196 : + * + * <-sensor#1--> <-sensor#0--> <-sensor#3--> <-sensor#2--> + * 0x30 | 0x31 | 0x32 | 0x33 | 0x34 | 0x35 | 0x36 | 0x37 + * + * <-sensor#5--> <-sensor#4--> <-sensor#6--> <-sensor#7--> + * 0x38 | 0x39 | 0x3A | 0x3B | 0x3C | 0x3D | 0x3E | 0x3F + * * Note: In some cases, values don't strictly follow a little endian ordering. * The data description gives byte offsets constituting each calibration value * for each sensor. @@ -711,26 +833,29 @@ static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl u8 *efuse_calibration, size_t calib_len) { - int i; + const struct lvts_data *lvts_data = lvts_ctrl->lvts_data; + int i, ret; u32 gt; /* A zero value for gt means that device has invalid efuse data */ - gt = (((u32 *)efuse_calibration)[0] >> lvts_ctrl->lvts_data->gt_calib_bit_offset) & 0xff; + gt = (((u32 *)efuse_calibration)[0] >> lvts_data->gt_calib_bit_offset) & 0xff; lvts_for_each_valid_sensor(i, lvts_ctrl_data) { const struct lvts_sensor_data *sensor = &lvts_ctrl_data->lvts_sensor[i]; + u32 calib = 0; - if (sensor->cal_offsets[0] >= calib_len || - sensor->cal_offsets[1] >= calib_len || - sensor->cal_offsets[2] >= calib_len) - return -EINVAL; + ret = lvts_decode_sensor_calibration(sensor, efuse_calibration, + calib_len, + lvts_data->num_cal_offsets, + &calib); + if (ret) + return ret; if (gt) { - lvts_ctrl->calibration[i] = - (efuse_calibration[sensor->cal_offsets[0]] << 0) + - (efuse_calibration[sensor->cal_offsets[1]] << 8) + - (efuse_calibration[sensor->cal_offsets[2]] << 16); + lvts_ctrl->calibration[i] = calib; + if (lvts_ctrl->lvts_data->msr_offset) + lvts_ctrl->calibration[i] += lvts_ctrl->lvts_data->msr_offset; } else if (lvts_ctrl->lvts_data->def_calibration) { lvts_ctrl->calibration[i] = lvts_ctrl->lvts_data->def_calibration; } else { @@ -884,7 +1009,7 @@ static void lvts_ctrl_monitor_enable(struct device *dev, struct lvts_ctrl *lvts_ u32 sensor_map = 0; int i; - if (lvts_ctrl->mode != LVTS_MSR_FILTERED_MODE) + if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) return; if (enable) { @@ -1038,6 +1163,17 @@ static int lvts_ctrl_calibrate(struct device *dev, struct lvts_ctrl *lvts_ctrl) for (i = 0; i < LVTS_SENSOR_MAX; i++) writel(lvts_ctrl->calibration[i], lvts_edata[i]); + /* LVTS_MSROFT : Constant offset applied to MSR values + * for post-processing + * + * Bits: + * + * 20-0 : Constant data added to MSR values + */ + if (lvts_ctrl->lvts_data->msr_offset) + writel(lvts_ctrl->lvts_data->msr_offset, + LVTS_MSROFT(lvts_ctrl->base)); + return 0; } @@ -1373,6 +1509,20 @@ static void lvts_remove(struct platform_device *pdev) lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false); } +static const struct lvts_ctrl_data mt7987_lvts_ap_data_ctrl[] = { + { + .lvts_sensor = { + { .dt_id = MT7987_CPU, + .cal_offsets = { 0x04, 0x05, 0x06 } }, + { .dt_id = MT7987_ETH2P5G, + .cal_offsets = { 0x08, 0x09, 0x0a } }, + }, + VALID_SENSOR_MAP(1, 1, 0, 0), + .offset = 0x0, + .mode = LVTS_MSR_FILTERED_MODE, + }, +}; + static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = { { .lvts_sensor = { @@ -1455,6 +1605,12 @@ static const u32 default_init_cmds[] = { 0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1 }; +static const u32 mt7987_init_cmds[] = { + 0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC10308C7, + 0xC103098D, 0xC1030C7C, 0xC1030AA8, 0xC10308CE, 0xC10308C7, + 0xC1030B04, 0xC1030E01, 0xC10306B8 +}; + static const u32 mt7988_init_cmds[] = { 0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC1030CFC, 0xC1030A8C, 0xC103098D, 0xC10308F1, 0xC1030B04, 0xC1030E01, @@ -1753,6 +1909,125 @@ static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = { } }; +static const struct lvts_ctrl_data mt8196_lvts_mcu_data_ctrl[] = { + { + .lvts_sensor = { + { .dt_id = MT8196_MCU_MEDIUM_CPU6_0, + .cal_offsets = { 0x06, 0x07 } }, + { .dt_id = MT8196_MCU_MEDIUM_CPU6_1, + .cal_offsets = { 0x04, 0x05 } }, + { .dt_id = MT8196_MCU_DSU2, + .cal_offsets = { 0x0A, 0x0B } }, + { .dt_id = MT8196_MCU_DSU3, + .cal_offsets = { 0x08, 0x09 } } + }, + VALID_SENSOR_MAP(1, 1, 1, 1), + .offset = 0x0, + .mode = LVTS_MSR_ATP_MODE, + }, + { + .lvts_sensor = { + { .dt_id = MT8196_MCU_LITTLE_CPU3, + .cal_offsets = { 0x0E, 0x0F } }, + { .dt_id = MT8196_MCU_LITTLE_CPU0, + .cal_offsets = { 0x0C, 0x0D } }, + { .dt_id = MT8196_MCU_LITTLE_CPU1, + .cal_offsets = { 0x12, 0x13 } }, + { .dt_id = MT8196_MCU_LITTLE_CPU2, + .cal_offsets = { 0x10, 0x11 } } + }, + VALID_SENSOR_MAP(1, 1, 1, 1), + .offset = 0x100, + .mode = LVTS_MSR_ATP_MODE, + }, + { + .lvts_sensor = { + { .dt_id = MT8196_MCU_MEDIUM_CPU4_0, + .cal_offsets = { 0x16, 0x17 } }, + { .dt_id = MT8196_MCU_MEDIUM_CPU4_1, + .cal_offsets = { 0x14, 0x15 } }, + { .dt_id = MT8196_MCU_MEDIUM_CPU5_0, + .cal_offsets = { 0x1A, 0x1B } }, + { .dt_id = MT8196_MCU_MEDIUM_CPU5_1, + .cal_offsets = { 0x18, 0x19 } } + }, + VALID_SENSOR_MAP(1, 1, 1, 1), + .offset = 0x200, + .mode = LVTS_MSR_ATP_MODE, + }, + { + .lvts_sensor = { + { .dt_id = MT8196_MCU_DSU0, + .cal_offsets = { 0x1E, 0x1F } }, + { .dt_id = MT8196_MCU_DSU1, + .cal_offsets = { 0x1C, 0x1D } }, + { .dt_id = MT8196_MCU_BIG_CPU7_0, + .cal_offsets = { 0x22, 0x23 } }, + { .dt_id = MT8196_MCU_BIG_CPU7_1, + .cal_offsets = { 0x20, 0x21 } } + }, + VALID_SENSOR_MAP(1, 1, 1, 1), + .offset = 0x300, + .mode = LVTS_MSR_ATP_MODE, + } +}; + +static const struct lvts_ctrl_data mt8196_lvts_ap_data_ctrl[] = { + { + .lvts_sensor = { + { .dt_id = MT8196_AP_TOP0, + .cal_offsets = { 0x32, 0x33 } }, + { .dt_id = MT8196_AP_TOP1, + .cal_offsets = { 0x30, 0x31 } }, + { .dt_id = MT8196_AP_TOP2, + .cal_offsets = { 0x36, 0x37 } }, + { .dt_id = MT8196_AP_TOP3, + .cal_offsets = { 0x34, 0x35 } } + }, + VALID_SENSOR_MAP(1, 1, 1, 1), + .offset = 0x0, + .mode = LVTS_MSR_ATP_MODE, + }, + { + .lvts_sensor = { + { .dt_id = MT8196_AP_BOT0, + .cal_offsets = { 0x3A, 0x3B } }, + { .dt_id = MT8196_AP_BOT1, + .cal_offsets = { 0x38, 0x39 } }, + { .dt_id = MT8196_AP_BOT2, + .cal_offsets = { 0x3E, 0x3F } }, + { .dt_id = MT8196_AP_BOT3, + .cal_offsets = { 0x3C, 0x3D } } + }, + VALID_SENSOR_MAP(1, 1, 1, 1), + .offset = 0x100, + .mode = LVTS_MSR_ATP_MODE, + } +}; + +static const struct lvts_platform_ops lvts_platform_ops_mt7988 = { + .lvts_raw_to_temp = lvts_raw_to_temp_mt7988, + .lvts_temp_to_raw = lvts_temp_to_raw_mt7988, +}; + +static const struct lvts_platform_ops lvts_platform_ops_mt8196 = { + .lvts_raw_to_temp = lvts_raw_to_temp_mt7988, + .lvts_temp_to_raw = lvts_temp_to_raw_mt8196, +}; + +static const struct lvts_data mt7987_lvts_ap_data = { + .lvts_ctrl = mt7987_lvts_ap_data_ctrl, + .num_lvts_ctrl = ARRAY_SIZE(mt7987_lvts_ap_data_ctrl), + .conn_cmd = mt7988_conn_cmds, + .init_cmd = mt7987_init_cmds, + .num_conn_cmd = ARRAY_SIZE(mt7988_conn_cmds), + .num_init_cmd = ARRAY_SIZE(mt7987_init_cmds), + .temp_factor = LVTS_COEFF_A_MT7987, + .temp_offset = LVTS_COEFF_B_MT7987, + .gt_calib_bit_offset = 32, + .def_calibration = 19380, +}; + static const struct lvts_data mt7988_lvts_ap_data = { .lvts_ctrl = mt7988_lvts_ap_data_ctrl, .conn_cmd = mt7988_conn_cmds, @@ -1763,6 +2038,8 @@ static const struct lvts_data mt7988_lvts_ap_data = { .temp_factor = LVTS_COEFF_A_MT7988, .temp_offset = LVTS_COEFF_B_MT7988, .gt_calib_bit_offset = 24, + .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988, + .ops = &lvts_platform_ops_mt7988, }; static const struct lvts_data mt8186_lvts_data = { @@ -1776,6 +2053,8 @@ static const struct lvts_data mt8186_lvts_data = { .temp_offset = LVTS_COEFF_B_MT7988, .gt_calib_bit_offset = 24, .def_calibration = 19000, + .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988, + .ops = &lvts_platform_ops_mt7988, }; static const struct lvts_data mt8188_lvts_mcu_data = { @@ -1789,6 +2068,8 @@ static const struct lvts_data mt8188_lvts_mcu_data = { .temp_offset = LVTS_COEFF_B_MT8195, .gt_calib_bit_offset = 20, .def_calibration = 35000, + .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988, + .ops = &lvts_platform_ops_mt7988, }; static const struct lvts_data mt8188_lvts_ap_data = { @@ -1802,6 +2083,8 @@ static const struct lvts_data mt8188_lvts_ap_data = { .temp_offset = LVTS_COEFF_B_MT8195, .gt_calib_bit_offset = 20, .def_calibration = 35000, + .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988, + .ops = &lvts_platform_ops_mt7988, }; static const struct lvts_data mt8192_lvts_mcu_data = { @@ -1815,6 +2098,8 @@ static const struct lvts_data mt8192_lvts_mcu_data = { .temp_offset = LVTS_COEFF_B_MT8195, .gt_calib_bit_offset = 24, .def_calibration = 35000, + .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988, + .ops = &lvts_platform_ops_mt7988, }; static const struct lvts_data mt8192_lvts_ap_data = { @@ -1828,6 +2113,8 @@ static const struct lvts_data mt8192_lvts_ap_data = { .temp_offset = LVTS_COEFF_B_MT8195, .gt_calib_bit_offset = 24, .def_calibration = 35000, + .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988, + .ops = &lvts_platform_ops_mt7988, }; static const struct lvts_data mt8195_lvts_mcu_data = { @@ -1841,6 +2128,8 @@ static const struct lvts_data mt8195_lvts_mcu_data = { .temp_offset = LVTS_COEFF_B_MT8195, .gt_calib_bit_offset = 24, .def_calibration = 35000, + .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988, + .ops = &lvts_platform_ops_mt7988, }; static const struct lvts_data mt8195_lvts_ap_data = { @@ -1854,9 +2143,36 @@ static const struct lvts_data mt8195_lvts_ap_data = { .temp_offset = LVTS_COEFF_B_MT8195, .gt_calib_bit_offset = 24, .def_calibration = 35000, + .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT7988, + .ops = &lvts_platform_ops_mt7988, +}; + +static const struct lvts_data mt8196_lvts_mcu_data = { + .lvts_ctrl = mt8196_lvts_mcu_data_ctrl, + .num_lvts_ctrl = ARRAY_SIZE(mt8196_lvts_mcu_data_ctrl), + .temp_factor = LVTS_COEFF_A_MT8196, + .temp_offset = LVTS_COEFF_B_MT8196, + .gt_calib_bit_offset = 0, + .def_calibration = 14437, + .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT8196, + .msr_offset = LVTS_MSR_OFFSET_MT8196, + .ops = &lvts_platform_ops_mt8196, +}; + +static const struct lvts_data mt8196_lvts_ap_data = { + .lvts_ctrl = mt8196_lvts_ap_data_ctrl, + .num_lvts_ctrl = ARRAY_SIZE(mt8196_lvts_ap_data_ctrl), + .temp_factor = LVTS_COEFF_A_MT8196, + .temp_offset = LVTS_COEFF_B_MT8196, + .gt_calib_bit_offset = 0, + .def_calibration = 14437, + .num_cal_offsets = LVTS_NUM_CAL_OFFSETS_MT8196, + .msr_offset = LVTS_MSR_OFFSET_MT8196, + .ops = &lvts_platform_ops_mt8196, }; static const struct of_device_id lvts_of_match[] = { + { .compatible = "mediatek,mt7987-lvts-ap", .data = &mt7987_lvts_ap_data }, { .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data }, { .compatible = "mediatek,mt8186-lvts", .data = &mt8186_lvts_data }, { .compatible = "mediatek,mt8188-lvts-mcu", .data = &mt8188_lvts_mcu_data }, @@ -1865,6 +2181,8 @@ static const struct of_device_id lvts_of_match[] = { { .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data }, { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data }, { .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data }, + { .compatible = "mediatek,mt8196-lvts-mcu", .data = &mt8196_lvts_mcu_data }, + { .compatible = "mediatek,mt8196-lvts-ap", .data = &mt8196_lvts_ap_data }, {}, }; MODULE_DEVICE_TABLE(of, lvts_of_match);
diff --git a/drivers/thermal/renesas/rzg3e_thermal.c b/drivers/thermal/renesas/rzg3e_thermal.c index e66d73c..dde021e 100644 --- a/drivers/thermal/renesas/rzg3e_thermal.c +++ b/drivers/thermal/renesas/rzg3e_thermal.c
@@ -4,6 +4,7 @@ * * Copyright (C) 2025 Renesas Electronics Corporation */ +#include <linux/arm-smccc.h> #include <linux/clk.h> #include <linux/cleanup.h> #include <linux/delay.h> @@ -62,8 +63,6 @@ #define TSU_SICR_CMPCLR BIT(1) /* Temperature calculation constants from datasheet */ -#define TSU_TEMP_D (-41) -#define TSU_TEMP_E 126 #define TSU_CODE_MAX 0xFFF /* Timing specifications from datasheet */ @@ -72,6 +71,18 @@ #define TSU_POLL_DELAY_US 10 /* Polling interval */ #define TSU_MIN_CLOCK_RATE 24000000 /* TSU_PCLK minimum 24MHz */ +#define RZ_SIP_SVC_GET_SYSTSU 0x82000022 +#define OTP_TSU_REG_ADR_TEMPHI 0x01DC +#define OTP_TSU_REG_ADR_TEMPLO 0x01DD + +struct rzg3e_thermal_priv; + +struct rzg3e_thermal_info { + int (*get_trim)(struct rzg3e_thermal_priv *priv); + int temp_d_mc; + int temp_e_mc; +}; + /** * struct rzg3e_thermal_priv - RZ/G3E TSU private data * @base: TSU register base @@ -79,6 +90,7 @@ * @syscon: regmap for calibration values * @zone: thermal zone device * @rstc: reset control + * @info: chip type specific information * @trmval0: calibration value 0 (b) * @trmval1: calibration value 1 (c) * @trim_offset: offset for trim registers in syscon @@ -87,12 +99,11 @@ struct rzg3e_thermal_priv { void __iomem *base; struct device *dev; - struct regmap *syscon; struct thermal_zone_device *zone; struct reset_control *rstc; + const struct rzg3e_thermal_info *info; u16 trmval0; u16 trmval1; - u32 trim_offset; struct mutex lock; }; @@ -161,17 +172,17 @@ static void rzg3e_thermal_power_off(struct rzg3e_thermal_priv *priv) */ static int rzg3e_thermal_code_to_temp(struct rzg3e_thermal_priv *priv, u16 code) { - int temp_e_mc = TSU_TEMP_E * MILLIDEGREE_PER_DEGREE; - int temp_d_mc = TSU_TEMP_D * MILLIDEGREE_PER_DEGREE; + const struct rzg3e_thermal_info *info = priv->info; s64 numerator, denominator; int temp_mc; - numerator = (temp_e_mc - temp_d_mc) * (s64)(code - priv->trmval0); + numerator = (info->temp_e_mc - info->temp_d_mc) * + (s64)(code - priv->trmval0); denominator = priv->trmval1 - priv->trmval0; - temp_mc = div64_s64(numerator, denominator) + temp_d_mc; + temp_mc = div64_s64(numerator, denominator) + info->temp_d_mc; - return clamp(temp_mc, temp_d_mc, temp_e_mc); + return clamp(temp_mc, info->temp_d_mc, info->temp_e_mc); } /* @@ -180,13 +191,12 @@ static int rzg3e_thermal_code_to_temp(struct rzg3e_thermal_priv *priv, u16 code) */ static u16 rzg3e_thermal_temp_to_code(struct rzg3e_thermal_priv *priv, int temp_mc) { - int temp_e_mc = TSU_TEMP_E * MILLIDEGREE_PER_DEGREE; - int temp_d_mc = TSU_TEMP_D * MILLIDEGREE_PER_DEGREE; + const struct rzg3e_thermal_info *info = priv->info; s64 numerator, denominator; s64 code; - numerator = (temp_mc - temp_d_mc) * (priv->trmval1 - priv->trmval0); - denominator = temp_e_mc - temp_d_mc; + numerator = (temp_mc - info->temp_d_mc) * (priv->trmval1 - priv->trmval0); + denominator = info->temp_e_mc - info->temp_d_mc; code = div64_s64(numerator, denominator) + priv->trmval0; @@ -330,48 +340,45 @@ static const struct thermal_zone_device_ops rzg3e_tz_ops = { .set_trips = rzg3e_thermal_set_trips, }; -static int rzg3e_thermal_get_calibration(struct rzg3e_thermal_priv *priv) +static int rzg3e_thermal_get_syscon_trim(struct rzg3e_thermal_priv *priv) { - u32 val; + struct device_node *np = priv->dev->of_node; + struct regmap *syscon; + u32 offset; int ret; + u32 val; + + syscon = syscon_regmap_lookup_by_phandle_args(np, "renesas,tsu-trim", 1, &offset); + if (IS_ERR(syscon)) + return dev_err_probe(priv->dev, PTR_ERR(syscon), + "Failed to parse renesas,tsu-trim\n"); /* Read calibration values from syscon */ - ret = regmap_read(priv->syscon, priv->trim_offset, &val); + ret = regmap_read(syscon, offset, &val); if (ret) return ret; - priv->trmval0 = val & GENMASK(11, 0); + priv->trmval0 = val & TSU_CODE_MAX; - ret = regmap_read(priv->syscon, priv->trim_offset + 4, &val); + ret = regmap_read(syscon, offset + 4, &val); if (ret) return ret; - priv->trmval1 = val & GENMASK(11, 0); - - /* Validate calibration data */ - if (!priv->trmval0 || !priv->trmval1 || - priv->trmval0 == priv->trmval1 || - priv->trmval0 == 0xFFF || priv->trmval1 == 0xFFF) { - dev_err(priv->dev, "Invalid calibration: b=0x%03x, c=0x%03x\n", - priv->trmval0, priv->trmval1); - return -EINVAL; - } - - dev_dbg(priv->dev, "Calibration: b=0x%03x (%u), c=0x%03x (%u)\n", - priv->trmval0, priv->trmval0, priv->trmval1, priv->trmval1); + priv->trmval1 = val & TSU_CODE_MAX; return 0; } -static int rzg3e_thermal_parse_dt(struct rzg3e_thermal_priv *priv) +static int rzg3e_thermal_get_smc_trim(struct rzg3e_thermal_priv *priv) { - struct device_node *np = priv->dev->of_node; - u32 offset; + struct arm_smccc_res local_res; - priv->syscon = syscon_regmap_lookup_by_phandle_args(np, "renesas,tsu-trim", 1, &offset); - if (IS_ERR(priv->syscon)) - return dev_err_probe(priv->dev, PTR_ERR(priv->syscon), - "Failed to parse renesas,tsu-trim\n"); + arm_smccc_smc(RZ_SIP_SVC_GET_SYSTSU, OTP_TSU_REG_ADR_TEMPLO, + 0, 0, 0, 0, 0, 0, &local_res); + priv->trmval0 = local_res.a0 & TSU_CODE_MAX; - priv->trim_offset = offset; + arm_smccc_smc(RZ_SIP_SVC_GET_SYSTSU, OTP_TSU_REG_ADR_TEMPHI, + 0, 0, 0, 0, 0, 0, &local_res); + priv->trmval1 = local_res.a0 & TSU_CODE_MAX; + return 0; } @@ -392,15 +399,26 @@ static int rzg3e_thermal_probe(struct platform_device *pdev) return ret; platform_set_drvdata(pdev, priv); + priv->info = device_get_match_data(dev); + priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - /* Parse device tree for trim register info */ - ret = rzg3e_thermal_parse_dt(priv); + ret = priv->info->get_trim(priv); if (ret) return ret; + if (!priv->trmval0 || !priv->trmval1 || + priv->trmval0 == priv->trmval1 || + priv->trmval0 == TSU_CODE_MAX || priv->trmval1 == TSU_CODE_MAX) + return dev_err_probe(priv->dev, -EINVAL, + "Invalid calibration: b=0x%03x, c=0x%03x\n", + priv->trmval0, priv->trmval1); + + dev_dbg(priv->dev, "Calibration: b=0x%03x (%u), c=0x%03x (%u)\n", + priv->trmval0, priv->trmval0, priv->trmval1, priv->trmval1); + /* Get clock to verify frequency - clock is managed by power domain */ clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) @@ -412,17 +430,11 @@ static int rzg3e_thermal_probe(struct platform_device *pdev) "Clock rate %lu Hz too low (min %u Hz)\n", clk_get_rate(clk), TSU_MIN_CLOCK_RATE); - priv->rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL); + priv->rstc = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL); if (IS_ERR(priv->rstc)) return dev_err_probe(dev, PTR_ERR(priv->rstc), "Failed to get/deassert reset control\n"); - /* Get calibration data */ - ret = rzg3e_thermal_get_calibration(priv); - if (ret) - return dev_err_probe(dev, ret, - "Failed to get valid calibration data\n"); - /* Get comparison interrupt */ irq = platform_get_irq_byname(pdev, "adcmpi"); if (irq < 0) @@ -526,8 +538,21 @@ static const struct dev_pm_ops rzg3e_thermal_pm_ops = { SYSTEM_SLEEP_PM_OPS(rzg3e_thermal_suspend, rzg3e_thermal_resume) }; +static const struct rzg3e_thermal_info rzg3e_thermal_info = { + .get_trim = rzg3e_thermal_get_syscon_trim, + .temp_d_mc = -41000, + .temp_e_mc = 126000, +}; + +static const struct rzg3e_thermal_info rzt2h_thermal_info = { + .get_trim = rzg3e_thermal_get_smc_trim, + .temp_d_mc = -40000, + .temp_e_mc = 125000, +}; + static const struct of_device_id rzg3e_thermal_dt_ids[] = { - { .compatible = "renesas,r9a09g047-tsu" }, + { .compatible = "renesas,r9a09g047-tsu", .data = &rzg3e_thermal_info }, + { .compatible = "renesas,r9a09g077-tsu", .data = &rzt2h_thermal_info }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, rzg3e_thermal_dt_ids);
diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c index 6e90eb9..5d8170b 100644 --- a/drivers/thermal/st/stm_thermal.c +++ b/drivers/thermal/st/stm_thermal.c
@@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/thermal.h> +#include <linux/units.h> #include "../thermal_hwmon.h" @@ -76,7 +77,6 @@ /* Constants */ #define ADJUST 100 -#define ONE_MHZ 1000000 #define POLL_TIMEOUT 5000 #define STARTUP_TIME 40 #define TS1_T0_VAL0 30000 /* 30 celsius */ @@ -205,7 +205,7 @@ static int stm_thermal_calibration(struct stm_thermal_sensor *sensor) return -EINVAL; prescaler = 0; - clk_freq /= ONE_MHZ; + clk_freq /= HZ_PER_MHZ; if (clk_freq) { while (prescaler <= clk_freq) prescaler++;
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 89758c9..dc9f741 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c
@@ -1505,15 +1505,19 @@ thermal_zone_device_register_with_trips(const char *type, const struct thermal_trip *trip = trips; struct thermal_zone_device *tz; struct thermal_trip_desc *td; + size_t type_len = 0; int id; int result; - if (!type || strlen(type) == 0) { + if (type) + type_len = strnlen(type, THERMAL_NAME_LENGTH); + + if (type_len == 0) { pr_err("No thermal zone type defined\n"); return ERR_PTR(-EINVAL); } - if (strlen(type) >= THERMAL_NAME_LENGTH) { + if (type_len == THERMAL_NAME_LENGTH) { pr_err("Thermal zone name (%s) too long, should be under %d chars\n", type, THERMAL_NAME_LENGTH); return ERR_PTR(-EINVAL);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index bdadd14..d3acff6 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h
@@ -77,6 +77,7 @@ struct thermal_governor { * @device: &struct device for this thermal zone * @removal: removal completion * @resume: resume completion + * @trips_attribute_group: trip point sysfs attributes * @trips_high: trips above the current zone temperature * @trips_reached: trips below or at the current zone temperature * @trips_invalid: trips with invalid temperature @@ -97,9 +98,9 @@ struct thermal_governor { * @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION * @passive: 1 if you've crossed a passive trip point, 0 otherwise. * @prev_low_trip: the low current temperature if you've crossed a passive - trip point. + * trip point. * @prev_high_trip: the above current temperature if you've crossed a - passive trip point. + * passive trip point. * @ops: operations this &thermal_zone_device supports * @tzp: thermal zone parameters * @governor: pointer to the governor for this thermal zone @@ -111,6 +112,8 @@ struct thermal_governor { * @poll_queue: delayed work for polling * @notify_event: Last notification event * @state: current state of the thermal zone + * @debugfs: this thermal zone device's thermal zone debug info + * @user_thresholds: list of userspace thresholds for temp. limit notifications * @trips: array of struct thermal_trip objects */ struct thermal_zone_device {
diff --git a/drivers/thermal/thermal_debugfs.c b/drivers/thermal/thermal_debugfs.c index 11d34f2..11668f5 100644 --- a/drivers/thermal/thermal_debugfs.c +++ b/drivers/thermal/thermal_debugfs.c
@@ -807,7 +807,7 @@ static int tze_seq_show(struct seq_file *s, void *v) seq_printf(s, ",-Mitigation at %llums, duration%c%llums, max. temp=%dm°C\n", ktime_to_ms(tze->timestamp), c, duration_ms, tze->max_temp); - seq_printf(s, "| trip | type | temp(m°C) | hyst(m°C) | duration(ms) | avg(m°C) | min(m°C) |\n"); + seq_puts(s, "| trip | type | temp(m°C) | hyst(m°C) | duration(ms) | avg(m°C) | min(m°C) |\n"); for_each_trip_desc(tz, td) { const struct thermal_trip *trip = &td->trip;
diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c index 64cc3ab..faf1d00 100644 --- a/drivers/thermal/thermal_hwmon.c +++ b/drivers/thermal/thermal_hwmon.c
@@ -63,7 +63,7 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) if (ret) return ret; - return sprintf(buf, "%d\n", temperature); + return sysfs_emit(buf, "%d\n", temperature); } static ssize_t @@ -84,7 +84,7 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, char *buf) if (ret) return ret; - return sprintf(buf, "%d\n", temperature); + return sysfs_emit(buf, "%d\n", temperature); }
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c index 1a51a4d..b6d0c92 100644 --- a/drivers/thermal/thermal_of.c +++ b/drivers/thermal/thermal_of.c
@@ -280,10 +280,10 @@ static bool thermal_of_cm_lookup(struct device_node *cm_np, struct cooling_spec *c) { for_each_child_of_node_scoped(cm_np, child) { - struct device_node *tr_np; int count, i; - tr_np = of_parse_phandle(child, "trip", 0); + struct device_node *tr_np __free(device_node) = + of_parse_phandle(child, "trip", 0); if (tr_np != trip->priv) continue;
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index d806125..2538c2dc 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c
@@ -29,7 +29,7 @@ type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); - return sprintf(buf, "%s\n", tz->type); + return sysfs_emit(buf, "%s\n", tz->type); } static ssize_t @@ -41,7 +41,7 @@ temp_show(struct device *dev, struct device_attribute *attr, char *buf) ret = thermal_zone_get_temp(tz, &temperature); if (!ret) - return sprintf(buf, "%d\n", temperature); + return sysfs_emit(buf, "%d\n", temperature); if (ret == -EAGAIN) return -ENODATA; @@ -57,9 +57,9 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf) guard(thermal_zone)(tz); if (tz->mode == THERMAL_DEVICE_ENABLED) - return sprintf(buf, "enabled\n"); + return sysfs_emit(buf, "enabled\n"); - return sprintf(buf, "disabled\n"); + return sysfs_emit(buf, "disabled\n"); } static ssize_t @@ -97,7 +97,7 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr, { struct thermal_trip *trip = thermal_trip_of_attr(attr, type); - return sprintf(buf, "%s\n", thermal_trip_type_name(trip->type)); + return sysfs_emit(buf, "%s\n", thermal_trip_type_name(trip->type)); } static ssize_t @@ -142,7 +142,7 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr, { struct thermal_trip *trip = thermal_trip_of_attr(attr, temp); - return sprintf(buf, "%d\n", READ_ONCE(trip->temperature)); + return sysfs_emit(buf, "%d\n", READ_ONCE(trip->temperature)); } static ssize_t @@ -188,7 +188,7 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr, { struct thermal_trip *trip = thermal_trip_of_attr(attr, hyst); - return sprintf(buf, "%d\n", READ_ONCE(trip->hysteresis)); + return sysfs_emit(buf, "%d\n", READ_ONCE(trip->hysteresis)); } static ssize_t @@ -199,7 +199,7 @@ policy_store(struct device *dev, struct device_attribute *attr, char name[THERMAL_NAME_LENGTH]; int ret; - snprintf(name, sizeof(name), "%s", buf); + strscpy(name, buf); ret = thermal_zone_device_set_policy(tz, name); if (!ret) @@ -213,7 +213,7 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); - return sprintf(buf, "%s\n", tz->governor->name); + return sysfs_emit(buf, "%s\n", tz->governor->name); } static ssize_t @@ -260,7 +260,7 @@ sustainable_power_show(struct device *dev, struct device_attribute *devattr, struct thermal_zone_device *tz = to_thermal_zone(dev); if (tz->tzp) - return sprintf(buf, "%u\n", tz->tzp->sustainable_power); + return sysfs_emit(buf, "%u\n", tz->tzp->sustainable_power); else return -EIO; } @@ -291,7 +291,7 @@ sustainable_power_store(struct device *dev, struct device_attribute *devattr, struct thermal_zone_device *tz = to_thermal_zone(dev); \ \ if (tz->tzp) \ - return sprintf(buf, "%d\n", tz->tzp->name); \ + return sysfs_emit(buf, "%d\n", tz->tzp->name); \ else \ return -EIO; \ } \ @@ -505,7 +505,7 @@ cdev_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_cooling_device *cdev = to_cooling_device(dev); - return sprintf(buf, "%s\n", cdev->type); + return sysfs_emit(buf, "%s\n", cdev->type); } static ssize_t max_state_show(struct device *dev, struct device_attribute *attr, @@ -513,7 +513,7 @@ static ssize_t max_state_show(struct device *dev, struct device_attribute *attr, { struct thermal_cooling_device *cdev = to_cooling_device(dev); - return sprintf(buf, "%ld\n", cdev->max_state); + return sysfs_emit(buf, "%ld\n", cdev->max_state); } static ssize_t cur_state_show(struct device *dev, struct device_attribute *attr, @@ -526,7 +526,7 @@ static ssize_t cur_state_show(struct device *dev, struct device_attribute *attr, ret = cdev->ops->get_cur_state(cdev, &state); if (ret) return ret; - return sprintf(buf, "%ld\n", state); + return sysfs_emit(buf, "%ld\n", state); } static ssize_t @@ -638,7 +638,7 @@ static ssize_t total_trans_show(struct device *dev, return 0; spin_lock(&stats->lock); - ret = sprintf(buf, "%u\n", stats->total_trans); + ret = sysfs_emit(buf, "%u\n", stats->total_trans); spin_unlock(&stats->lock); return ret; @@ -664,8 +664,8 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, update_time_in_state(stats); for (i = 0; i <= cdev->max_state; i++) { - len += sprintf(buf + len, "state%u\t%llu\n", i, - ktime_to_ms(stats->time_in_state[i])); + len += sysfs_emit_at(buf, len, "state%u\t%llu\n", i, + ktime_to_ms(stats->time_in_state[i])); } spin_unlock(&stats->lock); @@ -846,7 +846,7 @@ trip_point_show(struct device *dev, struct device_attribute *attr, char *buf) instance = container_of(attr, struct thermal_instance, attr); - return sprintf(buf, "%d\n", thermal_zone_trip_id(tz, instance->trip)); + return sysfs_emit(buf, "%d\n", thermal_zone_trip_id(tz, instance->trip)); } ssize_t @@ -856,7 +856,7 @@ weight_show(struct device *dev, struct device_attribute *attr, char *buf) instance = container_of(attr, struct thermal_instance, weight_attr); - return sprintf(buf, "%d\n", instance->weight); + return sysfs_emit(buf, "%d\n", instance->weight); } ssize_t weight_store(struct device *dev, struct device_attribute *attr,
diff --git a/include/dt-bindings/thermal/mediatek,lvts-thermal.h b/include/dt-bindings/thermal/mediatek,lvts-thermal.h index ddc7302..350f981 100644 --- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h +++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
@@ -7,6 +7,9 @@ #ifndef __MEDIATEK_LVTS_DT_H #define __MEDIATEK_LVTS_DT_H +#define MT7987_CPU 0 +#define MT7987_ETH2P5G 1 + #define MT7988_CPU_0 0 #define MT7988_CPU_1 1 #define MT7988_ETH2P5G_0 2 @@ -80,4 +83,30 @@ #define MT8192_AP_MD1 15 #define MT8192_AP_MD2 16 +#define MT8196_MCU_MEDIUM_CPU6_0 0 +#define MT8196_MCU_MEDIUM_CPU6_1 1 +#define MT8196_MCU_DSU2 2 +#define MT8196_MCU_DSU3 3 +#define MT8196_MCU_LITTLE_CPU3 4 +#define MT8196_MCU_LITTLE_CPU0 5 +#define MT8196_MCU_LITTLE_CPU1 6 +#define MT8196_MCU_LITTLE_CPU2 7 +#define MT8196_MCU_MEDIUM_CPU4_0 8 +#define MT8196_MCU_MEDIUM_CPU4_1 9 +#define MT8196_MCU_MEDIUM_CPU5_0 10 +#define MT8196_MCU_MEDIUM_CPU5_1 11 +#define MT8196_MCU_DSU0 12 +#define MT8196_MCU_DSU1 13 +#define MT8196_MCU_BIG_CPU7_0 14 +#define MT8196_MCU_BIG_CPU7_1 15 + +#define MT8196_AP_TOP0 0 +#define MT8196_AP_TOP1 1 +#define MT8196_AP_TOP2 2 +#define MT8196_AP_TOP3 3 +#define MT8196_AP_BOT0 4 +#define MT8196_AP_BOT1 5 +#define MT8196_AP_BOT2 6 +#define MT8196_AP_BOT3 7 + #endif /* __MEDIATEK_LVTS_DT_H */
diff --git a/tools/lib/thermal/libthermal.pc.template b/tools/lib/thermal/libthermal.pc.template index ac24d0a..3b8a24d 100644 --- a/tools/lib/thermal/libthermal.pc.template +++ b/tools/lib/thermal/libthermal.pc.template
@@ -8,5 +8,5 @@ Description: thermal library Requires: libnl-3.0 libnl-genl-3.0 Version: @VERSION@ -Libs: -L${libdir} -lnl-genl-3 -lnl-3 -Cflags: -I${includedir} -I${include}/libnl3 +Libs: -L${libdir} -lnl-genl-3 -lnl-3 -lthermal +Cflags: -I${includedir} -I${includedir}/libnl3
diff --git a/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c b/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c index ca2bd03..569d44f 100644 --- a/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c +++ b/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c
@@ -12,6 +12,7 @@ #define WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/notification_delay_ms" #define WORKLOAD_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_hint_enable" +#define WORKLOAD_SLOW_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_slow_hint_enable" #define WORKLOAD_TYPE_INDEX_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_type_index" static const char * const workload_types[] = { @@ -22,6 +23,9 @@ static const char * const workload_types[] = { NULL }; +static int wlt_slow; +static char *wlt_enable_attr; + #define WORKLOAD_TYPE_MAX_INDEX 3 void workload_hint_exit(int signum) @@ -30,7 +34,7 @@ void workload_hint_exit(int signum) /* Disable feature via sysfs knob */ - fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR); + fd = open(wlt_enable_attr, O_RDWR); if (fd < 0) { perror("Unable to open workload type feature enable file"); exit(1); @@ -46,6 +50,26 @@ void workload_hint_exit(int signum) close(fd); } +static void update_delay(char *delay_str) +{ + int fd; + + printf("Setting notification delay in ms to %s\n", delay_str); + + fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR); + if (fd < 0) { + perror("Unable to open workload notification delay"); + exit(1); + } + + if (write(fd, delay_str, strlen(delay_str)) < 0) { + perror("Can't set delay"); + exit(1); + } + + close(fd); +} + int main(int argc, char **argv) { struct pollfd ufd; @@ -54,32 +78,26 @@ int main(int argc, char **argv) char delay_str[64]; int delay = 0; - printf("Usage: workload_hint_test [notification delay in milli seconds]\n"); + printf("Usage: workload_hint_test [notification delay in milli seconds][slow]\n"); if (argc > 1) { - ret = sscanf(argv[1], "%d", &delay); - if (ret < 0) { - printf("Invalid delay\n"); - exit(1); + int i; + + for (i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "slow")) { + wlt_slow = 1; + continue; + } + + ret = sscanf(argv[1], "%d", &delay); + if (ret < 0) { + printf("Invalid delay\n"); + exit(1); + } + + sprintf(delay_str, "%s\n", argv[1]); + update_delay(delay_str); } - - printf("Setting notification delay to %d ms\n", delay); - if (delay < 0) - exit(1); - - sprintf(delay_str, "%s\n", argv[1]); - fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR); - if (fd < 0) { - perror("Unable to open workload notification delay"); - exit(1); - } - - if (write(fd, delay_str, strlen(delay_str)) < 0) { - perror("Can't set delay"); - exit(1); - } - - close(fd); } if (signal(SIGINT, workload_hint_exit) == SIG_IGN) @@ -89,8 +107,13 @@ int main(int argc, char **argv) if (signal(SIGTERM, workload_hint_exit) == SIG_IGN) signal(SIGTERM, SIG_IGN); + if (wlt_slow) + wlt_enable_attr = WORKLOAD_SLOW_ENABLE_ATTRIBUTE; + else + wlt_enable_attr = WORKLOAD_ENABLE_ATTRIBUTE; + /* Enable feature via sysfs knob */ - fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR); + fd = open(wlt_enable_attr, O_RDWR); if (fd < 0) { perror("Unable to open workload type feature enable file"); exit(1); @@ -145,6 +168,13 @@ int main(int argc, char **argv) if (ret < 0) break; + if (wlt_slow) { + if (index & 0x10) + printf("workload type slow:%s\n", "power"); + else + printf("workload type slow:%s\n", "performance"); + } + index &= 0x0f; if (index > WORKLOAD_TYPE_MAX_INDEX) printf("Invalid workload type index\n");