[PATCH v5 00/11] Add HW throttle for Tegra soctherm

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH v5 00/11] Add HW throttle for Tegra soctherm

Wei Ni
This series add following functions for Tegra soctherm:
1. add HW throttle function.
2. enable soctherm node for Tegra124, Tegra132, Tegra210, and
set "critical", "hot" trips for them.

Main changes from v4:
1. drop the "nvidia" prefix from the node name, per Rob's comments.

Main changes from v3:
1. change some properties'name and descriptions, per Rob's comments.
2. change the corresponding driver codes.

Main changes from v2:
1. improve the of-binding, per Eduardo's comments, and
change the corresponding driver codes.
2. move two setting critical trip patches in this series,
3. fix some bugs in dts changes.

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

The v2 series is in:
https://lkml.org/lkml/2016/4/26/1577

The v3 series is in:
https://lkml.org/lkml/2016/5/3/274

The v4 series is in:
https://lkml.org/lkml/2016/5/9/45

Wei Ni (11):
  of: Add bindings of hw throttle for Tegra soctherm
  thermal: tegra: add hw-throttle function
  thermal: tegra: add hw-throttle for Tegra132
  arm: tegra: set critical trips for Tegra124
  arm: tegra: set hot trips for Tegra124
  arm64: tegra: use tegra132-soctherm for Tegra132
  arm64: tegra: set critical trips for Tegra132
  arm64: tegra: set hot trips for Tegra132
  arm64: tegra: add soctherm node for Tegra210
  arm64: tegra: set critical trips for Tegra210
  arm64: tegra: set hot trips for Tegra210

 .../bindings/thermal/nvidia,tegra124-soctherm.txt  | 121 ++-
 arch/arm/boot/dts/tegra124-jetson-tk1.dts          |  18 +-
 arch/arm/boot/dts/tegra124.dtsi                    |  83 +-
 arch/arm64/boot/dts/nvidia/tegra132.dtsi           | 119 ++-
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           | 127 ++++
 drivers/thermal/tegra/soctherm.c                   | 842 ++++++++++++++++++++-
 drivers/thermal/tegra/soctherm.h                   |  10 +
 drivers/thermal/tegra/tegra124-soctherm.c          |  18 +
 drivers/thermal/tegra/tegra132-soctherm.c          |  18 +
 drivers/thermal/tegra/tegra210-soctherm.c          |  18 +
 include/dt-bindings/thermal/tegra124-soctherm.h    |   5 +
 11 files changed, 1344 insertions(+), 35 deletions(-)

--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 01/11] of: Add bindings of hw throttle for Tegra soctherm

Wei Ni
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 <[hidden email]>
---
 .../bindings/thermal/nvidia,tegra124-soctherm.txt  | 121 ++++++++++++++++++++-
 1 file changed, 119 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..b6c0ae53d4dc 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,45 @@ 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:
+      - nvidia,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.
+        The range of this value is 1~100.
+      - nvidia,cpu-throt-percent: This property is for Tegra124 and Tegra210.
+        It is the throttling depth of pulse skippers, it's the percentage
+        throttling.
+      - nvidia,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 +78,76 @@ Example :
  reset-names = "soctherm";
 
  #thermal-sensor-cells = <1>;
