@@ -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,42 @@ 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);
@@ -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 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
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)