summaryrefslogtreecommitdiff
path: root/drivers/thermal/tegra
diff options
context:
space:
mode:
authorWei Ni <wni@nvidia.com>2019-02-21 13:18:47 +0300
committerEduardo Valentin <edubezval@gmail.com>2019-05-14 06:35:34 +0300
commit1dcc242c7c75897bf0dfbcd1f563b7ab71cb4bb4 (patch)
tree4e1c12b76daf8d2c0fe52bec178ba1a7a30486a0 /drivers/thermal/tegra
parent8d3d462b684a064a45e68b64d40e9937966802d9 (diff)
downloadlinux-1dcc242c7c75897bf0dfbcd1f563b7ab71cb4bb4.tar.xz
thermal: tegra: enable OC hw throttle
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>
Diffstat (limited to 'drivers/thermal/tegra')
-rw-r--r--drivers/thermal/tegra/soctherm.c130
1 files changed, 120 insertions, 10 deletions
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index 35a9f1ef9d85..fcf70a3728b6 100644
--- a/drivers/thermal/tegra/soctherm.c
+++ b/drivers/thermal/tegra/soctherm.c
@@ -106,9 +106,26 @@
#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)
@@ -207,6 +224,25 @@
#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 + \
@@ -218,6 +254,9 @@
#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);