+
+ throttle-cfgs {
+ /*
+ * When the "heavy" cooling device triggered,
+ * the HW will skip cpu clock's pulse in 85% depth
+ */
+ throttle_heavy: heavy {
+ nvidia,priority = <100>;
+ nvidia,cpu-throt-percent = <85>;
+
+ #cooling-cells = <1>;
+ };
+
+ /*
+ * When the "light" cooling device triggered,
+ * the HW will skip cpu clock's pulse in 50% depth
+ */
+ throttle_light: light {
+ nvidia,priority = <80>;
+ nvidia,cpu-throt-percent = <50>;
+
+ #cooling-cells = <1>;
+ };
+
+ /*
+ * 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 Tegra132's "reg", "reg-names" and "throttle-cfgs" :
+
+ soctherm@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 {
+ /*
+ * When the "heavy" cooling device triggered,
+ * the HW will skip cpu clock's pulse in HIGH level
+ */
+ throttle_heavy: heavy {
+ nvidia,priority = <100>;
+ nvidia,cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_HIGH>;
+
+ #cooling-cells = <1>;
+ };
+
+ /*
+ * When the "light" cooling device triggered,
+ * the HW will skip cpu clock's pulse in MED level
+ */
+ throttle_light: light {
+ nvidia,priority = <80>;
+ nvidia,cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_MED>;
+
+ #cooling-cells = <1>;
+ };
+
+ /*
+ * 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 +166,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

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 04/11] arm: tegra: set critical trips for Tegra124

Wei Ni
In reply to this post by Wei Ni
Set general "critical" trip temperatures for cpu, gpu, mem and pllx
thermal zones for all Tegra124 platform, these trips can trigger
shut down or reset.
Tegra124 Jetson TK1 was already set "critical" trips before, so it
can overwrite the general values.

Signed-off-by: Wei Ni <[hidden email]>
---
 arch/arm/boot/dts/tegra124-jetson-tk1.dts | 18 ++--------
 arch/arm/boot/dts/tegra124.dtsi           | 60 +++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+), 15 deletions(-)

diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
index 941f36263c8f..40ad62c9c62e 100644
--- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts
+++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
@@ -2049,44 +2049,32 @@
  thermal-zones {
  cpu {
  trips {
- trip@0 {
+ cpu-shutdown-trip {
  temperature = <101000>;
  hysteresis = <0>;
  type = "critical";
  };
  };
-
- cooling-maps {
- /* There are currently no cooling maps because there are no cooling devices */
- };
  };
 
  mem {
  trips {
- trip@0 {
+ mem-shutdown-trip {
  temperature = <101000>;
  hysteresis = <0>;
  type = "critical";
  };
  };
-
- cooling-maps {
- /* There are currently no cooling maps because there are no cooling devices */
- };
  };
 
  gpu {
  trips {
- trip@0 {
+ gpu-shutdown-trip {
  temperature = <101000>;
  hysteresis = <0>;
  type = "critical";
  };
  };
-
- cooling-maps {
- /* There are currently no cooling maps because there are no cooling devices */
- };
  };
  };
 };
diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index ea4811870de2..08c7f85ea2c8 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -1149,6 +1149,21 @@
 
  thermal-sensors =
  <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>;
+
+ trips {
+ cpu-shutdown-trip {
+ temperature = <103000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
  };
 
  mem {
@@ -1157,6 +1172,21 @@
 
  thermal-sensors =
  <&soctherm TEGRA124_SOCTHERM_SENSOR_MEM>;
+
+ trips {
+ mem-shutdown-trip {
+ temperature = <103000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
  };
 
  gpu {
@@ -1165,6 +1195,21 @@
 
  thermal-sensors =
  <&soctherm TEGRA124_SOCTHERM_SENSOR_GPU>;
+
+ trips {
+ gpu-shutdown-trip {
+ temperature = <101000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
  };
 
  pllx {
@@ -1173,6 +1218,21 @@
 
  thermal-sensors =
  <&soctherm TEGRA124_SOCTHERM_SENSOR_PLLX>;
+
+ trips {
+ pllx-shutdown-trip {
+ temperature = <103000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
  };
  };
 
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 10/11] arm64: tegra: set critical trips for Tegra210

Wei Ni
In reply to this post by Wei Ni
Set general "critical" trip temperatures for cpu, gpu, mem and pllx
thermal zones on Tegra210, these trips can trigger shut down or reset.

Signed-off-by: Wei Ni <[hidden email]>
---
 arch/arm64/boot/dts/nvidia/tegra210.dtsi | 60 ++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 97d75149a1ac..e55589c8a561 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -825,6 +825,21 @@
 
  thermal-sensors =
  <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>;
+
+ trips {
+ cpu-shutdown-trip {
+ temperature = <102500>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
  };
  mem {
  polling-delay-passive = <0>;
@@ -832,6 +847,21 @@
 
  thermal-sensors =
  <&soctherm TEGRA124_SOCTHERM_SENSOR_MEM>;
+
+ trips {
+ mem-shutdown-trip {
+ temperature = <103000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
  };
  gpu {
  polling-delay-passive = <1000>;
@@ -839,6 +869,21 @@
 
  thermal-sensors =
  <&soctherm TEGRA124_SOCTHERM_SENSOR_GPU>;
+
+ trips {
+ gpu-shutdown-trip {
+ temperature = <103000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
  };
  pllx {
  polling-delay-passive = <0>;
@@ -846,6 +891,21 @@
 
  thermal-sensors =
  <&soctherm TEGRA124_SOCTHERM_SENSOR_PLLX>;
+
+ trips {
+ pllx-shutdown-trip {
+ temperature = <103000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * There are currently no cooling maps,
+ * because there are no cooling devices.
+ */
+ };
  };
  };
 };
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 07/11] arm64: tegra: set critical trips for Tegra132

Wei Ni
In reply to this post by Wei Ni
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 <[hidden email]>
---
 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

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 06/11] arm64: tegra: use tegra132-soctherm for Tegra132

Wei Ni
In reply to this post by Wei Ni
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 <[hidden email]>
---
 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

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 11/11] arm64: tegra: set hot trips for Tegra210

Wei Ni
In reply to this post by Wei Ni
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 <[hidden email]>
---
 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 e55589c8a561..1bcd424d9da9 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -808,7 +808,9 @@
 
  soctherm: thermal-sensor@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>;
@@ -816,6 +818,15 @@
  resets = <&tegra_car 78>;
  reset-names = "soctherm";
  #thermal-sensor-cells = <1>;
+
+ throttle-cfgs {
+ throttle_heavy: heavy {
+ nvidia,priority = <100>;
+ nvidia,cpu-throt-percent = <85>;
+
+ #cooling-cells = <2>;
+ };
+ };
  };
 
  thermal-zones {
@@ -832,13 +843,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 {
@@ -876,13 +893,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

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 09/11] arm64: tegra: add soctherm node for Tegra210

Wei Ni
In reply to this post by Wei Ni
Adds soctherm node for Tegra210, and add cpu,
gpu, mem, pllx as thermal-zones. Set critical
trip temperatures for them.

Signed-off-by: Wei Ni <[hidden email]>
---
 arch/arm64/boot/dts/nvidia/tegra210.dtsi | 44 ++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 76fe31faa1a5..97d75149a1ac 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -3,6 +3,7 @@
 #include <dt-bindings/memory/tegra210-mc.h>
 #include <dt-bindings/pinctrl/pinctrl-tegra.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/tegra124-soctherm.h>
 
 / {
  compatible = "nvidia,tegra210";
@@ -804,4 +805,47 @@
  (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
  interrupt-parent = <&gic>;
  };
+
+ soctherm: thermal-sensor@700e2000 {
+ compatible = "nvidia,tegra210-soctherm";
+ reg = <0x0 0x700e2000 0x0 0x1000>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&tegra_car TEGRA210_CLK_TSENSOR>,
+ <&tegra_car TEGRA210_CLK_SOC_THERM>;
+ clock-names = "tsensor", "soctherm";
+ resets = <&tegra_car 78>;
+ reset-names = "soctherm";
+ #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>;
+ };
+ };
 };
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 08/11] arm64: tegra: set hot trips for Tegra132

Wei Ni
In reply to this post by Wei Ni
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 <[hidden email]>
---
 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..3f3a46a4bd01 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 {
+ nvidia,priority = <100>;
+ nvidia,cpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_HIGH>;
+
+ #cooling-cells = <2>;
+ };
+ };
  };
 
  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

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 05/11] arm: tegra: set hot trips for Tegra124

Wei Ni
In reply to this post by Wei Ni
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 <[hidden email]>
---
 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..0a47a29406ce 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 {
+ nvidia,priority = <100>;
+ nvidia,cpu-throt-percent = <85>;
+
+ #cooling-cells = <2>;
+ };
+ };
  };
 
  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 = <&gpu_throttle_trip>;
