Commit d654362d authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge tag 'thermal-v6.8-rc1' of...

Merge tag 'thermal-v6.8-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux into thermal

Merge thermal control material for 6.8-rc1 from Daniel Lezcano:

"- Converted Mediatek Thermal to the json-schema (Rafał Miłecki)

 - Fixed DT bindings issue on Loongson (Binbin Zhou)

 - Fixed returning NULL instead of -ENODEV on Loogsoo (Binbin Zhou)

 - Added the DT binding for the tsens on SM8650 platform (Neil Armstrong)

 - Added a reboot on critical option feature (Fabio Estevam)

 - Made usage of DEFINE_SIMPLE_DEV_PM_OPS on AmLogic (Uwe Kleine-König)

 - Added the D1/T113s THS controller support on Sun8i (Maxim Kiselev)

 - Fixed example in the DT binding for QCom SPMI (Johan Hovold)

 - Fixed compilation warning for the tmon utility (Florian Eckert)

 - Added interrupt based configuration on Exynos along with a set of
   related cleanups (Mateusz Majewski)"

* tag 'thermal-v6.8-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (24 commits)
  thermal/drivers/exynos: Use set_trips ops
  thermal/drivers/exynos: Use BIT wherever possible
  thermal/drivers/exynos: Split initialization of TMU and the thermal zone
  thermal/drivers/exynos: Stop using the threshold mechanism on Exynos 4210
  thermal/drivers/exynos: Simplify regulator (de)initialization
  thermal/drivers/exynos: Handle devm_regulator_get_optional return value correctly
  thermal/drivers/exynos: Wwitch from workqueue-driven interrupt handling to threaded interrupts
  thermal/drivers/exynos: Drop id field
  thermal/drivers/exynos: Remove an unnecessary field description
  tools/thermal/tmon: Fix compilation warning for wrong format
  dt-bindings: thermal: qcom-spmi-adc-tm5/hc: Clean up examples
  dt-bindings: thermal: qcom-spmi-adc-tm5/hc: Fix example node names
  thermal/drivers/sun8i: Add D1/T113s THS controller support
  dt-bindings: thermal: sun8i: Add binding for D1/T113s THS controller
  thermal: amlogic: Use DEFINE_SIMPLE_DEV_PM_OPS for PM functions
  thermal: amlogic: Make amlogic_thermal_disable() return void
  thermal/thermal_of: Allow rebooting after critical temp
  reboot: Introduce thermal_zone_device_critical_reboot()
  thermal/core: Prepare for introduction of thermal reboot
  dt-bindings: thermal-zones: Document critical-action
  ...
