thermal: tegra: enable OC hw throttle
authorWei Ni <wni@nvidia.com>
Thu, 21 Feb 2019 10:18:47 +0000 (18:18 +0800)
committerEduardo Valentin <edubezval@gmail.com>
Tue, 14 May 2019 03:35:34 +0000 (20:35 -0700)
Parse Over Current settings from DT and program them to
generate interrupts. Also enable hw throttling whenever
there are OC events. Log the OC events as debug messages.

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

index 35a9f1e..fcf70a3 100644 (file)
 #define STATS_CTL_CLR_UP                       0x2
 #define STATS_CTL_EN_UP                                0x1
 
+#define OC1_CFG                                        0x310
+#define OC1_CFG_LONG_LATENCY_MASK              BIT(6)
+#define OC1_CFG_HW_RESTORE_MASK                        BIT(5)
+#define OC1_CFG_PWR_GOOD_MASK_MASK             BIT(4)
+#define OC1_CFG_THROTTLE_MODE_MASK             (0x3 << 2)
+#define OC1_CFG_ALARM_POLARITY_MASK            BIT(1)
+#define OC1_CFG_EN_THROTTLE_MASK               BIT(0)
+
+#define OC1_CNT_THRESHOLD                      0x314
+#define OC1_THROTTLE_PERIOD                    0x318
+#define OC1_ALARM_COUNT                                0x31c
+#define OC1_FILTER                             0x320
+#define OC1_STATS                              0x3a8
+
 #define OC_INTR_STATUS                         0x39c
 #define OC_INTR_ENABLE                         0x3a0
 #define OC_INTR_DISABLE                                0x3a4
+#define OC_STATS_CTL                           0x3c4
+#define OC_STATS_CTL_CLR_ALL                   0x2
+#define OC_STATS_CTL_EN_ALL                    0x1
 
 #define OC_INTR_OC1_MASK                       BIT(0)
 #define OC_INTR_OC2_MASK                       BIT(1)
 #define THROT_DELAY_CTRL(throt)                (THROT_DELAY_LITE + \
                                        (THROT_OFFSET * throt))
 
+#define ALARM_OFFSET                   0x14
+#define ALARM_CFG(throt)               (OC1_CFG + \
+                                       (ALARM_OFFSET * (throt - THROTTLE_OC1)))
+
+#define ALARM_CNT_THRESHOLD(throt)     (OC1_CNT_THRESHOLD + \
+                                       (ALARM_OFFSET * (throt - THROTTLE_OC1)))
+
+#define ALARM_THROTTLE_PERIOD(throt)   (OC1_THROTTLE_PERIOD + \
+                                       (ALARM_OFFSET * (throt - THROTTLE_OC1)))
+
+#define ALARM_ALARM_COUNT(throt)       (OC1_ALARM_COUNT + \
+                                       (ALARM_OFFSET * (throt - THROTTLE_OC1)))
+
+#define ALARM_FILTER(throt)            (OC1_FILTER + \
+                                       (ALARM_OFFSET * (throt - THROTTLE_OC1)))
+
+#define ALARM_STATS(throt)             (OC1_STATS + \
+                                       (4 * (throt - THROTTLE_OC1)))
+
 /* 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 + \
 #define THERMCTL_LVL_REGS_SIZE         0x20
 #define THERMCTL_LVL_REG(rg, lv)       ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE))
 
+#define OC_THROTTLE_MODE_DISABLED      0
+#define OC_THROTTLE_MODE_BRIEF         2
+
 static const int min_low_temp = -127000;
 static const int max_high_temp = 127000;
 
@@ -266,6 +305,15 @@ struct tegra_thermctl_zone {
        const struct tegra_tsensor_group *sg;
 };
 
+struct soctherm_oc_cfg {
+       u32 active_low;
+       u32 throt_period;
+       u32 alarm_cnt_thresh;
+       u32 alarm_filter;
+       u32 mode;
+       bool intr_en;
+};
+
 struct soctherm_throt_cfg {
        const char *name;
        unsigned int id;
@@ -273,6 +321,7 @@ struct soctherm_throt_cfg {
        u8 cpu_throt_level;
        u32 cpu_throt_depth;
        u32 gpu_throt_level;
+       struct soctherm_oc_cfg oc_cfg;
        struct thermal_cooling_device *cdev;
        bool init;
 };
@@ -747,7 +796,7 @@ static int tegra_soctherm_set_hwtrips(struct device *dev,
                return 0;
        }
 
-       for (i = 0; i < THROTTLE_SIZE; i++) {
+       for (i = 0; i < THROTTLE_OC1; i++) {
                struct thermal_cooling_device *cdev;
 
                if (!ts->throt_cfgs[i].init)
@@ -1569,6 +1618,32 @@ static int soctherm_thermtrips_parse(struct platform_device *pdev)
        return 0;
 }
 
+static void soctherm_oc_cfg_parse(struct device *dev,
+                               struct device_node *np_oc,
+                               struct soctherm_throt_cfg *stc)
+{
+       u32 val;
+
+       if (of_property_read_bool(np_oc, "nvidia,polarity-active-low"))
+               stc->oc_cfg.active_low = 1;
+       else
+               stc->oc_cfg.active_low = 0;
+
+       if (!of_property_read_u32(np_oc, "nvidia,count-threshold", &val)) {
+               stc->oc_cfg.intr_en = 1;
+               stc->oc_cfg.alarm_cnt_thresh = val;
+       }
+
+       if (!of_property_read_u32(np_oc, "nvidia,throttle-period-us", &val))
+               stc->oc_cfg.throt_period = val;
+
+       if (!of_property_read_u32(np_oc, "nvidia,alarm-filter", &val))
+               stc->oc_cfg.alarm_filter = val;
+
+       /* BRIEF throttling by default, do not support STICKY */
+       stc->oc_cfg.mode = OC_THROTTLE_MODE_BRIEF;
+}
+
 static int soctherm_throt_cfg_parse(struct device *dev,
                                    struct device_node *np,
                                    struct soctherm_throt_cfg *stc)