+ cooling-device = <&throttle_heavy 1 1>;
+ };
  };
  };
 
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 02/11] thermal: tegra: add hw-throttle function

Wei Ni
In reply to this post by Wei Ni
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 <[hidden email]>
---
 drivers/thermal/tegra/soctherm.c          | 668 +++++++++++++++++++++++++++++-
 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, 700 insertions(+), 15 deletions(-)

diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index b8651726201e..dc75f92e1d8e 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, "throttrip: %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,204 @@ 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, "nvidia,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, "nvidia,cpu-throt-percent",
+ &val);
+ if (r) {
+ dev_info(dev,
+ "throttle-cfg: %s: missing cpu-throt-percent\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 +1083,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 +1141,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 +1207,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 +1223,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 +1239,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 +1294,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

Reply | Threaded
Open this post in threaded view
|

[PATCH v5 03/11] thermal: tegra: add hw-throttle for Tegra132

Wei Ni
In reply to this post by Wei Ni
Tegra132 use CCROC throttle registers to configure
pulse skiper, set these registers to enable throttle
function for Tegra132.

Signed-off-by: Wei Ni <[hidden email]>
---
 drivers/thermal/tegra/soctherm.c                | 234 +++++++++++++++++++++---
 drivers/thermal/tegra/tegra132-soctherm.c       |  17 ++
 include/dt-bindings/thermal/tegra124-soctherm.h |   5 +
 3 files changed, 226 insertions(+), 30 deletions(-)

diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index dc75f92e1d8e..7d2db23d71a3 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, "throttrip: %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,15 +987,29 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
  }
  stc->priority = val;
 
- r = of_property_read_u32(np_stcc, "nvidia,cpu-throt-percent",
- &val);
- if (r) {
- dev_info(dev,
- "throttle-cfg: %s: missing cpu-throt-percent\n",
- name);
- continue;
+ if (ts->soc->use_ccroc) {
+ r = of_property_read_u32(np_stcc,
+ "nvidia,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,
+ "nvidia,cpu-throt-percent",
+ &val);
+ if (r) {
+ dev_info(dev,
+ "throttle-cfg: %s: missing cpu-throt-percent\n",
+ name);
+ continue;
+ }
+ stc->cpu_throt_depth = val;
  }
- stc->cpu_throt_depth = val;
 
  tcd = thermal_of_cooling_device_register(np_stcc,
  (char *)name, ts,
@@ -968,6 +1030,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
  *
@@ -1017,7 +1169,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));
@@ -1040,16 +1195,31 @@ 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);
 
  v = REG_SET_MASK(0, THROT_GLOBAL_ENB_MASK, 1);
