msm: thermal: Add thermal reset feature to KTM

Add support for issuing a thermal reset from msm thermal driver.
The thermal driver is capable of monitoring all the tsens
temperatures and issuing a reset right from the boot.
The reset temperature can be given as input using devicetree.
Failure to do so will disable this feature for the target.

Change-Id: Iaf8f1764d4e4e3abb7e65f1d4397d895d195636d
Signed-off-by: Ram Chandrasekar <rkumbako@codeaurora.org>
This commit is contained in:
Ram Chandrasekar
2014-11-11 14:48:15 +05:30
committed by Manaf Meethalavalappu Pallikunhi
parent 9d80b06852
commit 750153998d
3 changed files with 119 additions and 0 deletions
@@ -100,6 +100,12 @@ Optional properties
- qcom,efuse-temperature-map: Truth table of efuse value temperature value pair for
different parts. if qcom,default temp is defined, then it can
specify only pairs which deviate from default temperature.
- qcom,therm-reset-temp: Degree above which the KTM will initiate a secure watchdog reset.
When this property is defined, KTM will monitor all the tsens from
boot time and will initiate a secure watchdog reset if any of the
tsens temperature reaches this threshold. This reset helps in
generating more informative crash dumps opposed to the crash dump
generated by the hardware reset.
Optional child nodes
- qti,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request
@@ -139,6 +145,7 @@ Example:
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
qcom,freq-control-mask = <0xf>
qcom,therm-reset-temp = <115>;
qcom,core-limit-temp = <90>;
qcom,core-temp-hysteresis = <10>;
qcom,core-control-mask = <7>;
+111
View File
@@ -39,6 +39,8 @@
#include <mach/rpm-regulator-smd.h>
#include <linux/regulator/consumer.h>
#include <linux/msm_thermal_ioctl.h>
#include <mach/rpm-smd.h>
#include <mach/scm.h>
#define MAX_CURRENT_UA 1000000
#define MAX_RAILS 5
@@ -46,6 +48,7 @@
#define MONITOR_ALL_TSENS -1
#define BYTES_PER_FUSE_ROW 8
#define MAX_EFUSE_VALUE 16
#define THERM_SECURE_BITE_CMD 8
static struct msm_thermal_data msm_thermal_info;
static struct delayed_work check_temp_work;
@@ -89,6 +92,7 @@ static bool ocr_nodes_called;
static bool ocr_probed;
static bool interrupt_mode_enable;
static bool msm_thermal_probed;
static bool therm_reset_enabled;
static int *tsens_id_map;
static DEFINE_MUTEX(vdd_rstr_mutex);
static DEFINE_MUTEX(psm_mutex);
@@ -169,6 +173,7 @@ struct psm_rail {
};
enum msm_thresh_list {
MSM_THERM_RESET,
MSM_VDD_RESTRICTION,
MSM_LIST_MAX_NR,
};
@@ -929,6 +934,73 @@ set_threshold_exit:
return ret;
}
static void msm_thermal_bite(int tsens_id, long temp)
{
pr_err("TSENS:%d reached temperature:%ld. System reset\n",
tsens_id, temp);
scm_call_atomic1(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, 0);
}
static int do_therm_reset(void)
{
int ret = 0, i;
long temp = 0;
if (!therm_reset_enabled)
return ret;
for (i = 0; i < thresh[MSM_THERM_RESET].thresh_ct; i++) {
ret = therm_get_temp(
thresh[MSM_THERM_RESET].thresh_list[i].sensor_id,
THERM_TSENS_ID,
&temp);
if (ret) {
pr_err("Unable to read TSENS sensor:%d. err:%d\n",
thresh[MSM_THERM_RESET].thresh_list[i].sensor_id,
ret);
continue;
}
if (temp >= msm_thermal_info.therm_reset_temp_degC)
msm_thermal_bite(
thresh[MSM_THERM_RESET].thresh_list[i].sensor_id, temp);
}
return ret;
}
static void therm_reset_notify(struct therm_threshold *thresh_data)
{
long temp;
int ret = 0;
if (!therm_reset_enabled)
return;
if (!thresh_data) {
pr_err("Invalid input\n");
return;
}
switch (thresh_data->trip_triggered) {
case THERMAL_TRIP_CONFIGURABLE_HI:
ret = therm_get_temp(thresh_data->sensor_id,
THERM_TSENS_ID, &temp);
if (ret)
pr_err("Unable to read TSENS sensor:%d. err:%d\n",
thresh_data->sensor_id, ret);
msm_thermal_bite(tsens_id_map[thresh_data->sensor_id],
temp);
break;
case THERMAL_TRIP_CONFIGURABLE_LOW:
break;
default:
pr_err("Invalid trip type\n");
break;
}
set_threshold(thresh_data->sensor_id, thresh_data->threshold);
}
#ifdef CONFIG_SMP
static void __ref do_core_control(long temp)
{
@@ -1266,6 +1338,8 @@ static void __ref check_temp(struct work_struct *work)
long temp = 0;
int ret = 0;
do_therm_reset();
ret = therm_get_temp(msm_thermal_info.sensor_id, THERM_TSENS_ID, &temp);
if (ret) {
pr_err("Unable to read TSENS sensor:%d. err:%d\n",
@@ -1740,6 +1814,9 @@ static void thermal_monitor_init(void)
goto init_exit;
}
if (therm_reset_enabled)
therm_set_threshold(&thresh[MSM_THERM_RESET]);
if (vdd_rstr_enabled)
therm_set_threshold(&thresh[MSM_VDD_RESTRICTION]);
@@ -3047,6 +3124,38 @@ hotplug_node_fail:
return ret;
}
static int probe_therm_reset(struct device_node *node,
struct msm_thermal_data *data,
struct platform_device *pdev)
{
char *key = NULL;
int ret = 0;
key = "qcom,therm-reset-temp";
ret = of_property_read_u32(node, key, &data->therm_reset_temp_degC);
if (ret)
goto PROBE_RESET_EXIT;
ret = init_threshold(MSM_THERM_RESET, MONITOR_ALL_TSENS,
data->therm_reset_temp_degC, data->therm_reset_temp_degC - 10,
therm_reset_notify);
if (ret) {
pr_err("Therm reset data structure init failed\n");
goto PROBE_RESET_EXIT;
}
therm_reset_enabled = true;
PROBE_RESET_EXIT:
if (ret) {
dev_info(&pdev->dev,
"%s:Failed reading node=%s, key=%s err=%d. KTM continues\n",
__func__, node->full_name, key, ret);
therm_reset_enabled = false;
}
return ret;
}
static int probe_freq_mitigation(struct device_node *node,
struct msm_thermal_data *data,
struct platform_device *pdev)
@@ -3132,6 +3241,8 @@ static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
ret = probe_cc(node, &data, pdev);
ret = probe_freq_mitigation(node, &data, pdev);
ret = probe_therm_reset(node, &data, pdev);
/*
* Probe optional properties below. Call probe_psm before
* probe_vdd_rstr because rpm_regulator_get has to be called
+1
View File
@@ -36,6 +36,7 @@ struct msm_thermal_data {
int32_t psm_temp_hyst_degC;
int32_t ocr_temp_degC;
int32_t ocr_temp_hyst_degC;
int32_t therm_reset_temp_degC;
};
#ifdef CONFIG_THERMAL_MONITOR