Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 320731c1 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: thermal: Add support for emergency frequency mitigation"

parents 7c7307a1 85947c7f
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -43,6 +43,29 @@ Optional properties
- qcpm,cpu-sensors:     List of type names in thermal zone device struct which maps
			to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many
			cpus there are.
- qcom,freq-mitigation-temp: Threshold temperature to mitigate
			the CPU max frequency in degC. This will be
			used when polling based frequency control is disabled.
			The difference between freq-mitigation-temp
			and limit-temp is that limit-temp is used during
			early boot prior to thermal_sys being available for registering
			temperature thresholds. Also, this emergency frequency
			mitigation is a single step frequency mitigation to a predefined value
			as opposed to the step by step frequency mitigation during boot-up.
- qcom,freq-mitigation-temp-hysteresis: Degrees C below which thermal will not mitigate the
			cpu max frequency.
- qcom,freq-mitigation-value: The frequency value (in kHz) to which the thermal
			should mitigate the CPU, when the freq-mitigation-temp
			threshold is reached.
- qcom,freq-mitigation-control-mask: The frequency mitigation bitmask that will be
			used to determine if KTM should do emergency frequency
			mitigation for a core or not. A mask of 0x00 indicates the
			mitigation is disabled for all the cores and a mask of 0x05
			indicates this mitigation is enabled for cpu-0 and cpu-2.
			Note: For KTM's frequency mitigation to work, the data for all the
			above four properties (qcom,freq-mitigation-temp; qcom,
			freq-mitigation-temp-hysteresis; qcom,freq-mitigation-value and
			qcom,freq-mitigation-control-mask) should be populated.
- qcom,vdd-restriction-temp: When temperature is below this threshold, will
			enable vdd restriction which will set higher voltage on
			key voltage rails, in degC.
@@ -97,6 +120,10 @@ Example:
		qcom,hotplug-temp-hysteresis = <20>;
		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
				"tsens_tz_sensor7", "tsens_tz_sensor8";
		qcom,freq-mitigation-temp = <110>;
		qcom,freq-mitigation-temp-hysteresis = <20>;
		qcom,freq-mitigation-value = <960000>;
		qcom,freq-mitigation-control-mask = <0x01>;
		qcom,pmic-sw-mode-temp = <90>;
		qcom,pmic-sw-mode-temp-hysteresis = <80>;
		qcom,pmic-sw-mode-regs = "vdd-dig";
+271 −79
Original line number Diff line number Diff line
@@ -40,8 +40,6 @@
#define MAX_THRESHOLD 2

static struct msm_thermal_data msm_thermal_info;
static uint32_t limited_max_freq = UINT_MAX;
static uint32_t limited_min_freq;
static struct delayed_work check_temp_work;
static bool core_control_enabled;
static uint32_t cpus_offlined;
@@ -52,7 +50,9 @@ static struct kobject *tt_kobj;
static struct kobject *cc_kobj;
static struct work_struct timer_work;
static struct task_struct *hotplug_task;
static struct task_struct *freq_mitigation_task;
static struct completion hotplug_notify_complete;
static struct completion freq_mitigation_complete;

static int enabled;
static int rails_cnt;
@@ -70,18 +70,32 @@ static bool vdd_rstr_probed;
static bool psm_enabled;
static bool psm_nodes_called;
static bool psm_probed;
static bool freq_mitigation_enabled;
static int *tsens_id_map;
static DEFINE_MUTEX(vdd_rstr_mutex);
static DEFINE_MUTEX(psm_mutex);
static uint32_t min_freq_limit;

enum thermal_threshold {
	HOTPLUG_THRESHOLD_HIGH,
	HOTPLUG_THRESHOLD_LOW,
	FREQ_THRESHOLD_HIGH,
	FREQ_THRESHOLD_LOW,
	THRESHOLD_MAX_NR,
};