- writel(v, ts->regs + THROT_GLOBAL_CFG);
+ if (ts->soc->use_ccroc) {
+ ccroc_writel(ts, v, CCROC_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);
+ v = ccroc_readl(ts, CCROC_SUPER_CCLKG_DIVIDER);
+ v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1);
+ ccroc_writel(ts, v, CCROC_SUPER_CCLKG_DIVIDER);
+ } else {
+ 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 |
@@ -1084,9 +1254,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);
 }
@@ -1157,6 +1324,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");
@@ -1207,8 +1382,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

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v5 01/11] of: Add bindings of hw throttle for Tegra soctherm

Rob Herring-3
In reply to this post by Wei Ni
On Wed, May 11, 2016 at 06:20:16PM +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 <[hidden email]>
> ---
>  .../bindings/thermal/nvidia,tegra124-soctherm.txt  | 121 ++++++++++++++++++++-
>  1 file changed, 119 insertions(+), 2 deletions(-)

Acked-by: Rob Herring <[hidden email]>
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v5 00/11] Add HW throttle for Tegra soctherm

Wei Ni
In reply to this post by Wei Ni
Hi,
Does there have any comments on this series?
Let me know if someone has suggestions.

Thanks.
Wei.

On 05/11/2016 06:20 PM, Wei Ni wrote:

> This series add following functions for Tegra soctherm:
> 1. add HW throttle function.
> 2. enable soctherm node for Tegra124, Tegra132, Tegra210, and
> set "critical", "hot" trips for them.
>
> Main changes from v4:
> 1. drop the "nvidia" prefix from the node name, per Rob's comments.
>
> Main changes from v3:
> 1. change some properties'name and descriptions, per Rob's comments.
> 2. change the corresponding driver codes.
>
> Main changes from v2:
> 1. improve the of-binding, per Eduardo's comments, and
> change the corresponding driver codes.
> 2. move two setting critical trip patches in this series,
> 3. fix some bugs in dts changes.
>
> 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
>
> The v2 series is in:
> https://lkml.org/lkml/2016/4/26/1577
>
> The v3 series is in:
> https://lkml.org/lkml/2016/5/3/274
>
> The v4 series is in:
> https://lkml.org/lkml/2016/5/9/45
>
> Wei Ni (11):
>   of: Add bindings of hw throttle for Tegra soctherm
>   thermal: tegra: add hw-throttle function
>   thermal: tegra: add hw-throttle for Tegra132
>   arm: tegra: set critical trips for Tegra124
>   arm: tegra: set hot trips for Tegra124
>   arm64: tegra: use tegra132-soctherm for Tegra132
>   arm64: tegra: set critical trips for Tegra132
>   arm64: tegra: set hot trips for Tegra132
>   arm64: tegra: add soctherm node for Tegra210
>   arm64: tegra: set critical trips for Tegra210
>   arm64: tegra: set hot trips for Tegra210
>
>  .../bindings/thermal/nvidia,tegra124-soctherm.txt  | 121 ++-
>  arch/arm/boot/dts/tegra124-jetson-tk1.dts          |  18 +-
>  arch/arm/boot/dts/tegra124.dtsi                    |  83 +-
>  arch/arm64/boot/dts/nvidia/tegra132.dtsi           | 119 ++-
>  arch/arm64/boot/dts/nvidia/tegra210.dtsi           | 127 ++++
>  drivers/thermal/tegra/soctherm.c                   | 842 ++++++++++++++++++++-
>  drivers/thermal/tegra/soctherm.h                   |  10 +
>  drivers/thermal/tegra/tegra124-soctherm.c          |  18 +
>  drivers/thermal/tegra/tegra132-soctherm.c          |  18 +
>  drivers/thermal/tegra/tegra210-soctherm.c          |  18 +
>  include/dt-bindings/thermal/tegra124-soctherm.h    |   5 +
>  11 files changed, 1344 insertions(+), 35 deletions(-)
>