Commit 1b72607d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'thermal-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull thermal control updates from Rafael Wysocki:
 "The majority of changes here are related to the general switch-over to
  using arrays of generic trip point structures registered along with a
  thermal zone instead of trip point callbacks (this has been done
  mostly by Daniel Lezcano with some help from yours truly on the Intel
  drivers front).

  Apart from that and the related reorganization of code, there are some
  enhancements of the existing driver and a new Mediatek Low Voltage
  Thermal Sensor (LVTS) driver. The Intel powerclamp undergoes a major
  rework so it will use the generic idle_inject facility for CPU idle
  time injection going forward and it will take additional module
  parameters for specifying the subset of CPUs to be affected by it
  (work done by Srinivas Pandruvada).

  Also included are assorted fixes and a whole bunch of cleanups.

  Specifics:

   - Rework a large bunch of drivers to use the generic thermal trip
     structure and use the opportunity to do more cleanups by removing
     unused functions from the OF code (Daniel Lezcano)

   - Remove core header inclusion from drivers (Daniel Lezcano)

   - Fix some locking issues related to the generic thermal trip rework
     (Johan Hovold)

   - Fix a crash when requesting the critical temperature on tegra,
     which is related to the generic trip point work (Jon Hunter)

   - Clean up thermal device unregistration code (Viresh Kumar)

   - Fix and clean up thermal control core initialization error code
     paths (Daniel Lezcano)

   - Relocate the trip points handling code into a separate file (Daniel
     Lezcano)

   - Make the thermal core fail registration of thermal zones and
     cooling devices if the thermal class has not been registered
     (Rafael Wysocki)

   - Add trip point initialization helper functions for ACPI-defined
     trip points and modify two thermal drivers to use them (Rafael
     Wysocki, Daniel Lezcano)

   - Make the core thermal control code use sysfs_emit_at() instead of
     scnprintf() where applicable (ye xingchen)

   - Consolidate code accessing the Intel TCC (Thermal Control
     Circuitry) MSRs by introducing library functions for that and
     making the TCC-related code in thermal drivers use them (Zhang Rui)

   - Enhance the x86_pkg_temp_thermal driver to support dynamic tjmax
     changes (Zhang Rui)

   - Address an "unsigned expression compared with zero" warning in the
     intel_soc_dts_iosf thermal driver (Yang Li)

   - Update comments regarding two functions in the Intel Menlow thermal
     driver (Deming Wang)

   - Use sysfs_emit_at() instead of scnprintf() in the int340x thermal
     driver (ye xingchen)

   - Make the intel_pch thermal driver support the Wellsburg PCH (Tim
     Zimmermann)

   - Modify the intel_pch and processor_thermal_device_pci thermal
     drivers use generic trip point tables instead of thermal zone trip
     point callbacks (Daniel Lezcano)

   - Add production mode attribute sysfs attribute to the int340x
     thermal driver (Srinivas Pandruvada)

   - Rework dynamic trip point updates handling and locking in the
     int340x thermal driver (Rafael Wysocki)

   - Make the int340x thermal driver use a generic trip points table
     instead of thermal zone trip point callbacks (Rafael Wysocki,
     Daniel Lezcano)

   - Clean up and improve the int340x thermal driver (Rafael Wysocki)

   - Simplify and clean up the intel_pch thermal driver (Rafael Wysocki)

   - Fix the Intel powerclamp thermal driver and make it use the common
     idle injection framework (Srinivas Pandruvada)

   - Add two module parameters, cpumask and max_idle, to the Intel
     powerclamp thermal driver to allow it to affect only a specific
     subset of CPUs instead of all of them (Srinivas Pandruvada)

   - Make the Intel quark_dts thermal driver Use generic trip point
     objects instead of its own trip point representation (Daniel
     Lezcano)

   - Add toctree entry for thermal documents and fix two issues in the
     Intel powerclamp driver documentation (Bagas Sanjaya)

   - Use strscpy() to instead of strncpy() in the thermal core (Xu
     Panda)

   - Fix thermal_sampling_exit() (Vincent Guittot)

   - Add Mediatek Low Voltage Thermal Sensor (LVTS) driver (Balsam
     Chihi)

   - Add r8a779g0 RCar support to the rcar_gen3 thermal driver (Geert
     Uytterhoeven)

   - Fix useless call to set_trips() when resuming in the rcar_gen3
     thermal control driver and add interrupt support detection at init
     time to it (Niklas Söderlund)

   - Fix memory corruption in the hi3660 thermal driver (Yongqin Liu)

   - Fix include path for libnl3 in pkg-config file for libthermal
     (Vibhav Pant)

   - Remove syscfg-based driver for st as the platform is not supported
     any more (Alain Volmat)"

* tag 'thermal-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (135 commits)
  thermal/drivers/st: Remove syscfg based driver
  thermal: Remove core header inclusion from drivers
  tools/lib/thermal: Fix include path for libnl3 in pkg-config file.
  thermal/drivers/hisi: Drop second sensor hi3660
  thermal/drivers/rcar_gen3_thermal: Fix device initialization
  thermal/drivers/rcar_gen3_thermal: Create device local ops struct
  thermal/drivers/rcar_gen3_thermal: Do not call set_trips() when resuming
  thermal/drivers/rcar_gen3: Add support for R-Car V4H
  dt-bindings: thermal: rcar-gen3-thermal: Add r8a779g0 support
  thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver
  dt-bindings: thermal: mediatek: Add LVTS thermal controllers
  thermal/drivers/mediatek: Relocate driver to mediatek folder
  tools/lib/thermal: Fix thermal_sampling_exit()
  Documentation: powerclamp: Fix numbered lists formatting
  Documentation: powerclamp: Escape wildcard in cpumask description
  Documentation: admin-guide: Add toctree entry for thermal docs
  thermal: intel: powerclamp: Add two module parameters
  Documentation: admin-guide: Move intel_powerclamp documentation
  thermal: core: Use sysfs_emit_at() instead of scnprintf()
  thermal: intel: powerclamp: Fix duration module parameter
  ...
