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

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

Merge "ARM: dts: mdm: Enable thermal DDR frequency restriction for mdm9607"

parents d5e23dae 0ae06ac2
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -105,6 +105,10 @@ Optional properties
- qcom,disable-cx-phase-ctrl: If this property is defined, the feature
			cx phase control will be disabled. All other properties
			corresponding to this feature will be ignored.
- qcom,therm-ddr-lm-info: If this optional property is defined, it enables
			DDR frequency restriction feature. It expects array of
			sensor id to be monitored, high threshold  and low threshold
			for that sensor respectively.

Optional child nodes
- qcom,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request
@@ -280,6 +284,7 @@ Example:
		qcom,cx-retention-min = <RPM_SMD_REGULATOR_LEVEL_RETENTION_PLUS>;
		vdd-cx-supply = <&pmd9635_s5_level>;
		qcom,online-hotplug-core;
		qcom,therm-ddr-lm-info = <1 90 75>;
		qcom,synchronous-cluster-id = <0 1>; /* Indicates cluster 0 and 1 are synchronous */
		qcom,synchronous-cluster-map =  <0 2 &CPU0 &CPU1>,
						<1 2 &CPU2 &CPU3>;
+1 −0
Original line number Diff line number Diff line
@@ -1224,6 +1224,7 @@
		qcom,vdd-restriction-temp = <5>;
		qcom,vdd-restriction-temp-hysteresis = <10>;
		vdd-dig-supply = <&mdm9607_s3_floor_level>;
		qcom,therm-ddr-lm-info = <2 78 70>;

		qcom,vdd-dig-rstr{
			qcom,vdd-rstr-reg = "vdd-dig";
+246 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#include <linux/suspend.h>
#include <linux/uaccess.h>
#include <linux/uio_driver.h>
#include <linux/msm-bus.h>

#define CREATE_TRACE_POINTS
#define TRACE_MSM_THERMAL
@@ -74,6 +75,9 @@
#define DEVM_NAME_MAX 30
#define HOTPLUG_RETRY_INTERVAL_MS 100
#define UIO_VERSION "1.0"
#define THERM_DDR_MASTER_ID  1
#define THERM_DDR_SLAVE_ID   512
#define THERM_DDR_IB_VOTE_REQ   366000000

#define VALIDATE_AND_SET_MASK(_node, _key, _mask, _cpu) \
	do { \
@@ -165,6 +169,7 @@ static bool gfx_warm_phase_ctrl_enabled;
static bool cx_phase_ctrl_enabled;
static bool vdd_mx_enabled;
static bool therm_reset_enabled;
static bool therm_ddr_lm_enabled;
static bool online_core;
static bool cluster_info_probed;
static bool cluster_info_nodes_called;
@@ -205,6 +210,12 @@ enum thermal_threshold {
	THRESHOLD_MAX_NR,
};

enum therm_ddr_events {
	THERM_DDR_LOW_THRESH = 0,
	THERM_DDR_HIGH_THRESH,
	THERM_DDR_MAX_THRESH
};

struct cluster_info {
	int cluster_id;
	uint32_t entity_count;
@@ -287,6 +298,7 @@ enum msm_thresh_list {
	MSM_GFX_PHASE_CTRL_HOT,
	MSM_OCR,
	MSM_VDD_MX_RESTRICTION,
	MSM_THERM_DDR_LM,
	MSM_LIST_MAX_NR,
};

@@ -348,6 +360,8 @@ static struct cluster_info *core_ptr;
static struct msm_thermal_debugfs_entry *msm_therm_debugfs;
static struct devmgr_devices *devices;
static struct msm_thermal_debugfs_thresh_config *mit_config;
static struct msm_bus_scale_pdata *therm_ddr_lm_data;
static uint8_t therm_ddr_lm_handle;

struct vdd_rstr_enable {
	struct kobj_attribute ko_attr;
@@ -2776,6 +2790,78 @@ static void therm_reset_notify(struct therm_threshold *thresh_data)
					thresh_data->threshold);
}

static int therm_ddr_lm_apply_limit(bool enable)
{
	static bool ddr_lm_applied;
	int ret = 0;

	if (ddr_lm_applied == enable)
		return 0;

	ret = msm_bus_scale_client_update_request(therm_ddr_lm_handle, enable);
	if (ret) {
		pr_err("Failed to %s ddr lm limit. ret:%d\n",
			enable ? "Apply" : "Clear", ret);
		return ret;
	}
	ddr_lm_applied = enable;
	pr_debug("Thermal DDR restriction is %s\n", enable ?
		"Applied" : "Cleared");

	return 0;
}

static inline void cleanup_bus_data(struct msm_bus_scale_pdata *data,
			struct platform_device *pdev)
{
	int i = 0;

	if (therm_ddr_lm_handle) {
		therm_ddr_lm_apply_limit(false);
		msm_bus_scale_unregister_client(therm_ddr_lm_handle);
	}
	if (data) {
		if (data->usecase) {
			for (; i < THERM_DDR_MAX_THRESH; i++)
				if (data->usecase[i].vectors)
					devm_kfree(&pdev->dev,
						data->usecase[i].vectors);

			devm_kfree(&pdev->dev, data->usecase);
		}
		devm_kfree(&pdev->dev, data);
	}
}

static void therm_ddr_lm_notify(struct therm_threshold *trig_thresh)
{
	if (!therm_ddr_lm_enabled)
		return;

	if (!trig_thresh) {
		pr_err("Invalid input\n");
		return;
	}

	switch (trig_thresh->trip_triggered) {
	case THERMAL_TRIP_CONFIGURABLE_HI:
		therm_ddr_lm_apply_limit(true);
		break;
	case THERMAL_TRIP_CONFIGURABLE_LOW:
		therm_ddr_lm_apply_limit(false);
		break;
	default:
		pr_err("Invalid trip type\n");
		return;
	}

	if (trig_thresh->cur_state != trig_thresh->trip_triggered) {
		sensor_mgr_set_threshold(trig_thresh->sensor_id,
			trig_thresh->threshold);
		trig_thresh->cur_state = trig_thresh->trip_triggered;
	}
}

static void retry_hotplug(struct work_struct *work)
{
	mutex_lock(&core_control_mutex);
@@ -4391,6 +4477,8 @@ therm_set_exit:

static void thermal_monitor_init(void)
{
	int ret = 0;

	if (thermal_monitor_task)
		return;

@@ -4436,6 +4524,15 @@ static void thermal_monitor_init(void)
		!(convert_to_zone_id(&thresh[MSM_VDD_MX_RESTRICTION])))
		therm_set_threshold(&thresh[MSM_VDD_MX_RESTRICTION]);

	if (therm_ddr_lm_enabled &&
		!(convert_to_zone_id(&thresh[MSM_THERM_DDR_LM]))) {
		thresh[MSM_THERM_DDR_LM].thresh_list->trip_triggered = -1;
		ret = sensor_mgr_set_threshold(
			thresh[MSM_THERM_DDR_LM].thresh_list->sensor_id,
			thresh[MSM_THERM_DDR_LM].thresh_list->threshold);
		if (!IS_HI_THRESHOLD_SET(ret))
			therm_ddr_lm_apply_limit(true);
	}
init_exit:
	return;
}
@@ -6106,6 +6203,128 @@ fetch_mitig_exit:
	return err;
}

static int msm_bus_data_init(struct platform_device *pdev)
{
	struct msm_bus_scale_pdata *ddr_bus_data = NULL;
	int ret = 0, i = 0;

	ddr_bus_data = devm_kzalloc(&pdev->dev, sizeof(*ddr_bus_data),
			GFP_KERNEL);
	if (!ddr_bus_data) {
		ret = -ENOMEM;
		goto bus_exit;
	}
	ddr_bus_data->num_usecases = THERM_DDR_MAX_THRESH;
	ddr_bus_data->name = KBUILD_MODNAME;
	ddr_bus_data->usecase = devm_kcalloc(&pdev->dev, THERM_DDR_MAX_THRESH,
					sizeof(*(ddr_bus_data->usecase)),
					GFP_KERNEL);
	if (!ddr_bus_data->usecase) {
		ret =  -ENOMEM;
		goto bus_exit;
	}
	for (i = 0; i < THERM_DDR_MAX_THRESH; i++) {
		ddr_bus_data->usecase[i].num_paths = 1;
		ddr_bus_data->usecase[i].vectors = devm_kzalloc(&pdev->dev,
				sizeof(*(ddr_bus_data->usecase[i].vectors)),
				GFP_KERNEL);
		if (!ddr_bus_data->usecase[i].vectors) {
			ret =  -ENOMEM;
			goto bus_exit;
		}
		/* set common entry values */
		ddr_bus_data->usecase[i].vectors->src = THERM_DDR_MASTER_ID;
		ddr_bus_data->usecase[i].vectors->dst = THERM_DDR_SLAVE_ID;
		ddr_bus_data->usecase[i].vectors->ab = 0;
	}

	ddr_bus_data->usecase[THERM_DDR_LOW_THRESH].vectors->ib = 0;
	ddr_bus_data->usecase[THERM_DDR_HIGH_THRESH].vectors->ib =
							THERM_DDR_IB_VOTE_REQ;
	therm_ddr_lm_handle = msm_bus_scale_register_client(ddr_bus_data);
	if (!therm_ddr_lm_handle) {
		pr_err("Failed to register with bus driver\n");
		ret = -EINVAL;
		goto bus_exit;
	}

	therm_ddr_lm_data = ddr_bus_data;
bus_exit:
	if (ret)
		cleanup_bus_data(ddr_bus_data, pdev);

	return ret;
}

static void thermal_ddr_lm_disable(void)
{
	int ret = 0;

	THERM_MITIGATION_DISABLE(therm_ddr_lm_enabled,
		MSM_THERM_DDR_LM);
	ret = therm_ddr_lm_apply_limit(false);
	if (ret)
		pr_err("Disable ddr lm failed. err:%d\n", ret);
}

static int probe_therm_ddr_lm(struct platform_device *pdev)
{
	char *key = NULL;
	int ret = 0, arr_size = 0;
	struct device_node *node = pdev->dev.of_node;
	enum ddr_therm_cfg {
		THERM_DDR_SENS_ID = 0,
		THERM_DDR_HIGH_TEMP,
		THERM_DDR_LOW_TEMP,
		THERM_DDR_MAX_ENTRY
	};
	uint32_t therm_ddr_data[THERM_DDR_MAX_ENTRY] = {0};

	key = "qcom,therm-ddr-lm-info";
	if (!of_get_property(node, key, &arr_size) ||
		arr_size <= 0)
		return 0;

	arr_size = arr_size / sizeof(__be32);
	if (arr_size != THERM_DDR_MAX_ENTRY)
		goto PROBE_DDR_LM_EXIT;

	ret = of_property_read_u32_array(node, key,
		therm_ddr_data, THERM_DDR_MAX_ENTRY);
	if (ret)
		goto PROBE_DDR_LM_EXIT;

	/* Initialize bus APIs */
	ret = msm_bus_data_init(pdev);
	if (ret)
		goto PROBE_DDR_LM_EXIT;

	ret = sensor_mgr_init_threshold(&thresh[MSM_THERM_DDR_LM],
		therm_ddr_data[THERM_DDR_SENS_ID],
		therm_ddr_data[THERM_DDR_HIGH_TEMP],
		therm_ddr_data[THERM_DDR_LOW_TEMP],
		therm_ddr_lm_notify);
	if (ret) {
		pr_err("ddr lm sensor init failed\n");
		goto PROBE_DDR_LM_EXIT;
	}

	therm_ddr_lm_enabled = true;
	snprintf(mit_config[MSM_THERM_DDR_LM].config_name,
		MAX_DEBUGFS_CONFIG_LEN, "ddr_lm");
	mit_config[MSM_THERM_DDR_LM].disable_config = thermal_ddr_lm_disable;

PROBE_DDR_LM_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_ddr_lm_enabled = false;
	}

	return ret;
}

