- Add rk3568 sensor support (Finley Xiao)
- Add missing MODULE_DEVICE_TABLE for the Spreadtrum sensor (Chunyan Zhang) - Export additionnal attributes for the int340x thermal processor (Srinivas Pandruvada) - Add SC7280 compatible for the tsens driver (Rajeshwari Ravindra Kamble) - Fix kernel documentation for thermal_zone_device_unregister() and use devm_platform_get_and_ioremap_resource() (Yang Yingliang) - Fix coefficient calculations for the rcar_gen3 sensor driver (Niklas Söderlund) - Fix shadowing variable rcar_gen3_ths_tj_1 (Geert Uytterhoeven) - Add missing of_node_put() for the iMX and Spreadtrum sensors (Krzysztof Kozlowski) - Add tegra3 thermal sensor DT bindings (Dmitry Osipenko) - Stop the thermal zone monitoring when unregistering it to prevent a temperature update without the 'get_temp' callback (Dmitry Osipenko) - Add rk3568 DT bindings, convert bindings to yaml schemas and add the corresponding compatible in the Rockchip sensor (Ezequiel Garcia) - Add the sc8180x compatible for the Qualcomm tsensor (Bjorn Andersson) - Use the find_first_zero_bit() function instead of custom code (Andy Shevchenko) - Fix the kernel doc for the device cooling device (Yang Li) - Reorg the processor thermal int340x to set the scene for the PCI mmio driver (Srinivas Pandruvada) - Add PCI MMIO driver for the int340x processor thermal driver (Srinivas Pandruvada) - Add hwmon sensors for the mediatek sensor (Frank Wunderlich) - Fix warning for return value reported by Smatch for the int340x thermal processor (Srinivas Pandruvada) - Fix wrong register access and decoding for the int340x thermal processor (Srinivas Pandruvada) -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEGn3N4YVz0WNVyHskqDIjiipP6E8FAmDkbdAACgkQqDIjiipP 6E8pTwgAgc4RMdSBdNMVWP1Lc3Gprmg8uXMhma9ZlmJD+l3h4b4P+Zm7HjU+SPHI emvvqHgiWGw/ta/Fuhx9XnqTUjZznG3gMYohnfKe7jPgVTxmud+Yf0/E3dRrDNWl WNolS8rv4dLf1mjR+vGZ63KasK0Rz5Z4YxDV4kOvh+/VUhqg3XpZ1OTKOh/B9IWX pUTedq7hIZ44ZMINcwObvLNTeaoEhPNpgA4Rs07vQPYugY0V61HszqR/Mu+l8Rgp LiE8NUBANJ+8+wydHe/vP6lvOthh7YGSx4091rUe+X17qgfBDKCTsOyECnZ/UX+r aB1MaTAnr1H0dfM49yeoFcMSPc1rGA== =q0nG -----END PGP SIGNATURE----- Merge tag 'thermal-v5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux Pull thermal updates from Daniel Lezcano: - Add rk3568 sensor support (Finley Xiao) - Add missing MODULE_DEVICE_TABLE for the Spreadtrum sensor (Chunyan Zhang) - Export additionnal attributes for the int340x thermal processor (Srinivas Pandruvada) - Add SC7280 compatible for the tsens driver (Rajeshwari Ravindra Kamble) - Fix kernel documentation for thermal_zone_device_unregister() and use devm_platform_get_and_ioremap_resource() (Yang Yingliang) - Fix coefficient calculations for the rcar_gen3 sensor driver (Niklas Söderlund) - Fix shadowing variable rcar_gen3_ths_tj_1 (Geert Uytterhoeven) - Add missing of_node_put() for the iMX and Spreadtrum sensors (Krzysztof Kozlowski) - Add tegra3 thermal sensor DT bindings (Dmitry Osipenko) - Stop the thermal zone monitoring when unregistering it to prevent a temperature update without the 'get_temp' callback (Dmitry Osipenko) - Add rk3568 DT bindings, convert bindings to yaml schemas and add the corresponding compatible in the Rockchip sensor (Ezequiel Garcia) - Add the sc8180x compatible for the Qualcomm tsensor (Bjorn Andersson) - Use the find_first_zero_bit() function instead of custom code (Andy Shevchenko) - Fix the kernel doc for the device cooling device (Yang Li) - Reorg the processor thermal int340x to set the scene for the PCI mmio driver (Srinivas Pandruvada) - Add PCI MMIO driver for the int340x processor thermal driver (Srinivas Pandruvada) - Add hwmon sensors for the mediatek sensor (Frank Wunderlich) - Fix warning for return value reported by Smatch for the int340x thermal processor (Srinivas Pandruvada) - Fix wrong register access and decoding for the int340x thermal processor (Srinivas Pandruvada) * tag 'thermal-v5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (23 commits) thermal/drivers/int340x/processor_thermal: Fix tcc setting thermal/drivers/int340x/processor_thermal: Fix warning for return value thermal/drivers/mediatek: Add sensors-support thermal/drivers/int340x/processor_thermal: Add PCI MMIO based thermal driver thermal/drivers/int340x/processor_thermal: Split enumeration and processing part thermal: devfreq_cooling: Fix kernel-doc thermal/drivers/intel/intel_soc_dts_iosf: Switch to use find_first_zero_bit() dt-bindings: thermal: tsens: Add sc8180x compatible dt-bindings: rockchip-thermal: Support the RK3568 SoC compatible dt-bindings: thermal: convert rockchip-thermal to json-schema thermal/core/thermal_of: Stop zone device before unregistering it dt-bindings: thermal: Add binding for Tegra30 thermal sensor thermal/drivers/sprd: Add missing of_node_put for loop iteration thermal/drivers/imx_sc: Add missing of_node_put for loop iteration thermal/drivers/rcar_gen3_thermal: Do not shadow rcar_gen3_ths_tj_1 thermal/drivers/rcar_gen3_thermal: Fix coefficient calculations thermal/drivers/st: Use devm_platform_get_and_ioremap_resource() thermal/core: Correct function name thermal_zone_device_unregister() dt-bindings: thermal: tsens: Add compatible string to TSENS binding for SC7280 thermal/drivers/int340x: processor_thermal: Export additional attributes ...
This commit is contained in:
commit
f7ea4be434
@ -0,0 +1,73 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/thermal/nvidia,tegra30-tsensor.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NVIDIA Tegra30 Thermal Sensor
|
||||
|
||||
maintainers:
|
||||
- Dmitry Osipenko <digetx@gmail.com>
|
||||
- Jon Hunter <jonathanh@nvidia.com>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
description: |
|
||||
TSENSOR provides thermal and voltage sensors which monitor temperature
|
||||
and voltage of the chip. Sensors are placed across the die to gauge the
|
||||
temperature of the whole chip. The TSENSOR module:
|
||||
|
||||
Generates an interrupt to SW to lower temperature via DVFS on reaching
|
||||
a certain thermal/voltage threshold.
|
||||
|
||||
Generates a signal to the CAR to reduce CPU frequency by half on reaching
|
||||
a certain thermal/voltage threshold.
|
||||
|
||||
Generates a signal to the PMC when the temperature reaches dangerously high
|
||||
levels to reset the chip and sets a flag in the PMC.
|
||||
|
||||
TSENSOR has two channels which monitor two different spots of the SoC.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nvidia,tegra30-tsensor
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 1
|
||||
|
||||
assigned-clock-parents: true
|
||||
assigned-clock-rates: true
|
||||
assigned-clocks: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- resets
|
||||
- interrupts
|
||||
- "#thermal-sensor-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
thermal-sensor@70014000 {
|
||||
compatible = "nvidia,tegra30-tsensor";
|
||||
reg = <0x70014000 0x500>;
|
||||
interrupts = <0 102 4>;
|
||||
clocks = <&clk 100>;
|
||||
resets = <&rst 100>;
|
||||
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
@ -46,6 +46,8 @@ properties:
|
||||
- qcom,msm8996-tsens
|
||||
- qcom,msm8998-tsens
|
||||
- qcom,sc7180-tsens
|
||||
- qcom,sc7280-tsens
|
||||
- qcom,sc8180x-tsens
|
||||
- qcom,sdm845-tsens
|
||||
- qcom,sm8150-tsens
|
||||
- qcom,sm8250-tsens
|
||||
|
@ -1,85 +0,0 @@
|
||||
* Temperature Sensor ADC (TSADC) on rockchip SoCs
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "rockchip,<name>-tsadc"
|
||||
"rockchip,px30-tsadc": found on PX30 SoCs
|
||||
"rockchip,rv1108-tsadc": found on RV1108 SoCs
|
||||
"rockchip,rk3228-tsadc": found on RK3228 SoCs
|
||||
"rockchip,rk3288-tsadc": found on RK3288 SoCs
|
||||
"rockchip,rk3328-tsadc": found on RK3328 SoCs
|
||||
"rockchip,rk3368-tsadc": found on RK3368 SoCs
|
||||
"rockchip,rk3399-tsadc": found on RK3399 SoCs
|
||||
- reg : physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts : The interrupt number to the cpu. The interrupt specifier format
|
||||
depends on the interrupt controller.
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
- clock-names : Shall be "tsadc" for the converter-clock, and "apb_pclk" for
|
||||
the peripheral clock.
|
||||
- resets : Must contain an entry for each entry in reset-names.
|
||||
See ../reset/reset.txt for details.
|
||||
- reset-names : Must include the name "tsadc-apb".
|
||||
- pinctrl-names : The pin control state names;
|
||||
- pinctrl-0 : The "init" pinctrl state, it will be set before device probe.
|
||||
- pinctrl-1 : The "default" pinctrl state, it will be set after reset the
|
||||
TSADC controller.
|
||||
- pinctrl-2 : The "sleep" pinctrl state, it will be in for suspend.
|
||||
- #thermal-sensor-cells : Should be 1. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description.
|
||||
|
||||
Optional properties:
|
||||
- rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value.
|
||||
- rockchip,hw-tshut-mode : The hardware-controlled shutdown mode 0:CRU 1:GPIO.
|
||||
- rockchip,hw-tshut-polarity : The hardware-controlled active polarity 0:LOW
|
||||
1:HIGH.
|
||||
- rockchip,grf : The phandle of the syscon node for the general register file.
|
||||
|
||||
Exiample:
|
||||
tsadc: tsadc@ff280000 {
|
||||
compatible = "rockchip,rk3288-tsadc";
|
||||
reg = <0xff280000 0x100>;
|
||||
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
|
||||
clock-names = "tsadc", "apb_pclk";
|
||||
resets = <&cru SRST_TSADC>;
|
||||
reset-names = "tsadc-apb";
|
||||
pinctrl-names = "init", "default", "sleep";
|
||||
pinctrl-0 = <&otp_gpio>;
|
||||
pinctrl-1 = <&otp_out>;
|
||||
pinctrl-2 = <&otp_gpio>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
rockchip,hw-tshut-temp = <95000>;
|
||||
rockchip,hw-tshut-mode = <0>;
|
||||
rockchip,hw-tshut-polarity = <0>;
|
||||
};
|
||||
|
||||
Example: referring to thermal sensors:
|
||||
thermal-zones {
|
||||
cpu_thermal: cpu_thermal {
|
||||
polling-delay-passive = <1000>; /* milliseconds */
|
||||
polling-delay = <5000>; /* milliseconds */
|
||||
|
||||
/* sensor ID */
|
||||
thermal-sensors = <&tsadc 1>;
|
||||
|
||||
trips {
|
||||
cpu_alert0: cpu_alert {
|
||||
temperature = <70000>; /* millicelsius */
|
||||
hysteresis = <2000>; /* millicelsius */
|
||||
type = "passive";
|
||||
};
|
||||
cpu_crit: cpu_crit {
|
||||
temperature = <90000>; /* millicelsius */
|
||||
hysteresis = <2000>; /* millicelsius */
|
||||
type = "critical";
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
map0 {
|
||||
trip = <&cpu_alert0>;
|
||||
cooling-device =
|
||||
<&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,96 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/thermal/rockchip-thermal.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Temperature Sensor ADC (TSADC) on Rockchip SoCs
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,px30-tsadc # PX30 SoCs
|
||||
- rockchip,rv1108-tsadc # RV1108 SoCs
|
||||
- rockchip,rk3228-tsadc # RK3228 SoCs
|
||||
- rockchip,rk3288-tsadc # RK3288 SoCs
|
||||
- rockchip,rk3328-tsadc # RK3328 SoCs
|
||||
- rockchip,rk3368-tsadc # RK3368 SoCs
|
||||
- rockchip,rk3399-tsadc # RK3399 SoCs
|
||||
- rockchip,rk3568-tsadc # RK3568 SoCs
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: tsadc
|
||||
- const: apb_pclk
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: tsadc-apb
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 1
|
||||
|
||||
rockchip,grf:
|
||||
description: The phandle of the syscon node for the general register file.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
rockchip,hw-tshut-temp:
|
||||
description: The hardware-controlled shutdown temperature value.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
rockchip,hw-tshut-mode:
|
||||
description: The hardware-controlled shutdown mode 0:CRU 1:GPIO.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
|
||||
rockchip,hw-tshut-polarity:
|
||||
description: The hardware-controlled active polarity 0:LOW 1:HIGH.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
- "#thermal-sensor-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/rk3288-cru.h>
|
||||
|
||||
tsadc: tsadc@ff280000 {
|
||||
compatible = "rockchip,rk3288-tsadc";
|
||||
reg = <0xff280000 0x100>;
|
||||
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
|
||||
clock-names = "tsadc", "apb_pclk";
|
||||
resets = <&cru SRST_TSADC>;
|
||||
reset-names = "tsadc-apb";
|
||||
#thermal-sensor-cells = <1>;
|
||||
rockchip,hw-tshut-temp = <95000>;
|
||||
rockchip,hw-tshut-mode = <0>;
|
||||
rockchip,hw-tshut-polarity = <0>;
|
||||
};
|
@ -458,7 +458,7 @@ struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df)
|
||||
EXPORT_SYMBOL_GPL(devfreq_cooling_register);
|
||||
|
||||
/**
|
||||
* devfreq_cooling_em_register_power() - Register devfreq cooling device with
|
||||
* devfreq_cooling_em_register() - Register devfreq cooling device with
|
||||
* power information and automatically register Energy Model (EM)
|
||||
* @df: Pointer to devfreq device.
|
||||
* @dfc_power: Pointer to devfreq_cooling_power.
|
||||
|
@ -93,6 +93,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
|
||||
for_each_available_child_of_node(np, child) {
|
||||
sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
|
||||
if (!sensor) {
|
||||
of_node_put(child);
|
||||
of_node_put(sensor_np);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -104,6 +105,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get valid sensor resource id: %d\n",
|
||||
ret);
|
||||
of_node_put(child);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -114,6 +116,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(sensor->tzd)) {
|
||||
dev_err(&pdev->dev, "failed to register thermal zone\n");
|
||||
ret = PTR_ERR(sensor->tzd);
|
||||
of_node_put(child);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,9 @@ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += int3401_thermal.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci_legacy.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci.o
|
||||
obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o
|
||||
|
82
drivers/thermal/intel/int340x_thermal/int3401_thermal.c
Normal file
82
drivers/thermal/intel/int340x_thermal/int3401_thermal.c
Normal file
@ -0,0 +1,82 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* INT3401 processor thermal device
|
||||
* Copyright (c) 2020, Intel Corporation.
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#include "int340x_thermal_zone.h"
|
||||
#include "processor_thermal_device.h"
|
||||
|
||||
static const struct acpi_device_id int3401_device_ids[] = {
|
||||
{"INT3401", 0},
|
||||
{"", 0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, int3401_device_ids);
|
||||
|
||||
static int int3401_add(struct platform_device *pdev)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
int ret;
|
||||
|
||||
proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
|
||||
if (!proc_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = proc_thermal_add(&pdev->dev, proc_priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, proc_priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int int3401_remove(struct platform_device *pdev)
|
||||
{
|
||||
proc_thermal_remove(platform_get_drvdata(pdev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int int3401_thermal_resume(struct device *dev)
|
||||
{
|
||||
return proc_thermal_resume(dev);
|
||||
}
|
||||
#else
|
||||
#define int3401_thermal_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, NULL, int3401_thermal_resume);
|
||||
|
||||
static struct platform_driver int3401_driver = {
|
||||
.probe = int3401_add,
|
||||
.remove = int3401_remove,
|
||||
.driver = {
|
||||
.name = "int3401 thermal",
|
||||
.acpi_match_table = int3401_device_ids,
|
||||
.pm = &int3401_proc_thermal_pm,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init proc_thermal_init(void)
|
||||
{
|
||||
return platform_driver_register(&int3401_driver);
|
||||
}
|
||||
|
||||
static void __exit proc_thermal_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&int3401_driver);
|
||||
}
|
||||
|
||||
module_init(proc_thermal_init);
|
||||
module_exit(proc_thermal_exit);
|
||||
|
||||
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -3,34 +3,17 @@
|
||||
* processor_thermal_device.c
|
||||
* Copyright (c) 2014, Intel Corporation.
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include "int340x_thermal_zone.h"
|
||||
#include "processor_thermal_device.h"
|
||||
#include "../intel_soc_dts_iosf.h"
|
||||
|
||||
#define DRV_NAME "proc_thermal"
|
||||
|
||||
enum proc_thermal_emum_mode_type {
|
||||
PROC_THERMAL_NONE,
|
||||
PROC_THERMAL_PCI,
|
||||
PROC_THERMAL_PLATFORM_DEV
|
||||
};
|
||||
|
||||
/*
|
||||
* We can have only one type of enumeration, PCI or Platform,
|
||||
* not both. So we don't need instance specific data.
|
||||
*/
|
||||
static enum proc_thermal_emum_mode_type proc_thermal_emum_mode =
|
||||
PROC_THERMAL_NONE;
|
||||
|
||||
#define POWER_LIMIT_SHOW(index, suffix) \
|
||||
static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
@ -38,11 +21,6 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \
|
||||
{ \
|
||||
struct proc_thermal_device *proc_dev = dev_get_drvdata(dev); \
|
||||
\
|
||||
if (proc_thermal_emum_mode == PROC_THERMAL_NONE) { \
|
||||
dev_warn(dev, "Attempted to get power limit before device was initialized!\n"); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
return sprintf(buf, "%lu\n",\
|
||||
(unsigned long)proc_dev->power_limits[index].suffix * 1000); \
|
||||
}
|
||||
@ -100,24 +78,27 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val = (val >> 24) & 0xff;
|
||||
val = (val >> 24) & 0x3f;
|
||||
return sprintf(buf, "%d\n", (int)val);
|
||||
}
|
||||
|
||||
static int tcc_offset_update(int tcc)
|
||||
static int tcc_offset_update(unsigned int tcc)
|
||||
{
|
||||
u64 val;
|
||||
int err;
|
||||
|
||||
if (!tcc)
|
||||
if (tcc > 63)
|
||||
return -EINVAL;
|
||||
|
||||
err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val &= ~GENMASK_ULL(31, 24);
|
||||
val |= (tcc & 0xff) << 24;
|
||||
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)
|
||||
@ -126,14 +107,15 @@ static int tcc_offset_update(int tcc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcc_offset_save;
|
||||
static unsigned int tcc_offset_save;
|
||||
|
||||
static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned int tcc;
|
||||
u64 val;
|
||||
int tcc, err;
|
||||
int err;
|
||||
|
||||
err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
|
||||
if (err)
|
||||
@ -142,7 +124,7 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
|
||||
if (!(val & BIT(30)))
|
||||
return -EACCES;
|
||||
|
||||
if (kstrtoint(buf, 0, &tcc))
|
||||
if (kstrtouint(buf, 0, &tcc))
|
||||
return -EINVAL;
|
||||
|
||||
err = tcc_offset_update(tcc);
|
||||
@ -291,11 +273,8 @@ static void proc_thermal_notify(acpi_handle handle, u32 event, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int proc_thermal_add(struct device *dev,
|
||||
struct proc_thermal_device **priv)
|
||||
int proc_thermal_add(struct device *dev, struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct acpi_device *adev;
|
||||
acpi_status status;
|
||||
unsigned long long tmp;
|
||||
@ -306,13 +285,8 @@ static int proc_thermal_add(struct device *dev,
|
||||
if (!adev)
|
||||
return -ENODEV;
|
||||
|
||||
proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL);
|
||||
if (!proc_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
proc_priv->dev = dev;
|
||||
proc_priv->adev = adev;
|
||||
*priv = proc_priv;
|
||||
|
||||
ret = proc_thermal_read_ppcc(proc_priv);
|
||||
if (ret)
|
||||
@ -338,15 +312,29 @@ static int proc_thermal_add(struct device *dev,
|
||||
if (ret)
|
||||
goto remove_zone;
|
||||
|
||||
ret = sysfs_create_file(&dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr);
|
||||
if (ret)
|
||||
goto remove_notify;
|
||||
|
||||
ret = sysfs_create_group(&dev->kobj, &power_limit_attribute_group);
|
||||
if (ret) {
|
||||
sysfs_remove_file(&dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr);
|
||||
goto remove_notify;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
remove_notify:
|
||||
acpi_remove_notify_handler(adev->handle,
|
||||
ACPI_DEVICE_NOTIFY, proc_thermal_notify);
|
||||
remove_zone:
|
||||
int340x_thermal_zone_remove(proc_priv->int340x_zone);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(proc_thermal_add);
|
||||
|
||||
static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
|
||||
void proc_thermal_remove(struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
acpi_remove_notify_handler(proc_priv->adev->handle,
|
||||
ACPI_DEVICE_NOTIFY, proc_thermal_notify);
|
||||
@ -355,60 +343,24 @@ static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
|
||||
sysfs_remove_group(&proc_priv->dev->kobj,
|
||||
&power_limit_attribute_group);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(proc_thermal_remove);
|
||||
|
||||
static int int3401_add(struct platform_device *pdev)
|
||||
int proc_thermal_resume(struct device *dev)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
int ret;
|
||||
struct proc_thermal_device *proc_dev;
|
||||
|
||||
if (proc_thermal_emum_mode == PROC_THERMAL_PCI) {
|
||||
dev_err(&pdev->dev, "error: enumerated as PCI dev\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
proc_dev = dev_get_drvdata(dev);
|
||||
proc_thermal_read_ppcc(proc_dev);
|
||||
|
||||
ret = proc_thermal_add(&pdev->dev, &proc_priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, proc_priv);
|
||||
proc_thermal_emum_mode = PROC_THERMAL_PLATFORM_DEV;
|
||||
|
||||
dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PLATFORM_DEV\n");
|
||||
|
||||
ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group);
|
||||
if (ret)
|
||||
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int int3401_remove(struct platform_device *pdev)
|
||||
{
|
||||
proc_thermal_remove(platform_get_drvdata(pdev));
|
||||
tcc_offset_update(tcc_offset_save);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct pci_dev *pdev = devid;
|
||||
|
||||
proc_priv = pci_get_drvdata(pdev);
|
||||
|
||||
intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(proc_thermal_resume);
|
||||
|
||||
#define MCHBAR 0
|
||||
|
||||
static int proc_thermal_set_mmio_base(struct pci_dev *pdev,
|
||||
struct proc_thermal_device *proc_priv)
|
||||
static int proc_thermal_set_mmio_base(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -423,9 +375,9 @@ static int proc_thermal_set_mmio_base(struct pci_dev *pdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int proc_thermal_mmio_add(struct pci_dev *pdev,
|
||||
struct proc_thermal_device *proc_priv,
|
||||
kernel_ulong_t feature_mask)
|
||||
int proc_thermal_mmio_add(struct pci_dev *pdev,
|
||||
struct proc_thermal_device *proc_priv,
|
||||
kernel_ulong_t feature_mask)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -471,11 +423,10 @@ err_rem_rapl:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(proc_thermal_mmio_add);
|
||||
|
||||
static void proc_thermal_mmio_remove(struct pci_dev *pdev)
|
||||
void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
|
||||
|
||||
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
|
||||
proc_thermal_rapl_remove();
|
||||
|
||||
@ -486,181 +437,7 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev)
|
||||
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX)
|
||||
proc_thermal_mbox_remove(pdev);
|
||||
}
|
||||
|
||||
static int proc_thermal_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
int ret;
|
||||
|
||||
if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) {
|
||||
dev_err(&pdev->dev, "error: enumerated as platform dev\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "error: could not enable device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = proc_thermal_add(&pdev->dev, &proc_priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_set_drvdata(pdev, proc_priv);
|
||||
proc_thermal_emum_mode = PROC_THERMAL_PCI;
|
||||
|
||||
if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) {
|
||||
/*
|
||||
* Enumerate additional DTS sensors available via IOSF.
|
||||
* But we are not treating as a failure condition, if
|
||||
* there are no aux DTSs enabled or fails. This driver
|
||||
* already exposes sensors, which can be accessed via
|
||||
* ACPI/MSR. So we don't want to fail for auxiliary DTSs.
|
||||
*/
|
||||
proc_priv->soc_dts = intel_soc_dts_iosf_init(
|
||||
INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0);
|
||||
|
||||
if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) {
|
||||
ret = pci_enable_msi(pdev);
|
||||
if (!ret) {
|
||||
ret = request_threaded_irq(pdev->irq, NULL,
|
||||
proc_thermal_pci_msi_irq,
|
||||
IRQF_ONESHOT, "proc_thermal",
|
||||
pdev);
|
||||
if (ret) {
|
||||
intel_soc_dts_iosf_exit(
|
||||
proc_priv->soc_dts);
|
||||
pci_disable_msi(pdev);
|
||||
proc_priv->soc_dts = NULL;
|
||||
}
|
||||
}
|
||||
} else
|
||||
dev_err(&pdev->dev, "No auxiliary DTSs enabled\n");
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PCI\n");
|
||||
|
||||
ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group);
|
||||
if (ret) {
|
||||
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
|
||||
if (ret) {
|
||||
proc_thermal_remove(proc_priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void proc_thermal_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
|
||||
|
||||
if (proc_priv->soc_dts) {
|
||||
intel_soc_dts_iosf_exit(proc_priv->soc_dts);
|
||||
if (pdev->irq) {
|
||||
free_irq(pdev->irq, pdev);
|
||||
pci_disable_msi(pdev);
|
||||
}
|
||||
}
|
||||
|
||||
proc_thermal_mmio_remove(pdev);
|
||||
proc_thermal_remove(proc_priv);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int proc_thermal_resume(struct device *dev)
|
||||
{
|
||||
struct proc_thermal_device *proc_dev;
|
||||
|
||||
proc_dev = dev_get_drvdata(dev);
|
||||
proc_thermal_read_ppcc(proc_dev);
|
||||
|
||||
tcc_offset_update(tcc_offset_save);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define proc_thermal_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
|
||||
|
||||
static const struct pci_device_id proc_thermal_pci_ids[] = {
|
||||
{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
|
||||
{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
|
||||
{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) },
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
|
||||
|
||||
static struct pci_driver proc_thermal_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.probe = proc_thermal_pci_probe,
|
||||
.remove = proc_thermal_pci_remove,
|
||||
.id_table = proc_thermal_pci_ids,
|
||||
.driver.pm = &proc_thermal_pm,
|
||||
};
|
||||
|
||||
static const struct acpi_device_id int3401_device_ids[] = {
|
||||
{"INT3401", 0},
|
||||
{"", 0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, int3401_device_ids);
|
||||
|
||||
static struct platform_driver int3401_driver = {
|
||||
.probe = int3401_add,
|
||||
.remove = int3401_remove,
|
||||
.driver = {
|
||||
.name = "int3401 thermal",
|
||||
.acpi_match_table = int3401_device_ids,
|
||||
.pm = &proc_thermal_pm,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init proc_thermal_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&int3401_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_register_driver(&proc_thermal_pci_driver);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit proc_thermal_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&int3401_driver);
|
||||
pci_unregister_driver(&proc_thermal_pci_driver);
|
||||
}
|
||||
|
||||
module_init(proc_thermal_init);
|
||||
module_exit(proc_thermal_exit);
|
||||
EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove);
|
||||
|
||||
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
|
||||
|
@ -44,6 +44,7 @@ struct proc_thermal_device {
|
||||
struct intel_soc_dts_sensors *soc_dts;
|
||||
u32 mmio_feature_mask;
|
||||
void __iomem *mmio_base;
|
||||
void *priv_data;
|
||||
};
|
||||
|
||||
struct rapl_mmio_regs {
|
||||
@ -79,4 +80,12 @@ void proc_thermal_rfim_remove(struct pci_dev *pdev);
|
||||
int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
|
||||
void proc_thermal_mbox_remove(struct pci_dev *pdev);
|
||||
|
||||
int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp);
|
||||
int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv);
|
||||
void proc_thermal_remove(struct proc_thermal_device *proc_priv);
|
||||
int proc_thermal_resume(struct device *dev);
|
||||
int proc_thermal_mmio_add(struct pci_dev *pdev,
|
||||
struct proc_thermal_device *proc_priv,
|
||||
kernel_ulong_t feature_mask);
|
||||
void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
|
||||
#endif
|
||||
|
@ -0,0 +1,373 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Processor thermal device for newer processors
|
||||
* Copyright (c) 2020, Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#include "int340x_thermal_zone.h"
|
||||
#include "processor_thermal_device.h"
|
||||
|
||||
#define DRV_NAME "proc_thermal_pci"
|
||||
|
||||
struct proc_thermal_pci {
|
||||
struct pci_dev *pdev;
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct thermal_zone_device *tzone;
|
||||
struct delayed_work work;
|
||||
int stored_thres;
|
||||
int no_legacy;
|
||||
};
|
||||
|
||||
enum proc_thermal_mmio_type {
|
||||
PROC_THERMAL_MMIO_TJMAX,
|
||||
PROC_THERMAL_MMIO_PP0_TEMP,
|
||||
PROC_THERMAL_MMIO_PP1_TEMP,
|
||||
PROC_THERMAL_MMIO_PKG_TEMP,
|
||||
PROC_THERMAL_MMIO_THRES_0,
|
||||
PROC_THERMAL_MMIO_THRES_1,
|
||||
PROC_THERMAL_MMIO_INT_ENABLE_0,
|
||||
PROC_THERMAL_MMIO_INT_ENABLE_1,
|
||||
PROC_THERMAL_MMIO_INT_STATUS_0,
|
||||
PROC_THERMAL_MMIO_INT_STATUS_1,
|
||||
PROC_THERMAL_MMIO_MAX
|
||||
};
|
||||
|
||||
struct proc_thermal_mmio_info {
|
||||
enum proc_thermal_mmio_type mmio_type;
|
||||
u64 mmio_addr;
|
||||
u64 shift;
|
||||
u64 mask;
|
||||
};
|
||||
|
||||
static struct proc_thermal_mmio_info proc_thermal_mmio_info[] = {
|
||||
{ PROC_THERMAL_MMIO_TJMAX, 0x599c, 16, 0xff },
|
||||
{ PROC_THERMAL_MMIO_PP0_TEMP, 0x597c, 0, 0xff },
|
||||
{ PROC_THERMAL_MMIO_PP1_TEMP, 0x5980, 0, 0xff },
|
||||
{ PROC_THERMAL_MMIO_PKG_TEMP, 0x5978, 0, 0xff },
|
||||
{ PROC_THERMAL_MMIO_THRES_0, 0x5820, 8, 0x7F },
|
||||
{ PROC_THERMAL_MMIO_THRES_1, 0x5820, 16, 0x7F },
|
||||
{ PROC_THERMAL_MMIO_INT_ENABLE_0, 0x5820, 15, 0x01 },
|
||||
{ PROC_THERMAL_MMIO_INT_ENABLE_1, 0x5820, 23, 0x01 },
|
||||
{ PROC_THERMAL_MMIO_INT_STATUS_0, 0x7200, 6, 0x01 },
|
||||
{ PROC_THERMAL_MMIO_INT_STATUS_1, 0x7200, 8, 0x01 },
|
||||
};
|
||||
|
||||
#define B0D4_THERMAL_NOTIFY_DELAY 1000
|
||||
static int notify_delay_ms = B0D4_THERMAL_NOTIFY_DELAY;
|
||||
|
||||
static void proc_thermal_mmio_read(struct proc_thermal_pci *pci_info,
|
||||
enum proc_thermal_mmio_type type,
|
||||
u32 *value)
|
||||
{
|
||||
*value = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base +
|
||||
proc_thermal_mmio_info[type].mmio_addr));
|
||||
*value >>= proc_thermal_mmio_info[type].shift;
|
||||
*value &= proc_thermal_mmio_info[type].mask;
|
||||
}
|
||||
|
||||
static void proc_thermal_mmio_write(struct proc_thermal_pci *pci_info,
|
||||
enum proc_thermal_mmio_type type,
|
||||
u32 value)
|
||||
{
|
||||
u32 current_val;
|
||||
u32 mask;
|
||||
|
||||
current_val = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base +
|
||||
proc_thermal_mmio_info[type].mmio_addr));
|
||||
mask = proc_thermal_mmio_info[type].mask << proc_thermal_mmio_info[type].shift;
|
||||
current_val &= ~mask;
|
||||
|
||||
value &= proc_thermal_mmio_info[type].mask;
|
||||
value <<= proc_thermal_mmio_info[type].shift;
|
||||
|
||||
current_val |= value;
|
||||
iowrite32(current_val, ((u8 __iomem *)pci_info->proc_priv->mmio_base +
|
||||
proc_thermal_mmio_info[type].mmio_addr));
|
||||
}
|
||||
|
||||
/*
|
||||
* To avoid sending two many messages to user space, we have 1 second delay.
|
||||
* On interrupt we are disabling interrupt and enabling after 1 second.
|
||||
* This workload function is delayed by 1 second.
|
||||
*/
|
||||
static void proc_thermal_threshold_work_fn(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
struct proc_thermal_pci *pci_info = container_of(delayed_work,
|
||||
struct proc_thermal_pci, work);
|
||||
struct thermal_zone_device *tzone = pci_info->tzone;
|
||||
|
||||
if (tzone)
|
||||
thermal_zone_device_update(tzone, THERMAL_TRIP_VIOLATED);
|
||||
|
||||
/* Enable interrupt flag */
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
|
||||
}
|
||||
|
||||
static void pkg_thermal_schedule_work(struct delayed_work *work)
|
||||
{
|
||||
unsigned long ms = msecs_to_jiffies(notify_delay_ms);
|
||||
|
||||
schedule_delayed_work(work, ms);
|
||||
}
|
||||
|
||||
static irqreturn_t proc_thermal_irq_handler(int irq, void *devid)
|
||||
{
|
||||
struct proc_thermal_pci *pci_info = devid;
|
||||
u32 status;
|
||||
|
||||
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
|
||||
|
||||
/* Disable enable interrupt flag */
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
|
||||
pci_write_config_byte(pci_info->pdev, 0xdc, 0x01);
|
||||
|
||||
pkg_thermal_schedule_work(&pci_info->work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
|
||||
{
|
||||
struct proc_thermal_pci *pci_info = tzd->devdata;
|
||||
u32 _temp;
|
||||
|
||||
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_PKG_TEMP, &_temp);
|
||||
*temp = (unsigned long)_temp * 1000;
|
||||
|
||||
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;
|
||||
int tjmax, _temp;
|
||||
|
||||
if (temp <= 0) {
|
||||
cancel_delayed_work_sync(&pci_info->work);
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0);
|
||||
thermal_zone_device_disable(tzd);
|
||||
pci_info->stored_thres = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax);
|
||||
_temp = tjmax - (temp / 1000);
|
||||
if (_temp < 0)
|
||||
return -EINVAL;
|
||||
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, _temp);
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
|
||||
|
||||
thermal_zone_device_enable(tzd);
|
||||
pci_info->stored_thres = temp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
static struct thermal_zone_params tzone_params = {
|
||||
.governor_name = "user_space",
|
||||
.no_hwmon = true,
|
||||
};
|
||||
|
||||
static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct proc_thermal_pci *pci_info;
|
||||
int irq_flag = 0, irq, ret;
|
||||
|
||||
proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
|
||||
if (!proc_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL);
|
||||
if (!pci_info)
|
||||
return -ENOMEM;
|
||||
|
||||
pci_info->pdev = pdev;
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "error: could not enable device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
INIT_DELAYED_WORK(&pci_info->work, proc_thermal_threshold_work_fn);
|
||||
|
||||
ret = proc_thermal_add(&pdev->dev, proc_priv);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "error: proc_thermal_add, will continue\n");
|
||||
pci_info->no_legacy = 1;
|
||||
}
|
||||
|
||||
proc_priv->priv_data = pci_info;
|
||||
pci_info->proc_priv = proc_priv;
|
||||
pci_set_drvdata(pdev, proc_priv);
|
||||
|
||||
ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
|
||||
if (ret)
|
||||
goto err_ret_thermal;
|
||||
|
||||
pci_info->tzone = thermal_zone_device_register("TCPU_PCI", 1, 1, pci_info,
|
||||
&tzone_ops,
|
||||
&tzone_params, 0, 0);
|
||||
if (IS_ERR(pci_info->tzone)) {
|
||||
ret = PTR_ERR(pci_info->tzone);
|
||||
goto err_ret_mmio;
|
||||
}
|
||||
|
||||
/* request and enable interrupt */
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to allocate vectors!\n");
|
||||
goto err_ret_tzone;
|
||||
}
|
||||
if (!pdev->msi_enabled && !pdev->msix_enabled)
|
||||
irq_flag = IRQF_SHARED;
|
||||
|
||||
irq = pci_irq_vector(pdev, 0);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq,
|
||||
proc_thermal_irq_handler, NULL,
|
||||
irq_flag, KBUILD_MODNAME, pci_info);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
|
||||
goto err_free_vectors;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_vectors:
|
||||
pci_free_irq_vectors(pdev);
|
||||
err_ret_tzone:
|
||||
thermal_zone_device_unregister(pci_info->tzone);
|
||||
err_ret_mmio:
|
||||
proc_thermal_mmio_remove(pdev, proc_priv);
|
||||
err_ret_thermal:
|
||||
if (!pci_info->no_legacy)
|
||||
proc_thermal_remove(proc_priv);
|
||||
pci_disable_device(pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void proc_thermal_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
|
||||
struct proc_thermal_pci *pci_info = proc_priv->priv_data;
|
||||
|
||||
cancel_delayed_work_sync(&pci_info->work);
|
||||
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0);
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
|
||||
|
||||
devm_free_irq(&pdev->dev, pdev->irq, pci_info);
|
||||
pci_free_irq_vectors(pdev);
|
||||
|
||||
thermal_zone_device_unregister(pci_info->tzone);
|
||||
proc_thermal_mmio_remove(pdev, pci_info->proc_priv);
|
||||
if (!pci_info->no_legacy)
|
||||
proc_thermal_remove(proc_priv);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int proc_thermal_pci_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct proc_thermal_pci *pci_info;
|
||||
|
||||
proc_priv = pci_get_drvdata(pdev);
|
||||
pci_info = proc_priv->priv_data;
|
||||
|
||||
if (pci_info->stored_thres) {
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0,
|
||||
pci_info->stored_thres / 1000);
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
|
||||
}
|
||||
|
||||
if (!pci_info->no_legacy)
|
||||
return proc_thermal_resume(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define proc_thermal_pci_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume);
|
||||
|
||||
static const struct pci_device_id proc_thermal_pci_ids[] = {
|
||||
{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
|
||||
|
||||
static struct pci_driver proc_thermal_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.probe = proc_thermal_pci_probe,
|
||||
.remove = proc_thermal_pci_remove,
|
||||
.id_table = proc_thermal_pci_ids,
|
||||
.driver.pm = &proc_thermal_pci_pm,
|
||||
};
|
||||
|
||||
static int __init proc_thermal_init(void)
|
||||
{
|
||||
return pci_register_driver(&proc_thermal_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit proc_thermal_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&proc_thermal_pci_driver);
|
||||
}
|
||||
|
||||
module_init(proc_thermal_init);
|
||||
module_exit(proc_thermal_exit);
|
||||
|
||||
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -0,0 +1,163 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* B0D4 processor thermal device
|
||||
* Copyright (c) 2020, Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#include "int340x_thermal_zone.h"
|
||||
#include "processor_thermal_device.h"
|
||||
#include "../intel_soc_dts_iosf.h"
|
||||
|
||||
#define DRV_NAME "proc_thermal"
|
||||
|
||||
static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct pci_dev *pdev = devid;
|
||||
|
||||
proc_priv = pci_get_drvdata(pdev);
|
||||
|
||||
intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int proc_thermal_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
int ret;
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "error: could not enable device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
|
||||
if (!proc_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = proc_thermal_add(&pdev->dev, proc_priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_set_drvdata(pdev, proc_priv);
|
||||
|
||||
if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) {
|
||||
/*
|
||||
* Enumerate additional DTS sensors available via IOSF.
|
||||
* But we are not treating as a failure condition, if
|
||||
* there are no aux DTSs enabled or fails. This driver
|
||||
* already exposes sensors, which can be accessed via
|
||||
* ACPI/MSR. So we don't want to fail for auxiliary DTSs.
|
||||
*/
|
||||
proc_priv->soc_dts = intel_soc_dts_iosf_init(
|
||||
INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0);
|
||||
|
||||
if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) {
|
||||
ret = pci_enable_msi(pdev);
|
||||
if (!ret) {
|
||||
ret = request_threaded_irq(pdev->irq, NULL,
|
||||
proc_thermal_pci_msi_irq,
|
||||
IRQF_ONESHOT, "proc_thermal",
|
||||
pdev);
|
||||
if (ret) {
|
||||
intel_soc_dts_iosf_exit(
|
||||
proc_priv->soc_dts);
|
||||
pci_disable_msi(pdev);
|
||||
proc_priv->soc_dts = NULL;
|
||||
}
|
||||
}
|
||||
} else
|
||||
dev_err(&pdev->dev, "No auxiliary DTSs enabled\n");
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
|
||||
if (ret) {
|
||||
proc_thermal_remove(proc_priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void proc_thermal_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
|
||||
|
||||
if (proc_priv->soc_dts) {
|
||||
intel_soc_dts_iosf_exit(proc_priv->soc_dts);
|
||||
if (pdev->irq) {
|
||||
free_irq(pdev->irq, pdev);
|
||||
pci_disable_msi(pdev);
|
||||
}
|
||||
}
|
||||
|
||||
proc_thermal_mmio_remove(pdev, proc_priv);
|
||||
proc_thermal_remove(proc_priv);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int proc_thermal_pci_resume(struct device *dev)
|
||||
{
|
||||
return proc_thermal_resume(dev);
|
||||
}
|
||||
#else
|
||||
#define proc_thermal_pci_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume);
|
||||
|
||||
static const struct pci_device_id proc_thermal_pci_ids[] = {
|
||||
{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
|
||||
{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
|
||||
{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) },
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
|
||||
|
||||
static struct pci_driver proc_thermal_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.probe = proc_thermal_pci_probe,
|
||||
.remove = proc_thermal_pci_remove,
|
||||
.id_table = proc_thermal_pci_ids,
|
||||
.driver.pm = &proc_thermal_pci_pm,
|
||||
};
|
||||
|
||||
static int __init proc_thermal_init(void)
|
||||
{
|
||||
return pci_register_driver(&proc_thermal_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit proc_thermal_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&proc_thermal_pci_driver);
|
||||
}
|
||||
|
||||
module_init(proc_thermal_init);
|
||||
module_exit(proc_thermal_exit);
|
||||
|
||||
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -23,7 +23,7 @@
|
||||
|
||||
static DEFINE_MUTEX(mbox_lock);
|
||||
|
||||
static int send_mbox_cmd(struct pci_dev *pdev, u8 cmd_id, u32 cmd_data, u8 *cmd_resp)
|
||||
static int send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
u32 retries, data;
|
||||
@ -82,6 +82,12 @@ unlock_mbox:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp)
|
||||
{
|
||||
return send_mbox_cmd(pdev, cmd_id, cmd_data, cmd_resp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(processor_thermal_send_mbox_cmd);
|
||||
|
||||
/* List of workload types */
|
||||
static const char * const workload_types[] = {
|
||||
"none",
|
||||
@ -147,7 +153,7 @@ static ssize_t workload_type_show(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
u8 cmd_resp;
|
||||
u32 cmd_resp;
|
||||
int ret;
|
||||
|
||||
ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
|
||||
@ -181,7 +187,7 @@ static bool workload_req_created;
|
||||
|
||||
int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
u8 cmd_resp;
|
||||
u32 cmd_resp;
|
||||
int ret;
|
||||
|
||||
/* Check if there is a mailbox support, if fails return success */
|
||||
|
@ -190,6 +190,59 @@ static DEVICE_ATTR_RO(ddr_data_rate_point_2);
|
||||
static DEVICE_ATTR_RO(ddr_data_rate_point_3);
|
||||
static DEVICE_ATTR_RW(rfi_disable);
|
||||
|
||||
static ssize_t rfi_restriction_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
u16 cmd_id = 0x0008;
|
||||
u32 cmd_resp;
|
||||
u32 input;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou32(buf, 10, &input);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, input, &cmd_resp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t rfi_restriction_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
u16 cmd_id = 0x0007;
|
||||
u32 cmd_resp;
|
||||
int ret;
|
||||
|
||||
ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%u\n", cmd_resp);
|
||||
}
|
||||
|
||||
static ssize_t ddr_data_rate_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
u16 cmd_id = 0x0107;
|
||||
u32 cmd_resp;
|
||||
int ret;
|
||||
|
||||
ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%u\n", cmd_resp);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(rfi_restriction);
|
||||
static DEVICE_ATTR_RO(ddr_data_rate);
|
||||
|
||||
static struct attribute *dvfs_attrs[] = {
|
||||
&dev_attr_rfi_restriction_run_busy.attr,
|
||||
&dev_attr_rfi_restriction_err_code.attr,
|
||||
@ -199,6 +252,8 @@ static struct attribute *dvfs_attrs[] = {
|
||||
&dev_attr_ddr_data_rate_point_2.attr,
|
||||
&dev_attr_ddr_data_rate_point_3.attr,
|
||||
&dev_attr_rfi_disable.attr,
|
||||
&dev_attr_ddr_data_rate.attr,
|
||||
&dev_attr_rfi_restriction.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -350,13 +350,14 @@ int intel_soc_dts_iosf_add_read_only_critical_trip(
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
|
||||
for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) {
|
||||
if (!(sensors->soc_dts[i].trip_mask & BIT(j))) {
|
||||
return update_trip_temp(&sensors->soc_dts[i], j,
|
||||
sensors->tj_max - critical_offset,
|
||||
THERMAL_TRIP_CRITICAL);
|
||||
}
|
||||
}
|
||||
struct intel_soc_dts_sensor_entry *entry = &sensors->soc_dts[i];
|
||||
int temp = sensors->tj_max - critical_offset;
|
||||
unsigned long count = entry->trip_count;
|
||||
unsigned long mask = entry->trip_mask;
|
||||
|
||||
j = find_first_zero_bit(&mask, count);
|
||||
if (j < count)
|
||||
return update_trip_temp(entry, j, temp, THERMAL_TRIP_CRITICAL);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <linux/reset.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "thermal_hwmon.h"
|
||||
|
||||
/* AUXADC Registers */
|
||||
#define AUXADC_CON1_SET_V 0x008
|
||||
#define AUXADC_CON1_CLR_V 0x00c
|
||||
@ -1087,6 +1089,10 @@ static int mtk_thermal_probe(struct platform_device *pdev)
|
||||
goto err_disable_clk_peri_therm;
|
||||
}
|
||||
|
||||
ret = devm_thermal_add_hwmon_sysfs(tzdev);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_clk_peri_therm:
|
||||
|
@ -143,7 +143,7 @@ static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc,
|
||||
* Division is not scaled in BSP and if scaled it might overflow
|
||||
* the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
|
||||
*/
|
||||
tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * 157)
|
||||
tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * (ths_tj_1 - TJ_3))
|
||||
/ (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3);
|
||||
|
||||
tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]),
|
||||
@ -307,7 +307,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_gen3_thermal_priv *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
const int *rcar_gen3_ths_tj_1 = of_device_get_match_data(dev);
|
||||
const int *ths_tj_1 = of_device_get_match_data(dev);
|
||||
struct resource *res;
|
||||
struct thermal_zone_device *zone;
|
||||
int ret, i;
|
||||
@ -352,8 +352,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
||||
priv->tscs[i] = tsc;
|
||||
|
||||
priv->thermal_init(tsc);
|
||||
rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i],
|
||||
*rcar_gen3_ths_tj_1);
|
||||
rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1);
|
||||
|
||||
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
|
||||
&rcar_gen3_tz_of_ops);
|
||||
|
@ -211,7 +211,11 @@ struct rockchip_thermal_data {
|
||||
#define TSADCV3_AUTO_PERIOD_TIME 1875 /* 2.5ms */
|
||||
#define TSADCV3_AUTO_PERIOD_HT_TIME 1875 /* 2.5ms */
|
||||
|
||||
#define TSADCV5_AUTO_PERIOD_TIME 1622 /* 2.5ms */
|
||||
#define TSADCV5_AUTO_PERIOD_HT_TIME 1622 /* 2.5ms */
|
||||
|
||||
#define TSADCV2_USER_INTER_PD_SOC 0x340 /* 13 clocks */
|
||||
#define TSADCV5_USER_INTER_PD_SOC 0xfc0 /* 97us, at least 90us */
|
||||
|
||||
#define GRF_SARADC_TESTBIT 0x0e644
|
||||
#define GRF_TSADC_TESTBIT_L 0x0e648
|
||||
@ -219,6 +223,12 @@ struct rockchip_thermal_data {
|
||||
|
||||
#define PX30_GRF_SOC_CON2 0x0408
|
||||
|
||||
#define RK3568_GRF_TSADC_CON 0x0600
|
||||
#define RK3568_GRF_TSADC_ANA_REG0 (0x10001 << 0)
|
||||
#define RK3568_GRF_TSADC_ANA_REG1 (0x10001 << 1)
|
||||
#define RK3568_GRF_TSADC_ANA_REG2 (0x10001 << 2)
|
||||
#define RK3568_GRF_TSADC_TSEN (0x10001 << 8)
|
||||
|
||||
#define GRF_SARADC_TESTBIT_ON (0x10001 << 2)
|
||||
#define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2)
|
||||
#define GRF_TSADC_VCM_EN_L (0x10001 << 7)
|
||||
@ -474,6 +484,45 @@ static const struct tsadc_table rk3399_code_table[] = {
|
||||
{TSADCV3_DATA_MASK, 125000},
|
||||
};
|
||||
|
||||
static const struct tsadc_table rk3568_code_table[] = {
|
||||
{0, -40000},
|
||||
{1584, -40000},
|
||||
{1620, -35000},
|
||||
{1652, -30000},
|
||||
{1688, -25000},
|
||||
{1720, -20000},
|
||||
{1756, -15000},
|
||||
{1788, -10000},
|
||||
{1824, -5000},
|
||||
{1856, 0},
|
||||
{1892, 5000},
|
||||
{1924, 10000},
|
||||
{1956, 15000},
|
||||
{1992, 20000},
|
||||
{2024, 25000},
|
||||
{2060, 30000},
|
||||
{2092, 35000},
|
||||
{2128, 40000},
|
||||
{2160, 45000},
|
||||
{2196, 50000},
|
||||
{2228, 55000},
|
||||
{2264, 60000},
|
||||
{2300, 65000},
|
||||
{2332, 70000},
|
||||
{2368, 75000},
|
||||
{2400, 80000},
|
||||
{2436, 85000},
|
||||
{2468, 90000},
|
||||
{2500, 95000},
|
||||
{2536, 100000},
|
||||
{2572, 105000},
|
||||
{2604, 110000},
|
||||
{2636, 115000},
|
||||
{2672, 120000},
|
||||
{2704, 125000},
|
||||
{TSADCV2_DATA_MASK, 125000},
|
||||
};
|
||||
|
||||
static u32 rk_tsadcv2_temp_to_code(const struct chip_tsadc_table *table,
|
||||
int temp)
|
||||
{
|
||||
@ -701,6 +750,49 @@ static void rk_tsadcv4_initialize(struct regmap *grf, void __iomem *regs,
|
||||
regmap_write(grf, PX30_GRF_SOC_CON2, GRF_CON_TSADC_CH_INV);
|
||||
}
|
||||
|
||||
static void rk_tsadcv7_initialize(struct regmap *grf, void __iomem *regs,
|
||||
enum tshut_polarity tshut_polarity)
|
||||
{
|
||||
writel_relaxed(TSADCV5_USER_INTER_PD_SOC, regs + TSADCV2_USER_CON);
|
||||
writel_relaxed(TSADCV5_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
|
||||
writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT,
|
||||
regs + TSADCV2_HIGHT_INT_DEBOUNCE);
|
||||
writel_relaxed(TSADCV5_AUTO_PERIOD_HT_TIME,
|
||||
regs + TSADCV2_AUTO_PERIOD_HT);
|
||||
writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT,
|
||||
regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE);
|
||||
|
||||
if (tshut_polarity == TSHUT_HIGH_ACTIVE)
|
||||
writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH,
|
||||
regs + TSADCV2_AUTO_CON);
|
||||
else
|
||||
writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH,
|
||||
regs + TSADCV2_AUTO_CON);
|
||||
|
||||
/*
|
||||
* The general register file will is optional
|
||||
* and might not be available.
|
||||
*/
|
||||
if (!IS_ERR(grf)) {
|
||||
regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_TSEN);
|
||||
/*
|
||||
* RK3568 TRM, section 18.5. requires a delay no less
|
||||
* than 10us between the rising edge of tsadc_tsen_en
|
||||
* and the rising edge of tsadc_ana_reg_0/1/2.
|
||||
*/
|
||||
udelay(15);
|
||||
regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG0);
|
||||
regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG1);
|
||||
regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG2);
|
||||
|
||||
/*
|
||||
* RK3568 TRM, section 18.5. requires a delay no less
|
||||
* than 90us after the rising edge of tsadc_ana_reg_0/1/2.
|
||||
*/
|
||||
usleep_range(100, 200);
|
||||
}
|
||||
}
|
||||
|
||||
static void rk_tsadcv2_irq_ack(void __iomem *regs)
|
||||
{
|
||||
u32 val;
|
||||
@ -1027,6 +1119,31 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rockchip_tsadc_chip rk3568_tsadc_data = {
|
||||
.chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
|
||||
.chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */
|
||||
.chn_num = 2, /* two channels for tsadc */
|
||||
|
||||
.tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
|
||||
.tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
|
||||
.tshut_temp = 95000,
|
||||
|
||||
.initialize = rk_tsadcv7_initialize,
|
||||
.irq_ack = rk_tsadcv3_irq_ack,
|
||||
.control = rk_tsadcv3_control,
|
||||
.get_temp = rk_tsadcv2_get_temp,
|
||||
.set_alarm_temp = rk_tsadcv2_alarm_temp,
|
||||
.set_tshut_temp = rk_tsadcv2_tshut_temp,
|
||||
.set_tshut_mode = rk_tsadcv2_tshut_mode,
|
||||
|
||||
.table = {
|
||||
.id = rk3568_code_table,
|
||||
.length = ARRAY_SIZE(rk3568_code_table),
|
||||
.data_mask = TSADCV2_DATA_MASK,
|
||||
.mode = ADC_INCREMENT,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id of_rockchip_thermal_match[] = {
|
||||
{ .compatible = "rockchip,px30-tsadc",
|
||||
.data = (void *)&px30_tsadc_data,
|
||||
@ -1059,6 +1176,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = {
|
||||
.compatible = "rockchip,rk3399-tsadc",
|
||||
.data = (void *)&rk3399_tsadc_data,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3568-tsadc",
|
||||
.data = (void *)&rk3568_tsadc_data,
|
||||
},
|
||||
{ /* end */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
|
||||
|
@ -388,7 +388,7 @@ static int sprd_thm_probe(struct platform_device *pdev)
|
||||
sen = devm_kzalloc(&pdev->dev, sizeof(*sen), GFP_KERNEL);
|
||||
if (!sen) {
|
||||
ret = -ENOMEM;
|
||||
goto disable_clk;
|
||||
goto of_put;
|
||||
}
|
||||
|
||||
sen->data = thm;
|
||||
@ -397,13 +397,13 @@ static int sprd_thm_probe(struct platform_device *pdev)
|
||||
ret = of_property_read_u32(sen_child, "reg", &sen->id);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "get sensor reg failed");
|
||||
goto disable_clk;
|
||||
goto of_put;
|
||||
}
|
||||
|
||||
ret = sprd_thm_sensor_calibration(sen_child, thm, sen);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "efuse cal analysis failed");
|
||||
goto disable_clk;
|
||||
goto of_put;
|
||||
}
|
||||
|
||||
sprd_thm_sensor_init(thm, sen);
|
||||
@ -416,19 +416,20 @@ static int sprd_thm_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "register thermal zone failed %d\n",
|
||||
sen->id);
|
||||
ret = PTR_ERR(sen->tzd);
|
||||
goto disable_clk;
|
||||
goto of_put;
|
||||
}
|
||||
|
||||
thm->sensor[sen->id] = sen;
|
||||
}
|
||||
/* sen_child set to NULL at this point */
|
||||
|
||||
ret = sprd_thm_set_ready(thm);
|
||||
if (ret)
|
||||
goto disable_clk;
|
||||
goto of_put;
|
||||
|
||||
ret = sprd_thm_wait_temp_ready(thm);
|
||||
if (ret)
|
||||
goto disable_clk;
|
||||
goto of_put;
|
||||
|
||||
for (i = 0; i < thm->nr_sensors; i++)
|
||||
sprd_thm_toggle_sensor(thm->sensor[i], true);
|
||||
@ -436,6 +437,8 @@ static int sprd_thm_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, thm);
|
||||
return 0;
|
||||
|
||||
of_put:
|
||||
of_node_put(sen_child);
|
||||
disable_clk:
|
||||
clk_disable_unprepare(thm->clk);
|
||||
return ret;
|
||||
@ -532,6 +535,7 @@ static const struct of_device_id sprd_thermal_of_match[] = {
|
||||
{ .compatible = "sprd,ums512-thermal", .data = &ums512_data },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sprd_thermal_of_match);
|
||||
|
||||
static const struct dev_pm_ops sprd_thermal_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sprd_thm_suspend, sprd_thm_resume)
|
||||
|
@ -119,19 +119,10 @@ static int st_mmap_regmap_init(struct st_thermal_sensor *sensor)
|
||||
{
|
||||
struct device *dev = sensor->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "no memory resources defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
sensor->mmio_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(sensor->mmio_base)) {
|
||||
dev_err(dev, "failed to remap IO\n");
|
||||
sensor->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||
if (IS_ERR(sensor->mmio_base))
|
||||
return PTR_ERR(sensor->mmio_base);
|
||||
}
|
||||
|
||||
sensor->regmap = devm_regmap_init_mmio(dev, sensor->mmio_base,
|
||||
&st_416mpe_regmap_config);
|
||||
|
@ -1315,7 +1315,7 @@ free_tz:
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_device_register);
|
||||
|
||||
/**
|
||||
* thermal_device_unregister - removes the registered thermal zone device
|
||||
* thermal_zone_device_unregister - removes the registered thermal zone device
|
||||
* @tz: the thermal zone device to remove
|
||||
*/
|
||||
void thermal_zone_device_unregister(struct thermal_zone_device *tz)
|
||||
|
@ -559,6 +559,9 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
|
||||
if (!tz)
|
||||
return;
|
||||
|
||||
/* stop temperature polling */
|
||||
thermal_zone_device_disable(tzd);
|
||||
|
||||
mutex_lock(&tzd->lock);
|
||||
tzd->ops->get_temp = NULL;
|
||||
tzd->ops->get_trend = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user