This series add following functions for Tegra soctherm:
1. add Tegra132 support.
2. add HW throttle function.
3. set hot trip temperatures which can trigger the HW throttle.
Main changes from V1:
1. use readl/writel instead of __raw_readl/__raw_writel.
2. rebase on the linux-next.
The v1 series is in:
https://lkml.org/lkml/2016/3/31/230
Wei Ni (9):
thermal: tegra: add Tegra132 specific SOC_THERM driver
arm64: tegra: use tegra132-soctherm for Tegra132
arm64: tegra: set critical trips for Tegra132
of: Add bindings of hw throttle for soctherm
thermal: tegra: add hw-throttle function
thermal: tegra: add hw-throttle for Tegra132
arm64: tegra: set hot trips for Tegra210
arm64: tegra: set hot trips for Tegra132
arm: tegra: set hot trips for Tegra124
.../bindings/thermal/nvidia,tegra124-soctherm.txt | 89 ++-
arch/arm/boot/dts/tegra124.dtsi | 39 +-
arch/arm64/boot/dts/nvidia/tegra132.dtsi | 119 ++-
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 41 +-
drivers/thermal/tegra/Makefile | 1 +
drivers/thermal/tegra/soctherm.c | 838 ++++++++++++++++++++-
drivers/thermal/tegra/soctherm.h | 14 +
drivers/thermal/tegra/tegra124-soctherm.c | 18 +
drivers/thermal/tegra/tegra132-soctherm.c | 214 ++++++
drivers/thermal/tegra/tegra210-soctherm.c | 18 +
include/dt-bindings/thermal/tegra124-soctherm.h | 5 +
11 files changed, 1359 insertions(+), 37 deletions(-)
create mode 100644 drivers/thermal/tegra/tegra132-soctherm.c
--
1.9.1
add Tegra132 specific SOC_THERM driver.
Signed-off-by: Wei Ni <[email protected]>
---
drivers/thermal/tegra/Makefile | 1 +
drivers/thermal/tegra/soctherm.c | 6 +
drivers/thermal/tegra/soctherm.h | 4 +
drivers/thermal/tegra/tegra132-soctherm.c | 196 ++++++++++++++++++++++++++++++
4 files changed, 207 insertions(+)
create mode 100644 drivers/thermal/tegra/tegra132-soctherm.c
diff --git a/drivers/thermal/tegra/Makefile b/drivers/thermal/tegra/Makefile
index bf9e028eba28..1ce1af2cf0f5 100644
--- a/drivers/thermal/tegra/Makefile
+++ b/drivers/thermal/tegra/Makefile
@@ -2,4 +2,5 @@ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o
tegra-soctherm-y := soctherm.o soctherm-fuse.o
tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o
+tegra-soctherm-$(CONFIG_ARCH_TEGRA_132_SOC) += tegra132-soctherm.o
tegra-soctherm-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-soctherm.o
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index 2b0417d7b754..b8651726201e 100644
--- a/drivers/thermal/tegra/soctherm.c
+++ b/drivers/thermal/tegra/soctherm.c
@@ -484,6 +484,12 @@ static const struct of_device_id tegra_soctherm_of_match[] = {
.data = &tegra124_soctherm,
},
#endif
+#ifdef CONFIG_ARCH_TEGRA_132_SOC
+ {
+ .compatible = "nvidia,tegra132-soctherm",
+ .data = &tegra132_soctherm,
+ },
+#endif
#ifdef CONFIG_ARCH_TEGRA_210_SOC
{
.compatible = "nvidia,tegra210-soctherm",
diff --git a/drivers/thermal/tegra/soctherm.h b/drivers/thermal/tegra/soctherm.h
index f6dbbba80367..28e18ec4b4c3 100644
--- a/drivers/thermal/tegra/soctherm.h
+++ b/drivers/thermal/tegra/soctherm.h
@@ -115,6 +115,10 @@ int tegra_calc_tsensor_calib(const struct tegra_tsensor *sensor,
extern const struct tegra_soctherm_soc tegra124_soctherm;
#endif
+#ifdef CONFIG_ARCH_TEGRA_132_SOC
+extern const struct tegra_soctherm_soc tegra132_soctherm;
+#endif
+
#ifdef CONFIG_ARCH_TEGRA_210_SOC
extern const struct tegra_soctherm_soc tegra210_soctherm;
#endif
diff --git a/drivers/thermal/tegra/tegra132-soctherm.c b/drivers/thermal/tegra/tegra132-soctherm.c
new file mode 100644
index 000000000000..e2aa84e1b307
--- /dev/null
+++ b/drivers/thermal/tegra/tegra132-soctherm.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <dt-bindings/thermal/tegra124-soctherm.h>
+
+#include "soctherm.h"
+
+#define TEGRA132_THERMTRIP_ANY_EN_MASK (0x1 << 28)
+#define TEGRA132_THERMTRIP_MEM_EN_MASK (0x1 << 27)
+#define TEGRA132_THERMTRIP_GPU_EN_MASK (0x1 << 26)
+#define TEGRA132_THERMTRIP_CPU_EN_MASK (0x1 << 25)
+#define TEGRA132_THERMTRIP_TSENSE_EN_MASK (0x1 << 24)
+#define TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK (0xff << 16)
+#define TEGRA132_THERMTRIP_CPU_THRESH_MASK (0xff << 8)
+#define TEGRA132_THERMTRIP_TSENSE_THRESH_MASK 0xff
+
+#define TEGRA132_THRESH_GRAIN 1000
+
+static const struct tegra_tsensor_configuration tegra132_tsensor_config = {
+ .tall = 16300,
+ .tiddq_en = 1,
+ .ten_count = 1,
+ .tsample = 120,
+ .tsample_ate = 480,
+};
+
+static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = {
+ .id = TEGRA124_SOCTHERM_SENSOR_CPU,
+ .name = "cpu",
+ .sensor_temp_offset = SENSOR_TEMP1,
+ .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_CPU_MASK,
+ .pllx_hotspot_diff = 10,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK,
+ .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
+ .thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK,
+ .thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK,
+};
+
+static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = {
+ .id = TEGRA124_SOCTHERM_SENSOR_GPU,
+ .name = "gpu",
+ .sensor_temp_offset = SENSOR_TEMP1,
+ .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_GPU_MASK,
+ .pllx_hotspot_diff = 5,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK,
+ .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
+ .thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK,
+ .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK,
+};
+
+static const struct tegra_tsensor_group tegra132_tsensor_group_pll = {
+ .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
+ .name = "pll",
+ .sensor_temp_offset = SENSOR_TEMP2,
+ .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_PLLX_MASK,
+ .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
+ .thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK,
+ .thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK,
+};
+
+static const struct tegra_tsensor_group tegra132_tsensor_group_mem = {
+ .id = TEGRA124_SOCTHERM_SENSOR_MEM,
+ .name = "mem",
+ .sensor_temp_offset = SENSOR_TEMP2,
+ .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_MEM_MASK,
+ .pllx_hotspot_diff = 0,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK,
+ .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
+ .thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK,
+ .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK,
+};
+
+static const struct tegra_tsensor_group *tegra132_tsensor_groups[] = {
+ &tegra132_tsensor_group_cpu,
+ &tegra132_tsensor_group_gpu,
+ &tegra132_tsensor_group_pll,
+ &tegra132_tsensor_group_mem,
+};
+
+static struct tegra_tsensor tegra132_tsensors[] = {
+ {
+ .name = "cpu0",
+ .base = 0xc0,
+ .config = &tegra132_tsensor_config,
+ .calib_fuse_offset = 0x098,
+ .fuse_corr_alpha = 1126600,
+ .fuse_corr_beta = -9433500,
+ .group = &tegra132_tsensor_group_cpu,
+ }, {
+ .name = "cpu1",
+ .base = 0xe0,
+ .config = &tegra132_tsensor_config,
+ .calib_fuse_offset = 0x084,
+ .fuse_corr_alpha = 1110800,
+ .fuse_corr_beta = -7383000,
+ .group = &tegra132_tsensor_group_cpu,
+ }, {
+ .name = "cpu2",
+ .base = 0x100,
+ .config = &tegra132_tsensor_config,
+ .calib_fuse_offset = 0x088,
+ .fuse_corr_alpha = 1113800,
+ .fuse_corr_beta = -6215200,
+ .group = &tegra132_tsensor_group_cpu,
+ }, {
+ .name = "cpu3",
+ .base = 0x120,
+ .config = &tegra132_tsensor_config,
+ .calib_fuse_offset = 0x12c,
+ .fuse_corr_alpha = 1129600,
+ .fuse_corr_beta = -8196100,
+ .group = &tegra132_tsensor_group_cpu,
+ }, {
+ .name = "mem0",
+ .base = 0x140,
+ .config = &tegra132_tsensor_config,
+ .calib_fuse_offset = 0x158,
+ .fuse_corr_alpha = 1132900,
+ .fuse_corr_beta = -6755300,
+ .group = &tegra132_tsensor_group_mem,
+ }, {
+ .name = "mem1",
+ .base = 0x160,
+ .config = &tegra132_tsensor_config,
+ .calib_fuse_offset = 0x15c,
+ .fuse_corr_alpha = 1142300,
+ .fuse_corr_beta = -7374200,
+ .group = &tegra132_tsensor_group_mem,
+ }, {
+ .name = "gpu",
+ .base = 0x180,
+ .config = &tegra132_tsensor_config,
+ .calib_fuse_offset = 0x154,
+ .fuse_corr_alpha = 1125100,
+ .fuse_corr_beta = -6350400,
+ .group = &tegra132_tsensor_group_gpu,
+ }, {
+ .name = "pllx",
+ .base = 0x1a0,
+ .config = &tegra132_tsensor_config,
+ .calib_fuse_offset = 0x160,
+ .fuse_corr_alpha = 1118100,
+ .fuse_corr_beta = -8208800,
+ .group = &tegra132_tsensor_group_pll,
+ },
+};
+
+/*
+ * Mask/shift bits in FUSE_TSENSOR_COMMON and
+ * FUSE_TSENSOR_COMMON, which are described in
+ * tegra_soctherm_fuse.c
+ */
+static const struct tegra_soctherm_fuse tegra132_soctherm_fuse = {
+ .fuse_base_cp_mask = 0x3ff,
+ .fuse_base_cp_shift = 0,
+ .fuse_base_ft_mask = 0x7ff << 10,
+ .fuse_base_ft_shift = 10,
+ .fuse_shift_ft_mask = 0x1f << 21,
+ .fuse_shift_ft_shift = 21,
+ .fuse_spare_realignment = 0x1fc,
+};
+
+const struct tegra_soctherm_soc tegra132_soctherm = {
+ .tsensors = tegra132_tsensors,
+ .num_tsensors = ARRAY_SIZE(tegra132_tsensors),
+ .ttgs = tegra132_tsensor_groups,
+ .num_ttgs = ARRAY_SIZE(tegra132_tsensor_groups),
+ .tfuse = &tegra132_soctherm_fuse,
+ .thresh_grain = TEGRA132_THRESH_GRAIN,
+};
--
1.9.1
Add HW throttle configuration sub-node for soctherm, which
is used to describe the throttle event, and worked as a
cooling device. The "hot" type trip in thermal zone can
be bound to this cooling device, and trigger the throttle
function.
Signed-off-by: Wei Ni <[email protected]>
---
.../bindings/thermal/nvidia,tegra124-soctherm.txt | 89 +++++++++++++++++++++-
1 file changed, 87 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
index edebfa0a985e..dc337d139f49 100644
--- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
+++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
@@ -10,8 +10,14 @@ Required properties :
- compatible : For Tegra124, must contain "nvidia,tegra124-soctherm".
For Tegra132, must contain "nvidia,tegra132-soctherm".
For Tegra210, must contain "nvidia,tegra210-soctherm".
-- reg : Should contain 1 entry:
+- reg : Should contain at least 2 entries for each entry in reg-names:
- SOCTHERM register set
+ - Tegra CAR register set: Required for Tegra124 and Tegra210.
+ - CCROC register set: Required for Tegra132.
+- reg-names : Should contain at least 2 entries:
+ - soctherm-reg
+ - car-reg
+ - ccroc-reg
- interrupts : Defines the interrupt used by SOCTHERM
- clocks : Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
@@ -25,17 +31,44 @@ Required properties :
- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description
of this property. See <dt-bindings/thermal/tegra124-soctherm.h> for a
list of valid values when referring to thermal sensors.
+- throttle-cfgs: A sub-node which is a container of configuration for each
+ hardware throttle events. These events can be set as cooling devices.
+ * throttle events: Sub-nodes must be named as "light" or "heavy".
+ Properties:
+ - priority: Each throttles has its own throttle settings, so the SW need
+ to set priorities for various throttle, the HW arbiter can select the
+ final throttle settings.
+ Bigger value indicates higher priority, In general, higher priority
+ translates to lower target frequency. SW needs to ensure that critical
+ thermal alarms are given higher priority, and ensure that there is
+ no race if priority of two vectors is set to the same value.
+ - cpu-throt-depth: This property is for Tegra124 and Tegra210. It is
+ the throttling depth of pulse skippers, it's the percentage
+ throttling.
+ - cpu-throt-level: This property is only for Tegra132, it is the level
+ of pulse skippers, which used to throttle clock frequencies. It
+ indicates cpu clock throttling depth, and the depth can be programmed.
+ Must set as following values:
+ TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED
+ TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE
+ - #cooling-cells: Should be 1. This cooling device only support on/off state.
+ See ./thermal.txt for a description of this property.
Note:
- the "critical" type trip points will be set to SOC_THERM hardware as the
shut down temperature. Once the temperature of this thermal zone is higher
than it, the system will be shutdown or reset by hardware.
+- the "hot" type trip points will be set to SOC_THERM hardware as the throttle
+temperature. Once the the temperature of this thermal zone is higher
+than it, it will trigger the HW throttle event.
Example :
soctherm@700e2000 {
compatible = "nvidia,tegra124-soctherm";
- reg = <0x0 0x700e2000 0x0 0x1000>;
+ reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
+ 0x0 0x60006000 0x0 0x400 /* CAR reg_base */
+ reg-names = "soctherm-reg", "car-reg";
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA124_CLK_TSENSOR>,
<&tegra_car TEGRA124_CLK_SOC_THERM>;
@@ -44,6 +77,45 @@ Example :
reset-names = "soctherm";
#thermal-sensor-cells = <1>;
+
+ throttle-cfgs {
+ throttle_heavy: heavy {
+ priority = <100>;
+ cpu-throt-depth = <85>;
+
+ #cooling-cells = <1>;
+ };
+ throttle_light: light {
+ priority = <80>;
+ cpu-throt-depth = <50>;
+
+ #cooling-cells = <1>;
+ };
+ };
+ };
+
+Example: referring to Tegra132's "reg", "reg-names" and "throttle-cfgs" :
+
+ soctherm@0,700e2000 {
+ compatible = "nvidia,tegra132-soctherm";
+ reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
+ 0x0 0x70040000 0x0 0x200>; /* CCROC reg_base */;
+ reg-names = "soctherm-reg", "ccroc-reg";
+
+ throttle-cfgs {
+ throttle_heavy: heavy {
+ priority = <100>;
+ cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_HIGH>;
+
+ #cooling-cells = <1>;
+ };
+ throttle_light: light {
+ priority = <80>;
+ cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_MED>;
+
+ #cooling-cells = <1>;
+ };
+ };
};
Example: referring to thermal sensors :
@@ -62,6 +134,19 @@ Example: referring to thermal sensors :
hysteresis = <1000>;
type = "critical";
};
+
+ cpu_throttle_trip: throttle-trip {
+ temperature = <100000>;
+ hysteresis = <1000>;
+ type = "hot";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_throttle_trip>;
+ cooling-device = <&throttle_heavy 1 1>;
+ };
};
};
};
--
1.9.1
Enable throttle function for SOC_THERM.
Set "hot" trips for cpu and gpu thermal zones, which
can trigger the SOC_THERM hardware throttle.
Signed-off-by: Wei Ni <[email protected]>
---
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 41 +++++++++++++++++++++++++-------
1 file changed, 32 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index e3cca58a4c86..332771ab38e8 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -804,7 +804,9 @@
soctherm: thermal-sensor@0,700e2000 {
compatible = "nvidia,tegra210-soctherm";
- reg = <0x0 0x700e2000 0x0 0x1000>;
+ reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
+ 0x0 0x60006000 0x0 0x400>; /* CAR reg_base */
+ reg-names = "soctherm-reg", "car-reg";
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_TSENSOR>,
<&tegra_car TEGRA210_CLK_SOC_THERM>;
@@ -812,6 +814,15 @@
resets = <&tegra_car 78>;
reset-names = "soctherm";
#thermal-sensor-cells = <1>;
+
+ throttle-cfgs {
+ throttle_heavy: heavy {
+ priority = <100>;
+ cpu-throt-depth = <85>;
+
+ #cooling-cells = <2>;
+ };
+ };
};
thermal-zones {
@@ -828,13 +839,19 @@
hysteresis = <0>;
type = "critical";
};
+
+ cpu_throttle_trip: throttle-trip {
+ temperature = <98500>;
+ hysteresis = <1000>;
+ type = "hot";
+ };
};
cooling-maps {
- /*
- * There are currently no cooling maps,
- * because there are no cooling devices.
- */
+ map0 {
+ trip = <&cpu_throttle_trip>;
+ cooling-device = <&throttle_heavy 1 1>;
+ };
};
};
mem {
@@ -872,13 +889,19 @@
hysteresis = <0>;
type = "critical";
};
+
+ gpu_throttle_trip: throttle-trip {
+ temperature = <100000>;
+ hysteresis = <1000>;
+ type = "hot";
+ };
};
cooling-maps {
- /*
- * There are currently no cooling maps,
- * because there are no cooling devices.
- */
+ map0 {
+ trip = <&gpu_throttle_trip>;
+ cooling-device = <&throttle_heavy 1 1>;
+ };
};
};
pllx {
--
1.9.1
Enable throttle function for SOC_THERM.
Set "hot" trips for cpu and gpu thermal zones, which
can trigger the SOC_THERM hardware throttle.
Signed-off-by: Wei Ni <[email protected]>
---
arch/arm/boot/dts/tegra124.dtsi | 39 ++++++++++++++++++++++++++++++---------
1 file changed, 30 insertions(+), 9 deletions(-)
diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 08c7f85ea2c8..c5dcb97e7bc4 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -846,7 +846,9 @@
soctherm: thermal-sensor@0,700e2000 {
compatible = "nvidia,tegra124-soctherm";
- reg = <0x0 0x700e2000 0x0 0x1000>;
+ reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
+ 0x0 0x60006000 0x0 0x400>; /* CAR reg_base */
+ reg-names = "soctherm-reg", "car-reg";
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA124_CLK_TSENSOR>,
<&tegra_car TEGRA124_CLK_SOC_THERM>;
@@ -854,6 +856,15 @@
resets = <&tegra_car 78>;
reset-names = "soctherm";
#thermal-sensor-cells = <1>;
+
+ throttle-cfgs {
+ throttle_heavy: heavy {
+ priority = <100>;
+ cpu-throt-depth = <85>;
+
+ #cooling-cells = <1>;
+ };
+ };
};
dfll: clock@0,70110000 {
@@ -1156,13 +1167,18 @@
hysteresis = <0>;
type = "critical";
};
+ cpu_throttle_trip: throttle-trip {
+ temperature = <100000>;
+ hysteresis = <1000>;
+ type = "hot";
+ };
};
cooling-maps {
- /*
- * There are currently no cooling maps,
- * because there are no cooling devices.
- */
+ map0 {
+ trip = <&cpu_throttle_trip>;
+ cooling-device = <&throttle_heavy 1 1>;
+ };
};
};
@@ -1202,13 +1218,18 @@
hysteresis = <0>;
type = "critical";
};
+ gpu_throttle_trip: throttle-trip {
+ temperature = <99000>;
+ hysteresis = <1000>;
+ type = "hot";
+ };
};
cooling-maps {
- /*
- * There are currently no cooling maps,
- * because there are no cooling devices.
- */
+ map0 {
+ trip = <&cpu_throttle_trip>;
+ cooling-device = <&throttle_heavy 1 1>;
+ };
};
};
--
1.9.1
Set general "critical" trip temperatures for cpu, gpu, mem and pllx
thermal zones on Tegra132, these trips can trigger shut down or reset.
Signed-off-by: Wei Ni <[email protected]>
---
arch/arm64/boot/dts/nvidia/tegra132.dtsi | 60 ++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra132.dtsi b/arch/arm64/boot/dts/nvidia/tegra132.dtsi
index e41d8e82d7ed..a3889e930010 100644
--- a/arch/arm64/boot/dts/nvidia/tegra132.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra132.dtsi
@@ -746,6 +746,21 @@
thermal-sensors =
<&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>;
+
+ trips {
+ cpu_shutdown_trip {
+ temperature = <105000>;
+ hysteresis = <1000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
};
mem {
polling-delay-passive = <0>;
@@ -753,6 +768,21 @@
thermal-sensors =
<&soctherm TEGRA124_SOCTHERM_SENSOR_MEM>;
+
+ trips {
+ mem_shutdown_trip {
+ temperature = <101000>;
+ hysteresis = <1000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
};
gpu {
polling-delay-passive = <1000>;
@@ -760,6 +790,21 @@
thermal-sensors =
<&soctherm TEGRA124_SOCTHERM_SENSOR_GPU>;
+
+ trips {
+ gpu_shutdown_trip {
+ temperature = <101000>;
+ hysteresis = <1000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
};
pllx {
polling-delay-passive = <0>;
@@ -767,6 +812,21 @@
thermal-sensors =
<&soctherm TEGRA124_SOCTHERM_SENSOR_PLLX>;
+
+ trips {
+ pllx_shutdown_trip {
+ temperature = <105000>;
+ hysteresis = <1000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
};
};
--
1.9.1
Enable throttle function for SOC_THERM.
Set "hot" trips for cpu and gpu thermal zones, which
can trigger the SOC_THERM hardware throttle.
Signed-off-by: Wei Ni <[email protected]>
---
arch/arm64/boot/dts/nvidia/tegra132.dtsi | 41 +++++++++++++++++++++++++-------
1 file changed, 32 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/boot/dts/nvidia/tegra132.dtsi b/arch/arm64/boot/dts/nvidia/tegra132.dtsi
index a3889e930010..fa671c1da279 100644
--- a/arch/arm64/boot/dts/nvidia/tegra132.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra132.dtsi
@@ -729,7 +729,9 @@
soctherm: thermal-sensor@700e2000 {
compatible = "nvidia,tegra132-soctherm";
- reg = <0x0 0x700e2000 0x0 0x600>;
+ reg = <0x0 0x700e2000 0x0 0x600 /* 0: SOC_THERM reg_base */
+ 0x0 0x70040000 0x0 0x200>; /* 2: CCROC reg_base */
+ reg-names = "soctherm-reg", "ccroc-reg";
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA124_CLK_TSENSOR>,
<&tegra_car TEGRA124_CLK_SOC_THERM>;
@@ -737,6 +739,15 @@
resets = <&tegra_car 78>;
reset-names = "soctherm";
#thermal-sensor-cells = <1>;
+
+ throttle-cfgs {
+ throttle_heavy: heavy {
+ priority = <100>;
+ cpu-throt-depth = <85>;
+
+ #cooling-cells = <1>;
+ };
+ };
};
thermal-zones {
@@ -753,13 +764,19 @@
hysteresis = <1000>;
type = "critical";
};
+
+ cpu_throttle_trip: throttle-trip {
+ temperature = <102000>;
+ hysteresis = <1000>;
+ type = "hot";
+ };
};
cooling-maps {
- /*
- * There are currently no cooling maps,
- * because there are no cooling devices.
- */
+ map0 {
+ trip = <&cpu_throttle_trip>;
+ cooling-device = <&throttle_heavy 1 1>;
+ };
};
};
mem {
@@ -797,13 +814,19 @@
hysteresis = <1000>;
type = "critical";
};
+
+ gpu_throttle_trip: throttle-trip {
+ temperature = <99000>;
+ hysteresis = <1000>;
+ type = "hot";
+ };
};
cooling-maps {
- /*
- * There are currently no cooling maps,
- * because there are no cooling devices.
- */
+ map0 {
+ trip = <&gpu_throttle_trip>;
+ cooling-device = <&throttle_heavy 1 1>;
+ };
};
};
pllx {
--
1.9.1
Tegra132 use CCROC throttle registers to configure
pulse skiper, set these registers to enable throttle
function for Tegra132.
Signed-off-by: Wei Ni <[email protected]>
---
drivers/thermal/tegra/soctherm.c | 215 +++++++++++++++++++++---
drivers/thermal/tegra/tegra132-soctherm.c | 17 ++
include/dt-bindings/thermal/tegra124-soctherm.h | 5 +
3 files changed, 212 insertions(+), 25 deletions(-)
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index e6c4085f876d..900834637464 100644
--- a/drivers/thermal/tegra/soctherm.c
+++ b/drivers/thermal/tegra/soctherm.c
@@ -136,6 +136,21 @@
#define CAR_SUPER_CCLKG_DIVIDER 0x36c
#define CDIVG_USE_THERM_CONTROLS_MASK BIT(30)
+/* ccroc register offsets needed for enabling HW throttling for Tegra132 */
+#define CCROC_SUPER_CCLKG_DIVIDER 0x024
+
+#define CCROC_GLOBAL_CFG 0x148
+
+#define CCROC_THROT_PSKIP_RAMP_CPU 0x150
+#define CCROC_THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31)
+#define CCROC_THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8)
+#define CCROC_THROT_PSKIP_RAMP_STEP_MASK 0xff
+
+#define CCROC_THROT_PSKIP_CTRL_CPU 0x154
+#define CCROC_THROT_PSKIP_CTRL_ENB_MASK BIT(31)
+#define CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8)
+#define CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK 0xff
+
/* get val from register(r) mask bits(m) */
#define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1))
/* set val(v) to mask bits(m) of register(r) */
@@ -158,6 +173,13 @@
#define THROT_DELAY_CTRL(throt) (THROT_DELAY_LITE + \
(THROT_OFFSET * throt))
+/* get CCROC_THROT_PSKIP_xxx offset per HIGH/MED/LOW vect*/
+#define CCROC_THROT_OFFSET 0x0c
+#define CCROC_THROT_PSKIP_CTRL_CPU_REG(vect) (CCROC_THROT_PSKIP_CTRL_CPU + \
+ (CCROC_THROT_OFFSET * vect))
+#define CCROC_THROT_PSKIP_RAMP_CPU_REG(vect) (CCROC_THROT_PSKIP_RAMP_CPU + \
+ (CCROC_THROT_OFFSET * vect))
+
/* get THERMCTL_LEVELx offset per CPU/GPU/MEM/TSENSE rg and LEVEL0~3 lv */
#define THERMCTL_LVL_REGS_SIZE 0x20
#define THERMCTL_LVL_REG(rg, lv) ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE))
@@ -195,6 +217,7 @@ struct soctherm_throt_cfg {
const char *name;
unsigned int id;
u8 priority;
+ u8 cpu_throt_level;
u32 cpu_throt_depth;
struct thermal_cooling_device *cdev;
bool init;
@@ -206,6 +229,7 @@ struct tegra_soctherm {
struct clk *clock_soctherm;
void __iomem *regs;
void __iomem *clk_regs;
+ void __iomem *ccroc_regs;
u32 *calib;
struct thermal_zone_device **thermctl_tzs;
@@ -241,6 +265,31 @@ static inline u32 clk_readl(struct tegra_soctherm *ts, u32 reg)
return readl(ts->clk_regs + reg);
}
+/**
+ * ccroc_writel() - writes a value to a CCROC register
+ * @ts: pointer to a struct tegra_soctherm
+ * @v: the value to write
+ * @reg: the register offset
+ *
+ * Writes @v to @reg. No return value.
+ */
+static inline void ccroc_writel(struct tegra_soctherm *ts, u32 value, u32 reg)
+{
+ writel(value, (ts->ccroc_regs + reg));
+}
+
+/**
+ * ccroc_readl() - reads specified register from CCROC IP block
+ * @ts: pointer to a struct tegra_soctherm
+ * @reg: register address to be read
+ *
+ * Return: the value of the register
+ */
+static inline u32 ccroc_readl(struct tegra_soctherm *ts, u32 reg)
+{
+ return readl(ts->ccroc_regs + reg);
+}
+
static void enable_tsensor(struct tegra_soctherm *tegra, unsigned int i)
{
const struct tegra_tsensor *sensor = &tegra->soc->tsensors[i];
@@ -552,9 +601,6 @@ static int tegra_soctherm_set_hwtrips(struct device *dev,
sg->name, temperature);
set_throttle:
- if (ts->soc->use_ccroc)
- return 0;
-
ret = get_hot_temp(tz, &trip, &temperature);
if (ret) {
dev_warn(dev, "throttle: %s: missing hot temperature\n",
@@ -676,9 +722,6 @@ static int regs_show(struct seq_file *s, void *data)
state = REG_GET_MASK(r, SENSOR_TEMP2_MEM_TEMP_MASK);
seq_printf(s, " MEM(%d)\n", translate_temp(state));
- if (ts->soc->use_ccroc)
- return 0;
-
for (i = 0; i < ts->soc->num_ttgs; i++) {
seq_printf(s, "%s:\n", ttgs[i]->name);
for (level = 0; level < 4; level++) {
@@ -779,12 +822,17 @@ static int regs_show(struct seq_file *s, void *data)
seq_printf(s, "enabled(%d)\n", state);
r = readl(ts->regs + CPU_PSKIP_STATUS);
- state = REG_GET_MASK(r, XPU_PSKIP_STATUS_M_MASK);
- seq_printf(s, "CPU PSKIP STATUS: M(%d) ", state);
- state = REG_GET_MASK(r, XPU_PSKIP_STATUS_N_MASK);
- seq_printf(s, "N(%d) ", state);
- state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK);
- seq_printf(s, "enabled(%d)\n", state);
+ if (ts->soc->use_ccroc) {
+ state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK);
+ seq_printf(s, "CPU PSKIP STATUS: enabled(%d)\n", state);
+ } else {
+ state = REG_GET_MASK(r, XPU_PSKIP_STATUS_M_MASK);
+ seq_printf(s, "CPU PSKIP STATUS: M(%d) ", state);
+ state = REG_GET_MASK(r, XPU_PSKIP_STATUS_N_MASK);
+ seq_printf(s, "N(%d) ", state);
+ state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK);
+ seq_printf(s, "enabled(%d)\n", state);
+ }
return 0;
}
@@ -939,14 +987,27 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
}
stc->priority = val;
- r = of_property_read_u32(np_stcc, "cpu-throt-depth", &val);
- if (r) {
- dev_info(dev,
- "throttle-cfg: %s: missing cpu_throt_depth\n",
- name);
- continue;
+ if (ts->soc->use_ccroc) {
+ r = of_property_read_u32(np_stcc, "cpu-throt-level",
+ &val);
+ if (r) {
+ dev_info(dev,
+ "throttle-cfg: %s: missing cpu_throt_level\n",
+ name);
+ continue;
+ }
+ stc->cpu_throt_level = val;
+ } else {
+ r = of_property_read_u32(np_stcc, "cpu-throt-depth",
+ &val);
+ if (r) {
+ dev_info(dev,
+ "throttle-cfg: %s: missing cpu_throt_depth\n",
+ name);
+ continue;
+ }
+ stc->cpu_throt_depth = val;
}
- stc->cpu_throt_depth = val;
tcd = thermal_of_cooling_device_register(np_stcc,
(char *)name, ts,
@@ -967,6 +1028,96 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
}
/**
+ * throttlectl_cpu_level_cfg() - programs CCROC NV_THERM level config
+ * @level: describing the level LOW/MED/HIGH of throttling
+ *
+ * It's necessary to set up the CPU-local CCROC NV_THERM instance with
+ * the M/N values desired for each level. This function does this.
+ *
+ * This function pre-programs the CCROC NV_THERM levels in terms of
+ * pre-configured "Low", "Medium" or "Heavy" throttle levels which are
+ * mapped to THROT_LEVEL_LOW, THROT_LEVEL_MED and THROT_LEVEL_HVY.
+ */
+static void throttlectl_cpu_level_cfg(struct tegra_soctherm *ts, int level)
+{
+ u8 depth, dividend;
+ u32 r;
+
+ switch (level) {
+ case TEGRA_SOCTHERM_THROT_LEVEL_LOW:
+ depth = 50;
+ break;
+ case TEGRA_SOCTHERM_THROT_LEVEL_MED:
+ depth = 75;
+ break;
+ case TEGRA_SOCTHERM_THROT_LEVEL_HIGH:
+ depth = 80;
+ break;
+ case TEGRA_SOCTHERM_THROT_LEVEL_NONE:
+ return;
+ default:
+ return;
+ }
+
+ dividend = THROT_DEPTH_DIVIDEND(depth);
+
+ /* setup PSKIP in ccroc nv_therm registers */
+ r = ccroc_readl(ts, CCROC_THROT_PSKIP_RAMP_CPU_REG(level));
+ r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_DURATION_MASK, 0xff);
+ r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_STEP_MASK, 0xf);
+ ccroc_writel(ts, r, CCROC_THROT_PSKIP_RAMP_CPU_REG(level));
+
+ r = ccroc_readl(ts, CCROC_THROT_PSKIP_CTRL_CPU_REG(level));
+ r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_ENB_MASK, 1);
+ r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend);
+ r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff);
+ ccroc_writel(ts, r, CCROC_THROT_PSKIP_CTRL_CPU_REG(level));
+}
+
+/**
+ * throttlectl_cpu_level_select() - program CPU pulse skipper config
+ * @throt: the LIGHT/HEAVY of throttle event id
+ *
+ * Pulse skippers are used to throttle clock frequencies. This
+ * function programs the pulse skippers based on @throt and platform
+ * data. This function is used on SoCs which have CPU-local pulse
+ * skipper control, such as T13x. It programs soctherm's interface to
+ * Denver:CCROC NV_THERM in terms of Low, Medium and HIGH throttling
+ * vectors. PSKIP_BYPASS mode is set as required per HW spec.
+ */
+static void throttlectl_cpu_level_select(struct tegra_soctherm *ts,
+ enum soctherm_throttle_id throt)
+{
+ u32 r, throt_vect;
+
+ /* Denver:CCROC NV_THERM interface N:3 Mapping */
+ switch (ts->throt_cfgs[throt].cpu_throt_level) {
+ case TEGRA_SOCTHERM_THROT_LEVEL_LOW:
+ throt_vect = THROT_VECT_LOW;
+ break;
+ case TEGRA_SOCTHERM_THROT_LEVEL_MED:
+ throt_vect = THROT_VECT_MED;
+ break;
+ case TEGRA_SOCTHERM_THROT_LEVEL_HIGH:
+ throt_vect = THROT_VECT_HIGH;
+ break;
+ default:
+ throt_vect = THROT_VECT_NONE;
+ break;
+ }
+
+ r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
+ r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1);
+ r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_CPU_MASK, throt_vect);
+ r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT2_CPU_MASK, throt_vect);
+ writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
+
+ /* bypass sequencer in soc_therm as it is programmed in ccroc */
+ r = REG_SET_MASK(0, THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK, 1);
+ writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
+}
+
+/**
* throttlectl_cpu_mn() - program CPU pulse skipper configuration
* @throt: the LIGHT/HEAVY of throttle event id
*
@@ -1016,7 +1167,10 @@ static void soctherm_throttle_program(struct tegra_soctherm *ts,
return;
/* Setup PSKIP parameters */
- throttlectl_cpu_mn(ts, throt);
+ if (ts->soc->use_ccroc)
+ throttlectl_cpu_level_select(ts, throt);
+ else
+ throttlectl_cpu_mn(ts, throt);
r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority);
writel(r, ts->regs + THROT_PRIORITY_CTRL(throt));
@@ -1039,6 +1193,13 @@ static void tegra_soctherm_throttle(struct device *dev)
u32 v;
int i;
+ /* configure LOW, MED and HIGH levels for CCROC NV_THERM */
+ if (ts->soc->use_ccroc) {
+ throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_LOW);
+ throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_MED);
+ throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_HIGH);
+ }
+
/* Thermal HW throttle programming */
for (i = 0; i < THROTTLE_SIZE; i++)
soctherm_throttle_program(ts, i);
@@ -1083,9 +1244,6 @@ static void soctherm_init(struct platform_device *pdev)
writel(pdiv, tegra->regs + SENSOR_PDIV);
writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF);
- if (tegra->soc->use_ccroc)
- return;
-
/* Configure hw throttle */
tegra_soctherm_throttle(&pdev->dev);
}
@@ -1156,6 +1314,14 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "can't get car clk registers");
return PTR_ERR(tegra->clk_regs);
}
+ } else {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "ccroc-reg");
+ tegra->ccroc_regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tegra->ccroc_regs)) {
+ dev_err(&pdev->dev, "can't get ccroc registers");
+ return PTR_ERR(tegra->ccroc_regs);
+ }
}
tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm");
@@ -1206,8 +1372,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
if (err)
return err;
- if (!tegra->soc->use_ccroc)
- soctherm_init_hw_throt_cdev(pdev);
+ soctherm_init_hw_throt_cdev(pdev);
soctherm_init(pdev);
diff --git a/drivers/thermal/tegra/tegra132-soctherm.c b/drivers/thermal/tegra/tegra132-soctherm.c
index ae5d61af2df3..97fa30501eb1 100644
--- a/drivers/thermal/tegra/tegra132-soctherm.c
+++ b/drivers/thermal/tegra/tegra132-soctherm.c
@@ -28,7 +28,11 @@
#define TEGRA132_THERMTRIP_CPU_THRESH_MASK (0xff << 8)
#define TEGRA132_THERMTRIP_TSENSE_THRESH_MASK 0xff
+#define TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK (0xff << 17)
+#define TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK (0xff << 9)
+
#define TEGRA132_THRESH_GRAIN 1000
+#define TEGRA132_BPTT 8
static const struct tegra_tsensor_configuration tegra132_tsensor_config = {
.tall = 16300,
@@ -51,6 +55,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = {
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
+ .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = {
@@ -66,6 +73,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = {
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
+ .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group tegra132_tsensor_group_pll = {
@@ -79,6 +89,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_pll = {
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK,
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
+ .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group tegra132_tsensor_group_mem = {
@@ -94,6 +107,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_mem = {
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK,
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
+ .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group *tegra132_tsensor_groups[] = {
@@ -193,5 +209,6 @@ const struct tegra_soctherm_soc tegra132_soctherm = {
.num_ttgs = ARRAY_SIZE(tegra132_tsensor_groups),
.tfuse = &tegra132_soctherm_fuse,
.thresh_grain = TEGRA132_THRESH_GRAIN,
+ .bptt = TEGRA132_BPTT,
.use_ccroc = true,
};
diff --git a/include/dt-bindings/thermal/tegra124-soctherm.h b/include/dt-bindings/thermal/tegra124-soctherm.h
index 729ab9fc325e..2a99f1d52bb5 100644
--- a/include/dt-bindings/thermal/tegra124-soctherm.h
+++ b/include/dt-bindings/thermal/tegra124-soctherm.h
@@ -11,4 +11,9 @@
#define TEGRA124_SOCTHERM_SENSOR_PLLX 3
#define TEGRA124_SOCTHERM_SENSOR_NUM 4
+#define TEGRA_SOCTHERM_THROT_LEVEL_LOW 0
+#define TEGRA_SOCTHERM_THROT_LEVEL_MED 1
+#define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 2
+#define TEGRA_SOCTHERM_THROT_LEVEL_NONE -1
+
#endif
--
1.9.1
Tegra soctherm support HW throttle, when the soctherm snesors'
temperature is above the throttle trip point, it will trigger
pulse skiper to tune clocks accroding to the throttle depth.
Add this function for Tegra124 and Tegra210.
Since Tegra132 use different registers to configure pulse skiper,
will support it in next patch.
Signed-off-by: Wei Ni <[email protected]>
---
drivers/thermal/tegra/soctherm.c | 667 +++++++++++++++++++++++++++++-
drivers/thermal/tegra/soctherm.h | 10 +
drivers/thermal/tegra/tegra124-soctherm.c | 18 +
drivers/thermal/tegra/tegra132-soctherm.c | 1 +
drivers/thermal/tegra/tegra210-soctherm.c | 18 +
5 files changed, 699 insertions(+), 15 deletions(-)
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index b8651726201e..e6c4085f876d 100644
--- a/drivers/thermal/tegra/soctherm.c
+++ b/drivers/thermal/tegra/soctherm.c
@@ -30,6 +30,7 @@
#include <dt-bindings/thermal/tegra124-soctherm.h>
+#include "../thermal_core.h"
#include "soctherm.h"
#define SENSOR_CONFIG0 0
@@ -67,35 +68,179 @@
#define READBACK_ADD_HALF BIT(7)
#define READBACK_NEGATE BIT(0)
+/*
+ * THERMCTL_LEVEL0_GROUP_CPU is defined in soctherm.h
+ * because it will be used by tegraxxx_soctherm.c
+ */
+#define THERMCTL_LVL0_CPU0_EN_MASK BIT(8)
+#define THERMCTL_LVL0_CPU0_CPU_THROT_MASK (0x3 << 5)
+#define THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT 0x1
+#define THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY 0x2
+#define THERMCTL_LVL0_CPU0_GPU_THROT_MASK (0x3 << 3)
+#define THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT 0x1
+#define THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY 0x2
+#define THERMCTL_LVL0_CPU0_MEM_THROT_MASK BIT(2)
+#define THERMCTL_LVL0_CPU0_STATUS_MASK 0x3
+
+#define THERMCTL_LVL0_UP_STATS 0x10
+#define THERMCTL_LVL0_DN_STATS 0x14
+
+#define THERMCTL_STATS_CTL 0x94
+#define STATS_CTL_CLR_DN 0x8
+#define STATS_CTL_EN_DN 0x4
+#define STATS_CTL_CLR_UP 0x2
+#define STATS_CTL_EN_UP 0x1
+
+#define THROT_GLOBAL_CFG 0x400
+#define THROT_GLOBAL_ENB_MASK BIT(0)
+
+#define CPU_PSKIP_STATUS 0x418
+#define XPU_PSKIP_STATUS_M_MASK (0xff << 12)
+#define XPU_PSKIP_STATUS_N_MASK (0xff << 4)
+#define XPU_PSKIP_STATUS_SW_OVERRIDE_MASK BIT(1)
+#define XPU_PSKIP_STATUS_ENABLED_MASK BIT(0)
+
+#define THROT_PRIORITY_LOCK 0x424
+#define THROT_PRIORITY_LOCK_PRIORITY_MASK 0xff
+
+#define THROT_STATUS 0x428
+#define THROT_STATUS_BREACH_MASK BIT(12)
+#define THROT_STATUS_STATE_MASK (0xff << 4)
+#define THROT_STATUS_ENABLED_MASK BIT(0)
+
+#define THROT_PSKIP_CTRL_LITE_CPU 0x430
+#define THROT_PSKIP_CTRL_ENABLE_MASK BIT(31)
+#define THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8)
+#define THROT_PSKIP_CTRL_DIVISOR_MASK 0xff
+#define THROT_PSKIP_CTRL_VECT_GPU_MASK (0x7 << 16)
+#define THROT_PSKIP_CTRL_VECT_CPU_MASK (0x7 << 8)
+#define THROT_PSKIP_CTRL_VECT2_CPU_MASK 0x7
+
+#define THROT_VECT_NONE 0x0 /* 3'b000 */
+#define THROT_VECT_LOW 0x1 /* 3'b001 */
+#define THROT_VECT_MED 0x3 /* 3'b011 */
+#define THROT_VECT_HIGH 0x7 /* 3'b111 */
+
+#define THROT_PSKIP_RAMP_LITE_CPU 0x434
+#define THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31)
+#define THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8)
+#define THROT_PSKIP_RAMP_STEP_MASK 0xff
+
+#define THROT_PRIORITY_LITE 0x444
+#define THROT_PRIORITY_LITE_PRIO_MASK 0xff
+
+#define THROT_DELAY_LITE 0x448
+#define THROT_DELAY_LITE_DELAY_MASK 0xff
+
+/* car register offsets needed for enabling HW throttling */
+#define CAR_SUPER_CCLKG_DIVIDER 0x36c
+#define CDIVG_USE_THERM_CONTROLS_MASK BIT(30)
+
/* get val from register(r) mask bits(m) */
#define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1))
/* set val(v) to mask bits(m) of register(r) */
#define REG_SET_MASK(r, m, v) (((r) & ~(m)) | \
(((v) & (m >> (ffs(m) - 1))) << (ffs(m) - 1)))
+/* get dividend from the depth */
+#define THROT_DEPTH_DIVIDEND(depth) ((256 * (100 - (depth)) / 100) - 1)
+
+/* get THROT_PSKIP_xxx offset per LIGHT/HEAVY throt and CPU/GPU dev */
+#define THROT_OFFSET 0x30
+#define THROT_PSKIP_CTRL(throt, dev) (THROT_PSKIP_CTRL_LITE_CPU + \
+ (THROT_OFFSET * throt) + (8 * dev))
+#define THROT_PSKIP_RAMP(throt, dev) (THROT_PSKIP_RAMP_LITE_CPU + \
+ (THROT_OFFSET * throt) + (8 * dev))
+
+/* get THROT_xxx_CTRL offset per LIGHT/HEAVY throt */
+#define THROT_PRIORITY_CTRL(throt) (THROT_PRIORITY_LITE + \
+ (THROT_OFFSET * throt))
+#define THROT_DELAY_CTRL(throt) (THROT_DELAY_LITE + \
+ (THROT_OFFSET * throt))
+
+/* get THERMCTL_LEVELx offset per CPU/GPU/MEM/TSENSE rg and LEVEL0~3 lv */
+#define THERMCTL_LVL_REGS_SIZE 0x20
+#define THERMCTL_LVL_REG(rg, lv) ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE))
+
static const int min_low_temp = -127000;
static const int max_high_temp = 127000;
+enum soctherm_throttle_id {
+ THROTTLE_LIGHT = 0,
+ THROTTLE_HEAVY,
+ THROTTLE_SIZE,
+};
+
+enum soctherm_throttle_dev_id {
+ THROTTLE_DEV_CPU = 0,
+ THROTTLE_DEV_GPU,
+ THROTTLE_DEV_SIZE,
+};
+
+static const char *const throt_names[] = {
+ [THROTTLE_LIGHT] = "light",
+ [THROTTLE_HEAVY] = "heavy",
+};
+
+struct tegra_soctherm;
struct tegra_thermctl_zone {
void __iomem *reg;
struct device *dev;
+ struct tegra_soctherm *ts;
struct thermal_zone_device *tz;
const struct tegra_tsensor_group *sg;
};
+struct soctherm_throt_cfg {
+ const char *name;
+ unsigned int id;
+ u8 priority;
+ u32 cpu_throt_depth;
+ struct thermal_cooling_device *cdev;
+ bool init;
+};
+
struct tegra_soctherm {
struct reset_control *reset;
struct clk *clock_tsensor;
struct clk *clock_soctherm;
void __iomem *regs;
- struct thermal_zone_device **thermctl_tzs;
+ void __iomem *clk_regs;
u32 *calib;
+ struct thermal_zone_device **thermctl_tzs;
struct tegra_soctherm_soc *soc;
+ struct soctherm_throt_cfg throt_cfgs[THROTTLE_SIZE];
+
struct dentry *debugfs_dir;
};
+/**
+ * clk_writel() - writes a value to a CAR register
+ * @ts: pointer to a struct tegra_soctherm
+ * @v: the value to write
+ * @reg: the register offset
+ *
+ * Writes @v to @reg. No return value.
+ */
+static inline void clk_writel(struct tegra_soctherm *ts, u32 value, u32 reg)
+{
+ writel(value, (ts->clk_regs + reg));
+}
+
+/**
+ * clk_readl() - reads specified register from CAR IP block
+ * @ts: pointer to a struct tegra_soctherm
+ * @reg: register address to be read
+ *
+ * Return: the value of the register
+ */
+static inline u32 clk_readl(struct tegra_soctherm *ts, u32 reg)
+{
+ return readl(ts->clk_regs + reg);
+}
+
static void enable_tsensor(struct tegra_soctherm *tegra, unsigned int i)
{
const struct tegra_tsensor *sensor = &tegra->soc->tsensors[i];
@@ -150,11 +295,17 @@ static int tegra_thermctl_get_temp(void *data, int *out_temp)
static int
thermtrip_program(struct device *dev, const struct tegra_tsensor_group *sg,
int trip_temp);
+static int
+throttrip_program(struct device *dev, const struct tegra_tsensor_group *sg,
+ struct soctherm_throt_cfg *stc, int trip_temp);
+static struct soctherm_throt_cfg *
+find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name);
static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp)
{
struct tegra_thermctl_zone *zone = data;
struct thermal_zone_device *tz = zone->tz;
+ struct tegra_soctherm *ts = zone->ts;
const struct tegra_tsensor_group *sg = zone->sg;
struct device *dev = zone->dev;
enum thermal_trip_type type;
@@ -167,10 +318,29 @@ static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp)
if (ret)
return ret;
- if (type != THERMAL_TRIP_CRITICAL)
- return 0;
+ if (type == THERMAL_TRIP_CRITICAL) {
+ return thermtrip_program(dev, sg, temp);
+ } else if (type == THERMAL_TRIP_HOT) {
+ int i;
+
+ for (i = 0; i < THROTTLE_SIZE; i++) {
+ struct thermal_cooling_device *cdev;
+ struct soctherm_throt_cfg *stc;
- return thermtrip_program(dev, sg, temp);
+ if (!ts->throt_cfgs[i].init)
+ continue;
+
+ cdev = ts->throt_cfgs[i].cdev;
+ if (get_thermal_instance(tz, cdev, trip))
+ stc = find_throttle_cfg_by_name(ts, cdev->type);
+ else
+ continue;
+
+ return throttrip_program(dev, sg, stc, temp);
+ }
+ }
+
+ return 0;
}
static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
@@ -238,14 +408,110 @@ static int thermtrip_program(struct device *dev,
}
/**
+ * throttrip_program() - Configures the hardware to throttle the
+ * pulse if a given sensor group reaches a given temperature
+ * @dev: ptr to the struct device for the SOC_THERM IP block
+ * @sg: pointer to the sensor group to set the thermtrip temperature for
+ * @stc: pointer to the throttle need to be triggered
+ * @trip_temp: the temperature in millicelsius to trigger the thermal trip at
+ *
+ * Sets the thermal trip threshold and throttle event of the given sensor
+ * group. If this threshold is crossed, the hardware will trigger the
+ * throttle.
+ *
+ * Note that, although @trip_temp is specified in millicelsius, the
+ * hardware is programmed in degrees Celsius.
+ *
+ * Return: 0 upon success, or %-EINVAL upon failure.
+ */
+static int throttrip_program(struct device *dev,
+ const struct tegra_tsensor_group *sg,
+ struct soctherm_throt_cfg *stc,
+ int trip_temp)
+{
+ struct tegra_soctherm *ts = dev_get_drvdata(dev);
+ int temp, cpu_throt, gpu_throt;
+ unsigned int throt;
+ u32 r, reg_off;
+
+ if (!dev || !sg || !stc || !stc->init)
+ return -EINVAL;
+
+ temp = enforce_temp_range(dev, trip_temp) / ts->soc->thresh_grain;
+
+ /* Hardcode LIGHT on LEVEL1 and HEAVY on LEVEL2 */
+ throt = stc->id;
+ reg_off = THERMCTL_LVL_REG(sg->thermctl_lvl0_offset, throt + 1);
+
+ if (throt == THROTTLE_LIGHT) {
+ cpu_throt = THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT;
+ gpu_throt = THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT;
+ } else {
+ cpu_throt = THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY;
+ gpu_throt = THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY;
+ if (throt != THROTTLE_HEAVY)
+ dev_warn(dev,
+ "invalid throt id %d - assuming HEAVY",
+ throt);
+ }
+
+ r = readl(ts->regs + reg_off);
+ r = REG_SET_MASK(r, sg->thermctl_lvl0_up_thresh_mask, temp);
+ r = REG_SET_MASK(r, sg->thermctl_lvl0_dn_thresh_mask, temp);
+ r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_CPU_THROT_MASK, cpu_throt);
+ r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_GPU_THROT_MASK, gpu_throt);
+ r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 1);
+ writel(r, ts->regs + reg_off);
+
+ return 0;
+}
+
+static struct soctherm_throt_cfg *
+find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; ts->throt_cfgs[i].name; i++)
+ if (!strcmp(ts->throt_cfgs[i].name, name))
+ return &ts->throt_cfgs[i];
+
+ return NULL;
+}
+
+static int get_hot_temp(struct thermal_zone_device *tz, int *trip, int *temp)
+{
+ int ntrips, i, ret;
+ enum thermal_trip_type type;
+
+ ntrips = of_thermal_get_ntrips(tz);
+ if (ntrips <= 0)
+ return -EINVAL;
+
+ for (i = 0; i < ntrips; i++) {
+ ret = tz->ops->get_trip_type(tz, i, &type);
+ if (ret)
+ return -EINVAL;
+ if (type == THERMAL_TRIP_HOT) {
+ ret = tz->ops->get_trip_temp(tz, i, temp);
+ if (!ret)
+ *trip = i;
+
+ return ret;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/**
* tegra_soctherm_set_hwtrips() - set HW trip point from DT data
* @dev: struct device * of the SOC_THERM instance
*
* Configure the SOC_THERM HW trip points, setting "THERMTRIP"
- * trip points , using "critical" type trip_temp from thermal
- * zone.
- * After they have been configured, THERMTRIP will take action
- * when the configured SoC thermal sensor group reaches a
+ * "THROTTLE" trip points , using "critical" or "hot" type trip_temp
+ * from thermal zone.
+ * After they have been configured, THERMTRIP or THROTTLE will take
+ * action when the configured SoC thermal sensor group reaches a
* certain temperature.
*
* Return: 0 upon success, or a negative error code on failure.
@@ -254,19 +520,24 @@ static int thermtrip_program(struct device *dev,
* THERMTRIP has been enabled successfully when a message similar to
* this one appears on the serial console:
* "thermtrip: will shut down when sensor group XXX reaches YYYYYY mC"
+ * THROTTLE has been enabled successfully when a message similar to
+ * this one appears on the serial console:
+ * ""throttrip: will throttle when sensor group XXX reaches YYYYYY mC"
*/
static int tegra_soctherm_set_hwtrips(struct device *dev,
const struct tegra_tsensor_group *sg,
struct thermal_zone_device *tz)
{
- int temperature;
+ struct tegra_soctherm *ts = dev_get_drvdata(dev);
+ struct soctherm_throt_cfg *stc;
+ int i, trip, temperature;
int ret;
ret = tz->ops->get_crit_temp(tz, &temperature);
if (ret) {
dev_warn(dev, "thermtrip: %s: missing critical temperature\n",
sg->name);
- return ret;
+ goto set_throttle;
}
ret = thermtrip_program(dev, sg, temperature);
@@ -280,6 +551,46 @@ static int tegra_soctherm_set_hwtrips(struct device *dev,
"thermtrip: will shut down when %s reaches %d mC\n",
sg->name, temperature);
+set_throttle:
+ if (ts->soc->use_ccroc)
+ return 0;
+
+ ret = get_hot_temp(tz, &trip, &temperature);
+ if (ret) {
+ dev_warn(dev, "throttle: %s: missing hot temperature\n",
+ sg->name);
+ return 0;
+ }
+
+ for (i = 0; i < THROTTLE_SIZE; i++) {
+ struct thermal_cooling_device *cdev;
+
+ if (!ts->throt_cfgs[i].init)
+ continue;
+
+ cdev = ts->throt_cfgs[i].cdev;
+ if (get_thermal_instance(tz, cdev, trip))
+ stc = find_throttle_cfg_by_name(ts, cdev->type);
+ else
+ continue;
+
+ ret = throttrip_program(dev, sg, stc, temperature);
+ if (ret) {
+ dev_err(dev, "throttrip: %s: error during enable\n",
+ sg->name);
+ return ret;
+ }
+
+ dev_info(dev,
+ "throttrip: will throttle when %s reaches %d mC\n",
+ sg->name, temperature);
+ break;
+ }
+
+ if (i == THROTTLE_SIZE)
+ dev_warn(dev, "throttrip: %s: missing throttle cdev\n",
+ sg->name);
+
return 0;
}
@@ -291,7 +602,7 @@ static int regs_show(struct seq_file *s, void *data)
const struct tegra_tsensor *tsensors = ts->soc->tsensors;
const struct tegra_tsensor_group **ttgs = ts->soc->ttgs;
u32 r, state;
- int i;
+ int i, level;
seq_puts(s, "-----TSENSE (convert HW)-----\n");
@@ -365,6 +676,84 @@ static int regs_show(struct seq_file *s, void *data)
state = REG_GET_MASK(r, SENSOR_TEMP2_MEM_TEMP_MASK);
seq_printf(s, " MEM(%d)\n", translate_temp(state));
+ if (ts->soc->use_ccroc)
+ return 0;
+
+ for (i = 0; i < ts->soc->num_ttgs; i++) {
+ seq_printf(s, "%s:\n", ttgs[i]->name);
+ for (level = 0; level < 4; level++) {
+ s32 v;
+ u32 mask;
+ u16 off = ttgs[i]->thermctl_lvl0_offset;
+
+ r = readl(ts->regs + THERMCTL_LVL_REG(off, level));
+
+ mask = ttgs[i]->thermctl_lvl0_up_thresh_mask;
+ state = REG_GET_MASK(r, mask);
+ v = sign_extend32(state, ts->soc->bptt - 1);
+ v *= ts->soc->thresh_grain;
+ seq_printf(s, " %d: Up/Dn(%d /", level, v);
+
+ mask = ttgs[i]->thermctl_lvl0_dn_thresh_mask;
+ state = REG_GET_MASK(r, mask);
+ v = sign_extend32(state, ts->soc->bptt - 1);
+ v *= ts->soc->thresh_grain;
+ seq_printf(s, "%d ) ", v);
+
+ mask = THERMCTL_LVL0_CPU0_EN_MASK;
+ state = REG_GET_MASK(r, mask);
+ seq_printf(s, "En(%d) ", state);
+
+ mask = THERMCTL_LVL0_CPU0_CPU_THROT_MASK;
+ state = REG_GET_MASK(r, mask);
+ seq_puts(s, "CPU Throt");
+ if (!state)
+ seq_printf(s, "(%s) ", "none");
+ else if (state == THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT)
+ seq_printf(s, "(%s) ", "L");
+ else if (state == THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY)
+ seq_printf(s, "(%s) ", "H");
+ else
+ seq_printf(s, "(%s) ", "H+L");
+
+ mask = THERMCTL_LVL0_CPU0_GPU_THROT_MASK;
+ state = REG_GET_MASK(r, mask);
+ seq_puts(s, "GPU Throt");
+ if (!state)
+ seq_printf(s, "(%s) ", "none");
+ else if (state == THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT)
+ seq_printf(s, "(%s) ", "L");
+ else if (state == THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY)
+ seq_printf(s, "(%s) ", "H");
+ else
+ seq_printf(s, "(%s) ", "H+L");
+
+ mask = THERMCTL_LVL0_CPU0_STATUS_MASK;
+ state = REG_GET_MASK(r, mask);
+ seq_printf(s, "Status(%s)\n",
+ state == 0 ? "LO" :
+ state == 1 ? "In" :
+ state == 2 ? "Res" : "HI");
+ }
+ }
+
+ r = readl(ts->regs + THERMCTL_STATS_CTL);
+ seq_printf(s, "STATS: Up(%s) Dn(%s)\n",
+ r & STATS_CTL_EN_UP ? "En" : "--",
+ r & STATS_CTL_EN_DN ? "En" : "--");
+
+ for (level = 0; level < 4; level++) {
+ u16 off;
+
+ off = THERMCTL_LVL0_UP_STATS;
+ r = readl(ts->regs + THERMCTL_LVL_REG(off, level));
+ seq_printf(s, " Level_%d Up(%d) ", level, r);
+
+ off = THERMCTL_LVL0_DN_STATS;
+ r = readl(ts->regs + THERMCTL_LVL_REG(off, level));
+ seq_printf(s, "Dn(%d)\n", r);
+ }
+
r = readl(ts->regs + THERMCTL_THERMTRIP_CTL);
state = REG_GET_MASK(r, ttgs[0]->thermtrip_any_en_mask);
seq_printf(s, "Thermtrip Any En(%d)\n", state);
@@ -376,6 +765,27 @@ static int regs_show(struct seq_file *s, void *data)
seq_printf(s, "Thresh(%d)\n", state);
}
+ r = readl(ts->regs + THROT_GLOBAL_CFG);
+ seq_puts(s, "\n");
+ seq_printf(s, "GLOBAL THROTTLE CONFIG: 0x%08x\n", r);
+
+ seq_puts(s, "---------------------------------------------------\n");
+ r = readl(ts->regs + THROT_STATUS);
+ state = REG_GET_MASK(r, THROT_STATUS_BREACH_MASK);
+ seq_printf(s, "THROT STATUS: breach(%d) ", state);
+ state = REG_GET_MASK(r, THROT_STATUS_STATE_MASK);
+ seq_printf(s, "state(%d) ", state);
+ state = REG_GET_MASK(r, THROT_STATUS_ENABLED_MASK);
+ seq_printf(s, "enabled(%d)\n", state);
+
+ r = readl(ts->regs + CPU_PSKIP_STATUS);
+ state = REG_GET_MASK(r, XPU_PSKIP_STATUS_M_MASK);
+ seq_printf(s, "CPU PSKIP STATUS: M(%d) ", state);
+ state = REG_GET_MASK(r, XPU_PSKIP_STATUS_N_MASK);
+ seq_printf(s, "N(%d) ", state);
+ state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK);
+ seq_printf(s, "enabled(%d)\n", state);
+
return 0;
}
@@ -449,6 +859,203 @@ static int soctherm_clk_enable(struct platform_device *pdev, bool enable)
return 0;
}
+static int throt_get_cdev_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *max_state)
+{
+ *max_state = 1;
+ return 0;
+}
+
+static int throt_get_cdev_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *cur_state)
+{
+ struct tegra_soctherm *ts = cdev->devdata;
+ u32 r;
+
+ r = readl(ts->regs + THROT_STATUS);
+ if (REG_GET_MASK(r, THROT_STATUS_STATE_MASK))
+ *cur_state = 1;
+ else
+ *cur_state = 0;
+
+ return 0;
+}
+
+static int throt_set_cdev_state(struct thermal_cooling_device *cdev,
+ unsigned long cur_state)
+{
+ return 0;
+}
+
+static struct thermal_cooling_device_ops throt_cooling_ops = {
+ .get_max_state = throt_get_cdev_max_state,
+ .get_cur_state = throt_get_cdev_cur_state,
+ .set_cur_state = throt_set_cdev_state,
+};
+
+/**
+ * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations
+ * and register them as cooling devices.
+ */
+static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct tegra_soctherm *ts = dev_get_drvdata(dev);
+ struct device_node *np_stc, *np_stcc;
+ const char *name;
+ u32 val;
+ int i, r;
+
+ for (i = 0; i < THROTTLE_SIZE; i++) {
+ ts->throt_cfgs[i].name = throt_names[i];
+ ts->throt_cfgs[i].id = i;
+ ts->throt_cfgs[i].init = false;
+ }
+
+ np_stc = of_get_child_by_name(dev->of_node, "throttle-cfgs");
+ if (!np_stc) {
+ dev_info(dev,
+ "throttle-cfg: no throttle-cfgs - not enabling\n");
+ return;
+ }
+
+ for_each_child_of_node(np_stc, np_stcc) {
+ struct soctherm_throt_cfg *stc;
+ struct thermal_cooling_device *tcd;
+
+ name = np_stcc->name;
+ stc = find_throttle_cfg_by_name(ts, name);
+ if (!stc) {
+ dev_err(dev,
+ "throttle-cfg: could not find %s\n", name);
+ continue;
+ }
+
+ r = of_property_read_u32(np_stcc, "priority", &val);
+ if (r) {
+ dev_info(dev,
+ "throttle-cfg: %s: missing priority\n", name);
+ continue;
+ }
+ stc->priority = val;
+
+ r = of_property_read_u32(np_stcc, "cpu-throt-depth", &val);
+ if (r) {
+ dev_info(dev,
+ "throttle-cfg: %s: missing cpu_throt_depth\n",
+ name);
+ continue;
+ }
+ stc->cpu_throt_depth = val;
+
+ tcd = thermal_of_cooling_device_register(np_stcc,
+ (char *)name, ts,
+ &throt_cooling_ops);
+ of_node_put(np_stcc);
+ if (IS_ERR_OR_NULL(tcd)) {
+ dev_err(dev,
+ "throttle-cfg: %s: failed to register cooling device\n",
+ name);
+ continue;
+ }
+
+ stc->cdev = tcd;
+ stc->init = true;
+ }
+
+ of_node_put(np_stc);
+}
+
+/**
+ * throttlectl_cpu_mn() - program CPU pulse skipper configuration
+ * @throt: the LIGHT/HEAVY of throttle event id
+ *
+ * Pulse skippers are used to throttle clock frequencies. This
+ * function programs the pulse skippers based on @throt and platform
+ * data. This function is used for CPUs that have "remote" pulse
+ * skipper control, e.g., the CPU pulse skipper is controlled by the
+ * SOC_THERM IP block. (SOC_THERM is located outside the CPU
+ * complex.)
+ */
+static void throttlectl_cpu_mn(struct tegra_soctherm *ts,
+ enum soctherm_throttle_id throt)
+{
+ u32 r;
+ int depth;
+ u8 dividend;
+
+ depth = ts->throt_cfgs[throt].cpu_throt_depth;
+ dividend = THROT_DEPTH_DIVIDEND(depth);
+
+ r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
+ r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1);
+ r = REG_SET_MASK(r, THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend);
+ r = REG_SET_MASK(r, THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff);
+ writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
+
+ r = readl(ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
+ r = REG_SET_MASK(r, THROT_PSKIP_RAMP_DURATION_MASK, 0xff);
+ r = REG_SET_MASK(r, THROT_PSKIP_RAMP_STEP_MASK, 0xf);
+ writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
+}
+
+/**
+ * soctherm_throttle_program() - programs pulse skippers' configuration
+ * @throt: the LIGHT/HEAVY of the throttle event id.
+ *
+ * Pulse skippers are used to throttle clock frequencies.
+ * This function programs the pulse skippers.
+ */
+static void soctherm_throttle_program(struct tegra_soctherm *ts,
+ enum soctherm_throttle_id throt)
+{
+ u32 r;
+ struct soctherm_throt_cfg stc = ts->throt_cfgs[throt];
+
+ if (!stc.init)
+ return;
+
+ /* Setup PSKIP parameters */
+ throttlectl_cpu_mn(ts, throt);
+
+ r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority);
+ writel(r, ts->regs + THROT_PRIORITY_CTRL(throt));
+
+ r = REG_SET_MASK(0, THROT_DELAY_LITE_DELAY_MASK, 0);
+ writel(r, ts->regs + THROT_DELAY_CTRL(throt));
+
+ r = readl(ts->regs + THROT_PRIORITY_LOCK);
+ r = REG_GET_MASK(r, THROT_PRIORITY_LOCK_PRIORITY_MASK);
+ if (r >= stc.priority)
+ return;
+ r = REG_SET_MASK(0, THROT_PRIORITY_LOCK_PRIORITY_MASK,
+ stc.priority);
+ writel(r, ts->regs + THROT_PRIORITY_LOCK);
+}
+
+static void tegra_soctherm_throttle(struct device *dev)
+{
+ struct tegra_soctherm *ts = dev_get_drvdata(dev);
+ u32 v;
+ int i;
+
+ /* Thermal HW throttle programming */
+ for (i = 0; i < THROTTLE_SIZE; i++)
+ soctherm_throttle_program(ts, i);
+
+ v = REG_SET_MASK(0, THROT_GLOBAL_ENB_MASK, 1);
+ writel(v, ts->regs + THROT_GLOBAL_CFG);
+
+ v = clk_readl(ts, CAR_SUPER_CCLKG_DIVIDER);
+ v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1);
+ clk_writel(ts, v, CAR_SUPER_CCLKG_DIVIDER);
+
+ /* initialize stats collection */
+ v = STATS_CTL_CLR_DN | STATS_CTL_EN_DN |
+ STATS_CTL_CLR_UP | STATS_CTL_EN_UP;
+ writel(v, ts->regs + THERMCTL_STATS_CTL);
+}
+
static void soctherm_init(struct platform_device *pdev)
{
struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
@@ -475,6 +1082,12 @@ static void soctherm_init(struct platform_device *pdev)
}
writel(pdiv, tegra->regs + SENSOR_PDIV);
writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF);
+
+ if (tegra->soc->use_ccroc)
+ return;
+
+ /* Configure hw throttle */
+ tegra_soctherm_throttle(&pdev->dev);
}
static const struct of_device_id tegra_soctherm_of_match[] = {
@@ -527,10 +1140,23 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
tegra->soc = soc;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "soctherm-reg");
tegra->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(tegra->regs))
+ if (IS_ERR(tegra->regs)) {
+ dev_err(&pdev->dev, "can't get soctherm registers");
return PTR_ERR(tegra->regs);
+ }
+
+ if (!tegra->soc->use_ccroc) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "car-reg");
+ tegra->clk_regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tegra->clk_regs)) {
+ dev_err(&pdev->dev, "can't get car clk registers");
+ return PTR_ERR(tegra->clk_regs);
+ }
+ }
tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm");
if (IS_ERR(tegra->reset)) {
@@ -580,6 +1206,9 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
if (err)
return err;
+ if (!tegra->soc->use_ccroc)
+ soctherm_init_hw_throt_cdev(pdev);
+
soctherm_init(pdev);
for (i = 0; i < soc->num_ttgs; ++i) {
@@ -593,6 +1222,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
zone->reg = tegra->regs + soc->ttgs[i]->sensor_temp_offset;
zone->dev = &pdev->dev;
zone->sg = soc->ttgs[i];
+ zone->ts = tegra;
z = devm_thermal_zone_of_sensor_register(&pdev->dev,
soc->ttgs[i]->id, zone,
@@ -608,7 +1238,9 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
tegra->thermctl_tzs[soc->ttgs[i]->id] = z;
/* Configure hw trip points */
- tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z);
+ err = tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z);
+ if (err)
+ goto disable_clocks;
}
soctherm_debug_init(pdev);
@@ -661,7 +1293,12 @@ static int __maybe_unused soctherm_resume(struct device *dev)
struct thermal_zone_device *tz;
tz = tegra->thermctl_tzs[soc->ttgs[i]->id];
- tegra_soctherm_set_hwtrips(dev, soc->ttgs[i], tz);
+ err = tegra_soctherm_set_hwtrips(dev, soc->ttgs[i], tz);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Resume failed: set hwtrips failed\n");
+ return err;
+ }
}
return 0;
diff --git a/drivers/thermal/tegra/soctherm.h b/drivers/thermal/tegra/soctherm.h
index 28e18ec4b4c3..e96ca73fd780 100644
--- a/drivers/thermal/tegra/soctherm.h
+++ b/drivers/thermal/tegra/soctherm.h
@@ -15,6 +15,11 @@
#ifndef __DRIVERS_THERMAL_TEGRA_SOCTHERM_H
#define __DRIVERS_THERMAL_TEGRA_SOCTHERM_H
+#define THERMCTL_LEVEL0_GROUP_CPU 0x0
+#define THERMCTL_LEVEL0_GROUP_GPU 0x4
+#define THERMCTL_LEVEL0_GROUP_MEM 0x8
+#define THERMCTL_LEVEL0_GROUP_TSENSE 0xc
+
#define SENSOR_CONFIG2 8
#define SENSOR_CONFIG2_THERMA_MASK (0xffff << 16)
#define SENSOR_CONFIG2_THERMA_SHIFT 16
@@ -65,6 +70,9 @@ struct tegra_tsensor_group {
u32 thermtrip_enable_mask;
u32 thermtrip_any_en_mask;
u32 thermtrip_threshold_mask;
+ u16 thermctl_lvl0_offset;
+ u32 thermctl_lvl0_up_thresh_mask;
+ u32 thermctl_lvl0_dn_thresh_mask;
};
struct tegra_tsensor_configuration {
@@ -103,6 +111,8 @@ struct tegra_soctherm_soc {
const unsigned int num_ttgs;
const struct tegra_soctherm_fuse *tfuse;
const int thresh_grain;
+ const unsigned int bptt;
+ const bool use_ccroc;
};
int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse,
diff --git a/drivers/thermal/tegra/tegra124-soctherm.c b/drivers/thermal/tegra/tegra124-soctherm.c
index beb9d36b9c8a..36768630f78c 100644
--- a/drivers/thermal/tegra/tegra124-soctherm.c
+++ b/drivers/thermal/tegra/tegra124-soctherm.c
@@ -28,7 +28,11 @@
#define TEGRA124_THERMTRIP_CPU_THRESH_MASK (0xff << 8)
#define TEGRA124_THERMTRIP_TSENSE_THRESH_MASK 0xff
+#define TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK (0xff << 17)
+#define TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK (0xff << 9)
+
#define TEGRA124_THRESH_GRAIN 1000
+#define TEGRA124_BPTT 8
static const struct tegra_tsensor_configuration tegra124_tsensor_config = {
.tall = 16300,
@@ -51,6 +55,9 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = {
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA124_THERMTRIP_CPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_CPU_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
+ .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
@@ -66,6 +73,9 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA124_THERMTRIP_GPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
+ .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group tegra124_tsensor_group_pll = {
@@ -79,6 +89,9 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_pll = {
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA124_THERMTRIP_TSENSE_EN_MASK,
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_TSENSE_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
+ .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group tegra124_tsensor_group_mem = {
@@ -94,6 +107,9 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_mem = {
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA124_THERMTRIP_MEM_EN_MASK,
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
+ .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group *tegra124_tsensor_groups[] = {
@@ -193,4 +209,6 @@ const struct tegra_soctherm_soc tegra124_soctherm = {
.num_ttgs = ARRAY_SIZE(tegra124_tsensor_groups),
.tfuse = &tegra124_soctherm_fuse,
.thresh_grain = TEGRA124_THRESH_GRAIN,
+ .bptt = TEGRA124_BPTT,
+ .use_ccroc = false,
};
diff --git a/drivers/thermal/tegra/tegra132-soctherm.c b/drivers/thermal/tegra/tegra132-soctherm.c
index e2aa84e1b307..ae5d61af2df3 100644
--- a/drivers/thermal/tegra/tegra132-soctherm.c
+++ b/drivers/thermal/tegra/tegra132-soctherm.c
@@ -193,4 +193,5 @@ const struct tegra_soctherm_soc tegra132_soctherm = {
.num_ttgs = ARRAY_SIZE(tegra132_tsensor_groups),
.tfuse = &tegra132_soctherm_fuse,
.thresh_grain = TEGRA132_THRESH_GRAIN,
+ .use_ccroc = true,
};
diff --git a/drivers/thermal/tegra/tegra210-soctherm.c b/drivers/thermal/tegra/tegra210-soctherm.c
index 19cc0ab66f0e..ad53169a8e95 100644
--- a/drivers/thermal/tegra/tegra210-soctherm.c
+++ b/drivers/thermal/tegra/tegra210-soctherm.c
@@ -29,7 +29,11 @@
#define TEGRA210_THERMTRIP_CPU_THRESH_MASK (0x1ff << 9)
#define TEGRA210_THERMTRIP_TSENSE_THRESH_MASK 0x1ff
+#define TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK (0x1ff << 18)
+#define TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK (0x1ff << 9)
+
#define TEGRA210_THRESH_GRAIN 500
+#define TEGRA210_BPTT 9
static const struct tegra_tsensor_configuration tegra210_tsensor_config = {
.tall = 16300,
@@ -52,6 +56,9 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_cpu = {
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA210_THERMTRIP_CPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_CPU_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
+ .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = {
@@ -67,6 +74,9 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = {
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA210_THERMTRIP_GPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
+ .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group tegra210_tsensor_group_pll = {
@@ -80,6 +90,9 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_pll = {
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA210_THERMTRIP_TSENSE_EN_MASK,
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_TSENSE_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
+ .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group tegra210_tsensor_group_mem = {
@@ -95,6 +108,9 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_mem = {
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA210_THERMTRIP_MEM_EN_MASK,
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK,
+ .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
+ .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
+ .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
};
static const struct tegra_tsensor_group *tegra210_tsensor_groups[] = {
@@ -194,4 +210,6 @@ const struct tegra_soctherm_soc tegra210_soctherm = {
.num_ttgs = ARRAY_SIZE(tegra210_tsensor_groups),
.tfuse = &tegra210_soctherm_fuse,
.thresh_grain = TEGRA210_THRESH_GRAIN,
+ .bptt = TEGRA210_BPTT,
+ .use_ccroc = false,
};
--
1.9.1
The Tegra132 has the specific settings for soctherm,
so change to use campatible "nvidia,tegra132-soctherm" for it.
And adds cpu, gpu, mem and pllx thermal zones.
Signed-off-by: Wei Ni <[email protected]>
---
arch/arm64/boot/dts/nvidia/tegra132.dtsi | 36 ++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/nvidia/tegra132.dtsi b/arch/arm64/boot/dts/nvidia/tegra132.dtsi
index 2013f8916084..e41d8e82d7ed 100644
--- a/arch/arm64/boot/dts/nvidia/tegra132.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra132.dtsi
@@ -4,6 +4,7 @@
#include <dt-bindings/pinctrl/pinctrl-tegra.h>
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/tegra124-soctherm.h>
/ {
compatible = "nvidia,tegra132", "nvidia,tegra124";
@@ -727,8 +728,8 @@
};
soctherm: thermal-sensor@700e2000 {
- compatible = "nvidia,tegra124-soctherm";
- reg = <0x0 0x700e2000 0x0 0x1000>;
+ compatible = "nvidia,tegra132-soctherm";
+ reg = <0x0 0x700e2000 0x0 0x600>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA124_CLK_TSENSOR>,
<&tegra_car TEGRA124_CLK_SOC_THERM>;
@@ -738,6 +739,37 @@
#thermal-sensor-cells = <1>;
};
+ thermal-zones {
+ cpu {
+ polling-delay-passive = <1000>;
+ polling-delay = <0>;
+
+ thermal-sensors =
+ <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>;
+ };
+ mem {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+
+ thermal-sensors =
+ <&soctherm TEGRA124_SOCTHERM_SENSOR_MEM>;
+ };
+ gpu {
+ polling-delay-passive = <1000>;
+ polling-delay = <0>;
+
+ thermal-sensors =
+ <&soctherm TEGRA124_SOCTHERM_SENSOR_GPU>;
+ };
+ pllx {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+
+ thermal-sensors =
+ <&soctherm TEGRA124_SOCTHERM_SENSOR_PLLX>;
+ };
+ };
+
ahub@70300000 {
compatible = "nvidia,tegra124-ahub";
reg = <0x0 0x70300000 0x0 0x200>,
--
1.9.1
From: Eduardo Valentin <[email protected]>
To: Wei Ni <[email protected]>
Cc: [email protected], [email protected], [email protected],
[email protected], [email protected],
[email protected], [email protected],
[email protected], [email protected],
[email protected]
Bcc:
Subject: Re: [PATCH v2 4/9] of: Add bindings of hw throttle for soctherm
Reply-To:
In-Reply-To: <[email protected]>
The patch title must say something about the fact that this is specific
to nvidia thermal driver.
On Wed, Apr 27, 2016 at 11:25:49AM +0800, Wei Ni wrote:
> Add HW throttle configuration sub-node for soctherm, which
> is used to describe the throttle event, and worked as a
> cooling device. The "hot" type trip in thermal zone can
> be bound to this cooling device, and trigger the throttle
> function.
>
> Signed-off-by: Wei Ni <[email protected]>
> ---
> .../bindings/thermal/nvidia,tegra124-soctherm.txt | 89 +++++++++++++++++++++-
> 1 file changed, 87 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
> index edebfa0a985e..dc337d139f49 100644
> --- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
> +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
> @@ -10,8 +10,14 @@ Required properties :
> - compatible : For Tegra124, must contain "nvidia,tegra124-soctherm".
> For Tegra132, must contain "nvidia,tegra132-soctherm".
> For Tegra210, must contain "nvidia,tegra210-soctherm".
> -- reg : Should contain 1 entry:
> +- reg : Should contain at least 2 entries for each entry in reg-names:
> - SOCTHERM register set
> + - Tegra CAR register set: Required for Tegra124 and Tegra210.
> + - CCROC register set: Required for Tegra132.
> +- reg-names : Should contain at least 2 entries:
> + - soctherm-reg
> + - car-reg
> + - ccroc-reg
> - interrupts : Defines the interrupt used by SOCTHERM
> - clocks : Must contain an entry for each entry in clock-names.
> See ../clocks/clock-bindings.txt for details.
> @@ -25,17 +31,44 @@ Required properties :
> - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description
> of this property. See <dt-bindings/thermal/tegra124-soctherm.h> for a
> list of valid values when referring to thermal sensors.
> +- throttle-cfgs: A sub-node which is a container of configuration for each
> + hardware throttle events. These events can be set as cooling devices.
> + * throttle events: Sub-nodes must be named as "light" or "heavy".
> + Properties:
> + - priority: Each throttles has its own throttle settings, so the SW need
> + to set priorities for various throttle, the HW arbiter can select the
> + final throttle settings.
> + Bigger value indicates higher priority, In general, higher priority
> + translates to lower target frequency. SW needs to ensure that critical
> + thermal alarms are given higher priority, and ensure that there is
> + no race if priority of two vectors is set to the same value.
> + - cpu-throt-depth: This property is for Tegra124 and Tegra210. It is
> + the throttling depth of pulse skippers, it's the percentage
> + throttling.
> + - cpu-throt-level: This property is only for Tegra132, it is the level
> + of pulse skippers, which used to throttle clock frequencies. It
> + indicates cpu clock throttling depth, and the depth can be programmed.
> + Must set as following values:
> + TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED
> + TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE
These properties are not generic properties. My understanding is that
you must have vendor prefix in such case. Same applies to the new nodes.
> + - #cooling-cells: Should be 1. This cooling device only support on/off state.
> + See ./thermal.txt for a description of this property.
>
> Note:
> - the "critical" type trip points will be set to SOC_THERM hardware as the
> shut down temperature. Once the temperature of this thermal zone is higher
> than it, the system will be shutdown or reset by hardware.
> +- the "hot" type trip points will be set to SOC_THERM hardware as the throttle
> +temperature. Once the the temperature of this thermal zone is higher
> +than it, it will trigger the HW throttle event.
>
> Example :
>
> soctherm@700e2000 {
> compatible = "nvidia,tegra124-soctherm";
> - reg = <0x0 0x700e2000 0x0 0x1000>;
> + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
> + 0x0 0x60006000 0x0 0x400 /* CAR reg_base */
> + reg-names = "soctherm-reg", "car-reg";
> interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
> clocks = <&tegra_car TEGRA124_CLK_TSENSOR>,
> <&tegra_car TEGRA124_CLK_SOC_THERM>;
> @@ -44,6 +77,45 @@ Example :
> reset-names = "soctherm";
>
> #thermal-sensor-cells = <1>;
> +
> + throttle-cfgs {
> + throttle_heavy: heavy {
> + priority = <100>;
> + cpu-throt-depth = <85>;
> +
> + #cooling-cells = <1>;
> + };
> + throttle_light: light {
> + priority = <80>;
> + cpu-throt-depth = <50>;
> +
> + #cooling-cells = <1>;
> + };
> + };
This is a sensor, which at the same time, has sub nodes that can be
cooling devices. Is my understanding correct of what you are trying to
do?
> + };
> +
> +Example: referring to Tegra132's "reg", "reg-names" and "throttle-cfgs" :
> +
> + soctherm@0,700e2000 {
> + compatible = "nvidia,tegra132-soctherm";
> + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
> + 0x0 0x70040000 0x0 0x200>; /* CCROC reg_base */;
> + reg-names = "soctherm-reg", "ccroc-reg";
> +
> + throttle-cfgs {
> + throttle_heavy: heavy {
> + priority = <100>;
> + cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_HIGH>;
> +
> + #cooling-cells = <1>;
> + };
> + throttle_light: light {
> + priority = <80>;
> + cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_MED>;
> +
> + #cooling-cells = <1>;
Could you please describe a little here what to expect of the above
setup?
> + };
> + };
> };
>
> Example: referring to thermal sensors :
> @@ -62,6 +134,19 @@ Example: referring to thermal sensors :
> hysteresis = <1000>;
> type = "critical";
> };
> +
> + cpu_throttle_trip: throttle-trip {
> + temperature = <100000>;
> + hysteresis = <1000>;
> + type = "hot";
> + };
> + };
> +
> + cooling-maps {
> + map0 {
> + trip = <&cpu_throttle_trip>;
> + cooling-device = <&throttle_heavy 1 1>;
> + };
> };
> };
> };
> --
> 1.9.1
>
On Wed, Apr 27, 2016 at 11:25:46AM +0800, Wei Ni wrote:
> add Tegra132 specific SOC_THERM driver.
Applied this one. You may also add my
Acked-by: Eduardo Valentin <[email protected]>
for patches 2 and 3. Remaining of the patches need to be further
discussed.
>
> Signed-off-by: Wei Ni <[email protected]>
On 2016年04月28日 07:30, Eduardo Valentin wrote:
> From: Eduardo Valentin <[email protected]>
> To: Wei Ni <[email protected]>
> Cc: [email protected], [email protected], [email protected],
> [email protected], [email protected],
> [email protected], [email protected],
> [email protected], [email protected],
> [email protected]
> Bcc:
> Subject: Re: [PATCH v2 4/9] of: Add bindings of hw throttle for soctherm
> Reply-To:
> In-Reply-To: <[email protected]>
>
> The patch title must say something about the fact that this is specific
> to nvidia thermal driver.
Yes, it's my mistake, will fix it in next series.
>
> On Wed, Apr 27, 2016 at 11:25:49AM +0800, Wei Ni wrote:
>> Add HW throttle configuration sub-node for soctherm, which
>> is used to describe the throttle event, and worked as a
>> cooling device. The "hot" type trip in thermal zone can
>> be bound to this cooling device, and trigger the throttle
>> function.
>>
>> Signed-off-by: Wei Ni <[email protected]>
>> ---
>> .../bindings/thermal/nvidia,tegra124-soctherm.txt | 89 +++++++++++++++++++++-
>> 1 file changed, 87 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
>> index edebfa0a985e..dc337d139f49 100644
>> --- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
>> +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
>> @@ -10,8 +10,14 @@ Required properties :
>> - compatible : For Tegra124, must contain "nvidia,tegra124-soctherm".
>> For Tegra132, must contain "nvidia,tegra132-soctherm".
>> For Tegra210, must contain "nvidia,tegra210-soctherm".
>> -- reg : Should contain 1 entry:
>> +- reg : Should contain at least 2 entries for each entry in reg-names:
>> - SOCTHERM register set
>> + - Tegra CAR register set: Required for Tegra124 and Tegra210.
>> + - CCROC register set: Required for Tegra132.
>> +- reg-names : Should contain at least 2 entries:
>> + - soctherm-reg
>> + - car-reg
>> + - ccroc-reg
>> - interrupts : Defines the interrupt used by SOCTHERM
>> - clocks : Must contain an entry for each entry in clock-names.
>> See ../clocks/clock-bindings.txt for details.
>> @@ -25,17 +31,44 @@ Required properties :
>> - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description
>> of this property. See <dt-bindings/thermal/tegra124-soctherm.h> for a
>> list of valid values when referring to thermal sensors.
>> +- throttle-cfgs: A sub-node which is a container of configuration for each
>> + hardware throttle events. These events can be set as cooling devices.
>> + * throttle events: Sub-nodes must be named as "light" or "heavy".
>> + Properties:
>> + - priority: Each throttles has its own throttle settings, so the SW need
>> + to set priorities for various throttle, the HW arbiter can select the
>> + final throttle settings.
>> + Bigger value indicates higher priority, In general, higher priority
>> + translates to lower target frequency. SW needs to ensure that critical
>> + thermal alarms are given higher priority, and ensure that there is
>> + no race if priority of two vectors is set to the same value.
>> + - cpu-throt-depth: This property is for Tegra124 and Tegra210. It is
>> + the throttling depth of pulse skippers, it's the percentage
>> + throttling.
>> + - cpu-throt-level: This property is only for Tegra132, it is the level
>> + of pulse skippers, which used to throttle clock frequencies. It
>> + indicates cpu clock throttling depth, and the depth can be programmed.
>> + Must set as following values:
>> + TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED
>> + TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE
>
> These properties are not generic properties. My understanding is that
> you must have vendor prefix in such case. Same applies to the new nodes.
Ok, will do it.
>
>> + - #cooling-cells: Should be 1. This cooling device only support on/off state.
>> + See ./thermal.txt for a description of this property.
>>
>> Note:
>> - the "critical" type trip points will be set to SOC_THERM hardware as the
>> shut down temperature. Once the temperature of this thermal zone is higher
>> than it, the system will be shutdown or reset by hardware.
>> +- the "hot" type trip points will be set to SOC_THERM hardware as the throttle
>> +temperature. Once the the temperature of this thermal zone is higher
>> +than it, it will trigger the HW throttle event.
>>
>> Example :
>>
>> soctherm@700e2000 {
>> compatible = "nvidia,tegra124-soctherm";
>> - reg = <0x0 0x700e2000 0x0 0x1000>;
>> + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
>> + 0x0 0x60006000 0x0 0x400 /* CAR reg_base */
>> + reg-names = "soctherm-reg", "car-reg";
>> interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
>> clocks = <&tegra_car TEGRA124_CLK_TSENSOR>,
>> <&tegra_car TEGRA124_CLK_SOC_THERM>;
>> @@ -44,6 +77,45 @@ Example :
>> reset-names = "soctherm";
>>
>> #thermal-sensor-cells = <1>;
>> +
>> + throttle-cfgs {
>> + throttle_heavy: heavy {
>> + priority = <100>;
>> + cpu-throt-depth = <85>;
>> +
>> + #cooling-cells = <1>;
>> + };
>> + throttle_light: light {
>> + priority = <80>;
>> + cpu-throt-depth = <50>;
>> +
>> + #cooling-cells = <1>;
>> + };
>> + };
>
> This is a sensor, which at the same time, has sub nodes that can be
> cooling devices. Is my understanding correct of what you are trying to
> do?
Yes, we set this sub nodes as cooling devices.
Let me explain it.
The Tegra's soctherm has the HW throttle function, it will be triggered when the
temperatures reach to the "hot" type trip. These throttle events can be
configured to different levels "heavy" and "light" on different sensors. So it
something like cooling devices which can be bound with thermal zones, and in
this way, we can use the linux of-thermal framework to handle it. If not, we
have to add more codes to parse these configuration and set them for those
sensors. I had used this method to handle the shutdown function in Tegra's
soctherm driver in my previous series, however Rob didn't like it, he preferred
to use linux framework to handle it.
So I think it's better to set these throttle-cfgs as cooling devices, so they
can be bound to the cpu/gpu thermal zones easily.
>
>
>> + };
>> +
>> +Example: referring to Tegra132's "reg", "reg-names" and "throttle-cfgs" :
>> +
>> + soctherm@0,700e2000 {
>> + compatible = "nvidia,tegra132-soctherm";
>> + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
>> + 0x0 0x70040000 0x0 0x200>; /* CCROC reg_base */;
>> + reg-names = "soctherm-reg", "ccroc-reg";
>> +
>> + throttle-cfgs {
>> + throttle_heavy: heavy {
>> + priority = <100>;
>> + cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_HIGH>;
>> +
>> + #cooling-cells = <1>;
>> + };
>> + throttle_light: light {
>> + priority = <80>;
>> + cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_MED>;
>> +
>> + #cooling-cells = <1>;
>
> Could you please describe a little here what to expect of the above
> setup?
Ok, let me describe it.
When the "heavy" cooling device triggered, the hardware will skip cpu clock's
pulse in HIGH level, and if the "light" triggered, the hardware will skip cpu
clock's pulse in MED level.
If these two devices are triggered in same time, the HW throttle arbiter will
select the highest priority as the final throttle settings to skip cpu pulse.
>
>
>> + };
>> + };
>> };
>>
>> Example: referring to thermal sensors :
>> @@ -62,6 +134,19 @@ Example: referring to thermal sensors :
>> hysteresis = <1000>;
>> type = "critical";
>> };
>> +
>> + cpu_throttle_trip: throttle-trip {
>> + temperature = <100000>;
>> + hysteresis = <1000>;
>> + type = "hot";
>> + };
>> + };
>> +
>> + cooling-maps {
>> + map0 {
>> + trip = <&cpu_throttle_trip>;
>> + cooling-device = <&throttle_heavy 1 1>;
>> + };
>> };
>> };
>> };
>> --
>> 1.9.1
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
On Thu, Apr 28, 2016 at 02:48:41PM +0800, Wei Ni wrote:
>
>
> On 2016年04月28日 07:30, Eduardo Valentin wrote:
> > From: Eduardo Valentin <[email protected]>
> > To: Wei Ni <[email protected]>
> > Cc: [email protected], [email protected], [email protected],
> > [email protected], [email protected],
> > [email protected], [email protected],
> > [email protected], [email protected],
> > [email protected]
> > Bcc:
> > Subject: Re: [PATCH v2 4/9] of: Add bindings of hw throttle for soctherm
> > Reply-To:
> > In-Reply-To: <[email protected]>
> >
> > The patch title must say something about the fact that this is specific
> > to nvidia thermal driver.
>
> Yes, it's my mistake, will fix it in next series.
>
> >
> > On Wed, Apr 27, 2016 at 11:25:49AM +0800, Wei Ni wrote:
> >> Add HW throttle configuration sub-node for soctherm, which
> >> is used to describe the throttle event, and worked as a
> >> cooling device. The "hot" type trip in thermal zone can
> >> be bound to this cooling device, and trigger the throttle
> >> function.
> >>
> >> Signed-off-by: Wei Ni <[email protected]>
> >> ---
> >> .../bindings/thermal/nvidia,tegra124-soctherm.txt | 89 +++++++++++++++++++++-
> >> 1 file changed, 87 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
> >> index edebfa0a985e..dc337d139f49 100644
> >> --- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
> >> +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
> >> @@ -10,8 +10,14 @@ Required properties :
> >> - compatible : For Tegra124, must contain "nvidia,tegra124-soctherm".
> >> For Tegra132, must contain "nvidia,tegra132-soctherm".
> >> For Tegra210, must contain "nvidia,tegra210-soctherm".
> >> -- reg : Should contain 1 entry:
> >> +- reg : Should contain at least 2 entries for each entry in reg-names:
> >> - SOCTHERM register set
> >> + - Tegra CAR register set: Required for Tegra124 and Tegra210.
> >> + - CCROC register set: Required for Tegra132.
> >> +- reg-names : Should contain at least 2 entries:
> >> + - soctherm-reg
> >> + - car-reg
> >> + - ccroc-reg
> >> - interrupts : Defines the interrupt used by SOCTHERM
> >> - clocks : Must contain an entry for each entry in clock-names.
> >> See ../clocks/clock-bindings.txt for details.
> >> @@ -25,17 +31,44 @@ Required properties :
> >> - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description
> >> of this property. See <dt-bindings/thermal/tegra124-soctherm.h> for a
> >> list of valid values when referring to thermal sensors.
> >> +- throttle-cfgs: A sub-node which is a container of configuration for each
> >> + hardware throttle events. These events can be set as cooling devices.
> >> + * throttle events: Sub-nodes must be named as "light" or "heavy".
> >> + Properties:
> >> + - priority: Each throttles has its own throttle settings, so the SW need
> >> + to set priorities for various throttle, the HW arbiter can select the
> >> + final throttle settings.
> >> + Bigger value indicates higher priority, In general, higher priority
> >> + translates to lower target frequency. SW needs to ensure that critical
> >> + thermal alarms are given higher priority, and ensure that there is
> >> + no race if priority of two vectors is set to the same value.
> >> + - cpu-throt-depth: This property is for Tegra124 and Tegra210. It is
> >> + the throttling depth of pulse skippers, it's the percentage
> >> + throttling.
> >> + - cpu-throt-level: This property is only for Tegra132, it is the level
> >> + of pulse skippers, which used to throttle clock frequencies. It
> >> + indicates cpu clock throttling depth, and the depth can be programmed.
> >> + Must set as following values:
> >> + TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED
> >> + TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE
> >
> > These properties are not generic properties. My understanding is that
> > you must have vendor prefix in such case. Same applies to the new nodes.
>
> Ok, will do it.
>
> >
> >> + - #cooling-cells: Should be 1. This cooling device only support on/off state.
> >> + See ./thermal.txt for a description of this property.
> >>
> >> Note:
> >> - the "critical" type trip points will be set to SOC_THERM hardware as the
> >> shut down temperature. Once the temperature of this thermal zone is higher
> >> than it, the system will be shutdown or reset by hardware.
> >> +- the "hot" type trip points will be set to SOC_THERM hardware as the throttle
> >> +temperature. Once the the temperature of this thermal zone is higher
> >> +than it, it will trigger the HW throttle event.
> >>
> >> Example :
> >>
> >> soctherm@700e2000 {
> >> compatible = "nvidia,tegra124-soctherm";
> >> - reg = <0x0 0x700e2000 0x0 0x1000>;
> >> + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
> >> + 0x0 0x60006000 0x0 0x400 /* CAR reg_base */
> >> + reg-names = "soctherm-reg", "car-reg";
> >> interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
> >> clocks = <&tegra_car TEGRA124_CLK_TSENSOR>,
> >> <&tegra_car TEGRA124_CLK_SOC_THERM>;
> >> @@ -44,6 +77,45 @@ Example :
> >> reset-names = "soctherm";
> >>
> >> #thermal-sensor-cells = <1>;
> >> +
> >> + throttle-cfgs {
> >> + throttle_heavy: heavy {
> >> + priority = <100>;
> >> + cpu-throt-depth = <85>;
> >> +
> >> + #cooling-cells = <1>;
> >> + };
> >> + throttle_light: light {
> >> + priority = <80>;
> >> + cpu-throt-depth = <50>;
> >> +
> >> + #cooling-cells = <1>;
> >> + };
> >> + };
> >
> > This is a sensor, which at the same time, has sub nodes that can be
> > cooling devices. Is my understanding correct of what you are trying to
> > do?
>
> Yes, we set this sub nodes as cooling devices.
> Let me explain it.
> The Tegra's soctherm has the HW throttle function, it will be triggered when the
> temperatures reach to the "hot" type trip. These throttle events can be
> configured to different levels "heavy" and "light" on different sensors. So it
> something like cooling devices which can be bound with thermal zones, and in
> this way, we can use the linux of-thermal framework to handle it. If not, we
> have to add more codes to parse these configuration and set them for those
> sensors. I had used this method to handle the shutdown function in Tegra's
> soctherm driver in my previous series, however Rob didn't like it, he preferred
> to use linux framework to handle it.
> So I think it's better to set these throttle-cfgs as cooling devices, so they
> can be bound to the cpu/gpu thermal zones easily.
>
> >
> >
> >> + };
> >> +
> >> +Example: referring to Tegra132's "reg", "reg-names" and "throttle-cfgs" :
> >> +
> >> + soctherm@0,700e2000 {
> >> + compatible = "nvidia,tegra132-soctherm";
> >> + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
> >> + 0x0 0x70040000 0x0 0x200>; /* CCROC reg_base */;
> >> + reg-names = "soctherm-reg", "ccroc-reg";
> >> +
> >> + throttle-cfgs {
> >> + throttle_heavy: heavy {
> >> + priority = <100>;
> >> + cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_HIGH>;
> >> +
> >> + #cooling-cells = <1>;
> >> + };
> >> + throttle_light: light {
> >> + priority = <80>;
> >> + cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_MED>;
> >> +
> >> + #cooling-cells = <1>;
> >
> > Could you please describe a little here what to expect of the above
> > setup?
>
> Ok, let me describe it.
> When the "heavy" cooling device triggered, the hardware will skip cpu clock's
> pulse in HIGH level, and if the "light" triggered, the hardware will skip cpu
> clock's pulse in MED level.
> If these two devices are triggered in same time, the HW throttle arbiter will
> select the highest priority as the final throttle settings to skip cpu pulse.
I would prefer if you add these descriptions into your examples in your
next version.
On 2016年04月28日 22:48, Eduardo Valentin wrote:
> On Thu, Apr 28, 2016 at 02:48:41PM +0800, Wei Ni wrote:
>>
>>
>> On 2016年04月28日 07:30, Eduardo Valentin wrote:
>>> From: Eduardo Valentin <[email protected]>
>>> To: Wei Ni <[email protected]>
>>> Cc: [email protected], [email protected], [email protected],
>>> [email protected], [email protected],
>>> [email protected], [email protected],
>>> [email protected], [email protected],
>>> [email protected]
>>> Bcc:
>>> Subject: Re: [PATCH v2 4/9] of: Add bindings of hw throttle for soctherm
>>> Reply-To:
>>> In-Reply-To: <[email protected]>
>>>
>>> The patch title must say something about the fact that this is specific
>>> to nvidia thermal driver.
>>
>> Yes, it's my mistake, will fix it in next series.
>>
>>>
>>> On Wed, Apr 27, 2016 at 11:25:49AM +0800, Wei Ni wrote:
>>>> Add HW throttle configuration sub-node for soctherm, which
>>>> is used to describe the throttle event, and worked as a
>>>> cooling device. The "hot" type trip in thermal zone can
>>>> be bound to this cooling device, and trigger the throttle
>>>> function.
>>>>
>>>> Signed-off-by: Wei Ni <[email protected]>
>>>> ---
>>>> .../bindings/thermal/nvidia,tegra124-soctherm.txt | 89 +++++++++++++++++++++-
>>>> 1 file changed, 87 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
>>>> index edebfa0a985e..dc337d139f49 100644
>>>> --- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
>>>> +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
>>>> @@ -10,8 +10,14 @@ Required properties :
>>>> - compatible : For Tegra124, must contain "nvidia,tegra124-soctherm".
>>>> For Tegra132, must contain "nvidia,tegra132-soctherm".
>>>> For Tegra210, must contain "nvidia,tegra210-soctherm".
>>>> -- reg : Should contain 1 entry:
>>>> +- reg : Should contain at least 2 entries for each entry in reg-names:
>>>> - SOCTHERM register set
>>>> + - Tegra CAR register set: Required for Tegra124 and Tegra210.
>>>> + - CCROC register set: Required for Tegra132.
>>>> +- reg-names : Should contain at least 2 entries:
>>>> + - soctherm-reg
>>>> + - car-reg
>>>> + - ccroc-reg
>>>> - interrupts : Defines the interrupt used by SOCTHERM
>>>> - clocks : Must contain an entry for each entry in clock-names.
>>>> See ../clocks/clock-bindings.txt for details.
>>>> @@ -25,17 +31,44 @@ Required properties :
>>>> - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description
>>>> of this property. See <dt-bindings/thermal/tegra124-soctherm.h> for a
>>>> list of valid values when referring to thermal sensors.
>>>> +- throttle-cfgs: A sub-node which is a container of configuration for each
>>>> + hardware throttle events. These events can be set as cooling devices.
>>>> + * throttle events: Sub-nodes must be named as "light" or "heavy".
>>>> + Properties:
>>>> + - priority: Each throttles has its own throttle settings, so the SW need
>>>> + to set priorities for various throttle, the HW arbiter can select the
>>>> + final throttle settings.
>>>> + Bigger value indicates higher priority, In general, higher priority
>>>> + translates to lower target frequency. SW needs to ensure that critical
>>>> + thermal alarms are given higher priority, and ensure that there is
>>>> + no race if priority of two vectors is set to the same value.
>>>> + - cpu-throt-depth: This property is for Tegra124 and Tegra210. It is
>>>> + the throttling depth of pulse skippers, it's the percentage
>>>> + throttling.
>>>> + - cpu-throt-level: This property is only for Tegra132, it is the level
>>>> + of pulse skippers, which used to throttle clock frequencies. It
>>>> + indicates cpu clock throttling depth, and the depth can be programmed.
>>>> + Must set as following values:
>>>> + TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED
>>>> + TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE
>>>
>>> These properties are not generic properties. My understanding is that
>>> you must have vendor prefix in such case. Same applies to the new nodes.
>>
>> Ok, will do it.
>>
>>>
>>>> + - #cooling-cells: Should be 1. This cooling device only support on/off state.
>>>> + See ./thermal.txt for a description of this property.
>>>>
>>>> Note:
>>>> - the "critical" type trip points will be set to SOC_THERM hardware as the
>>>> shut down temperature. Once the temperature of this thermal zone is higher
>>>> than it, the system will be shutdown or reset by hardware.
>>>> +- the "hot" type trip points will be set to SOC_THERM hardware as the throttle
>>>> +temperature. Once the the temperature of this thermal zone is higher
>>>> +than it, it will trigger the HW throttle event.
>>>>
>>>> Example :
>>>>
>>>> soctherm@700e2000 {
>>>> compatible = "nvidia,tegra124-soctherm";
>>>> - reg = <0x0 0x700e2000 0x0 0x1000>;
>>>> + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
>>>> + 0x0 0x60006000 0x0 0x400 /* CAR reg_base */
>>>> + reg-names = "soctherm-reg", "car-reg";
>>>> interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
>>>> clocks = <&tegra_car TEGRA124_CLK_TSENSOR>,
>>>> <&tegra_car TEGRA124_CLK_SOC_THERM>;
>>>> @@ -44,6 +77,45 @@ Example :
>>>> reset-names = "soctherm";
>>>>
>>>> #thermal-sensor-cells = <1>;
>>>> +
>>>> + throttle-cfgs {
>>>> + throttle_heavy: heavy {
>>>> + priority = <100>;
>>>> + cpu-throt-depth = <85>;
>>>> +
>>>> + #cooling-cells = <1>;
>>>> + };
>>>> + throttle_light: light {
>>>> + priority = <80>;
>>>> + cpu-throt-depth = <50>;
>>>> +
>>>> + #cooling-cells = <1>;
>>>> + };
>>>> + };
>>>
>>> This is a sensor, which at the same time, has sub nodes that can be
>>> cooling devices. Is my understanding correct of what you are trying to
>>> do?
>>
>> Yes, we set this sub nodes as cooling devices.
>> Let me explain it.
>> The Tegra's soctherm has the HW throttle function, it will be triggered when the
>> temperatures reach to the "hot" type trip. These throttle events can be
>> configured to different levels "heavy" and "light" on different sensors. So it
>> something like cooling devices which can be bound with thermal zones, and in
>> this way, we can use the linux of-thermal framework to handle it. If not, we
>> have to add more codes to parse these configuration and set them for those
>> sensors. I had used this method to handle the shutdown function in Tegra's
>> soctherm driver in my previous series, however Rob didn't like it, he preferred
>> to use linux framework to handle it.
>> So I think it's better to set these throttle-cfgs as cooling devices, so they
>> can be bound to the cpu/gpu thermal zones easily.
>>
>>>
>>>
>>>> + };
>>>> +
>>>> +Example: referring to Tegra132's "reg", "reg-names" and "throttle-cfgs" :
>>>> +
>>>> + soctherm@0,700e2000 {
>>>> + compatible = "nvidia,tegra132-soctherm";
>>>> + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */
>>>> + 0x0 0x70040000 0x0 0x200>; /* CCROC reg_base */;
>>>> + reg-names = "soctherm-reg", "ccroc-reg";
>>>> +
>>>> + throttle-cfgs {
>>>> + throttle_heavy: heavy {
>>>> + priority = <100>;
>>>> + cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_HIGH>;
>>>> +
>>>> + #cooling-cells = <1>;
>>>> + };
>>>> + throttle_light: light {
>>>> + priority = <80>;
>>>> + cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_MED>;
>>>> +
>>>> + #cooling-cells = <1>;
>>>
>>> Could you please describe a little here what to expect of the above
>>> setup?
>>
>> Ok, let me describe it.
>> When the "heavy" cooling device triggered, the hardware will skip cpu clock's
>> pulse in HIGH level, and if the "light" triggered, the hardware will skip cpu
>> clock's pulse in MED level.
>> If these two devices are triggered in same time, the HW throttle arbiter will
>> select the highest priority as the final throttle settings to skip cpu pulse.
>
>
> I would prefer if you add these descriptions into your examples in your
> next version.
Sure, will do it.
>