static void probe_sensor_info(struct device_node *node,
		struct msm_thermal_data *data, struct platform_device *pdev)
{
@@ -6823,6 +7042,21 @@ static void thermal_ocr_config_read(struct seq_file *m, void *data)
	}
}

static void therm_ddr_lm_config_read(struct seq_file *m, void *data)
{
	if (therm_ddr_lm_enabled) {
		seq_puts(m, "\n-----DDR Restriction(DDR LM)-----\n");
		seq_printf(m, "threshold:%ld degC\n",
			thresh[
			MSM_THERM_DDR_LM].thresh_list->threshold[0].temp);
		seq_printf(m, "threshold clear:%ld degC\n",
			thresh[
			MSM_THERM_DDR_LM].thresh_list->threshold[1].temp);
		seq_printf(m, "tsens sensor:tsens_tz_sensor%d\n",
			thresh[MSM_THERM_DDR_LM].thresh_list->sensor_id);
	}
}

static void thermal_phase_ctrl_config_read(struct seq_file *m, void *data)
{
	if (cx_phase_ctrl_enabled) {
@@ -6861,6 +7095,7 @@ static void thermal_disable_all_mitigation(void)
	thermal_vdd_mit_disable();
	thermal_psm_mit_disable();
	thermal_ocr_mit_disable();
	thermal_ddr_lm_disable();
	thermal_cx_phase_ctrl_mit_disable();
	thermal_gfx_phase_warm_ctrl_mit_disable();
	thermal_gfx_phase_crit_ctrl_mit_disable();
@@ -6890,6 +7125,9 @@ static void enable_config(int config_id)
	case MSM_VDD_MX_RESTRICTION:
		vdd_mx_enabled = 1;
		break;
	case MSM_THERM_DDR_LM:
		therm_ddr_lm_enabled = 1;
		break;
	case MSM_LIST_MAX_NR + HOTPLUG_CONFIG:
		hotplug_enabled = 1;
		break;
@@ -6993,6 +7231,7 @@ static int thermal_config_debugfs_read(struct seq_file *m, void *data)
	thermal_psm_config_read(m, data);
	thermal_ocr_config_read(m, data);
	thermal_phase_ctrl_config_read(m, data);
	therm_ddr_lm_config_read(m, data);

	return 0;
}
@@ -7182,6 +7421,12 @@ static int msm_thermal_dev_exit(struct platform_device *inp_dev)
				&thresh[MSM_VDD_MX_RESTRICTION]);
			kfree(thresh[MSM_VDD_MX_RESTRICTION].thresh_list);
		}
		if (therm_ddr_lm_enabled) {
			sensor_mgr_remove_threshold(
				&thresh[MSM_THERM_DDR_LM]);
			cleanup_bus_data(therm_ddr_lm_data, inp_dev);
		}

		kfree(thresh);
		thresh = NULL;
	}
@@ -7234,6 +7479,7 @@ int __init msm_thermal_late_init(void)
	if (!msm_thermal_probed)
		return 0;

	probe_therm_ddr_lm(msm_thermal_info.pdev);
	if (num_possible_cpus() > 1)
		msm_thermal_add_cc_nodes();
	msm_thermal_add_psm_nodes();