parents 88af9b16 6828e402
......@@ -116,6 +116,7 @@ configure specific aspects of kernel behavior to your liking.
svga
syscall-user-dispatch
sysrq
thermal/index
thunderbolt
ufs
unicode
......
=================
Thermal Subsystem
=================
.. toctree::
:maxdepth: 1
intel_powerclamp
......@@ -26,6 +26,8 @@ By:
- Generic Thermal Layer (sysfs)
- Kernel APIs (TBD)
(*) Module Parameters
INTRODUCTION
============
......@@ -153,13 +155,15 @@ b) determine the amount of compensation needed at each target ratio
Compensation to each target ratio consists of two parts:
a) steady state error compensation
This is to offset the error occurring when the system can
enter idle without extra wakeups (such as external interrupts).
This is to offset the error occurring when the system can
enter idle without extra wakeups (such as external interrupts).
b) dynamic error compensation
When an excessive amount of wakeups occurs during idle, an
additional idle ratio can be added to quiet interrupts, by
slowing down CPU activities.
When an excessive amount of wakeups occurs during idle, an
additional idle ratio can be added to quiet interrupts, by
slowing down CPU activities.
A debugfs file is provided for the user to examine compensation
progress and results, such as on a Westmere system::
......@@ -281,6 +285,7 @@ cur_state returns value -1 instead of 0 which is to avoid confusing
100% busy state with the disabled state.
Example usage:
- To inject 25% idle time::
$ sudo sh -c "echo 25 > /sys/class/thermal/cooling_device80/cur_state
......@@ -318,3 +323,23 @@ device, a PID based userspace thermal controller can manage to
control CPU temperature effectively, when no other thermal influence
is added. For example, a UltraBook user can compile the kernel under
certain temperature (below most active trip points).
Module Parameters
=================
``cpumask`` (RW)
A bit mask of CPUs to inject idle. The format of the bitmask is same as
used in other subsystems like in /proc/irq/\*/smp_affinity. The mask is
comma separated 32 bit groups. Each CPU is one bit. For example for a 256
CPU system the full mask is:
ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff
The rightmost mask is for CPU 0-32.
``max_idle`` (RW)
Maximum injected idle time to the total CPU time ratio in percent range
from 1 to 100. Even if the cooling device max_state is always 100 (100%),
this parameter allows to add a max idle percent limit. The default is 50,
to match the current implementation of powerclamp driver. Also doesn't
allow value more than 75, if the cpumask includes every CPU present in
the system.
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/thermal/mediatek,lvts-thermal.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek SoC Low Voltage Thermal Sensor (LVTS)
maintainers:
- Balsam CHIHI <bchihi@baylibre.com>
description: |
LVTS is a thermal management architecture composed of three subsystems,
a Sensing device - Thermal Sensing Micro Circuit Unit (TSMCU),
a Converter - Low Voltage Thermal Sensor converter (LVTS), and
a Digital controller (LVTS_CTRL).
properties:
compatible:
enum:
- mediatek,mt8192-lvts-ap
- mediatek,mt8192-lvts-mcu
- mediatek,mt8195-lvts-ap
- mediatek,mt8195-lvts-mcu
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
resets:
maxItems: 1
description: LVTS reset for clearing temporary data on AP/MCU.
nvmem-cells:
minItems: 1
items:
- description: Calibration eFuse data 1 for LVTS
- description: Calibration eFuse data 2 for LVTS
nvmem-cell-names:
minItems: 1
items:
- const: lvts-calib-data-1
- const: lvts-calib-data-2
"#thermal-sensor-cells":
const: 1
allOf:
- $ref: thermal-sensor.yaml#
- if:
properties:
compatible:
contains:
enum:
- mediatek,mt8192-lvts-ap
- mediatek,mt8192-lvts-mcu
then:
properties:
nvmem-cells:
maxItems: 1
nvmem-cell-names:
maxItems: 1
- if:
properties:
compatible:
contains:
enum:
- mediatek,mt8195-lvts-ap
- mediatek,mt8195-lvts-mcu
then:
properties:
nvmem-cells:
minItems: 2
nvmem-cell-names:
minItems: 2
required:
- compatible
- reg
- interrupts
- clocks
- resets
- nvmem-cells
- nvmem-cell-names
- "#thermal-sensor-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/mt8195-clk.h>
#include <dt-bindings/reset/mt8195-resets.h>
#include <dt-bindings/thermal/mediatek,lvts-thermal.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
lvts_mcu: thermal-sensor@11278000 {
compatible = "mediatek,mt8195-lvts-mcu";
reg = <0 0x11278000 0 0x1000>;
interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&infracfg_ao CLK_INFRA_AO_THERM>;
resets = <&infracfg_ao MT8195_INFRA_RST4_THERM_CTRL_MCU_SWRST>;
nvmem-cells = <&lvts_efuse_data1 &lvts_efuse_data2>;
nvmem-cell-names = "lvts-calib-data-1", "lvts-calib-data-2";
#thermal-sensor-cells = <1>;
};
};
thermal_zones: thermal-zones {
cpu0-thermal {
polling-delay = <1000>;
polling-delay-passive = <250>;
thermal-sensors = <&lvts_mcu MT8195_MCU_LITTLE_CPU0>;
trips {
cpu0_alert: trip-alert {
temperature = <85000>;
hysteresis = <2000>;
type = "passive";
};
cpu0_crit: trip-crit {
temperature = <100000>;
hysteresis = <2000>;
type = "critical";
};
};
};
};
......@@ -13,6 +13,7 @@ properties:
enum:
- qcom,spmi-adc-tm5
- qcom,spmi-adc-tm5-gen2
- qcom,adc-tm7 # Incomplete / subject to change
reg:
maxItems: 1
......
......@@ -37,6 +37,7 @@ properties:
- description: v1 of TSENS
items:
- enum:
- qcom,msm8956-tsens
- qcom,msm8976-tsens
- qcom,qcs404-tsens
- const: qcom,tsens-v1
......@@ -80,18 +81,120 @@ properties:
maxItems: 2
nvmem-cells:
minItems: 1
maxItems: 2
description:
Reference to an nvmem node for the calibration data
oneOf:
- minItems: 1
maxItems: 2
description:
Reference to an nvmem node for the calibration data
- minItems: 5
maxItems: 35
description: |
Reference to nvmem cells for the calibration mode, two calibration
bases and two cells per each sensor
# special case for msm8974 / apq8084
- maxItems: 51
description: |
Reference to nvmem cells for the calibration mode, two calibration
bases and two cells per each sensor, main and backup copies, plus use_backup cell
nvmem-cell-names:
minItems: 1
items:
- const: calib
- enum:
- calib_backup
- calib_sel
oneOf:
- minItems: 1
items:
- const: calib
- enum:
- calib_backup
- calib_sel
- minItems: 5
items:
- const: mode
- const: base1
- const: base2
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
- pattern: '^s[0-9]+_p1$'
- pattern: '^s[0-9]+_p2$'
# special case for msm8974 / apq8084
- items:
- const: mode
- const: base1
- const: base2
- const: use_backup
- const: mode_backup
- const: base1_backup
- const: base2_backup
- const: s0_p1
- const: s0_p2
- const: s1_p1
- const: s1_p2
- const: s2_p1
- const: s2_p2
- const: s3_p1
- const: s3_p2
- const: s4_p1
- const: s4_p2
- const: s5_p1
- const: s5_p2
- const: s6_p1
- const: s6_p2
- const: s7_p1
- const: s7_p2
- const: s8_p1
- const: s8_p2
- const: s9_p1
- const: s9_p2
- const: s10_p1
- const: s10_p2
- const: s0_p1_backup
- const: s0_p2_backup
- const: s1_p1_backup
- const: s1_p2_backup
- const: s2_p1_backup
- const: s2_p2_backup
- const: s3_p1_backup
- const: s3_p2_backup
- const: s4_p1_backup
- const: s4_p2_backup
- const: s5_p1_backup
- const: s5_p2_backup
- const: s6_p1_backup
- const: s6_p2_backup
- const: s7_p1_backup
- const: s7_p2_backup
- const: s8_p1_backup
- const: s8_p2_backup
- const: s9_p1_backup
- const: s9_p2_backup
- const: s10_p1_backup
- const: s10_p2_backup
"#qcom,sensors":
description:
......@@ -220,6 +323,36 @@ examples:
};
};
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
// Example 1 (new calbiration data: for pre v1 IP):
thermal-sensor@900000 {
compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1";
reg = <0x4a9000 0x1000>, /* TM */
<0x4a8000 0x1000>; /* SROT */
nvmem-cells = <&tsens_mode>,
<&tsens_base1>, <&tsens_base2>,
<&tsens_s0_p1>, <&tsens_s0_p2>,
<&tsens_s1_p1>, <&tsens_s1_p2>,
<&tsens_s2_p1>, <&tsens_s2_p2>,
<&tsens_s4_p1>, <&tsens_s4_p2>,
<&tsens_s5_p1>, <&tsens_s5_p2>;
nvmem-cell-names = "mode",
"base1", "base2",
"s0_p1", "s0_p2",
"s1_p1", "s1_p2",
"s2_p1", "s2_p2",
"s4_p1", "s4_p2",
"s5_p1", "s5_p2";
interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "uplow";
#qcom,sensors = <5>;
#thermal-sensor-cells = <1>;
};
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
// Example 1 (legacy: for pre v1 IP):
......
......@@ -28,6 +28,7 @@ properties:
- renesas,r8a77980-thermal # R-Car V3H
- renesas,r8a779a0-thermal # R-Car V3U
- renesas,r8a779f0-thermal # R-Car S4-8
- renesas,r8a779g0-thermal # R-Car V4H
reg: true
......@@ -80,6 +81,7 @@ else:
- description: TSC1 registers
- description: TSC2 registers
- description: TSC3 registers
- description: TSC4 registers
if:
not:
properties:
......@@ -87,6 +89,7 @@ else:
contains:
enum:
- renesas,r8a779f0-thermal
- renesas,r8a779g0-thermal
then:
required:
- interrupts
......
......@@ -14,7 +14,6 @@ Thermal
exynos_thermal
exynos_thermal_emulation
intel_powerclamp
nouveau_thermal
x86_pkg_temperature_thermal
intel_dptf
......@@ -84,6 +84,9 @@ DPTF ACPI Drivers interface
https:/github.com/intel/thermal_daemon for decoding
thermal table.
``production_mode`` (RO)
When different from zero, manufacturer locked thermal configuration
from further changes.
ACPI Thermal Relationship table interface
------------------------------------------
......
......@@ -20529,6 +20529,7 @@ S: Supported
Q: https://patchwork.kernel.org/project/linux-pm/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git thermal
F: Documentation/ABI/testing/sysfs-class-thermal
F: Documentation/admin-guide/thermal/
F: Documentation/devicetree/bindings/thermal/
F: Documentation/driver-api/thermal/
F: drivers/thermal/
......
......@@ -1079,8 +1079,6 @@ struct mbox_list {
#if IS_ENABLED(CONFIG_THERMAL)
struct ch_thermal {
struct thermal_zone_device *tzdev;
int trip_temp;
int trip_type;
};
#endif
......
......@@ -29,36 +29,12 @@ static int cxgb4_thermal_get_temp(struct thermal_zone_device *tzdev,
return 0;
}
static int cxgb4_thermal_get_trip_type(struct thermal_zone_device *tzdev,
int trip, enum thermal_trip_type *type)
{
struct adapter *adap = tzdev->devdata;
if (!adap->ch_thermal.trip_temp)
return -EINVAL;
*type = adap->ch_thermal.trip_type;
return 0;
}
static int cxgb4_thermal_get_trip_temp(struct thermal_zone_device *tzdev,
int trip, int *temp)
{
struct adapter *adap = tzdev->devdata;
if (!adap->ch_thermal.trip_temp)
return -EINVAL;
*temp = adap->ch_thermal.trip_temp;
return 0;
}
static struct thermal_zone_device_ops cxgb4_thermal_ops = {
.get_temp = cxgb4_thermal_get_temp,
.get_trip_type = cxgb4_thermal_get_trip_type,
.get_trip_temp = cxgb4_thermal_get_trip_temp,
};
static struct thermal_trip trip = { .type = THERMAL_TRIP_CRITICAL } ;
int cxgb4_thermal_init(struct adapter *adap)
{
struct ch_thermal *ch_thermal = &adap->ch_thermal;
......@@ -79,15 +55,14 @@ int cxgb4_thermal_init(struct adapter *adap)
if (ret < 0) {
num_trip = 0; /* could not get trip temperature */
} else {
ch_thermal->trip_temp = val * 1000;
ch_thermal->trip_type = THERMAL_TRIP_CRITICAL;
trip.temperature = val * 1000;
}
snprintf(ch_tz_name, sizeof(ch_tz_name), "cxgb4_%s", adap->name);
ch_thermal->tzdev = thermal_zone_device_register(ch_tz_name, num_trip,
0, adap,
&cxgb4_thermal_ops,
NULL, 0, 0);
ch_thermal->tzdev = thermal_zone_device_register_with_trips(ch_tz_name, &trip, num_trip,
0, adap,
&cxgb4_thermal_ops,
NULL, 0, 0);
if (IS_ERR(ch_thermal->tzdev)) {
ret = PTR_ERR(ch_thermal->tzdev);
dev_err(adap->pdev_dev, "Failed to register thermal zone\n");
......
......@@ -501,7 +501,7 @@ struct iwl_mvm_tt_mgmt {
* @tzone: thermal zone device data
*/
struct iwl_mvm_thermal_device {
s16 temp_trips[IWL_MAX_DTS_TRIPS];
struct thermal_trip trips[IWL_MAX_DTS_TRIPS];
u8 fw_trips_index[IWL_MAX_DTS_TRIPS];
struct thermal_zone_device *tzone;
};
......
......@@ -573,11 +573,11 @@ int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)
* and uncompressed, the FW should get it compressed and sorted
*/
/* compress temp_trips to cmd array, remove uninitialized values*/
/* compress trips to cmd array, remove uninitialized values*/
for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
if (mvm->tz_device.temp_trips[i] != S16_MIN) {
if (mvm->tz_device.trips[i].temperature != INT_MIN) {
cmd.thresholds[idx++] =
cpu_to_le16(mvm->tz_device.temp_trips[i]);
cpu_to_le16((s16)(mvm->tz_device.trips[i].temperature / 1000));
}
}
cmd.num_temps = cpu_to_le32(idx);
......@@ -593,8 +593,8 @@ int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)
*/
for (i = 0; i < idx; i++) {
for (j = 0; j < IWL_MAX_DTS_TRIPS; j++) {
if (le16_to_cpu(cmd.thresholds[i]) ==
mvm->tz_device.temp_trips[j])
if ((int)(le16_to_cpu(cmd.thresholds[i]) * 1000) ==
mvm->tz_device.trips[j].temperature)
mvm->tz_device.fw_trips_index[i] = j;
}
}
......@@ -638,37 +638,12 @@ static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device,
return ret;
}
static int iwl_mvm_tzone_get_trip_temp(struct thermal_zone_device *device,
int trip, int *temp)
{
struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
return -EINVAL;
*temp = mvm->tz_device.temp_trips[trip] * 1000;
return 0;
}
static int iwl_mvm_tzone_get_trip_type(struct thermal_zone_device *device,
int trip, enum thermal_trip_type *type)
{
if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
return -EINVAL;
*type = THERMAL_TRIP_PASSIVE;
return 0;
}
static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,
int trip, int temp)
{
struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
struct iwl_mvm_thermal_device *tzone;
int i, ret;
s16 temperature;
int ret;
mutex_lock(&mvm->mutex);
......@@ -678,40 +653,17 @@ static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,
goto out;
}
if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) {
ret = -EINVAL;
goto out;
}
if ((temp / 1000) > S16_MAX) {
ret = -EINVAL;
goto out;
}
temperature = (s16)(temp / 1000);
tzone = &mvm->tz_device;
if (!tzone) {
ret = -EIO;
goto out;
}
/* no updates*/
if (tzone->temp_trips[trip] == temperature) {
ret = 0;
goto out;
}
/* already existing temperature */
for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
if (tzone->temp_trips[i] == temperature) {
ret = -EINVAL;
goto out;
}
}
tzone->temp_trips[trip] = temperature;
ret = iwl_mvm_send_temp_report_ths_cmd(mvm);
out:
mutex_unlock(&mvm->mutex);
......@@ -720,8 +672,6 @@ static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,
static struct thermal_zone_device_ops tzone_ops = {
.get_temp = iwl_mvm_tzone_get_temp,
.get_trip_temp = iwl_mvm_tzone_get_trip_temp,
.get_trip_type = iwl_mvm_tzone_get_trip_type,
.set_trip_temp = iwl_mvm_tzone_set_trip_temp,
};
......@@ -743,7 +693,8 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF);
mvm->tz_device.tzone = thermal_zone_device_register(name,
mvm->tz_device.tzone = thermal_zone_device_register_with_trips(name,
mvm->tz_device.trips,
IWL_MAX_DTS_TRIPS,
IWL_WRITABLE_TRIPS_MSK,
mvm, &tzone_ops,
......@@ -766,8 +717,10 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
/* 0 is a valid temperature,
* so initialize the array with S16_MIN which invalid temperature
*/
for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++)
mvm->tz_device.temp_trips[i] = S16_MIN;
for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++) {
mvm->tz_device.trips[i].temperature = INT_MIN;
mvm->tz_device.trips[i].type = THERMAL_TRIP_PASSIVE;
}
}
static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
......
......@@ -46,6 +46,8 @@
* measured by the on-die thermal monitor are within 0 <= Tj <= 90. So,
* assume 89°C is critical temperature.
*/
#define ACERHDF_DEFAULT_TEMP_FANON 60000
#define ACERHDF_DEFAULT_TEMP_FANOFF 53000
#define ACERHDF_TEMP_CRIT 89000
#define ACERHDF_FAN_OFF 0
#define ACERHDF_FAN_AUTO 1
......@@ -70,8 +72,8 @@ static int kernelmode;
#endif
static unsigned int interval = 10;
static unsigned int fanon = 60000;
static unsigned int fanoff = 53000;
static unsigned int fanon = ACERHDF_DEFAULT_TEMP_FANON;
static unsigned int fanoff = ACERHDF_DEFAULT_TEMP_FANOFF;
static unsigned int verbose;
static unsigned int list_supported;
static unsigned int fanstate = ACERHDF_FAN_AUTO;
......@@ -137,6 +139,15 @@ struct ctrl_settings {
int mcmd_enable;
};
static struct thermal_trip trips[] = {
[0] = { .temperature = ACERHDF_DEFAULT_TEMP_FANON,
.hysteresis = ACERHDF_DEFAULT_TEMP_FANON - ACERHDF_DEFAULT_TEMP_FANOFF,
.type = THERMAL_TRIP_ACTIVE },
[1] = { .temperature = ACERHDF_TEMP_CRIT,
.type = THERMAL_TRIP_CRITICAL }
};
static struct ctrl_settings ctrl_cfg __read_mostly;
/* Register addresses and values for different BIOS versions */
......@@ -326,6 +337,15 @@ static void acerhdf_check_param(struct thermal_zone_device *thermal)
fanon = ACERHDF_MAX_FANON;
}
if (fanon < fanoff) {
pr_err("fanoff temperature (%d) is above fanon temperature (%d), clamping to %d\n",
fanoff, fanon, fanon);
fanoff = fanon;
};
trips[0].temperature = fanon;
trips[0].hysteresis = fanon - fanoff;
if (kernelmode && prev_interval != interval) {
if (interval > ACERHDF_MAX_INTERVAL) {
pr_err("interval too high, set to %d\n",
......@@ -424,43 +444,6 @@ static int acerhdf_change_mode(struct thermal_zone_device *thermal,
return 0;
}
static int acerhdf_get_trip_type(struct thermal_zone_device *thermal, int trip,
enum thermal_trip_type *type)
{
if (trip == 0)
*type = THERMAL_TRIP_ACTIVE;
else if (trip == 1)
*type = THERMAL_TRIP_CRITICAL;
else
return -EINVAL;
return 0;
}
static int acerhdf_get_trip_hyst(struct thermal_zone_device *thermal, int trip,
int *temp)
{
if (trip != 0)
return -EINVAL;
*temp = fanon - fanoff;
return 0;
}
static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip,
int *temp)
{
if (trip == 0)
*temp = fanon;
else if (trip == 1)
*temp = ACERHDF_TEMP_CRIT;
else
return -EINVAL;
return 0;
}
static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal,
int *temperature)
{
......@@ -474,13 +457,9 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
.unbind = acerhdf_unbind,
.get_temp = acerhdf_get_ec_temp,
.change_mode = acerhdf_change_mode,
.get_trip_type = acerhdf_get_trip_type,
.get_trip_hyst = acerhdf_get_trip_hyst,
.get_trip_temp = acerhdf_get_trip_temp,
.get_crit_temp = acerhdf_get_crit_temp,
};
/*
* cooling device callback functions
* get maximal fan cooling state
......@@ -710,10 +689,10 @@ static int __init acerhdf_register_thermal(void)
if (IS_ERR(cl_dev))
return -EINVAL;
thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
&acerhdf_dev_ops,
&acerhdf_zone_params, 0,
(kernelmode) ? interval*1000 : 0);
thz_dev = thermal_zone_device_register_with_trips("acerhdf", trips, ARRAY_SIZE(trips),
0, NULL, &acerhdf_dev_ops,
&acerhdf_zone_params, 0,
(kernelmode) ? interval*1000 : 0);
if (IS_ERR(thz_dev))
return -EINVAL;
......
......@@ -63,13 +63,29 @@ struct idle_inject_thread {
* @idle_duration_us: duration of CPU idle time to inject
* @run_duration_us: duration of CPU run time to allow
* @latency_us: max allowed latency
* @update: Optional callback deciding whether or not to skip idle
* injection in the given cycle.
* @cpumask: mask of CPUs affected by idle injection
*
* This structure is used to define per instance idle inject device data. Each
* instance has an idle duration, a run duration and mask of CPUs to inject
* idle.
*
* Actual CPU idle time is injected by calling kernel scheduler interface
* play_idle_precise(). There is one optional callback that can be registered
* by calling idle_inject_register_full():
*
* update() - This callback is invoked just before waking up CPUs to inject
* idle. If it returns false, CPUs are not woken up to inject idle in the given
* cycle. It also allows the caller to readjust the idle and run duration by
* calling idle_inject_set_duration() for the next cycle.
*/
struct idle_inject_device {
struct hrtimer timer;
unsigned int idle_duration_us;
unsigned int run_duration_us;
unsigned int latency_us;
bool (*update)(void);
unsigned long cpumask[];
};
......@@ -111,11 +127,12 @@ static enum hrtimer_restart idle_inject_timer_fn(struct hrtimer *timer)
struct idle_inject_device *ii_dev =
container_of(timer, struct idle_inject_device, timer);
if (!ii_dev->update || (ii_dev->update && ii_dev->update()))
idle_inject_wakeup(ii_dev);
duration_us = READ_ONCE(ii_dev->run_duration_us);
duration_us += READ_ONCE(ii_dev->idle_duration_us);
idle_inject_wakeup(ii_dev);
hrtimer_forward_now(timer, ns_to_ktime(duration_us * NSEC_PER_USEC));
return HRTIMER_RESTART;
......@@ -162,6 +179,7 @@ void idle_inject_set_duration(struct idle_inject_device *ii_dev,
if (!run_duration_us)
pr_debug("CPU is forced to 100 percent idle\n");
}
EXPORT_SYMBOL_NS_GPL(idle_inject_set_duration, IDLE_INJECT);
/**
* idle_inject_get_duration - idle and run duration retrieval helper
......@@ -176,6 +194,7 @@ void idle_inject_get_duration(struct idle_inject_device *ii_dev,
*run_duration_us = READ_ONCE(ii_dev->run_duration_us);
*idle_duration_us = READ_ONCE(ii_dev->idle_duration_us);
}
EXPORT_SYMBOL_NS_GPL(idle_inject_get_duration, IDLE_INJECT);
/**
* idle_inject_set_latency - set the maximum latency allowed
......@@ -187,6 +206,7 @@ void idle_inject_set_latency(struct idle_inject_device *ii_dev,
{
WRITE_ONCE(ii_dev->latency_us, latency_us);
}
EXPORT_SYMBOL_NS_GPL(idle_inject_set_latency, IDLE_INJECT);
/**
* idle_inject_start - start idle injections
......@@ -218,6 +238,7 @@ int idle_inject_start(struct idle_inject_device *ii_dev)
return 0;
}
EXPORT_SYMBOL_NS_GPL(idle_inject_start, IDLE_INJECT);
/**
* idle_inject_stop - stops idle injections
......@@ -264,6 +285,7 @@ void idle_inject_stop(struct idle_inject_device *ii_dev)
cpu_hotplug_enable();
}
EXPORT_SYMBOL_NS_GPL(idle_inject_stop, IDLE_INJECT);
/**
* idle_inject_setup - prepare the current task for idle injection
......@@ -292,17 +314,22 @@ static int idle_inject_should_run(unsigned int cpu)
}
/**
* idle_inject_register - initialize idle injection on a set of CPUs
* idle_inject_register_full - initialize idle injection on a set of CPUs
* @cpumask: CPUs to be affected by idle injection
* @update: This callback is called just before waking up CPUs to inject
* idle
*
* This function creates an idle injection control device structure for the
* given set of CPUs and initializes the timer associated with it. It does not
* start any injection cycles.
* given set of CPUs and initializes the timer associated with it. This
* function also allows to register update()callback.
* It does not start any injection cycles.
*
* Return: NULL if memory allocation fails, idle injection control device
* pointer on success.
*/
struct idle_inject_device *idle_inject_register(struct cpumask *cpumask)
struct idle_inject_device *idle_inject_register_full(struct cpumask *cpumask,
bool (*update)(void))
{
struct idle_inject_device *ii_dev;
int cpu, cpu_rb;
......@@ -315,6 +342,7 @@ struct idle_inject_device *idle_inject_register(struct cpumask *cpumask)
hrtimer_init(&ii_dev->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ii_dev->timer.function = idle_inject_timer_fn;
ii_dev->latency_us = UINT_MAX;
ii_dev->update = update;
for_each_cpu(cpu, to_cpumask(ii_dev->cpumask)) {
......@@ -339,6 +367,24 @@ struct idle_inject_device *idle_inject_register(struct cpumask *cpumask)
return NULL;
}
EXPORT_SYMBOL_NS_GPL(idle_inject_register_full, IDLE_INJECT);
/**
* idle_inject_register - initialize idle injection on a set of CPUs
* @cpumask: CPUs to be affected by idle injection
*
* This function creates an idle injection control device structure for the
* given set of CPUs and initializes the timer associated with it. It does not
* start any injection cycles.
*
* Return: NULL if memory allocation fails, idle injection control device
* pointer on success.
*/
struct idle_inject_device *idle_inject_register(struct cpumask *cpumask)
{
return idle_inject_register_full(cpumask, NULL);
}
EXPORT_SYMBOL_NS_GPL(idle_inject_register, IDLE_INJECT);
/**
* idle_inject_unregister - unregister idle injection control device
......@@ -359,6 +405,7 @@ void idle_inject_unregister(struct idle_inject_device *ii_dev)
kfree(ii_dev);
}
EXPORT_SYMBOL_NS_GPL(idle_inject_unregister, IDLE_INJECT);
static struct smp_hotplug_thread idle_inject_threads = {
.store = &idle_inject_thread.tsk,
......
......@@ -76,6 +76,10 @@ config THERMAL_OF
Say 'Y' here if you need to build thermal infrastructure
based on device tree.
config THERMAL_ACPI
depends on ACPI
bool
config THERMAL_WRITABLE_TRIPS
bool "Enable writable trip points"
help
......@@ -412,16 +416,10 @@ config DA9062_THERMAL
zone.
Compatible with the DA9062 and DA9061 PMICs.
config MTK_THERMAL
tristate "Temperature sensor driver for mediatek SoCs"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_IOMEM
depends on NVMEM || NVMEM=n
depends on RESET_CONTROLLER
default y
help
Enable this option if you want to have support for thermal management
controller present in Mediatek SoCs
menu "Mediatek thermal drivers"
depends on ARCH_MEDIATEK || COMPILE_TEST
source "drivers/thermal/mediatek/Kconfig"
endmenu
config AMLOGIC_THERMAL
tristate "Amlogic Thermal Support"
......
......@@ -4,8 +4,8 @@
#
obj-$(CONFIG_THERMAL) += thermal_sys.o
thermal_sys-y += thermal_core.o thermal_sysfs.o \
thermal_helpers.o
thermal_sys-y += thermal_core.o thermal_sysfs.o
thermal_sys-y += thermal_trip.o thermal_helpers.o
# netlink interface to manage the thermal framework
thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o
......@@ -13,6 +13,7 @@ thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o
# interface to/from other layers providing sensors
thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
thermal_sys-$(CONFIG_THERMAL_OF) += thermal_of.o
thermal_sys-$(CONFIG_THERMAL_ACPI) += thermal_acpi.o
# governors
thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += gov_fair_share.o
......@@ -55,7 +56,7 @@ obj-y += st/
obj-y += qcom/
obj-y += tegra/
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
obj-y += mediatek/
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o
......
......@@ -28,7 +28,6 @@
#include <linux/regmap.h>
#include <linux/thermal.h>
#include "thermal_core.h"
#include "thermal_hwmon.h"
#define TSENSOR_CFG_REG1 0x4
......
......@@ -19,8 +19,6 @@
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include "thermal_core.h"
/* Thermal Manager Control and Status Register */
#define PMU_TDC0_SW_RST_MASK (0x1 << 1)
#define PMU_TM_DISABLE_OFFS 0
......@@ -709,12 +707,10 @@ static int armada_thermal_probe_legacy(struct platform_device *pdev,
struct armada_thermal_priv *priv)
{
struct armada_thermal_data *data = priv->data;
struct resource *res;
void __iomem *base;
/* First memory region points towards the status register */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(base))
return PTR_ERR(base);
......@@ -761,8 +757,7 @@ static void armada_set_sane_name(struct platform_device *pdev,
}
/* Save the name locally */
strncpy(priv->zone_name, name, THERMAL_NAME_LENGTH - 1);
priv->zone_name[THERMAL_NAME_LENGTH - 1] = '\0';
strscpy(priv->zone_name, name, THERMAL_NAME_LENGTH);
/* Then check there are no '-' or hwmon core will complain */
do {
......@@ -785,30 +780,23 @@ static int armada_configure_overheat_int(struct armada_thermal_priv *priv,
int sensor_id)
{
/* Retrieve the critical trip point to enable the overheat interrupt */
const struct thermal_trip *trips = of_thermal_get_trip_points(tz);
int temperature;
int ret;
int i;
if (!trips)
return -EINVAL;
for (i = 0; i < of_thermal_get_ntrips(tz); i++)
if (trips[i].type == THERMAL_TRIP_CRITICAL)
break;
if (i == of_thermal_get_ntrips(tz))
return -EINVAL;
ret = thermal_zone_get_crit_temp(tz, &temperature);
if (ret)
return ret;
ret = armada_select_channel(priv, sensor_id);
if (ret)
return ret;
armada_set_overheat_thresholds(priv,
trips[i].temperature,
trips[i].hysteresis);
/*
* A critical temperature does not have a hysteresis
*/
armada_set_overheat_thresholds(priv, temperature, 0);
priv->overheat_sensor = tz;
priv->interrupt_source = sensor_id;
armada_enable_overheat_interrupt(priv);
return 0;
......
......@@ -166,7 +166,6 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
const struct of_device_id *match;
struct thermal_zone_device *tz;
struct bcm2835_thermal_data *data;
struct resource *res;
int err = 0;
u32 val;
unsigned long rate;
......@@ -180,8 +179,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
if (!match)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->regs = devm_ioremap_resource(&pdev->dev, res);
data->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(data->regs)) {
err = PTR_ERR(data->regs);
return err;
......@@ -224,7 +222,8 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
*/
val = readl(data->regs + BCM2835_TS_TSENSCTL);
if (!(val & BCM2835_TS_TSENSCTL_RSTB)) {
int trip_temp, offset, slope;
struct thermal_trip trip;
int offset, slope;
slope = thermal_zone_get_slope(tz);
offset = thermal_zone_get_offset(tz);
......@@ -232,7 +231,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
* For now we deal only with critical, otherwise
* would need to iterate
*/
err = tz->ops->get_trip_temp(tz, 0, &trip_temp);
err = thermal_zone_get_trip(tz, 0, &trip);
if (err < 0) {
dev_err(&pdev->dev,
"Not able to read trip_temp: %d\n",
......@@ -249,7 +248,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
val |= (0xFE << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT);
/* trip_adc value from info */
val |= bcm2835_thermal_temp2adc(trip_temp,
val |= bcm2835_thermal_temp2adc(trip.temperature,
offset,
slope)
<< BCM2835_TS_TSENSCTL_THOLD_SHIFT;
......
......@@ -321,7 +321,6 @@ static int brcmstb_thermal_probe(struct platform_device *pdev)
const struct thermal_zone_device_ops *of_ops;
struct thermal_zone_device *thermal;
struct brcmstb_thermal_priv *priv;
struct resource *res;
int irq, ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
......@@ -332,8 +331,7 @@ static int brcmstb_thermal_probe(struct platform_device *pdev)
if (!priv->temp_params)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
priv->tmon_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(priv->tmon_base))
return PTR_ERR(priv->tmon_base);
......
......@@ -120,44 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
int trip,
enum thermal_trip_type *type)
{
struct da9062_thermal *thermal = z->devdata;
switch (trip) {
case 0:
*type = THERMAL_TRIP_HOT;
break;
default:
dev_err(thermal->dev,
"Driver does not support more than 1 trip-wire\n");
return -EINVAL;
}
return 0;
}
static int da9062_thermal_get_trip_temp(struct thermal_zone_device *z,
int trip,
int *temp)
{
struct da9062_thermal *thermal = z->devdata;
switch (trip) {
case 0:
*temp = DA9062_MILLI_CELSIUS(125);
break;
default:
dev_err(thermal->dev,
"Driver does not support more than 1 trip-wire\n");
return -EINVAL;
}
return 0;
}
static int da9062_thermal_get_temp(struct thermal_zone_device *z,
int *temp)
{
......@@ -172,8 +134,10 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
static struct thermal_zone_device_ops da9062_thermal_ops = {
.get_temp = da9062_thermal_get_temp,
.get_trip_type = da9062_thermal_get_trip_type,
.get_trip_temp = da9062_thermal_get_trip_temp,
};
static struct thermal_trip trips[] = {
{ .temperature = DA9062_MILLI_CELSIUS(125), .type = THERMAL_TRIP_HOT },
};
static const struct da9062_thermal_config da9062_config = {
......@@ -228,10 +192,10 @@ static int da9062_thermal_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
mutex_init(&thermal->lock);
thermal->zone = thermal_zone_device_register(thermal->config->name,
1, 0, thermal,
&da9062_thermal_ops, NULL, pp_tmp,
0);
thermal->zone = thermal_zone_device_register_with_trips(thermal->config->name,
trips, ARRAY_SIZE(trips), 0, thermal,
&da9062_thermal_ops, NULL, pp_tmp,
0);
if (IS_ERR(thermal->zone)) {
dev_err(&pdev->dev, "Cannot register thermal zone device\n");
ret = PTR_ERR(thermal->zone);
......
......@@ -122,20 +122,17 @@ static int dove_thermal_probe(struct platform_device *pdev)
{
struct thermal_zone_device *thermal = NULL;
struct dove_thermal_priv *priv;
struct resource *res;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->sensor = devm_ioremap_resource(&pdev->dev, res);
priv->sensor = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(priv->sensor))
return PTR_ERR(priv->sensor);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
priv->control = devm_ioremap_resource(&pdev->dev, res);
priv->control = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
if (IS_ERR(priv->control))
return PTR_ERR(priv->control);
......
......@@ -13,26 +13,28 @@
#include "thermal_core.h"
static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
static int thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id)
{
int trip_temp, trip_hyst;
struct thermal_trip trip;
struct thermal_instance *instance;
int ret;
tz->ops->get_trip_temp(tz, trip, &trip_temp);
ret = __thermal_zone_get_trip(tz, trip_id, &trip);
if (ret) {
pr_warn_once("Failed to retrieve trip point %d\n", trip_id);
return ret;
}
if (!tz->ops->get_trip_hyst) {
pr_warn_once("Undefined get_trip_hyst for thermal zone %s - "
"running with default hysteresis zero\n", tz->type);
trip_hyst = 0;
} else
tz->ops->get_trip_hyst(tz, trip, &trip_hyst);
if (!trip.hysteresis)
dev_info_once(&tz->device,
"Zero hysteresis value for thermal zone %s\n", tz->type);
dev_dbg(&tz->device, "Trip%d[temp=%d]:temp=%d:hyst=%d\n",
trip, trip_temp, tz->temperature,
trip_hyst);
trip_id, trip.temperature, tz->temperature,
trip.hysteresis);
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
if (instance->trip != trip)
if (instance->trip != trip_id)
continue;
/* in case fan is in initial state, switch the fan off */
......@@ -50,10 +52,10 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
* enable fan when temperature exceeds trip_temp and disable
* the fan in case it falls below trip_temp minus hysteresis
*/
if (instance->target == 0 && tz->temperature >= trip_temp)
if (instance->target == 0 && tz->temperature >= trip.temperature)
instance->target = 1;
else if (instance->target == 1 &&
tz->temperature <= trip_temp - trip_hyst)
tz->temperature <= trip.temperature - trip.hysteresis)
instance->target = 0;
dev_dbg(&instance->cdev->device, "target=%d\n",
......@@ -63,6 +65,8 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
instance->cdev->updated = false; /* cdev needs update */
mutex_unlock(&instance->cdev->lock);
}
return 0;
}
/**
......@@ -95,10 +99,13 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
static int bang_bang_control(struct thermal_zone_device *tz, int trip)
{
struct thermal_instance *instance;
int ret;
lockdep_assert_held(&tz->lock);
thermal_zone_trip_update(tz, trip);
ret = thermal_zone_trip_update(tz, trip);
if (ret)
return ret;
list_for_each_entry(instance, &tz->thermal_instances, tz_node)
thermal_cdev_update(instance->cdev);
......
......@@ -21,16 +21,12 @@
*/
static int get_trip_level(struct thermal_zone_device *tz)
{
int count = 0;
int trip_temp;
enum thermal_trip_type trip_type;
if (tz->num_trips == 0 || !tz->ops->get_trip_temp)
return 0;
struct thermal_trip trip;
int count;
for (count = 0; count < tz->num_trips; count++) {
tz->ops->get_trip_temp(tz, count, &trip_temp);
if (tz->temperature < trip_temp)
__thermal_zone_get_trip(tz, count, &trip);
if (tz->temperature < trip.temperature)
break;
}
......@@ -38,10 +34,8 @@ static int get_trip_level(struct thermal_zone_device *tz)
* count > 0 only if temperature is greater than first trip
* point, in which case, trip_point = count - 1
*/
if (count > 0) {
tz->ops->get_trip_type(tz, count - 1, &trip_type);
trace_thermal_zone_trip(tz, count - 1, trip_type);
}
if (count > 0)
trace_thermal_zone_trip(tz, count - 1, trip.type);
return count;
}
......
......@@ -124,16 +124,15 @@ static void estimate_pid_constants(struct thermal_zone_device *tz,
u32 sustainable_power, int trip_switch_on,
int control_temp)
{
struct thermal_trip trip;
u32 temperature_threshold = control_temp;
int ret;
int switch_on_temp;
u32 temperature_threshold;
s32 k_i;
ret = tz->ops->get_trip_temp(tz, trip_switch_on, &switch_on_temp);
if (ret)
switch_on_temp = 0;
ret = __thermal_zone_get_trip(tz, trip_switch_on, &trip);
if (!ret)
temperature_threshold -= trip.temperature;
temperature_threshold = control_temp - switch_on_temp;
/*
* estimate_pid_constants() tries to find appropriate default
* values for thermal zones that don't provide them. If a
......@@ -519,10 +518,10 @@ static void get_governor_trips(struct thermal_zone_device *tz,
last_passive = INVALID_TRIP;
for (i = 0; i < tz->num_trips; i++) {
enum thermal_trip_type type;
struct thermal_trip trip;
int ret;
ret = tz->ops->get_trip_type(tz, i, &type);
ret = __thermal_zone_get_trip(tz, i, &trip);
if (ret) {
dev_warn(&tz->device,
"Failed to get trip point %d type: %d\n", i,
......@@ -530,14 +529,14 @@ static void get_governor_trips(struct thermal_zone_device *tz,
continue;
}
if (type == THERMAL_TRIP_PASSIVE) {
if (trip.type == THERMAL_TRIP_PASSIVE) {
if (!found_first_passive) {
params->trip_switch_on = i;
found_first_passive = true;
} else {
last_passive = i;
}
} else if (type == THERMAL_TRIP_ACTIVE) {
} else if (trip.type == THERMAL_TRIP_ACTIVE) {
last_active = i;
} else {
break;
......@@ -632,7 +631,7 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
{
int ret;
struct power_allocator_params *params;
int control_temp;
struct thermal_trip trip;
ret = check_power_actors(tz);
if (ret)
......@@ -658,13 +657,12 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
get_governor_trips(tz, params);
if (tz->num_trips > 0) {
ret = tz->ops->get_trip_temp(tz,
params->trip_max_desired_temperature,
&control_temp);
ret = __thermal_zone_get_trip(tz, params->trip_max_desired_temperature,
&trip);
if (!ret)
estimate_pid_constants(tz, tz->tzp->sustainable_power,
params->trip_switch_on,
control_temp);
trip.temperature);
}
reset_pid_controller(params);
......@@ -694,11 +692,11 @@ static void power_allocator_unbind(struct thermal_zone_device *tz)
tz->governor_data = NULL;
}
static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
static int power_allocator_throttle(struct thermal_zone_device *tz, int trip_id)
{
int ret;
int switch_on_temp, control_temp;
struct power_allocator_params *params = tz->governor_data;
struct thermal_trip trip;
int ret;
bool update;
lockdep_assert_held(&tz->lock);
......@@ -707,13 +705,12 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
* We get called for every trip point but we only need to do
* our calculations once
*/
if (trip != params->trip_max_desired_temperature)
if (trip_id != params->trip_max_desired_temperature)
return 0;
ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,
&switch_on_temp);
if (!ret && (tz->temperature < switch_on_temp)) {
update = (tz->last_temperature >= switch_on_temp);
ret = __thermal_zone_get_trip(tz, params->trip_switch_on, &trip);
if (!ret && (tz->temperature < trip.temperature)) {
update = (tz->last_temperature >= trip.temperature);
tz->passive = 0;
reset_pid_controller(params);
allow_maximum_power(tz, update);
......@@ -722,16 +719,14 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
tz->passive = 1;
ret = tz->ops->get_trip_temp(tz, params->trip_max_desired_temperature,
&control_temp);
ret = __thermal_zone_get_trip(tz, params->trip_max_desired_temperature, &trip);
if (ret) {
dev_warn(&tz->device,
"Failed to get the maximum desired temperature: %d\n",
dev_warn(&tz->device, "Failed to get the maximum desired temperature: %d\n",
ret);
return ret;
}
return allocate_power(tz, control_temp);
return allocate_power(tz, trip.temperature);
}
static struct thermal_governor thermal_gov_power_allocator = {
......
......@@ -95,30 +95,28 @@ static void update_passive_instance(struct thermal_zone_device *tz,
tz->passive += value;
}
static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id)
{
int trip_temp;
enum thermal_trip_type trip_type;
enum thermal_trend trend;
struct thermal_instance *instance;
struct thermal_trip trip;
bool throttle = false;
int old_target;
tz->ops->get_trip_temp(tz, trip, &trip_temp);
tz->ops->get_trip_type(tz, trip, &trip_type);
__thermal_zone_get_trip(tz, trip_id, &trip);
trend = get_tz_trend(tz, trip);
trend = get_tz_trend(tz, trip_id);
if (tz->temperature >= trip_temp) {
if (tz->temperature >= trip.temperature) {
throttle = true;
trace_thermal_zone_trip(tz, trip, trip_type);
trace_thermal_zone_trip(tz, trip_id, trip.type);
}
dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
trip, trip_type, trip_temp, trend, throttle);
trip_id, trip.type, trip.temperature, trend, throttle);
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
if (instance->trip != trip)
if (instance->trip != trip_id)
continue;
old_target = instance->target;
......@@ -132,11 +130,11 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
/* Activate a passive thermal instance */
if (old_target == THERMAL_NO_TARGET &&
instance->target != THERMAL_NO_TARGET)
update_passive_instance(tz, trip_type, 1);
update_passive_instance(tz, trip.type, 1);
/* Deactivate a passive thermal instance */
else if (old_target != THERMAL_NO_TARGET &&
instance->target == THERMAL_NO_TARGET)
update_passive_instance(tz, trip_type, -1);
update_passive_instance(tz, trip.type, -1);
instance->initialized = true;
mutex_lock(&instance->cdev->lock);
......
......@@ -16,8 +16,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/of_device.h>
#include "thermal_core.h"
#include <linux/thermal.h>
#define HI6220_TEMP0_LAG (0x0)
#define HI6220_TEMP0_TH (0x4)
......@@ -427,10 +426,6 @@ static int hi3660_thermal_probe(struct hisi_thermal_data *data)
data->sensor[0].irq_name = "tsensor_a73";
data->sensor[0].data = data;
data->sensor[1].id = HI3660_LITTLE_SENSOR;
data->sensor[1].irq_name = "tsensor_a53";
data->sensor[1].data = data;
return 0;
}
......@@ -482,7 +477,7 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev,
struct hisi_thermal_sensor *sensor)
{
int ret, i;
const struct thermal_trip *trip;
struct thermal_trip trip;
sensor->tzd = devm_thermal_of_zone_register(&pdev->dev,
sensor->id, sensor,
......@@ -495,11 +490,12 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev,
return ret;
}
trip = of_thermal_get_trip_points(sensor->tzd);
for (i = 0; i < thermal_zone_get_num_trips(sensor->tzd); i++) {
thermal_zone_get_trip(sensor->tzd, i, &trip);
for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) {
if (trip[i].type == THERMAL_TRIP_PASSIVE) {
sensor->thres_temp = trip[i].temperature;
if (trip.type == THERMAL_TRIP_PASSIVE) {
sensor->thres_temp = trip.temperature;
break;
}
}
......
......@@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/thermal.h>
#include "thermal_core.h"
#include "thermal_hwmon.h"
#define TER 0x0 /* TMU enable */
......
......@@ -13,7 +13,6 @@
#include <linux/slab.h>
#include <linux/thermal.h>
#include "thermal_core.h"
#include "thermal_hwmon.h"
#define IMX_SC_MISC_FUNC_GET_TEMP 13
......@@ -88,7 +87,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
if (!resource_id)
return -EINVAL;
for (i = 0; resource_id[i] > 0; i++) {
for (i = 0; resource_id[i] >= 0; i++) {
sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
......@@ -127,7 +126,11 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
return 0;
}
static int imx_sc_sensors[] = { IMX_SC_R_SYSTEM, IMX_SC_R_PMIC_0, -1 };
static const int imx_sc_sensors[] = {
IMX_SC_R_SYSTEM, IMX_SC_R_PMIC_0,
IMX_SC_R_AP_0, IMX_SC_R_AP_1,
IMX_SC_R_GPU_0_PID0, IMX_SC_R_GPU_1_PID0,
IMX_SC_R_DRC_0, -1 };
static const struct of_device_id imx_sc_thermal_table[] = {
{ .compatible = "fsl,imx-sc-thermal", .data = imx_sc_sensors },
......
......@@ -76,7 +76,6 @@
enum imx_thermal_trip {
IMX_TRIP_PASSIVE,
IMX_TRIP_CRITICAL,
IMX_TRIP_NUM,
};
#define IMX_POLLING_DELAY 2000 /* millisecond */
......@@ -115,6 +114,11 @@ struct thermal_soc_data {
u32 low_alarm_shift;
};
static struct thermal_trip trips[] = {
[IMX_TRIP_PASSIVE] = { .type = THERMAL_TRIP_PASSIVE },
[IMX_TRIP_CRITICAL] = { .type = THERMAL_TRIP_CRITICAL },
};
static struct thermal_soc_data thermal_imx6q_data = {
.version = TEMPMON_IMX6Q,
......@@ -201,8 +205,6 @@ struct imx_thermal_data {
struct thermal_cooling_device *cdev;
struct regmap *tempmon;
u32 c1, c2; /* See formula in imx_init_calib() */
int temp_passive;
int temp_critical;
int temp_max;
int alarm_temp;
int last_temp;
......@@ -279,12 +281,12 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
/* Update alarm value to next higher trip point for TEMPMON_IMX6Q */
if (data->socdata->version == TEMPMON_IMX6Q) {
if (data->alarm_temp == data->temp_passive &&
*temp >= data->temp_passive)
imx_set_alarm_temp(data, data->temp_critical);
if (data->alarm_temp == data->temp_critical &&
*temp < data->temp_passive) {
imx_set_alarm_temp(data, data->temp_passive);
if (data->alarm_temp == trips[IMX_TRIP_PASSIVE].temperature &&
*temp >= trips[IMX_TRIP_PASSIVE].temperature)
imx_set_alarm_temp(data, trips[IMX_TRIP_CRITICAL].temperature);
if (data->alarm_temp == trips[IMX_TRIP_CRITICAL].temperature &&
*temp < trips[IMX_TRIP_PASSIVE].temperature) {
imx_set_alarm_temp(data, trips[IMX_TRIP_PASSIVE].temperature);
dev_dbg(&tz->device, "thermal alarm off: T < %d\n",
data->alarm_temp / 1000);
}
......@@ -330,29 +332,10 @@ static int imx_change_mode(struct thermal_zone_device *tz,
return 0;
}
static int imx_get_trip_type(struct thermal_zone_device *tz, int trip,
enum thermal_trip_type *type)
{
*type = (trip == IMX_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
THERMAL_TRIP_CRITICAL;
return 0;
}
static int imx_get_crit_temp(struct thermal_zone_device *tz, int *temp)
{
struct imx_thermal_data *data = tz->devdata;
*temp = data->temp_critical;
return 0;
}
static int imx_get_trip_temp(struct thermal_zone_device *tz, int trip,
int *temp)
{
struct imx_thermal_data *data = tz->devdata;
*temp = trips[IMX_TRIP_CRITICAL].temperature;
*temp = (trip == IMX_TRIP_PASSIVE) ? data->temp_passive :
data->temp_critical;
return 0;
}
......@@ -371,10 +354,10 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
return -EPERM;
/* do not allow passive to be set higher than critical */
if (temp < 0 || temp > data->temp_critical)
if (temp < 0 || temp > trips[IMX_TRIP_CRITICAL].temperature)
return -EINVAL;
data->temp_passive = temp;
trips[IMX_TRIP_PASSIVE].temperature = temp;
imx_set_alarm_temp(data, temp);
......@@ -423,8 +406,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
.unbind = imx_unbind,
.get_temp = imx_get_temp,
.change_mode = imx_change_mode,
.get_trip_type = imx_get_trip_type,
.get_trip_temp = imx_get_trip_temp,
.get_crit_temp = imx_get_crit_temp,
.set_trip_temp = imx_set_trip_temp,
};
......@@ -507,8 +488,8 @@ static void imx_init_temp_grade(struct platform_device *pdev, u32 ocotp_mem0)
* Set the critical trip point at 5 °C under max
* Set the passive trip point at 10 °C under max (changeable via sysfs)
*/
data->temp_critical = data->temp_max - (1000 * 5);
data->temp_passive = data->temp_max - (1000 * 10);
trips[IMX_TRIP_PASSIVE].temperature = data->temp_max - (1000 * 10);
trips[IMX_TRIP_CRITICAL].temperature = data->temp_max - (1000 * 5);
}
static int imx_init_from_tempmon_data(struct platform_device *pdev)
......@@ -743,12 +724,13 @@ static int imx_thermal_probe(struct platform_device *pdev)
goto legacy_cleanup;
}
data->tz = thermal_zone_device_register("imx_thermal_zone",
IMX_TRIP_NUM,
BIT(IMX_TRIP_PASSIVE), data,
&imx_tz_ops, NULL,
IMX_PASSIVE_DELAY,
IMX_POLLING_DELAY);
data->tz = thermal_zone_device_register_with_trips("imx_thermal_zone",
trips,
ARRAY_SIZE(trips),
BIT(IMX_TRIP_PASSIVE), data,
&imx_tz_ops, NULL,
IMX_PASSIVE_DELAY,
IMX_POLLING_DELAY);
if (IS_ERR(data->tz)) {
ret = PTR_ERR(data->tz);
dev_err(&pdev->dev,
......@@ -758,8 +740,8 @@ static int imx_thermal_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "%s CPU temperature grade - max:%dC"
" critical:%dC passive:%dC\n", data->temp_grade,
data->temp_max / 1000, data->temp_critical / 1000,
data->temp_passive / 1000);
data->temp_max / 1000, trips[IMX_TRIP_CRITICAL].temperature / 1000,
trips[IMX_TRIP_PASSIVE].temperature / 1000);
/* Enable measurements at ~ 10 Hz */
regmap_write(map, data->socdata->measure_freq_ctrl + REG_CLR,
......@@ -767,10 +749,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
regmap_write(map, data->socdata->measure_freq_ctrl + REG_SET,
measure_freq << data->socdata->measure_freq_shift);
imx_set_alarm_temp(data, data->temp_passive);
imx_set_alarm_temp(data, trips[IMX_TRIP_PASSIVE].temperature);
if (data->socdata->version == TEMPMON_IMX6SX)
imx_set_panic_temp(data, data->temp_critical);
imx_set_panic_temp(data, trips[IMX_TRIP_CRITICAL].temperature);
regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
data->socdata->power_down_mask);
......
......@@ -3,6 +3,9 @@ config INTEL_POWERCLAMP
tristate "Intel PowerClamp idle injection driver"
depends on X86
depends on CPU_SUP_INTEL
depends on CPU_IDLE
select POWERCAP
select IDLE_INJECT
help
Enable this to enable Intel PowerClamp idle injection driver. This
enforce idle time which results in more package C-state residency. The
......@@ -12,11 +15,16 @@ config X86_THERMAL_VECTOR
def_bool y
depends on X86 && CPU_SUP_INTEL && X86_LOCAL_APIC
config INTEL_TCC
bool
depends on X86
config X86_PKG_TEMP_THERMAL
tristate "X86 package temperature thermal driver"
depends on X86_THERMAL_VECTOR
select THERMAL_GOV_USER_SPACE
select THERMAL_WRITABLE_TRIPS
select INTEL_TCC
default m
help
Enable this to register CPU digital sensor for package temperature as
......@@ -28,6 +36,7 @@ config INTEL_SOC_DTS_IOSF_CORE
tristate
depends on X86 && PCI
select IOSF_MBI
select INTEL_TCC
help
This is becoming a common feature for Intel SoCs to expose the additional
digital temperature sensors (DTSs) using side band interface (IOSF). This
......@@ -75,6 +84,7 @@ config INTEL_BXT_PMIC_THERMAL
config INTEL_PCH_THERMAL
tristate "Intel PCH Thermal Reporting Driver"
depends on X86 && PCI
select THERMAL_ACPI if ACPI
help
Enable this to support thermal reporting on certain intel PCHs.
Thermal reporting device will provide temperature reading,
......@@ -83,6 +93,7 @@ config INTEL_PCH_THERMAL
config INTEL_TCC_COOLING
tristate "Intel TCC offset cooling Driver"
depends on X86
select INTEL_TCC
help
Enable this to support system cooling by adjusting the effective TCC
activation temperature via the TCC Offset register, which is widely
......
......@@ -2,6 +2,7 @@
#
# Makefile for various Intel thermal drivers.
obj-$(CONFIG_INTEL_TCC) += intel_tcc.o
obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o
......
......@@ -9,7 +9,9 @@ config INT340X_THERMAL
select THERMAL_GOV_USER_SPACE
select ACPI_THERMAL_REL
select ACPI_FAN
select THERMAL_ACPI
select INTEL_SOC_DTS_IOSF_CORE
select INTEL_TCC
select PROC_THERMAL_MMIO_RAPL if POWERCAP
help
Newer laptops and tablets that use ACPI may have thermal sensors and
......
......@@ -60,6 +60,7 @@ struct int3400_thermal_priv {
int odvp_count;
int *odvp;
u32 os_uuid_mask;
int production_mode;
struct odvp_attr *odvp_attrs;
};
......@@ -130,10 +131,7 @@ static ssize_t available_uuids_show(struct device *dev,
for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) {
if (priv->uuid_bitmap & (1 << i))
length += scnprintf(&buf[length],
PAGE_SIZE - length,
"%s\n",
int3400_thermal_uuids[i]);
length += sysfs_emit_at(buf, length, int3400_thermal_uuids[i]);
}
return length;
......@@ -151,10 +149,7 @@ static ssize_t current_uuid_show(struct device *dev,
for (i = 0; i <= INT3400_THERMAL_CRITICAL; i++) {
if (priv->os_uuid_mask & BIT(i))
length += scnprintf(&buf[length],
PAGE_SIZE - length,
"%s\n",
int3400_thermal_uuids[i]);
length += sysfs_emit_at(buf, length, int3400_thermal_uuids[i]);
}
if (length)
......@@ -315,6 +310,44 @@ static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv)
return result;
}
static ssize_t production_mode_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct int3400_thermal_priv *priv = dev_get_drvdata(dev);
return sysfs_emit(buf, "%d\n", priv->production_mode);
}
static DEVICE_ATTR_RO(production_mode);
static int production_mode_init(struct int3400_thermal_priv *priv)
{
unsigned long long mode;
acpi_status status;
int ret;
priv->production_mode = -1;
status = acpi_evaluate_integer(priv->adev->handle, "DCFG", NULL, &mode);
/* If the method is not present, this is not an error */
if (ACPI_FAILURE(status))
return 0;
ret = sysfs_create_file(&priv->pdev->dev.kobj, &dev_attr_production_mode.attr);
if (ret)
return ret;
priv->production_mode = mode;
return 0;
}
static void production_mode_exit(struct int3400_thermal_priv *priv)
{
if (priv->production_mode >= 0)
sysfs_remove_file(&priv->pdev->dev.kobj, &dev_attr_production_mode.attr);
}
static ssize_t odvp_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
......@@ -610,8 +643,15 @@ static int int3400_thermal_probe(struct platform_device *pdev)
if (result)
goto free_sysfs;
result = production_mode_init(priv);
if (result)
goto free_notify;
return 0;
free_notify:
acpi_remove_notify_handler(priv->adev->handle, ACPI_DEVICE_NOTIFY,
int3400_notify);
free_sysfs:
cleanup_odvp(priv);
if (!ZERO_OR_NULL_PTR(priv->data_vault)) {
......@@ -638,6 +678,8 @@ static int int3400_thermal_remove(struct platform_device *pdev)
{
struct int3400_thermal_priv *priv = platform_get_drvdata(pdev);
production_mode_exit(priv);
acpi_remove_notify_handler(
priv->adev->handle, ACPI_DEVICE_NOTIFY,
int3400_notify);
......
......@@ -69,7 +69,7 @@ static void int3403_notify(acpi_handle handle,
THERMAL_TRIP_VIOLATED);
break;
case INT3403_PERF_TRIP_POINT_CHANGED:
int340x_thermal_read_trips(obj->int340x_zone);
int340x_thermal_update_trips(obj->int340x_zone);
int340x_thermal_zone_device_update(obj->int340x_zone,
THERMAL_TRIP_CHANGED);
break;
......
......@@ -10,6 +10,7 @@
#include <acpi/acpi_lpat.h>
#define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10
#define INT340X_THERMAL_MAX_TRIP_COUNT INT340X_THERMAL_MAX_ACT_TRIP_COUNT + 3
struct active_trip {
int temp;
......@@ -19,26 +20,18 @@ struct active_trip {
struct int34x_thermal_zone {
struct acpi_device *adev;
struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT];
unsigned long *aux_trips;
struct thermal_trip *trips;
int aux_trip_nr;
int psv_temp;
int psv_trip_id;
int crt_temp;
int crt_trip_id;
int hot_temp;
int hot_trip_id;
struct thermal_zone_device *zone;
struct thermal_zone_device_ops *override_ops;
struct thermal_zone_device_ops *ops;
void *priv_data;
struct acpi_lpat_conversion_table *lpat_table;
struct mutex trip_mutex;
};
struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *,
struct thermal_zone_device_ops *override_ops);
int (*get_temp) (struct thermal_zone_device *, int *));
void int340x_thermal_zone_remove(struct int34x_thermal_zone *);
int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone);
void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone);
static inline void int340x_thermal_zone_set_priv_data(
struct int34x_thermal_zone *tzone, void *priv_data)
......
......@@ -4,6 +4,7 @@
* Copyright (c) 2014, Intel Corporation.
*/
#include <linux/acpi.h>
#include <linux/intel_tcc.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
......@@ -68,54 +69,17 @@ static const struct attribute_group power_limit_attribute_group = {
.name = "power_limits"
};
static int tcc_get_offset(void)
{
u64 val;
int err;
err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
if (err)
return err;
return (val >> 24) & 0x3f;
}
static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int tcc;
tcc = tcc_get_offset();
if (tcc < 0)
return tcc;
return sprintf(buf, "%d\n", tcc);
}
static int tcc_offset_update(unsigned int tcc)
{
u64 val;
int err;
int offset;
if (tcc > 63)
return -EINVAL;
err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
if (err)
return err;
offset = intel_tcc_get_offset(-1);
if (offset < 0)
return offset;
if (val & BIT(31))
return -EPERM;
val &= ~GENMASK_ULL(29, 24);
val |= (tcc & 0x3f) << 24;
err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
if (err)
return err;
return 0;
return sprintf(buf, "%d\n", offset);
}
static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
......@@ -136,7 +100,7 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
if (kstrtouint(buf, 0, &tcc))
return -EINVAL;
err = tcc_offset_update(tcc);
err = intel_tcc_set_offset(-1, tcc);
if (err)
return err;
......@@ -145,72 +109,27 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
static DEVICE_ATTR_RW(tcc_offset_degree_celsius);
static int stored_tjmax; /* since it is fixed, we can have local storage */
static int get_tjmax(void)
{
u32 eax, edx;
u32 val;
int err;
err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
if (err)
return err;
val = (eax >> 16) & 0xff;
if (val)
return val;
return -EINVAL;
}
static int read_temp_msr(int *temp)
static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone,
int *temp)
{
int cpu;
u32 eax, edx;
int err;
unsigned long curr_temp_off = 0;
int curr_temp;
*temp = 0;
for_each_online_cpu(cpu) {
err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax,
&edx);
if (err)
goto err_ret;
else {
if (eax & 0x80000000) {
curr_temp_off = (eax >> 16) & 0x7f;
if (!*temp || curr_temp_off < *temp)
*temp = curr_temp_off;
} else {
err = -EINVAL;
goto err_ret;
}
}
curr_temp = intel_tcc_get_temp(cpu, false);
if (curr_temp < 0)
return curr_temp;
if (!*temp || curr_temp > *temp)
*temp = curr_temp;
}
return 0;
err_ret:
return err;
}
*temp *= 1000;
static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone,
int *temp)
{
int ret;
ret = read_temp_msr(temp);
if (!ret)
*temp = (stored_tjmax - *temp) * 1000;
return ret;
return 0;
}
static struct thermal_zone_device_ops proc_thermal_local_ops = {
.get_temp = proc_thermal_get_zone_temp,
};
static int proc_thermal_read_ppcc(struct proc_thermal_device *proc_priv)
{
int i;
......@@ -285,7 +204,7 @@ int proc_thermal_add(struct device *dev, struct proc_thermal_device *proc_priv)
struct acpi_device *adev;
acpi_status status;
unsigned long long tmp;
struct thermal_zone_device_ops *ops = NULL;
int (*get_temp) (struct thermal_zone_device *, int *) = NULL;
int ret;
adev = ACPI_COMPANION(dev);
......@@ -302,12 +221,11 @@ int proc_thermal_add(struct device *dev, struct proc_thermal_device *proc_priv)
status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp);
if (ACPI_FAILURE(status)) {
/* there is no _TMP method, add local method */
stored_tjmax = get_tjmax();
if (stored_tjmax > 0)
ops = &proc_thermal_local_ops;
if (intel_tcc_get_tjmax(-1) > 0)
get_temp = proc_thermal_get_zone_temp;
}
proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops);
proc_priv->int340x_zone = int340x_thermal_zone_add(adev, get_temp);
if (IS_ERR(proc_priv->int340x_zone)) {
return PTR_ERR(proc_priv->int340x_zone);
} else
......@@ -356,7 +274,7 @@ static int tcc_offset_save = -1;
int proc_thermal_suspend(struct device *dev)
{
tcc_offset_save = tcc_get_offset();
tcc_offset_save = intel_tcc_get_offset(-1);
if (tcc_offset_save < 0)
dev_warn(dev, "failed to save offset (%d)\n", tcc_offset_save);
......@@ -373,7 +291,7 @@ int proc_thermal_resume(struct device *dev)
/* Do not update if saving failed */
if (tcc_offset_save >= 0)
tcc_offset_update(tcc_offset_save);
intel_tcc_set_offset(-1, tcc_offset_save);
return 0;
}
......@@ -460,6 +378,7 @@ void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *
}
EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove);
MODULE_IMPORT_NS(INTEL_TCC);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
MODULE_LICENSE("GPL v2");
......@@ -144,34 +144,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
return 0;
}
static int sys_get_trip_temp(struct thermal_zone_device *tzd,
int trip, int *temp)
{
struct proc_thermal_pci *pci_info = tzd->devdata;
u32 _temp;
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_THRES_0, &_temp);
if (!_temp) {
*temp = THERMAL_TEMP_INVALID;
} else {
int tjmax;
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax);
_temp = tjmax - _temp;
*temp = (unsigned long)_temp * 1000;
}
return 0;
}
static int sys_get_trip_type(struct thermal_zone_device *tzd, int trip,
enum thermal_trip_type *type)
{
*type = THERMAL_TRIP_PASSIVE;
return 0;
}
static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
{
struct proc_thermal_pci *pci_info = tzd->devdata;
......@@ -200,10 +172,26 @@ static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp
return 0;
}
static int get_trip_temp(struct proc_thermal_pci *pci_info)
{
int temp, tjmax;
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_THRES_0, &temp);
if (!temp)
return THERMAL_TEMP_INVALID;
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax);
temp = (tjmax - temp) * 1000;
return temp;
}
static struct thermal_trip psv_trip = {
.type = THERMAL_TRIP_PASSIVE,
};
static struct thermal_zone_device_ops tzone_ops = {
.get_temp = sys_get_curr_temp,
.get_trip_temp = sys_get_trip_temp,
.get_trip_type = sys_get_trip_type,
.set_trip_temp = sys_set_trip_temp,
};
......@@ -251,7 +239,10 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
if (ret)
goto err_ret_thermal;
pci_info->tzone = thermal_zone_device_register("TCPU_PCI", 1, 1, pci_info,
psv_trip.temperature = get_trip_temp(pci_info);
pci_info->tzone = thermal_zone_device_register_with_trips("TCPU_PCI", &psv_trip,
1, 1, pci_info,
&tzone_ops,
&tzone_params, 0, 0);
if (IS_ERR(pci_info->tzone)) {
......
......@@ -40,10 +40,11 @@
#include <asm/msr.h>
#include "../thermal_core.h"
#include "intel_hfi.h"
#include "thermal_interrupt.h"
#include "../thermal_netlink.h"
/* Hardware Feedback Interface MSR configuration bits */
#define HW_FEEDBACK_PTR_VALID_BIT BIT(0)
#define HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT BIT(0)
......
......@@ -232,9 +232,9 @@ static DEFINE_MUTEX(intel_menlow_attr_lock);
/*
* sensor_get_auxtrip - get the current auxtrip value from sensor
* @name: Thermalzone name
* @auxtype : AUX0/AUX1
* @buf: syfs buffer
* @handle: Object handle
* @index : GET_AUX1/GET_AUX0
* @value : The address will be fill by the value
*/
static int sensor_get_auxtrip(acpi_handle handle, int index,
unsigned long long *value)
......@@ -254,9 +254,9 @@ static int sensor_get_auxtrip(acpi_handle handle, int index,
/*
* sensor_set_auxtrip - set the new auxtrip value to sensor
* @name: Thermalzone name
* @auxtype : AUX0/AUX1
* @buf: syfs buffer
* @handle: Object handle
* @index : GET_AUX1/GET_AUX0
* @value : The value will be set
*/
static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
{
......
This diff is collapsed.
This diff is collapsed.
......@@ -84,6 +84,7 @@
#define QRK_DTS_MASK_TP_THRES 0xFF
#define QRK_DTS_SHIFT_TP 8
#define QRK_DTS_ID_TP_CRITICAL 0
#define QRK_DTS_ID_TP_HOT 1
#define QRK_DTS_SAFE_TP_THRES 105
/* Thermal Sensor Register Lock */
......@@ -104,6 +105,7 @@ struct soc_sensor_entry {
u32 store_ptps;
u32 store_dts_enable;
struct thermal_zone_device *tzone;
struct thermal_trip trips[QRK_MAX_DTS_TRIPS];
};
static struct soc_sensor_entry *soc_dts;
......@@ -172,9 +174,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
return ret;
}
static int _get_trip_temp(int trip, int *temp)
static int get_trip_temp(int trip)
{
int status;
int status, temp;
u32 out;
mutex_lock(&dts_update_mutex);
......@@ -183,7 +185,7 @@ static int _get_trip_temp(int trip, int *temp)
mutex_unlock(&dts_update_mutex);
if (status)
return status;
return THERMAL_TEMP_INVALID;
/*
* Thermal Sensor Programmable Trip Point Register has 8-bit
......@@ -191,21 +193,10 @@ static int _get_trip_temp(int trip, int *temp)
* thresholds. The threshold value is always offset by its
* temperature base (50 degree Celsius).
*/
*temp = (out >> (trip * QRK_DTS_SHIFT_TP)) & QRK_DTS_MASK_TP_THRES;
*temp -= QRK_DTS_TEMP_BASE;
temp = (out >> (trip * QRK_DTS_SHIFT_TP)) & QRK_DTS_MASK_TP_THRES;
temp -= QRK_DTS_TEMP_BASE;
return 0;
}
static inline int sys_get_trip_temp(struct thermal_zone_device *tzd,
int trip, int *temp)
{
return _get_trip_temp(trip, temp);
}
static inline int sys_get_crit_temp(struct thermal_zone_device *tzd, int *temp)
{
return _get_trip_temp(QRK_DTS_ID_TP_CRITICAL, temp);
return temp;
}
static int update_trip_temp(struct soc_sensor_entry *aux_entry,
......@@ -262,17 +253,6 @@ static inline int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
return update_trip_temp(tzd->devdata, trip, temp);
}
static int sys_get_trip_type(struct thermal_zone_device *thermal,
int trip, enum thermal_trip_type *type)
{
if (trip)
*type = THERMAL_TRIP_HOT;
else
*type = THERMAL_TRIP_CRITICAL;
return 0;
}
static int sys_get_curr_temp(struct thermal_zone_device *tzd,
int *temp)
{
......@@ -315,10 +295,7 @@ static int sys_change_mode(struct thermal_zone_device *tzd,
static struct thermal_zone_device_ops tzone_ops = {
.get_temp = sys_get_curr_temp,
.get_trip_temp = sys_get_trip_temp,
.get_trip_type = sys_get_trip_type,
.set_trip_temp = sys_set_trip_temp,
.get_crit_temp = sys_get_crit_temp,
.change_mode = sys_change_mode,
};
......@@ -385,10 +362,18 @@ static struct soc_sensor_entry *alloc_soc_dts(void)
goto err_ret;
}
aux_entry->tzone = thermal_zone_device_register("quark_dts",
QRK_MAX_DTS_TRIPS,
wr_mask,
aux_entry, &tzone_ops, NULL, 0, polling_delay);
aux_entry->trips[QRK_DTS_ID_TP_CRITICAL].temperature = get_trip_temp(QRK_DTS_ID_TP_CRITICAL);
aux_entry->trips[QRK_DTS_ID_TP_CRITICAL].type = THERMAL_TRIP_CRITICAL;
aux_entry->trips[QRK_DTS_ID_TP_HOT].temperature = get_trip_temp(QRK_DTS_ID_TP_HOT);
aux_entry->trips[QRK_DTS_ID_TP_HOT].type = THERMAL_TRIP_HOT;
aux_entry->tzone = thermal_zone_device_register_with_trips("quark_dts",
aux_entry->trips,
QRK_MAX_DTS_TRIPS,
wr_mask,
aux_entry, &tzone_ops,
NULL, 0, polling_delay);
if (IS_ERR(aux_entry->tzone)) {
err = PTR_ERR(aux_entry->tzone);
goto err_ret;
......
......@@ -7,6 +7,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitops.h>
#include <linux/intel_tcc.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
......@@ -45,32 +46,6 @@
/* DTS0 and DTS 1 */
#define SOC_MAX_DTS_SENSORS 2
static int get_tj_max(u32 *tj_max)
{
u32 eax, edx;
u32 val;
int err;
err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
if (err)
goto err_ret;
else {
val = (eax >> 16) & 0xff;
if (val)
*tj_max = val * 1000;
else {
err = -EINVAL;
goto err_ret;
}
}
return 0;
err_ret:
*tj_max = 0;
return err;
}
static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip,
int *temp)
{
......@@ -405,7 +380,7 @@ struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
{
struct intel_soc_dts_sensors *sensors;
bool notification;
u32 tj_max;
int tj_max;
int ret;
int i;
......@@ -415,8 +390,9 @@ struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
if (!trip_count || read_only_trip_count > trip_count)
return ERR_PTR(-EINVAL);
if (get_tj_max(&tj_max))
return ERR_PTR(-EINVAL);
tj_max = intel_tcc_get_tjmax(-1);
if (tj_max < 0)
return ERR_PTR(tj_max);
sensors = kzalloc(sizeof(*sensors), GFP_KERNEL);
if (!sensors)
......@@ -475,4 +451,5 @@ void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors)
}
EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit);
MODULE_IMPORT_NS(INTEL_TCC);
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0-only
/*
* intel_tcc.c - Library for Intel TCC (thermal control circuitry) MSR access
* Copyright (c) 2022, Intel Corporation.
*/
#include <linux/errno.h>
#include <linux/intel_tcc.h>
#include <asm/msr.h>
/**
* intel_tcc_get_tjmax() - returns the default TCC activation Temperature
* @cpu: cpu that the MSR should be run on, nagative value means any cpu.
*
* Get the TjMax value, which is the default thermal throttling or TCC
* activation temperature in degrees C.
*
* Return: Tjmax value in degrees C on success, negative error code otherwise.
*/
int intel_tcc_get_tjmax(int cpu)
{
u32 low, high;
int val, err;
if (cpu < 0)
err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
else
err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
if (err)
return err;
val = (low >> 16) & 0xff;
return val ? val : -ENODATA;
}
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.
*
* Get the TCC offset value to Tjmax. The effective thermal throttling or TCC
* activation temperature equals "Tjmax" - "TCC Offset", in degrees C.
*
* Return: Tcc offset value in degrees C on success, negative error code otherwise.
*/
int intel_tcc_get_offset(int cpu)
{
u32 low, high;
int err;
if (cpu < 0)
err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
else
err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
if (err)
return err;
return (low >> 24) & 0x3f;
}
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.
* @offset: TCC offset value in degree C
*
* Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC
* activation temperature equals "Tjmax" - "TCC Offset", in degree C.
*
* Return: On success returns 0, negative error code otherwise.
*/
int intel_tcc_set_offset(int cpu, int offset)
{
u32 low, high;
int err;
if (offset < 0 || offset > 0x3f)
return -EINVAL;
if (cpu < 0)
err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
else
err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
if (err)
return err;
/* MSR Locked */
if (low & BIT(31))
return -EPERM;
low &= ~(0x3f << 24);
low |= offset << 24;
if (cpu < 0)
return wrmsr_safe(MSR_IA32_TEMPERATURE_TARGET, low, high);
else
return wrmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, low, high);
}
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.
* @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
*
* Get the current temperature returned by the CPU core/package level
* thermal sensor, in degrees C.
*
* Return: Temperature in degrees C on success, negative error code otherwise.
*/
int intel_tcc_get_temp(int cpu, bool pkg)
{
u32 low, high;
u32 msr = pkg ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS;
int tjmax, temp, err;
tjmax = intel_tcc_get_tjmax(cpu);
if (tjmax < 0)
return tjmax;
if (cpu < 0)
err = rdmsr_safe(msr, &low, &high);
else
err = rdmsr_safe_on_cpu(cpu, msr, &low, &high);
if (err)
return err;
/* Temperature is beyond the valid thermal sensor range */
if (!(low & BIT(31)))
return -ENODATA;
temp = tjmax - ((low >> 16) & 0x7f);
/* Do not allow negative CPU temperature */
return temp >= 0 ? temp : -ENODATA;
}
EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, INTEL_TCC);
......@@ -7,12 +7,11 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/device.h>
#include <linux/intel_tcc.h>
#include <linux/module.h>
#include <linux/thermal.h>
#include <asm/cpu_device_id.h>
#define TCC_SHIFT 24
#define TCC_MASK (0x3fULL<<24)
#define TCC_PROGRAMMABLE BIT(30)
#define TCC_LOCKED BIT(31)
......@@ -21,47 +20,26 @@ static struct thermal_cooling_device *tcc_cdev;
static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
*state)
{
*state = TCC_MASK >> TCC_SHIFT;
return 0;
}
static int tcc_offset_update(int tcc)
{
u64 val;
int err;
err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
if (err)
return err;
val &= ~TCC_MASK;
val |= tcc << TCC_SHIFT;
err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
if (err)
return err;
*state = 0x3f;
return 0;
}
static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
*state)
{
u64 val;
int err;
int offset = intel_tcc_get_offset(-1);
err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
if (err)
return err;
if (offset < 0)
return offset;
*state = (val & TCC_MASK) >> TCC_SHIFT;
*state = offset;
return 0;
}
static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long
state)
{
return tcc_offset_update(state);
return intel_tcc_set_offset(-1, (int)state);
}
static const struct thermal_cooling_device_ops tcc_cooling_ops = {
......@@ -140,6 +118,7 @@ static void __exit tcc_cooling_exit(void)
module_exit(tcc_cooling_exit)
MODULE_IMPORT_NS(INTEL_TCC);
MODULE_DESCRIPTION("TCC offset cooling device Driver");
MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
MODULE_LICENSE("GPL v2");
......@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/intel_tcc.h>
#include <linux/err.h>
#include <linux/param.h>
#include <linux/device.h>
......@@ -48,11 +49,11 @@ MODULE_PARM_DESC(notify_delay_ms,
struct zone_device {
int cpu;
bool work_scheduled;
u32 tj_max;
u32 msr_pkg_therm_low;
u32 msr_pkg_therm_high;
struct delayed_work work;
struct thermal_zone_device *tzone;
struct thermal_trip *trips;
struct cpumask cpumask;
};
......@@ -104,71 +105,17 @@ static struct zone_device *pkg_temp_thermal_get_dev(unsigned int cpu)
return NULL;
}
/*
* tj-max is interesting because threshold is set relative to this
* temperature.
*/
static int get_tj_max(int cpu, u32 *tj_max)
{
u32 eax, edx, val;
int err;
err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
if (err)
return err;
val = (eax >> 16) & 0xff;
*tj_max = val * 1000;
return val ? 0 : -EINVAL;
}
static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
{
struct zone_device *zonedev = tzd->devdata;
u32 eax, edx;
rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_STATUS,
&eax, &edx);
if (eax & 0x80000000) {
*temp = zonedev->tj_max - ((eax >> 16) & 0x7f) * 1000;
pr_debug("sys_get_curr_temp %d\n", *temp);
return 0;
}
return -EINVAL;
}
static int sys_get_trip_temp(struct thermal_zone_device *tzd,
int trip, int *temp)
{
struct zone_device *zonedev = tzd->devdata;
unsigned long thres_reg_value;
u32 mask, shift, eax, edx;
int ret;
if (trip >= MAX_NUMBER_OF_TRIPS)
return -EINVAL;
if (trip) {
mask = THERM_MASK_THRESHOLD1;
shift = THERM_SHIFT_THRESHOLD1;
} else {
mask = THERM_MASK_THRESHOLD0;
shift = THERM_SHIFT_THRESHOLD0;
}
ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
&eax, &edx);
if (ret < 0)
return ret;
int val;
thres_reg_value = (eax & mask) >> shift;
if (thres_reg_value)
*temp = zonedev->tj_max - thres_reg_value * 1000;
else
*temp = THERMAL_TEMP_INVALID;
pr_debug("sys_get_trip_temp %d\n", *temp);
val = intel_tcc_get_temp(zonedev->cpu, true);
if (val < 0)
return val;
*temp = val * 1000;
pr_debug("sys_get_curr_temp %d\n", *temp);
return 0;
}
......@@ -177,9 +124,14 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
{
struct zone_device *zonedev = tzd->devdata;
u32 l, h, mask, shift, intr;
int ret;
int tj_max, ret;
tj_max = intel_tcc_get_tjmax(zonedev->cpu);
if (tj_max < 0)
return tj_max;
tj_max *= 1000;
if (trip >= MAX_NUMBER_OF_TRIPS || temp >= zonedev->tj_max)
if (trip >= MAX_NUMBER_OF_TRIPS || temp >= tj_max)
return -EINVAL;
ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
......@@ -204,7 +156,7 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
if (!temp) {
l &= ~intr;
} else {
l |= (zonedev->tj_max - temp)/1000 << shift;
l |= (tj_max - temp)/1000 << shift;
l |= intr;
}
......@@ -212,18 +164,9 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
l, h);
}
static int sys_get_trip_type(struct thermal_zone_device *thermal, int trip,
enum thermal_trip_type *type)
{
*type = THERMAL_TRIP_PASSIVE;
return 0;
}
/* Thermal zone callback registry */
static struct thermal_zone_device_ops tzone_ops = {
.get_temp = sys_get_curr_temp,
.get_trip_temp = sys_get_trip_temp,
.get_trip_type = sys_get_trip_type,
.set_trip_temp = sys_set_trip_temp,
};
......@@ -323,12 +266,55 @@ static int pkg_thermal_notify(u64 msr_val)
return 0;
}
static struct thermal_trip *pkg_temp_thermal_trips_init(int cpu, int tj_max, int num_trips)
{
struct thermal_trip *trips;
unsigned long thres_reg_value;
u32 mask, shift, eax, edx;
int ret, i;
trips = kzalloc(sizeof(*trips) * num_trips, GFP_KERNEL);
if (!trips)
return ERR_PTR(-ENOMEM);
for (i = 0; i < num_trips; i++) {
if (i) {
mask = THERM_MASK_THRESHOLD1;
shift = THERM_SHIFT_THRESHOLD1;
} else {
mask = THERM_MASK_THRESHOLD0;
shift = THERM_SHIFT_THRESHOLD0;
}
ret = rdmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
&eax, &edx);
if (ret < 0) {
kfree(trips);
return ERR_PTR(ret);
}
thres_reg_value = (eax & mask) >> shift;
trips[i].temperature = thres_reg_value ?
tj_max - thres_reg_value * 1000 : THERMAL_TEMP_INVALID;
trips[i].type = THERMAL_TRIP_PASSIVE;
pr_debug("%s: cpu=%d, trip=%d, temp=%d\n",
__func__, cpu, i, trips[i].temperature);
}
return trips;
}
static int pkg_temp_thermal_device_add(unsigned int cpu)
{
int id = topology_logical_die_id(cpu);
u32 tj_max, eax, ebx, ecx, edx;
u32 eax, ebx, ecx, edx;
struct zone_device *zonedev;
int thres_count, err;
int tj_max;
if (id >= max_id)
return -ENOMEM;
......@@ -340,32 +326,34 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS);
err = get_tj_max(cpu, &tj_max);
if (err)
return err;
tj_max = intel_tcc_get_tjmax(cpu);
if (tj_max < 0)
return tj_max;
zonedev = kzalloc(sizeof(*zonedev), GFP_KERNEL);
if (!zonedev)
return -ENOMEM;
zonedev->trips = pkg_temp_thermal_trips_init(cpu, tj_max, thres_count);
if (IS_ERR(zonedev->trips)) {
err = PTR_ERR(zonedev->trips);
goto out_kfree_zonedev;
}
INIT_DELAYED_WORK(&zonedev->work, pkg_temp_thermal_threshold_work_fn);
zonedev->cpu = cpu;
zonedev->tj_max = tj_max;
zonedev->tzone = thermal_zone_device_register("x86_pkg_temp",
thres_count,
zonedev->tzone = thermal_zone_device_register_with_trips("x86_pkg_temp",
zonedev->trips, thres_count,
(thres_count == MAX_NUMBER_OF_TRIPS) ? 0x03 : 0x01,
zonedev, &tzone_ops, &pkg_temp_tz_params, 0, 0);
if (IS_ERR(zonedev->tzone)) {
err = PTR_ERR(zonedev->tzone);
kfree(zonedev);
return err;
goto out_kfree_trips;
}
err = thermal_zone_device_enable(zonedev->tzone);
if (err) {
thermal_zone_device_unregister(zonedev->tzone);
kfree(zonedev);
return err;
}
if (err)
goto out_unregister_tz;
/* Store MSR value for package thermal interrupt, to restore at exit */
rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, zonedev->msr_pkg_therm_low,
zonedev->msr_pkg_therm_high);
......@@ -374,7 +362,16 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
raw_spin_lock_irq(&pkg_temp_lock);
zones[id] = zonedev;
raw_spin_unlock_irq(&pkg_temp_lock);
return 0;
out_unregister_tz:
thermal_zone_device_unregister(zonedev->tzone);
out_kfree_trips:
kfree(zonedev->trips);
out_kfree_zonedev:
kfree(zonedev);
return err;
}
static int pkg_thermal_cpu_offline(unsigned int cpu)
......@@ -458,8 +455,10 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
raw_spin_unlock_irq(&pkg_temp_lock);
/* Final cleanup if this is the last cpu */
if (lastcpu)
if (lastcpu) {
kfree(zonedev->trips);
kfree(zonedev);
}
return 0;
}
......@@ -531,6 +530,7 @@ static void __exit pkg_temp_thermal_exit(void)
}
module_exit(pkg_temp_thermal_exit)
MODULE_IMPORT_NS(INTEL_TCC);
MODULE_DESCRIPTION("X86 PKG TEMP Thermal Driver");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL v2");
......@@ -64,15 +64,13 @@ static int kirkwood_thermal_probe(struct platform_device *pdev)
{
struct thermal_zone_device *thermal = NULL;
struct kirkwood_thermal_priv *priv;
struct resource *res;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->sensor = devm_ioremap_resource(&pdev->dev, res);
priv->sensor = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(priv->sensor))
return PTR_ERR(priv->sensor);
......
config MTK_THERMAL
tristate "MediaTek thermal drivers"
depends on THERMAL_OF
help
This is the option for MediaTek thermal software solutions.
Please enable corresponding options to get temperature
information from thermal sensors or turn on throttle
mechaisms for thermal mitigation.
if MTK_THERMAL
config MTK_SOC_THERMAL
tristate "AUXADC temperature sensor driver for MediaTek SoCs"
depends on HAS_IOMEM
help
Enable this option if you want to get SoC temperature
information for MediaTek platforms.
This driver configures thermal controllers to collect
temperature via AUXADC interface.
config MTK_LVTS_THERMAL
tristate "LVTS Thermal Driver for MediaTek SoCs"
depends on HAS_IOMEM
help
Enable this option if you want to get SoC temperature
information for supported MediaTek platforms.
This driver configures LVTS (Low Voltage Thermal Sensor)
thermal controllers to collect temperatures via ASIF
(Analog Serial Interface).
config MTK_LVTS_THERMAL_DEBUGFS
bool "LVTS thermal debugfs"
depends on MTK_LVTS_THERMAL && DEBUG_FS
help
Enable this option to debug the internals of the device driver.
endif
obj-$(CONFIG_MTK_SOC_THERMAL) += auxadc_thermal.o
obj-$(CONFIG_MTK_LVTS_THERMAL) += lvts_thermal.o
This diff is collapsed.
......@@ -18,7 +18,8 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/thermal.h>
#include <asm-generic/unaligned.h>
#include <asm/unaligned.h>
#include "../thermal_hwmon.h"
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -13,7 +13,6 @@
#include <linux/thermal.h>
#include <linux/units.h>
#include "thermal_core.h"
#include "thermal_hwmon.h"
#define SITES_MAX 16
......
This diff is collapsed.
This diff is collapsed.
......@@ -60,7 +60,7 @@ enum adc_sort_mode {
#include "thermal_hwmon.h"
/**
/*
* The max sensors is two in rockchip SoCs.
* Two sensors: CPU and GPU sensor.
*/
......@@ -169,7 +169,7 @@ struct rockchip_thermal_data {
enum tshut_polarity tshut_polarity;
};
/**
/*
* TSADC Sensor Register description:
*
* TSADCV2_* are used for RK3288 SoCs, the other chips can reuse it.
......@@ -1339,7 +1339,7 @@ rockchip_thermal_register_sensor(struct platform_device *pdev,
}
/**
* Reset TSADC Controller, reset all tsadc registers.
* rockchip_thermal_reset_controller - Reset TSADC Controller, reset all tsadc registers.
* @reset: the reset controller of tsadc
*/
static void rockchip_thermal_reset_controller(struct reset_control *reset)
......@@ -1354,7 +1354,6 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct rockchip_thermal_data *thermal;
const struct of_device_id *match;
struct resource *res;
int irq;
int i;
int error;
......@@ -1378,8 +1377,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
if (!thermal->chip)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
thermal->regs = devm_ioremap_resource(&pdev->dev, res);
thermal->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(thermal->regs))
return PTR_ERR(thermal->regs);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ST_THERMAL) := st_thermal.o
obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o
obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o
obj-$(CONFIG_STM32_THERMAL) += stm_thermal.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment