[1/2] thermal/drivers/cpufreq_cooling: Add platform callback functions

Message ID 1587365320-25222-1-git-send-email-gao.yunxiao6@gmail.com
State New
Headers show
Series
  • [1/2] thermal/drivers/cpufreq_cooling: Add platform callback functions
Related show

Commit Message

gao.yunxiao6@gmail.com April 20, 2020, 6:48 a.m.
From: Jeson Gao <jeson.gao@unisoc.com>

On some platforms, due to the high power consumption, thermal frequency
reduction policy cannot control the desired temperature, platform have to
use the hotplug mechanism to mitigate temperature rising,so adding the
platform callback to support this function.

platform will hotplug out CPU when the normalised power is lower than
the power corresponding to the minimum frequency limit that is set by
platform.

Signed-off-by: Jeson Gao <jeson.gao@unisoc.com>
---
 drivers/thermal/cpufreq_cooling.c | 52 +++++++++++++++++++++++++++++++++++++++
 include/linux/cpu_cooling.h       | 30 ++++++++++++++++++++++
 2 files changed, 82 insertions(+)

Patch

diff --git a/drivers/thermal/cpufreq_cooling.c b/drivers/thermal/cpufreq_cooling.c
index e297e13..16cbf58 100644
--- a/drivers/thermal/cpufreq_cooling.c
+++ b/drivers/thermal/cpufreq_cooling.c
@@ -64,6 +64,7 @@  struct time_in_idle {
  * @node: list_head to link all cpufreq_cooling_device together.
  * @idle_time: idle time stats
  * @qos_req: PM QoS contraint to apply
+ * @plat_ops: point to platform callback function.
  *
  * This structure is required for keeping information of each registered
  * cpufreq_cooling_device.
@@ -78,6 +79,7 @@  struct cpufreq_cooling_device {
 	struct list_head node;
 	struct time_in_idle *idle_time;
 	struct freq_qos_request qos_req;
+	struct cpufreq_cooling_plat_ops *plat_ops;
 };
 
 static DEFINE_IDA(cpufreq_ida);
@@ -313,12 +315,24 @@  static int cpufreq_power2state(struct thermal_cooling_device *cdev,
 	u32 last_load, normalised_power;
 	struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
 	struct cpufreq_policy *policy = cpufreq_cdev->policy;
+	struct cpufreq_cooling_plat_ops *plat_ops = cpufreq_cdev->plat_ops;
 
 	last_load = cpufreq_cdev->last_load ?: 1;
 	normalised_power = (power * 100) / last_load;
 	target_freq = cpu_power_to_freq(cpufreq_cdev, normalised_power);
 
 	*state = get_level(cpufreq_cdev, target_freq);
+	if (*state == cpufreq_cdev->max_level &&
+			plat_ops && plat_ops->cpufreq_plat_min_freq_limit) {
+		plat_ops->cpufreq_plat_min_freq_limit(policy, &target_freq);
+		*state = get_level(cpufreq_cdev, target_freq);
+	}
+
+	if (plat_ops && plat_ops->cpufreq_plat_cpu_ctrl)
+		plat_ops->cpufreq_plat_cpu_ctrl(policy,
+				last_load, normalised_power,
+				cpu_freq_to_power(cpufreq_cdev, target_freq));
+
 	trace_thermal_power_cpu_limit(policy->related_cpus, target_freq, *state,
 				      power);
 	return 0;
@@ -684,3 +698,41 @@  void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 	kfree(cpufreq_cdev);
 }
 EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister);
+
+/**
+ * cpufreq_cooling_plat_ops_register - register platform callback function.
+ * @cdev: thermal cooling device pointer.
+ * @plat_ops: platform callback function pointer.
+ */
+int  cpufreq_cooling_plat_ops_register(struct thermal_cooling_device *cdev,
+			struct cpufreq_cooling_plat_ops *plat_ops)
+{
+	struct cpufreq_cooling_device *cpufreq_cdev;
+
+	if (!cdev && !cdev->devdata && !plat_ops)
+		return -EINVAL;
+
+	cpufreq_cdev = cdev->devdata;
+	cpufreq_cdev->plat_ops = plat_ops;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_cooling_plat_ops_register);
+
+/**
+ * cpufreq_cooling_plat_ops_unregister - unregister platform callback function.
+ * @cdev: thermal cooling device pointer.
+ */
+int  cpufreq_cooling_plat_ops_unregister(struct thermal_cooling_device *cdev)
+{
+	struct cpufreq_cooling_device *cpufreq_cdev;
+
+	if (!cdev && !cdev->devdata)
+		return -EINVAL;
+
+	cpufreq_cdev = cdev->devdata;
+	cpufreq_cdev->plat_ops = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_cooling_plat_ops_unregister);
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index 65501d8..3934918 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -19,6 +19,23 @@ 
 
 struct cpufreq_policy;
 
+/**
+ * struct cpufreq_cooling_plat_ops - platfom cpu cooling policy ops
+ *
+ * @cpufreq_plat_cpu_ctrl: this function provides a further core control
+ * policy when the current policies cannot cool down to an expected
+ * temperature value.
+ *
+ * @cpufreq_plat_min_freq_limit: set cpu frequency limit, cooling devices
+ * are not allowed to adjust cpu frequency to out of that limit.
+ */
+struct cpufreq_cooling_plat_ops {
+	int (*cpufreq_plat_cpu_ctrl)(struct cpufreq_policy *policy,
+				u32 load, u32 normalised_power, u32 freq_power);
+	void (*cpufreq_plat_min_freq_limit)(struct cpufreq_policy *policy,
+						u32 *target_freq);
+};
+
 #ifdef CONFIG_CPU_FREQ_THERMAL
 /**
  * cpufreq_cooling_register - function to create cpufreq cooling device.
@@ -40,6 +57,19 @@  struct thermal_cooling_device *
 struct thermal_cooling_device *
 of_cpufreq_cooling_register(struct cpufreq_policy *policy);
 
+/**
+ * cpufreq_cooling_plat_ops_register - register platform callback function.
+ * @cdev: thermal cooling device pointer.
+ * @plat_ops: platform callback function pointer.
+ */
+int cpufreq_cooling_plat_ops_register(struct thermal_cooling_device *cdev,
+			struct cpufreq_cooling_plat_ops *plat_ops);
+/**
+ * cpufreq_cooling_plat_ops_unregister - unregister platform callback function.
+ * @cdev: thermal cooling device pointer.
+ */
+int  cpufreq_cooling_plat_ops_unregister(struct thermal_cooling_device *cdev);
+
 #else /* !CONFIG_CPU_FREQ_THERMAL */
 static inline struct thermal_cooling_device *
 cpufreq_cooling_register(struct cpufreq_policy *policy)