@@ -1651,24 +1726,34 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
                        continue;
                }
 
+               if (stc->init) {
+                       dev_err(dev, "throttle-cfg: %s: redefined!\n", name);
+                       of_node_put(np_stcc);
+                       break;
+               }
 
                err = soctherm_throt_cfg_parse(dev, np_stcc, stc);
                if (err)
                        continue;
 
-               tcd = thermal_of_cooling_device_register(np_stcc,
+               if (stc->id >= THROTTLE_OC1) {
+                       soctherm_oc_cfg_parse(dev, np_stcc, stc);
+                       stc->init = true;
+               } else {
+
+                       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;
+                       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;
                }
 
-               stc->cdev = tcd;
-               stc->init = true;
        }
 
        of_node_put(np_stc);
@@ -1819,6 +1904,28 @@ static void throttlectl_gpu_level_select(struct tegra_soctherm *ts,
        writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU));
 }
 
+static int soctherm_oc_cfg_program(struct tegra_soctherm *ts,
+                                     enum soctherm_throttle_id throt)
+{
+       u32 r;
+       struct soctherm_oc_cfg *oc = &ts->throt_cfgs[throt].oc_cfg;
+
+       if (oc->mode == OC_THROTTLE_MODE_DISABLED)
+               return -EINVAL;
+
+       r = REG_SET_MASK(0, OC1_CFG_HW_RESTORE_MASK, 1);
+       r = REG_SET_MASK(r, OC1_CFG_THROTTLE_MODE_MASK, oc->mode);
+       r = REG_SET_MASK(r, OC1_CFG_ALARM_POLARITY_MASK, oc->active_low);
+       r = REG_SET_MASK(r, OC1_CFG_EN_THROTTLE_MASK, 1);
+       writel(r, ts->regs + ALARM_CFG(throt));
+       writel(oc->throt_period, ts->regs + ALARM_THROTTLE_PERIOD(throt));
+       writel(oc->alarm_cnt_thresh, ts->regs + ALARM_CNT_THRESHOLD(throt));
+       writel(oc->alarm_filter, ts->regs + ALARM_FILTER(throt));
+       soctherm_oc_intr_enable(ts, throt, oc->intr_en);
+
+       return 0;
+}
+
 /**
  * soctherm_throttle_program() - programs pulse skippers' configuration
  * @throt: the LIGHT/HEAVY of the throttle event id.
@@ -1835,6 +1942,9 @@ static void soctherm_throttle_program(struct tegra_soctherm *ts,
        if (!stc.init)
                return;
 
+       if ((throt >= THROTTLE_OC1) && (soctherm_oc_cfg_program(ts, throt)))
+               return;
+
        /* Setup PSKIP parameters */
        if (ts->soc->use_ccroc)
                throttlectl_cpu_level_select(ts, throt);