--- /dev/null
+# 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>;
+ };
- qcom,msm8996-tsens
- qcom,msm8998-tsens
- qcom,sc7180-tsens
+ - qcom,sc7280-tsens
+ - qcom,sc8180x-tsens
- qcom,sdm845-tsens
- qcom,sm8150-tsens
- qcom,sm8250-tsens
+++ /dev/null
-* 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>;
- };
- };
- };
-};
--- /dev/null
+# 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>;
+ };
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.
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;
}
dev_err(&pdev->dev,
"failed to get valid sensor resource id: %d\n",
ret);
+ of_node_put(child);
break;
}
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;
}
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
--- /dev/null
+// 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");
* 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, \
{ \
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); \
}
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)
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)
if (!(val & BIT(30)))
return -EACCES;
- if (kstrtoint(buf, 0, &tcc))
+ if (kstrtouint(buf, 0, &tcc))
return -EINVAL;
err = tcc_offset_update(tcc);
}
}
-
-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;
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)
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);
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;
-
- if (proc_thermal_emum_mode == PROC_THERMAL_PCI) {
- dev_err(&pdev->dev, "error: enumerated as PCI dev\n");
- return -ENODEV;
- }
-
- 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);
+ struct proc_thermal_device *proc_dev;
- return ret;
-}
+ proc_dev = dev_get_drvdata(dev);
+ proc_thermal_read_ppcc(proc_dev);
-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;
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;
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();
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");
struct intel_soc_dts_sensors *soc_dts;
u32 mmio_feature_mask;
void __iomem *mmio_base;
+ void *priv_data;
};
struct rapl_mmio_regs {
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
--- /dev/null
+// 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");
--- /dev/null
+// 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");
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;
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",
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);
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 */
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,
&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
};
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;
#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
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:
* 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]),
{
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;
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);
#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
#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)
{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)
{
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;
},
};
+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,
.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);
sen = devm_kzalloc(&pdev->dev, sizeof(*sen), GFP_KERNEL);
if (!sen) {
ret = -ENOMEM;
- goto disable_clk;
+ goto of_put;
}
sen->data = thm;
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);
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);
platform_set_drvdata(pdev, thm);
return 0;
+of_put:
+ of_node_put(sen_child);
disable_clk:
clk_disable_unprepare(thm->clk);
return ret;
{ .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)
{
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);
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)
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;