@@ -33,7 +33,6 @@
#include <dt-bindings/thermal/tegra124-soctherm.h>
-#include "../thermal_core.h"
#include "soctherm.h"
#define SENSOR_CONFIG0 0
@@ -317,12 +316,16 @@ struct soctherm_throt_cfg {
const char *name;
unsigned int id;
u8 priority;
+ int temperature;
+ int hysteresis;
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;
+
+ unsigned int num_zones;
+ struct device_node **zones;
};
struct tegra_soctherm {
@@ -497,9 +500,7 @@ static int thermtrip_program(struct tegra_soctherm *ts,
* throttrip_program() - Configures the hardware to throttle the
* pulse if a given sensor group reaches a given temperature
* @ts: pointer to a struct tegra_soctherm
- * @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
@@ -510,43 +511,68 @@ static int thermtrip_program(struct tegra_soctherm *ts,
*
* Return: 0 upon success, or %-EINVAL upon failure.
*/
-static int throttrip_program(struct tegra_soctherm *ts,
- const struct tegra_tsensor_group *sg,
- struct soctherm_throt_cfg *stc,
- int trip_temp)
+static int throttrip_program(struct tegra_soctherm *tegra,
+ struct soctherm_throt_cfg *stc)
{
- int temp, cpu_throt, gpu_throt;
- unsigned int throt;
- u32 r, reg_off;
+ int high, low, cpu_throt, gpu_throt;
+ unsigned int throt, i, j;
- if (!sg || !stc || !stc->init)
- return -EINVAL;
+ high = enforce_temp_range(tegra, stc->temperature);
+ high /= tegra->soc->thresh_grain;
+ low = enforce_temp_range(tegra, stc->temperature - stc->hysteresis);
+ low /= tegra->soc->thresh_grain;
- temp = enforce_temp_range(ts, trip_temp) / ts->soc->thresh_grain;
+ for (i = 0; i < stc->num_zones; i++) {
+ struct tegra_thermctl_zone *zone = NULL;
+ unsigned int offset;
+ u32 r;
- /* Hardcode LIGHT on LEVEL1 and HEAVY on LEVEL2 */
- throt = stc->id;
- reg_off = THERMCTL_LVL_REG(sg->thermctl_lvl0_offset, throt + 1);
+ for (j = 0; j < tegra->soc->num_ttgs; j++) {
+ struct thermal_zone_device *tz = tegra->thermctl_tzs[j];
- 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(ts->dev,
- "invalid throt id %d - assuming HEAVY",
- throt);
- }
+ if (tz->device.of_node == stc->zones[i]) {
+ zone = thermal_zone_device_priv(tz);
+ break;
+ }
+ }
- 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);
+ if (!zone)
+ continue;
+
+ if (!zone->sg->can_throttle) {
+ dev_warn(tegra->dev, "zone %s cannot be throttled\n",
+ zone->sg->name);
+ continue;
+ }
+
+ /* Hardcode LIGHT on LEVEL1 and HEAVY on LEVEL2 */
+ throt = stc->id;
+ offset = THERMCTL_LVL_REG(zone->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(tegra->dev,
+ "invalid throt id %d - assuming HEAVY",
+ throt);
+ }
+
+ r = readl(tegra->regs + offset);
+ r = REG_SET_MASK(r, zone->sg->thermctl_lvl0_up_thresh_mask, high);
+ r = REG_SET_MASK(r, zone->sg->thermctl_lvl0_dn_thresh_mask, low);
+ 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, tegra->regs + offset);
+
+ dev_info(tegra->dev,
+ "throttrip: will throttle when %s reaches %d mC\n",
+ zone->sg->name, stc->temperature);
+ }
return 0;
}
@@ -606,25 +632,6 @@ static int tegra_thermctl_set_trip_temp(struct thermal_zone_device *tz, int trip
return thermtrip_program(ts, sg, temp);
else
return 0;
-
- } else if (trip.type == THERMAL_TRIP_HOT) {
- int i;
-
- for (i = 0; i < THROTTLE_SIZE; i++) {
- struct thermal_cooling_device *cdev;
- struct soctherm_throt_cfg *stc;
-
- if (!ts->throt_cfgs[i].init)
- continue;
-
- cdev = ts->throt_cfgs[i].cdev;
- if (get_thermal_instance(tz, cdev, trip_id))
- stc = find_throttle_cfg_by_name(ts, cdev->type);
- else
- continue;
-
- return throttrip_program(ts, sg, stc, temp);
- }
}
return 0;
@@ -685,29 +692,9 @@ static const struct thermal_zone_device_ops tegra_of_thermal_ops = {
.set_trips = tegra_thermctl_set_trips,
};
-static int get_hot_temp(struct thermal_zone_device *tz, int *trip_id, int *temp)
-{
- int i, ret;
- struct thermal_trip trip;
-
- for (i = 0; i < thermal_zone_get_num_trips(tz); i++) {
-
- ret = thermal_zone_get_trip(tz, i, &trip);
- if (ret)
- return -EINVAL;
-
- if (trip.type == THERMAL_TRIP_HOT) {
- *trip_id = i;
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
/**
* tegra_soctherm_set_hwtrips() - set HW trip point from DT data
- * @dev: struct device * of the SOC_THERM instance
+ * @ts: pointer to a struct tegra_soctherm
* @sg: pointer to the sensor group to set the thermtrip temperature for
* @tz: struct thermal_zone_device *
*
@@ -725,16 +712,12 @@ static int get_hot_temp(struct thermal_zone_device *tz, int *trip_id, int *temp)
* 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 tegra_soctherm *ts,
const struct tegra_tsensor_group *sg,
struct thermal_zone_device *tz)
{
- struct soctherm_throt_cfg *stc;
- int i, trip, temperature, ret;
+ int temperature, ret;
/* Get thermtrips. If missing, try to get critical trips. */
temperature = tsensor_group_thermtrip_get(ts, sg->id);
@@ -752,43 +735,31 @@ static int tegra_soctherm_set_hwtrips(struct tegra_soctherm *ts,
dev_info(ts->dev, "thermtrip: will shut down when %s reaches %d mC\n",
sg->name, temperature);
- ret = get_hot_temp(tz, &trip, &temperature);
- if (ret) {
- dev_info(ts->dev, "throttrip: %s: missing hot temperature\n",
- sg->name);
- return 0;
- }
-
- for (i = 0; i < THROTTLE_OC1; 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(ts, sg, stc, temperature);
- if (ret) {
- dev_err(ts->dev, "throttrip: %s: error during enable\n",
- sg->name);
- return ret;
- }
+ return 0;
+}
- dev_info(ts->dev,
- "throttrip: will throttle when %s reaches %d mC\n",
- sg->name, temperature);
- break;
- }
+/*
+ * soctherm_enable_hw_throttling() - enable hardware throttling trip points
+ * @tegra: pointer to a struct tegra_soctherm
+ *
+ * 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 void soctherm_enable_hw_throttling(struct tegra_soctherm *tegra)
+{
+ struct soctherm_throt_cfg *stc;
+ int err;
- if (i == THROTTLE_SIZE)
- dev_info(ts->dev, "throttrip: %s: missing throttle cdev\n",
- sg->name);
+ /* if configured, program the pulse skipper for CPU and GPU zones */
+ stc = find_throttle_cfg_by_name(tegra, "heavy");
+ if (!stc)
+ return;
- return 0;
+ err = throttrip_program(tegra, stc);
+ if (err)
+ dev_err(tegra->dev, "throttrip: %s: failed to enable: %d\n",
+ stc->name, err);
}
static irqreturn_t soctherm_thermal_isr(int irq, void *dev_id)
@@ -1494,40 +1465,6 @@ static int soctherm_clk_enable(struct tegra_soctherm *tegra, 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 const 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,
-};
-
static int soctherm_thermtrips_parse(struct tegra_soctherm *ts)
{
struct tsensor_group_thermtrips *tt = ts->soc->thermtrips;
@@ -1633,6 +1570,33 @@ static int soctherm_throt_cfg_parse(struct tegra_soctherm *ts,
else
goto err;
+ ret = of_property_read_u32(np, "temperature-millicelsius",
+ &stc->temperature);
+ if (ret < 0)
+ goto err;
+
+ ret = of_property_read_u32(np, "hysteresis-millicelsius",
+ &stc->hysteresis);
+ if (ret < 0)
+ goto err;
+
+ stc->num_zones = of_count_phandle_with_args(np, "nvidia,thermal-zones",
+ NULL);
+ if (stc->num_zones > 0) {
+ struct device_node *zone;
+ unsigned int i;
+
+ stc->zones = devm_kcalloc(ts->dev, stc->num_zones, sizeof(zone),
+ GFP_KERNEL);
+ if (!stc->zones)
+ return -ENOMEM;
+
+ for (i = 0; i < stc->num_zones; i++) {
+ zone = of_parse_phandle(np, "nvidia,thermal-zones", i);
+ stc->zones[i] = zone;
+ }
+ }
+
return 0;
err:
@@ -1642,14 +1606,12 @@ static int soctherm_throt_cfg_parse(struct tegra_soctherm *ts,
}
/**
- * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations
- * and register them as cooling devices.
+ * soctherm_init_hw_throttling() - parse the HW throttle configurations
* @tegra: pointer to Tegra soctherm structure
*/
-static void soctherm_init_hw_throt_cdev(struct tegra_soctherm *tegra)
+static void soctherm_init_hw_throttling(struct tegra_soctherm *tegra)
{
struct device_node *np_stc, *np_stcc;
- const char *name;
int i;
for (i = 0; i < THROTTLE_SIZE; i++) {
@@ -1666,11 +1628,10 @@ static void soctherm_init_hw_throt_cdev(struct tegra_soctherm *tegra)
}
for_each_child_of_node(np_stc, np_stcc) {
+ const char *name = np_stcc->name;
struct soctherm_throt_cfg *stc;
- struct thermal_cooling_device *tcd;
int err;
- name = np_stcc->name;
stc = find_throttle_cfg_by_name(tegra, name);
if (!stc) {
dev_err(tegra->dev, "throttle-cfg: could not find %s\n",
@@ -1692,19 +1653,6 @@ static void soctherm_init_hw_throt_cdev(struct tegra_soctherm *tegra)
if (stc->id >= THROTTLE_OC1) {
soctherm_oc_cfg_parse(tegra, np_stcc, stc);
stc->init = true;
- } else {
-
- tcd = thermal_of_cooling_device_register(np_stcc,
- (char *)name, tegra,
- &throt_cooling_ops);
- if (IS_ERR_OR_NULL(tcd)) {
- dev_err(tegra->dev,
- "throttle-cfg: %s: failed to register cooling device\n",
- name);
- continue;
- }
- stc->cdev = tcd;
- stc->init = true;
}
}
@@ -2148,7 +2096,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
soctherm_thermtrips_parse(tegra);
- soctherm_init_hw_throt_cdev(tegra);
+ soctherm_init_hw_throttling(tegra);
soctherm_init(tegra);
@@ -2183,6 +2131,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
goto disable_clocks;
}
+ soctherm_enable_hw_throttling(tegra);
err = soctherm_interrupts_init(tegra);
soctherm_debug_init(tegra);
@@ -2238,6 +2187,8 @@ static int __maybe_unused soctherm_resume(struct device *dev)
}
}
+ soctherm_enable_hw_throttling(tegra);
+
return 0;
}
@@ -83,6 +83,7 @@ struct tegra_tsensor_group {
u16 thermctl_lvl0_offset;
u32 thermctl_lvl0_up_thresh_mask;
u32 thermctl_lvl0_dn_thresh_mask;
+ bool can_throttle;
};
struct tegra_tsensor_configuration {
@@ -60,6 +60,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = {
.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,
+ .can_throttle = true,
};
static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
@@ -79,6 +80,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
.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,
+ .can_throttle = true,
};
static const struct tegra_tsensor_group tegra124_tsensor_group_pll = {
@@ -96,6 +98,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_pll = {
.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,
+ .can_throttle = false,
};
static const struct tegra_tsensor_group tegra124_tsensor_group_mem = {
@@ -115,6 +118,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_mem = {
.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,
+ .can_throttle = false,
};
static const struct tegra_tsensor_group *tegra124_tsensor_groups[] = {
@@ -60,6 +60,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = {
.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,
+ .can_throttle = true,
};
static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = {
@@ -79,6 +80,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = {
.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,
+ .can_throttle = true,
};
static const struct tegra_tsensor_group tegra132_tsensor_group_pll = {
@@ -96,6 +98,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_pll = {
.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,
+ .can_throttle = false,
};
static const struct tegra_tsensor_group tegra132_tsensor_group_mem = {
@@ -115,6 +118,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_mem = {
.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,
+ .can_throttle = false,
};
static const struct tegra_tsensor_group *tegra132_tsensor_groups[] = {
@@ -61,6 +61,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_cpu = {
.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,
+ .can_throttle = true,
};
static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = {
@@ -80,6 +81,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = {
.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,
+ .can_throttle = true,
};
static const struct tegra_tsensor_group tegra210_tsensor_group_pll = {
@@ -97,6 +99,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_pll = {
.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,
+ .can_throttle = false,
};
static const struct tegra_tsensor_group tegra210_tsensor_group_mem = {
@@ -116,6 +119,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_mem = {
.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,
+ .can_throttle = false,
};
static const struct tegra_tsensor_group *tegra210_tsensor_groups[] = {