struct cpu_info {
	uint32_t cpu;
	bool offline;
	bool user_offline;
	bool thresh_cleared;
	const char *sensor_type;
	uint32_t sensor_id;
	struct sensor_threshold thresh[MAX_THRESHOLD];
	bool offline;
	bool user_offline;
	bool hotplug_thresh_clear;
	struct sensor_threshold threshold[THRESHOLD_MAX_NR];
	bool max_freq;
	uint32_t limited_max_freq;
	uint32_t limited_min_freq;
	bool freq_thresh_clear;
};

struct rail {
@@ -162,11 +176,20 @@ static int msm_thermal_cpufreq_callback(struct notifier_block *nfb,
		unsigned long event, void *data)
{
	struct cpufreq_policy *policy = data;
	uint32_t max_freq_req = cpus[policy->cpu].limited_max_freq;
	uint32_t min_freq_req = cpus[policy->cpu].limited_min_freq;

	switch (event) {
	case CPUFREQ_INCOMPATIBLE:
		cpufreq_verify_within_limits(policy, limited_min_freq,
				limited_max_freq);
		pr_debug("%s: mitigating cpu %d to freq max: %u min: %u\n",
		KBUILD_MODNAME, policy->cpu, max_freq_req, min_freq_req);

		cpufreq_verify_within_limits(policy, min_freq_req,
			max_freq_req);

		if (max_freq_req < min_freq_req)
			pr_err("Invalid frequency request Max:%u Min:%u\n",
				max_freq_req, min_freq_req);
		break;
	}
	return NOTIFY_OK;
@@ -192,9 +215,17 @@ static int check_freq_table(void)
	return ret;
}

static void update_cpu_freq(int cpu)
{
	if (cpu_online(cpu)) {
		if (cpufreq_update_policy(cpu))
			pr_err("Unable to update policy for cpu:%d\n", cpu);
	}
}

static int update_cpu_min_freq_all(uint32_t min)
{
	int cpu = 0;
	uint32_t cpu = 0;
	int ret = 0;

	if (!freq_table_get) {
@@ -207,15 +238,17 @@ static int update_cpu_min_freq_all(uint32_t min)
	/* If min is larger than allowed max */
	min = min(min, table[limit_idx_high].frequency);

	limited_min_freq = min;

	if (freq_mitigation_task) {
		min_freq_limit = min;
		complete(&freq_mitigation_complete);
	} else {
		get_online_cpus();
	for_each_online_cpu(cpu) {
		if (cpufreq_update_policy(cpu))
			pr_info("%s: Unable to update policy for cpu:%d\n",
				KBUILD_MODNAME, cpu);
		for_each_possible_cpu(cpu) {
			cpus[cpu].limited_min_freq = min;
			update_cpu_freq(cpu);
		}
		put_online_cpus();
	}

	return ret;
}
@@ -606,27 +639,6 @@ fail:
	return ret;
}

static int update_cpu_max_freq(int cpu, uint32_t max_freq)
{
	int ret = 0;

	if (max_freq != UINT_MAX)
		pr_info("%s: Limiting cpu%d max frequency to %d\n",
				KBUILD_MODNAME, cpu, max_freq);
	else
		pr_info("%s: Max frequency reset for cpu%d\n",
				KBUILD_MODNAME, cpu);
	get_online_cpus();
	for_each_online_cpu(cpu) {
		if (cpufreq_update_policy(cpu))
			pr_info("%s: Unable to update policy for cpu:%d\n",
				KBUILD_MODNAME, cpu);
	}
	put_online_cpus();

	return ret;
}

static int set_and_activate_threshold(uint32_t sensor_id,
	struct sensor_threshold *threshold)
{
@@ -786,10 +798,11 @@ static __ref int do_hotplug(void *data)

		mutex_lock(&core_control_mutex);
		for_each_possible_cpu(cpu) {
			if (cpus[cpu].thresh_cleared) {
			if (cpus[cpu].hotplug_thresh_clear) {
				set_threshold(cpus[cpu].sensor_id,
					cpus[cpu].thresh);
				cpus[cpu].thresh_cleared = false;
				&cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH]);

				cpus[cpu].hotplug_thresh_clear = false;
			}
			if (cpus[cpu].offline || cpus[cpu].user_offline)
				mask |= BIT(cpu);
@@ -913,14 +926,14 @@ exit:

static void do_freq_control(long temp)
{
	int cpu = 0;
	uint32_t max_freq = limited_max_freq;
	uint32_t cpu = 0;
	uint32_t max_freq = cpus[cpu].limited_max_freq;

	if (temp >= msm_thermal_info.limit_temp_degC) {
		if (limit_idx == limit_idx_low)
			return;

		limit_idx -= msm_thermal_info.freq_step;
		limit_idx -= msm_thermal_info.bootup_freq_step;
		if (limit_idx < limit_idx_low)
			limit_idx = limit_idx_low;
		max_freq = table[limit_idx].frequency;
@@ -929,7 +942,7 @@ static void do_freq_control(long temp)
		if (limit_idx == limit_idx_high)
			return;

		limit_idx += msm_thermal_info.freq_step;
		limit_idx += msm_thermal_info.bootup_freq_step;
		if (limit_idx >= limit_idx_high) {
			limit_idx = limit_idx_high;
			max_freq = UINT_MAX;
@@ -937,16 +950,18 @@ static void do_freq_control(long temp)
			max_freq = table[limit_idx].frequency;
	}

	if (max_freq == limited_max_freq)
	if (max_freq == cpus[cpu].limited_max_freq)
		return;

	limited_max_freq = max_freq;
	/* Update new limits */
	get_online_cpus();
	for_each_possible_cpu(cpu) {
		if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
		if (!(msm_thermal_info.bootup_freq_control_mask & BIT(cpu)))
			continue;
		update_cpu_max_freq(cpu, max_freq);
		cpus[cpu].limited_max_freq = max_freq;
		update_cpu_freq(cpu);
	}
	put_online_cpus();
}

static void check_temp(struct work_struct *work)
@@ -986,7 +1001,7 @@ reschedule:
static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb,
		unsigned long action, void *hcpu)
{
	unsigned int cpu = (unsigned long)hcpu;
	uint32_t cpu = (uint32_t)hcpu;

	if (action == CPU_UP_PREPARE || action == CPU_UP_PREPARE_FROZEN) {
		if (core_control_enabled &&
@@ -1058,7 +1073,7 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data)
		break;
	}
	if (hotplug_task) {
		cpu_node->thresh_cleared = true;
		cpu_node->hotplug_thresh_clear = true;
		complete(&hotplug_notify_complete);
	} else
		pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
@@ -1069,7 +1084,7 @@ static int hotplug_init_cpu_offlined(void)
{
	struct tsens_device tsens_dev;
	long temp = 0;
	int cpu = 0;
	uint32_t cpu = 0;

	mutex_lock(&core_control_mutex);
	for_each_possible_cpu(cpu) {
@@ -1102,29 +1117,29 @@ static int hotplug_init_cpu_offlined(void)

static void hotplug_init(void)
{
	int cpu = 0;
	uint32_t cpu = 0;
	struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL;

	if (hotplug_task)
		return;

	for_each_possible_cpu(cpu) {
		cpus[cpu].cpu = (uint32_t)cpu;
		cpus[cpu].thresh_cleared = false;
		cpus[cpu].sensor_id =
			sensor_get_id((char *)cpus[cpu].sensor_type);
		if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
			continue;
		cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
		cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
		cpus[cpu].thresh[0].notify = hotplug_notify;
		cpus[cpu].thresh[0].data = (void *)&cpus[cpu];

		cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
		hi_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH];
		low_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_LOW];
		hi_thresh->temp = msm_thermal_info.hotplug_temp_degC;
		hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI;
		low_thresh->temp = msm_thermal_info.hotplug_temp_degC -
				msm_thermal_info.hotplug_temp_hysteresis_degC;
		cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
		cpus[cpu].thresh[1].notify = hotplug_notify;
		cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
		set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh);
		low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW;
		hi_thresh->notify = low_thresh->notify = hotplug_notify;
		hi_thresh->data = low_thresh->data = (void *)&cpus[cpu];

		set_threshold(cpus[cpu].sensor_id, hi_thresh);
	}
	init_completion(&hotplug_notify_complete);
	hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
@@ -1141,6 +1156,124 @@ static void hotplug_init(void)
		kthread_stop(hotplug_task);
}

static __ref int do_freq_mitigation(void *data)
{
	int ret = 0;
	uint32_t cpu = 0, max_freq_req = 0;

	while (!kthread_should_stop()) {
		wait_for_completion(&freq_mitigation_complete);
		INIT_COMPLETION(freq_mitigation_complete);

		get_online_cpus();
		for_each_possible_cpu(cpu) {
			max_freq_req = (cpus[cpu].max_freq) ?
					msm_thermal_info.freq_limit :
					UINT_MAX;

			if ((max_freq_req == cpus[cpu].limited_max_freq)
				&& (min_freq_limit ==
				cpus[cpu].limited_min_freq))
				goto reset_threshold;

			cpus[cpu].limited_max_freq = max_freq_req;
			cpus[cpu].limited_min_freq = min_freq_limit;
			update_cpu_freq(cpu);
reset_threshold:
			if (cpus[cpu].freq_thresh_clear) {
				set_threshold(cpus[cpu].sensor_id,
				&cpus[cpu].threshold[FREQ_THRESHOLD_HIGH]);

				cpus[cpu].freq_thresh_clear = false;
			}
		}
		put_online_cpus();
	}
	return ret;
}

static int freq_mitigation_notify(enum thermal_trip_type type,
	int temp, void *data)
{
	struct cpu_info *cpu_node = (struct cpu_info *) data;

	pr_debug("%s: %s reached temp threshold: %d\n", KBUILD_MODNAME,
		cpu_node->sensor_type, temp);

	if (!(msm_thermal_info.freq_mitig_control_mask &
		BIT(cpu_node->cpu)))
		return 0;

	switch (type) {
	case THERMAL_TRIP_CONFIGURABLE_HI:
		if (!cpu_node->max_freq) {
			pr_info("%s: Mitigating cpu %d frequency to %d\n",
				KBUILD_MODNAME, cpu_node->cpu,
				msm_thermal_info.freq_limit);

			cpu_node->max_freq = true;
		}
		break;
	case THERMAL_TRIP_CONFIGURABLE_LOW:
		if (cpu_node->max_freq) {
			pr_info("%s: Removing frequency mitigation for cpu%d\n",
				KBUILD_MODNAME, cpu_node->cpu);

			cpu_node->max_freq = false;
		}
		break;
	default:
		break;
	}

	if (freq_mitigation_task) {
		cpu_node->freq_thresh_clear = true;
		complete(&freq_mitigation_complete);
	} else {
		pr_err("%s: Frequency mitigation task is not initialized\n",
			KBUILD_MODNAME);
	}

	return 0;
}

static void freq_mitigation_init(void)
{
	uint32_t cpu = 0;
	struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL;

	if (!freq_mitigation_enabled || freq_mitigation_task)
		return;

	for_each_possible_cpu(cpu) {
		if (!(msm_thermal_info.freq_mitig_control_mask & BIT(cpu)))
			continue;
		hi_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH];
		low_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_LOW];

		hi_thresh->temp = msm_thermal_info.freq_mitig_temp_degc;
		hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI;
		low_thresh->temp = msm_thermal_info.freq_mitig_temp_degc -
			msm_thermal_info.freq_mitig_temp_hysteresis_degc;
		low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW;
		hi_thresh->notify = low_thresh->notify =
			freq_mitigation_notify;
		hi_thresh->data = low_thresh->data = (void *)&cpus[cpu];

		set_threshold(cpus[cpu].sensor_id, hi_thresh);
	}

	init_completion(&freq_mitigation_complete);
	freq_mitigation_task = kthread_run(do_freq_mitigation, NULL,
		"msm_thermal:freq_mitig");

	if (IS_ERR(freq_mitigation_task)) {
		pr_err("%s: Failed to create frequency mitigation thread\n",
				KBUILD_MODNAME);
		return;
	}
}

/*
 * We will reset the cpu frequencies limits here. The core online/offline
 * status will be carried over to the process stopping the msm_thermal, as
@@ -1148,21 +1281,20 @@ static void hotplug_init(void)
 */
static void __ref disable_msm_thermal(void)
{
	int cpu = 0;
	uint32_t cpu = 0;

	/* make sure check_temp is no longer running */
	cancel_delayed_work(&check_temp_work);
	flush_scheduled_work();

	if (limited_max_freq == UINT_MAX)
		return;

	limited_max_freq = UINT_MAX;
	get_online_cpus();
	for_each_online_cpu(cpu) {
		if (cpufreq_update_policy(cpu))
			pr_info("%s: Unable to update policy for cpu:%d\n",
				KBUILD_MODNAME, cpu);
	for_each_possible_cpu(cpu) {
		if (cpus[cpu].limited_max_freq == UINT_MAX &&
			cpus[cpu].limited_min_freq == 0)
			continue;
		cpus[cpu].limited_max_freq = UINT_MAX;
		cpus[cpu].limited_min_freq = 0;
		update_cpu_freq(cpu);
	}
	put_online_cpus();
}
@@ -1175,6 +1307,7 @@ static int __ref set_enabled(const char *val, const struct kernel_param *kp)
	if (!enabled) {
		disable_msm_thermal();
		hotplug_init();
		freq_mitigation_init();
	} else
		pr_info("%s: no action for enabled = %d\n",
			KBUILD_MODNAME, enabled);
@@ -1242,7 +1375,7 @@ static ssize_t __ref store_cpus_offlined(struct kobject *kobj,
{
	int ret = 0;
	uint32_t val = 0;
	int cpu;
	uint32_t cpu;

	mutex_lock(&core_control_mutex);
	ret = kstrtouint(buf, 10, &val);
@@ -1407,6 +1540,7 @@ failed:
int msm_thermal_init(struct msm_thermal_data *pdata)
{
	int ret = 0;
	uint32_t cpu;

	BUG_ON(!pdata);
	tsens_get_max_sensor_num(&max_tsens_num);
@@ -1418,7 +1552,10 @@ int msm_thermal_init(struct msm_thermal_data *pdata)
		return -EINVAL;

	enabled = 1;

	for_each_possible_cpu(cpu) {
		cpus[cpu].limited_max_freq = UINT_MAX;
		cpus[cpu].limited_min_freq = 0;
	}
	ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
			CPUFREQ_POLICY_NOTIFIER);
	if (ret)
@@ -1839,9 +1976,9 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data,
		struct platform_device *pdev)
{
	char *key = NULL;
	int cpu_cnt = 0;
	uint32_t cpu_cnt = 0;
	int ret = 0;
	int cpu = 0;
	uint32_t cpu = 0;

	key = "qcom,core-limit-temp";
	ret = of_property_read_u32(node, key, &data->core_limit_temp_degC);
@@ -1880,6 +2017,7 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data,
		cpus[cpu].cpu = cpu;
		cpus[cpu].offline = 0;
		cpus[cpu].user_offline = 0;
		cpus[cpu].hotplug_thresh_clear = false;
		ret = of_property_read_string_index(node, key, cpu,
				&cpus[cpu].sensor_type);
		if (ret)
@@ -1900,6 +2038,53 @@ read_node_fail:
	return ret;
}

static int probe_freq_mitigation(struct device_node *node,
		struct msm_thermal_data *data,
		struct platform_device *pdev)
{
	char *key = NULL;
	int ret = 0;
	uint32_t cpu;

	key = "qcom,freq-mitigation-temp";
	ret = of_property_read_u32(node, key, &data->freq_mitig_temp_degc);
	if (ret)
		goto PROBE_FREQ_EXIT;

	key = "qcom,freq-mitigation-temp-hysteresis";
	ret = of_property_read_u32(node, key,
		&data->freq_mitig_temp_hysteresis_degc);
	if (ret)
		goto PROBE_FREQ_EXIT;

	key = "qcom,freq-mitigation-value";
	ret = of_property_read_u32(node, key, &data->freq_limit);
	if (ret)
		goto PROBE_FREQ_EXIT;

	key = "qcom,freq-mitigation-control-mask";
	ret = of_property_read_u32(node, key, &data->freq_mitig_control_mask);
	if (ret)
		goto PROBE_FREQ_EXIT;

	freq_mitigation_enabled = 1;
	for_each_possible_cpu(cpu) {
		cpus[cpu].max_freq = false;
		cpus[cpu].limited_max_freq = UINT_MAX;
		cpus[cpu].limited_min_freq = 0;
		cpus[cpu].freq_thresh_clear = false;
	}

PROBE_FREQ_EXIT:
	if (ret) {
		dev_info(&pdev->dev,
			"%s:Failed reading node=%s, key=%s. KTM continues\n",
			__func__, node->full_name, key);
		freq_mitigation_enabled = 0;
	}
	return ret;
}

static int msm_thermal_dev_probe(struct platform_device *pdev)
{
	int ret = 0;
@@ -1930,14 +2115,16 @@ static int msm_thermal_dev_probe(struct platform_device *pdev)
		goto fail;

	key = "qcom,freq-step";
	ret = of_property_read_u32(node, key, &data.freq_step);
	ret = of_property_read_u32(node, key, &data.bootup_freq_step);
	if (ret)
		goto fail;

	key = "qcom,freq-control-mask";
	ret = of_property_read_u32(node, key, &data.freq_control_mask);
	ret = of_property_read_u32(node, key, &data.bootup_freq_control_mask);

	ret = probe_cc(node, &data, pdev);

	ret = probe_freq_mitigation(node, &data, pdev);
	/*
	 * Probe optional properties below. Call probe_psm before
	 * probe_vdd_rstr because rpm_regulator_get has to be called
@@ -1973,6 +2160,10 @@ fail:
	return ret;
}

static int msm_thermal_dev_exit(struct platform_device *inp_dev)
{
	return 0;
}

static struct of_device_id msm_thermal_match_table[] = {
	{.compatible = "qcom,msm-thermal"},
@@ -1986,6 +2177,7 @@ static struct platform_driver msm_thermal_device_driver = {
		.owner = THIS_MODULE,
		.of_match_table = msm_thermal_match_table,
	},
	.remove = msm_thermal_dev_exit,
};

int __init msm_thermal_device_init(void)
+6 −2
Original line number Diff line number Diff line
@@ -19,13 +19,17 @@ struct msm_thermal_data {
	uint32_t poll_ms;
	int32_t limit_temp_degC;
	int32_t temp_hysteresis_degC;
	uint32_t freq_step;
	uint32_t freq_control_mask;
	uint32_t bootup_freq_step;
	uint32_t bootup_freq_control_mask;
	int32_t core_limit_temp_degC;
	int32_t core_temp_hysteresis_degC;
	int32_t hotplug_temp_degC;
	int32_t hotplug_temp_hysteresis_degC;
	uint32_t core_control_mask;
	uint32_t freq_mitig_temp_degc;
	uint32_t freq_mitig_temp_hysteresis_degc;
	uint32_t freq_mitig_control_mask;
	uint32_t freq_limit;
	int32_t vdd_rstr_temp_degC;
	int32_t vdd_rstr_temp_hyst_degC;
	int32_t psm_temp_degC;