parents a3cd6db4 5314b154
......@@ -16,6 +16,7 @@ properties:
- allwinner,sun8i-a83t-ths
- allwinner,sun8i-h3-ths
- allwinner,sun8i-r40-ths
- allwinner,sun20i-d1-ths
- allwinner,sun50i-a64-ths
- allwinner,sun50i-a100-ths
- allwinner,sun50i-h5-ths
......@@ -61,6 +62,7 @@ allOf:
compatible:
contains:
enum:
- allwinner,sun20i-d1-ths
- allwinner,sun50i-a100-ths
- allwinner,sun50i-h6-ths
......@@ -84,7 +86,9 @@ allOf:
properties:
compatible:
contains:
const: allwinner,sun8i-h3-ths
enum:
- allwinner,sun8i-h3-ths
- allwinner,sun20i-d1-ths
then:
properties:
......@@ -103,6 +107,7 @@ allOf:
enum:
- allwinner,sun8i-h3-ths
- allwinner,sun8i-r40-ths
- allwinner,sun20i-d1-ths
- allwinner,sun50i-a64-ths
- allwinner,sun50i-a100-ths
- allwinner,sun50i-h5-ths
......
......@@ -10,6 +10,9 @@ maintainers:
- zhanghongchen <zhanghongchen@loongson.cn>
- Yinbo Zhu <zhuyinbo@loongson.cn>
allOf:
- $ref: /schemas/thermal/thermal-sensor.yaml#
properties:
compatible:
oneOf:
......@@ -26,12 +29,16 @@ properties:
interrupts:
maxItems: 1
'#thermal-sensor-cells':
const: 1
required:
- compatible
- reg
- interrupts
- '#thermal-sensor-cells'
additionalProperties: false
unevaluatedProperties: false
examples:
- |
......@@ -41,4 +48,5 @@ examples:
reg = <0x1fe01500 0x30>;
interrupt-parent = <&liointc0>;
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
#thermal-sensor-cells = <1>;
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/thermal/mediatek,thermal.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mediatek thermal controller for on-SoC temperatures
maintainers:
- Sascha Hauer <s.hauer@pengutronix.de>
description:
This device does not have its own ADC, instead it directly controls the AUXADC
via AHB bus accesses. For this reason it needs phandles to the AUXADC. Also it
controls a mux in the apmixedsys register space via AHB bus accesses, so a
phandle to the APMIXEDSYS is also needed.
allOf:
- $ref: thermal-sensor.yaml#
properties:
compatible:
enum:
- mediatek,mt2701-thermal
- mediatek,mt2712-thermal
- mediatek,mt7622-thermal
- mediatek,mt7981-thermal
- mediatek,mt7986-thermal
- mediatek,mt8173-thermal
- mediatek,mt8183-thermal
- mediatek,mt8365-thermal
- mediatek,mt8516-thermal
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: Main clock needed for register access
- description: The AUXADC clock
clock-names:
items:
- const: therm
- const: auxadc
mediatek,auxadc:
$ref: /schemas/types.yaml#/definitions/phandle
description: A phandle to the AUXADC which the thermal controller uses
mediatek,apmixedsys:
$ref: /schemas/types.yaml#/definitions/phandle
description: A phandle to the APMIXEDSYS controller
resets:
description: Reset controller controlling the thermal controller
nvmem-cells:
items:
- description:
NVMEM cell with EEPROMA phandle to the calibration data provided by an
NVMEM device. If unspecified default values shall be used.
nvmem-cell-names:
items:
- const: calibration-data
required:
- reg
- interrupts
- clocks
- clock-names
- mediatek,auxadc
- mediatek,apmixedsys
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clock/mt8173-clk.h>
#include <dt-bindings/reset/mt8173-resets.h>
thermal@1100b000 {
compatible = "mediatek,mt8173-thermal";
reg = <0x1100b000 0x1000>;
interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
clock-names = "therm", "auxadc";
resets = <&pericfg MT8173_PERI_THERM_SW_RST>;
mediatek,auxadc = <&auxadc>;
mediatek,apmixedsys = <&apmixedsys>;
nvmem-cells = <&thermal_calibration_data>;
nvmem-cell-names = "calibration-data";
#thermal-sensor-cells = <1>;
};
* Mediatek Thermal
This describes the device tree binding for the Mediatek thermal controller
which measures the on-SoC temperatures. This device does not have its own ADC,
instead it directly controls the AUXADC via AHB bus accesses. For this reason
this device needs phandles to the AUXADC. Also it controls a mux in the
apmixedsys register space via AHB bus accesses, so a phandle to the APMIXEDSYS
is also needed.
Required properties:
- compatible:
- "mediatek,mt8173-thermal" : For MT8173 family of SoCs
- "mediatek,mt2701-thermal" : For MT2701 family of SoCs
- "mediatek,mt2712-thermal" : For MT2712 family of SoCs
- "mediatek,mt7622-thermal" : For MT7622 SoC
- "mediatek,mt7981-thermal", "mediatek,mt7986-thermal" : For MT7981 SoC
- "mediatek,mt7986-thermal" : For MT7986 SoC
- "mediatek,mt8183-thermal" : For MT8183 family of SoCs
- "mediatek,mt8365-thermal" : For MT8365 family of SoCs
- "mediatek,mt8516-thermal", "mediatek,mt2701-thermal : For MT8516 family of SoCs
- reg: Address range of the thermal controller
- interrupts: IRQ for the thermal controller
- clocks, clock-names: Clocks needed for the thermal controller. required
clocks are:
"therm": Main clock needed for register access
"auxadc": The AUXADC clock
- mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses
- mediatek,apmixedsys: A phandle to the APMIXEDSYS controller.
- #thermal-sensor-cells : Should be 0. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description.
Optional properties:
- resets: Reference to the reset controller controlling the thermal controller.
- nvmem-cells: A phandle to the calibration data provided by a nvmem device. If
unspecified default values shall be used.
- nvmem-cell-names: Should be "calibration-data"
Example:
thermal: thermal@1100b000 {
#thermal-sensor-cells = <1>;
compatible = "mediatek,mt8173-thermal";
reg = <0 0x1100b000 0 0x1000>;
interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
clock-names = "therm", "auxadc";
resets = <&pericfg MT8173_PERI_THERM_SW_RST>;
reset-names = "therm";
mediatek,auxadc = <&auxadc>;
mediatek,apmixedsys = <&apmixedsys>;
nvmem-cells = <&thermal_calibration_data>;
nvmem-cell-names = "calibration-data";
};
......@@ -114,12 +114,14 @@ examples:
- |
#include <dt-bindings/iio/qcom,spmi-vadc.h>
#include <dt-bindings/interrupt-controller/irq.h>
spmi_bus {
pmic {
#address-cells = <1>;
#size-cells = <0>;
pm8998_adc: adc@3100 {
reg = <0x3100>;
compatible = "qcom,spmi-adc-rev2";
reg = <0x3100>;
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
......@@ -130,7 +132,7 @@ examples:
};
};
pm8998_adc_tm: adc-tm@3400 {
adc-tm@3400 {
compatible = "qcom,spmi-adc-tm-hc";
reg = <0x3400>;
interrupts = <0x2 0x34 0x0 IRQ_TYPE_EDGE_RISING>;
......
......@@ -167,12 +167,14 @@ examples:
- |
#include <dt-bindings/iio/qcom,spmi-vadc.h>
#include <dt-bindings/interrupt-controller/irq.h>
spmi_bus {
pmic {
#address-cells = <1>;
#size-cells = <0>;
pm8150b_adc: adc@3100 {
reg = <0x3100>;
compatible = "qcom,spmi-adc5";
reg = <0x3100>;
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
......@@ -186,7 +188,7 @@ examples:
};
};
pm8150b_adc_tm: adc-tm@3500 {
adc-tm@3500 {
compatible = "qcom,spmi-adc-tm5";
reg = <0x3500>;
interrupts = <0x2 0x35 0x0 IRQ_TYPE_EDGE_RISING>;
......@@ -207,12 +209,14 @@ examples:
#include <dt-bindings/iio/qcom,spmi-adc7-pmk8350.h>
#include <dt-bindings/iio/qcom,spmi-adc7-pm8350.h>
#include <dt-bindings/interrupt-controller/irq.h>
spmi_bus {
pmic {
#address-cells = <1>;
#size-cells = <0>;
pmk8350_vadc: adc@3100 {
reg = <0x3100>;
compatible = "qcom,spmi-adc7";
reg = <0x3100>;
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
......@@ -233,7 +237,7 @@ examples:
};
};
pmk8350_adc_tm: adc-tm@3400 {
adc-tm@3400 {
compatible = "qcom,spmi-adc-tm5-gen2";
reg = <0x3400>;
interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>;
......
......@@ -66,6 +66,7 @@ properties:
- qcom,sm8350-tsens
- qcom,sm8450-tsens
- qcom,sm8550-tsens
- qcom,sm8650-tsens
- const: qcom,tsens-v2
- description: v2 of TSENS with combined interrupt
......
......@@ -75,6 +75,22 @@ patternProperties:
framework and assumes that the thermal sensors in this zone
support interrupts.
critical-action:
$ref: /schemas/types.yaml#/definitions/string
description: |
The action the OS should perform after the critical temperature is reached.
By default the system will shutdown as a safe action to prevent damage
to the hardware, if the property is not set.
The shutdown action should be always the default and preferred one.
Choose 'reboot' with care, as the hardware may be in thermal stress,
thus leading to infinite reboots that may cause damage to the hardware.
Make sure the firmware/bootloader will act as the last resort and take
over the thermal control.
enum:
- shutdown
- reboot
thermal-sensors:
$ref: /schemas/types.yaml#/definitions/phandle-array
maxItems: 1
......
......@@ -167,13 +167,11 @@ static int amlogic_thermal_enable(struct amlogic_thermal *data)
return 0;
}
static int amlogic_thermal_disable(struct amlogic_thermal *data)
static void amlogic_thermal_disable(struct amlogic_thermal *data)
{
regmap_update_bits(data->regmap, TSENSOR_CFG_REG1,
TSENSOR_CFG_REG1_ENABLE, 0);
clk_disable_unprepare(data->clk);
return 0;
}
static int amlogic_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
......@@ -298,27 +296,30 @@ static void amlogic_thermal_remove(struct platform_device *pdev)
amlogic_thermal_disable(data);
}
static int __maybe_unused amlogic_thermal_suspend(struct device *dev)
static int amlogic_thermal_suspend(struct device *dev)
{
struct amlogic_thermal *data = dev_get_drvdata(dev);
return amlogic_thermal_disable(data);
amlogic_thermal_disable(data);
return 0;
}
static int __maybe_unused amlogic_thermal_resume(struct device *dev)
static int amlogic_thermal_resume(struct device *dev)
{
struct amlogic_thermal *data = dev_get_drvdata(dev);
return amlogic_thermal_enable(data);
}
static SIMPLE_DEV_PM_OPS(amlogic_thermal_pm_ops,
amlogic_thermal_suspend, amlogic_thermal_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(amlogic_thermal_pm_ops,
amlogic_thermal_suspend,
amlogic_thermal_resume);
static struct platform_driver amlogic_thermal_driver = {
.driver = {
.name = "amlogic_thermal",
.pm = &amlogic_thermal_pm_ops,
.pm = pm_ptr(&amlogic_thermal_pm_ops),
.of_match_table = of_amlogic_thermal_match,
},
.probe = amlogic_thermal_probe,
......
......@@ -127,7 +127,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
if (!IS_ERR(tzd))
break;
if (PTR_ERR(tzd) != ENODEV)
if (PTR_ERR(tzd) != -ENODEV)
continue;
return dev_err_probe(dev, PTR_ERR(tzd), "failed to register");
......
This diff is collapsed.
......@@ -606,6 +606,18 @@ static const struct ths_thermal_chip sun50i_h6_ths = {
.calc_temp = sun8i_ths_calc_temp,
};
static const struct ths_thermal_chip sun20i_d1_ths = {
.sensor_num = 1,
.has_bus_clk_reset = true,
.offset = 188552,
.scale = 673,
.temp_data_base = SUN50I_H6_THS_TEMP_DATA,
.calibrate = sun50i_h6_ths_calibrate,
.init = sun50i_h6_thermal_init,
.irq_ack = sun50i_h6_irq_ack,
.calc_temp = sun8i_ths_calc_temp,
};
static const struct of_device_id of_ths_match[] = {
{ .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths },
{ .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths },
......@@ -614,6 +626,7 @@ static const struct of_device_id of_ths_match[] = {
{ .compatible = "allwinner,sun50i-a100-ths", .data = &sun50i_a100_ths },
{ .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths },
{ .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths },
{ .compatible = "allwinner,sun20i-d1-ths", .data = &sun20i_d1_ths },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, of_ths_match);
......
......@@ -318,21 +318,34 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz,
tz->governor->update_tz(tz, reason);
}
void thermal_zone_device_critical(struct thermal_zone_device *tz)
static void thermal_zone_device_halt(struct thermal_zone_device *tz, bool shutdown)
{
/*
* poweroff_delay_ms must be a carefully profiled positive value.
* Its a must for forced_emergency_poweroff_work to be scheduled.
*/
int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS;
const char *msg = "Temperature too high";
dev_emerg(&tz->device, "%s: critical temperature reached, "
"shutting down\n", tz->type);
dev_emerg(&tz->device, "%s: critical temperature reached\n", tz->type);
hw_protection_shutdown("Temperature too high", poweroff_delay_ms);
if (shutdown)
hw_protection_shutdown(msg, poweroff_delay_ms);
else
hw_protection_reboot(msg, poweroff_delay_ms);
}
void thermal_zone_device_critical(struct thermal_zone_device *tz)
{
thermal_zone_device_halt(tz, true);
}
EXPORT_SYMBOL(thermal_zone_device_critical);
void thermal_zone_device_critical_reboot(struct thermal_zone_device *tz)
{
thermal_zone_device_halt(tz, false);
}
static void handle_critical_trips(struct thermal_zone_device *tz,
const struct thermal_trip *trip)
{
......
......@@ -114,6 +114,7 @@ int thermal_zone_device_set_policy(struct thermal_zone_device *, char *);
int thermal_build_list_of_policies(char *buf);
void __thermal_zone_device_update(struct thermal_zone_device *tz,
enum thermal_notify_event event);
void thermal_zone_device_critical_reboot(struct thermal_zone_device *tz);
void thermal_governor_update_tz(struct thermal_zone_device *tz,
enum thermal_notify_event reason);
......
......@@ -475,6 +475,7 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
struct thermal_zone_params tzp = {};
struct thermal_zone_device_ops *of_ops;
struct device_node *np;
const char *action;
int delay, pdelay;
int ntrips, mask;
int ret;
......@@ -511,6 +512,11 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
mask = GENMASK_ULL((ntrips) - 1, 0);
ret = of_property_read_string(np, "critical-action", &action);
if (!ret)
if (!of_ops->critical && !strcasecmp(action, "reboot"))
of_ops->critical = thermal_zone_device_critical_reboot;
tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
mask, data, of_ops, &tzp,
pdelay, delay);
......
......@@ -177,7 +177,17 @@ void ctrl_alt_del(void);
extern void orderly_poweroff(bool force);
extern void orderly_reboot(void);
void hw_protection_shutdown(const char *reason, int ms_until_forced);
void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shutdown);
static inline void hw_protection_reboot(const char *reason, int ms_until_forced)
{
__hw_protection_shutdown(reason, ms_until_forced, false);
}
static inline void hw_protection_shutdown(const char *reason, int ms_until_forced)
{
__hw_protection_shutdown(reason, ms_until_forced, true);
}
/*
* Emergency restart, callable from an interrupt handler.
......
......@@ -957,21 +957,24 @@ static void hw_failure_emergency_poweroff(int poweroff_delay_ms)
}
/**
* hw_protection_shutdown - Trigger an emergency system poweroff
* __hw_protection_shutdown - Trigger an emergency system shutdown or reboot
*
* @reason: Reason of emergency shutdown to be printed.
* @ms_until_forced: Time to wait for orderly shutdown before tiggering a
* forced shudown. Negative value disables the forced
* shutdown.
* @reason: Reason of emergency shutdown or reboot to be printed.
* @ms_until_forced: Time to wait for orderly shutdown or reboot before
* triggering it. Negative value disables the forced
* shutdown or reboot.
* @shutdown: If true, indicates that a shutdown will happen
* after the critical tempeature is reached.
* If false, indicates that a reboot will happen
* after the critical tempeature is reached.
*
* Initiate an emergency system shutdown in order to protect hardware from
* further damage. Usage examples include a thermal protection or a voltage or
* current regulator failures.
* NOTE: The request is ignored if protection shutdown is already pending even
* if the previous request has given a large timeout for forced shutdown.
* Can be called from any context.
* Initiate an emergency system shutdown or reboot in order to protect
* hardware from further damage. Usage examples include a thermal protection.
* NOTE: The request is ignored if protection shutdown or reboot is already
* pending even if the previous request has given a large timeout for forced
* shutdown/reboot.
*/
void hw_protection_shutdown(const char *reason, int ms_until_forced)
void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shutdown)
{
static atomic_t allow_proceed = ATOMIC_INIT(1);
......@@ -986,9 +989,12 @@ void hw_protection_shutdown(const char *reason, int ms_until_forced)
* orderly_poweroff failure
*/
hw_failure_emergency_poweroff(ms_until_forced);
if (shutdown)
orderly_poweroff(true);
else
orderly_reboot();
}
EXPORT_SYMBOL_GPL(hw_protection_shutdown);
EXPORT_SYMBOL_GPL(__hw_protection_shutdown);
static int __init reboot_setup(char *str)
{
......
......@@ -213,7 +213,7 @@ void show_cooling_device(void)
* cooling device instances. skip unused idr.
*/
mvwprintw(cooling_device_window, j + 2, 1,
"%02d %12.12s%6d %6d",
"%02d %12.12s%6lu %6lu",
ptdata.cdi[j].instance,
ptdata.cdi[j].type,
ptdata.cdi[j].cur_state,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment