]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
thermal: tegra: add support for gpu hw-throttle
authorWei Ni <wni@nvidia.com>
Thu, 21 Feb 2019 10:18:40 +0000 (18:18 +0800)
committerEduardo Valentin <edubezval@gmail.com>
Tue, 14 May 2019 03:35:33 +0000 (20:35 -0700)
Add support to trigger pulse skippers on the GPU
when a HOT trip point is triggered. The pulse skippers
can be signalled to throttle at low, medium and high
depths\levels.

Signed-off-by: Wei Ni <wni@nvidia.com>
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
drivers/thermal/tegra/soctherm.c

index 5797d2122a2b735f6e1a44675fcbb19a495bf5e1..b7dc93c1a050f0d186e1f282f216ba908f4e963c 100644 (file)
@@ -1,5 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014 - 2018, NVIDIA CORPORATION.  All rights reserved.
  *
  * Author:
  *     Mikko Perttunen <mperttunen@nvidia.com>
 /* get dividend from the depth */
 #define THROT_DEPTH_DIVIDEND(depth)    ((256 * (100 - (depth)) / 100) - 1)
 
+/* gk20a nv_therm interface N:3 Mapping. Levels defined in tegra124-sochterm.h
+ * level       vector
+ * NONE                3'b000
+ * LOW         3'b001
+ * MED         3'b011
+ * HIGH                3'b111
+ */
+#define THROT_LEVEL_TO_DEPTH(level)    ((0x1 << (level)) - 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 + \
@@ -219,6 +229,7 @@ struct soctherm_throt_cfg {
        u8 priority;
        u8 cpu_throt_level;
        u32 cpu_throt_depth;
+       u32 gpu_throt_level;
        struct thermal_cooling_device *cdev;
        bool init;
 };
@@ -996,6 +1007,50 @@ static int soctherm_thermtrips_parse(struct platform_device *pdev)
        return 0;
 }
 
+static int soctherm_throt_cfg_parse(struct device *dev,
+                                   struct device_node *np,
+                                   struct soctherm_throt_cfg *stc)
+{
+       struct tegra_soctherm *ts = dev_get_drvdata(dev);
+       int ret;
+       u32 val;
+
+       ret = of_property_read_u32(np, "nvidia,priority", &val);
+       if (ret) {
+               dev_err(dev, "throttle-cfg: %s: invalid priority\n", stc->name);
+               return -EINVAL;
+       }
+       stc->priority = val;
+
+       ret = of_property_read_u32(np, ts->soc->use_ccroc ?
+                                  "nvidia,cpu-throt-level" :
+                                  "nvidia,cpu-throt-percent", &val);
+       if (!ret) {
+               if (ts->soc->use_ccroc &&
+                   val <= TEGRA_SOCTHERM_THROT_LEVEL_HIGH)
+                       stc->cpu_throt_level = val;
+               else if (!ts->soc->use_ccroc && val <= 100)
+                       stc->cpu_throt_depth = val;
+               else
+                       goto err;
+       } else {
+               goto err;
+       }
+
+       ret = of_property_read_u32(np, "nvidia,gpu-throt-level", &val);
+       if (!ret && val <= TEGRA_SOCTHERM_THROT_LEVEL_HIGH)
+               stc->gpu_throt_level = val;
+       else
+               goto err;
+
+       return 0;
+
+err:
+       dev_err(dev, "throttle-cfg: %s: no throt prop or invalid prop\n",
+               stc->name);
+       return -EINVAL;
+}
+
 /**
  * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations
  * and register them as cooling devices.
@@ -1006,8 +1061,7 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
        struct tegra_soctherm *ts = dev_get_drvdata(dev);
        struct device_node *np_stc, *np_stcc;
        const char *name;
-       u32 val;
-       int i, r;
+       int i;
 
        for (i = 0; i < THROTTLE_SIZE; i++) {
                ts->throt_cfgs[i].name = throt_names[i];
@@ -1025,6 +1079,7 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
        for_each_child_of_node(np_stc, np_stcc) {
                struct soctherm_throt_cfg *stc;
                struct thermal_cooling_device *tcd;
+               int err;
 
                name = np_stcc->name;
                stc = find_throttle_cfg_by_name(ts, name);
@@ -1034,37 +1089,10 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
                        continue;
                }
 
-               r = of_property_read_u32(np_stcc, "nvidia,priority", &val);
-               if (r) {
-                       dev_info(dev,
-                                "throttle-cfg: %s: missing priority\n", name);
+
+               err = soctherm_throt_cfg_parse(dev, np_stcc, stc);
+               if (err)
                        continue;
-               }
-               stc->priority = val;
-
-               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;
-               }
 
                tcd = thermal_of_cooling_device_register(np_stcc,
                                                         (char *)name, ts,
@@ -1207,6 +1235,28 @@ static void throttlectl_cpu_mn(struct tegra_soctherm *ts,
        writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
 }
 
+/**
+ * throttlectl_gpu_level_select() - selects throttling level for GPU
+ * @throt: the LIGHT/HEAVY of throttle event id
+ *
+ * This function programs soctherm's interface to GK20a NV_THERM to select
+ * pre-configured "Low", "Medium" or "Heavy" throttle levels.
+ *
+ * Return: boolean true if HW was programmed
+ */
+static void throttlectl_gpu_level_select(struct tegra_soctherm *ts,
+                                        enum soctherm_throttle_id throt)
+{
+       u32 r, level, throt_vect;
+
+       level = ts->throt_cfgs[throt].gpu_throt_level;
+       throt_vect = THROT_LEVEL_TO_DEPTH(level);
+       r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU));
+       r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1);
+       r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_GPU_MASK, throt_vect);
+       writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU));
+}
+
 /**
  * soctherm_throttle_program() - programs pulse skippers' configuration
  * @throt: the LIGHT/HEAVY of the throttle event id.
@@ -1229,6 +1279,8 @@ static void soctherm_throttle_program(struct tegra_soctherm *ts,
        else
                throttlectl_cpu_mn(ts, throt);
 
+       throttlectl_gpu_level_select(ts, throt);
+
        r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority);
        writel(r, ts->regs + THROT_PRIORITY_CTRL(throt));