mirror of
https://github.com/hardkernel/linux.git
synced 2026-04-07 05:33:20 +09:00
soc: rockchip: system_monitor: on/off cpu according to temperature
Change-Id: Ie2c55dd4c11700c0446cf0abec7e580f6abda8fe Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
This commit is contained in:
@@ -8,11 +8,25 @@ Required properties:
|
||||
Optional properties:
|
||||
- rockchip,video-4k-offline-cpus: A string containing cpus which will be killed
|
||||
when play 4k video.
|
||||
- rockchip,thermal-zone: A thermal zone node containing thermal sensor,
|
||||
it's used to get the current temperature.
|
||||
- rockchip,polling-delay: The maximum number of milliseconds to wait
|
||||
between polls.
|
||||
- rockchip,offline-cpu-temp: An integer indicating the trip temperature level.
|
||||
- rockchip,temp-hysteresis: A low hysteresis value on rockchip,offline-cpu-temp
|
||||
property (above).
|
||||
- rockchip,temp-offline-cpus: A string containing cpus which will be killed
|
||||
when temperature is high.
|
||||
|
||||
Example:
|
||||
|
||||
system-monitor {
|
||||
compatible = "rockchip,system-monitor";
|
||||
|
||||
rockchip,thermal-zone = "soc-thermal";
|
||||
rockchip,polling-delay = <200>; /* milliseconds */
|
||||
rockchip,offline-cpu-temp = <110000>; /* millicelsius */
|
||||
rockchip,temp-offline-cpus = "2-3";
|
||||
|
||||
rockchip,video-4k-offline-cpus = "2-3";
|
||||
};
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <soc/rockchip/rockchip-system-status.h>
|
||||
|
||||
#define VIDEO_1080P_SIZE (1920 * 1080)
|
||||
#define THERMAL_POLLING_DELAY 200 /* milliseconds */
|
||||
|
||||
struct video_info {
|
||||
unsigned int width;
|
||||
@@ -39,9 +41,17 @@ struct system_monitor {
|
||||
struct device *dev;
|
||||
struct cpumask video_4k_offline_cpus;
|
||||
struct cpumask status_offline_cpus;
|
||||
struct cpumask temp_offline_cpus;
|
||||
struct cpumask offline_cpus;
|
||||
struct notifier_block status_nb;
|
||||
struct kobject *kobj;
|
||||
|
||||
struct thermal_zone_device *tz;
|
||||
struct delayed_work thermal_work;
|
||||
int offline_cpus_temp;
|
||||
int temp_hysteresis;
|
||||
unsigned int delay;
|
||||
bool is_temp_offline;
|
||||
};
|
||||
|
||||
static unsigned long system_status;
|
||||
@@ -49,6 +59,7 @@ static unsigned long ref_count[32] = {0};
|
||||
|
||||
static DEFINE_MUTEX(system_status_mutex);
|
||||
static DEFINE_MUTEX(video_info_mutex);
|
||||
static DEFINE_MUTEX(cpu_on_off_mutex);
|
||||
|
||||
static LIST_HEAD(video_info_list);
|
||||
static struct system_monitor *system_monitor;
|
||||
@@ -354,26 +365,58 @@ static struct system_monitor_attr status =
|
||||
static int rockchip_system_monitor_parse_dt(struct system_monitor *monitor)
|
||||
{
|
||||
struct device_node *np = monitor->dev->of_node;
|
||||
const char *buf = NULL;
|
||||
const char *tz_name, *buf = NULL;
|
||||
|
||||
if (!of_property_read_string(np, "rockchip,video-4k-offline-cpus",
|
||||
&buf))
|
||||
if (of_property_read_string(np, "rockchip,video-4k-offline-cpus", &buf))
|
||||
cpumask_clear(&system_monitor->video_4k_offline_cpus);
|
||||
else
|
||||
cpulist_parse(buf, &monitor->video_4k_offline_cpus);
|
||||
|
||||
if (of_property_read_string(np, "rockchip,thermal-zone", &tz_name))
|
||||
goto out;
|
||||
monitor->tz = thermal_zone_get_zone_by_name(tz_name);
|
||||
if (IS_ERR(monitor->tz)) {
|
||||
monitor->tz = NULL;
|
||||
goto out;
|
||||
}
|
||||
if (of_property_read_u32(np, "rockchip,polling-delay",
|
||||
&monitor->delay))
|
||||
monitor->delay = THERMAL_POLLING_DELAY;
|
||||
|
||||
if (of_property_read_string(np, "rockchip,temp-offline-cpus",
|
||||
&buf))
|
||||
cpumask_clear(&system_monitor->temp_offline_cpus);
|
||||
else
|
||||
cpulist_parse(buf, &system_monitor->temp_offline_cpus);
|
||||
|
||||
if (of_property_read_u32(np, "rockchip,offline-cpu-temp",
|
||||
&system_monitor->offline_cpus_temp))
|
||||
system_monitor->offline_cpus_temp = INT_MAX;
|
||||
of_property_read_u32(np, "rockchip,temp-hysteresis",
|
||||
&system_monitor->temp_hysteresis);
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_system_monitor_cpu_on_off(void)
|
||||
{
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
struct cpumask online_cpus, offline_cpus;
|
||||
unsigned int cpu;
|
||||
struct cpumask online_cpus;
|
||||
|
||||
if (cpumask_equal(&system_monitor->offline_cpus,
|
||||
&system_monitor->status_offline_cpus))
|
||||
return;
|
||||
cpumask_copy(&system_monitor->offline_cpus,
|
||||
&system_monitor->status_offline_cpus);
|
||||
mutex_lock(&cpu_on_off_mutex);
|
||||
|
||||
cpumask_clear(&offline_cpus);
|
||||
if (system_monitor->is_temp_offline) {
|
||||
cpumask_or(&offline_cpus, &system_monitor->status_offline_cpus,
|
||||
&system_monitor->temp_offline_cpus);
|
||||
} else {
|
||||
cpumask_copy(&offline_cpus,
|
||||
&system_monitor->status_offline_cpus);
|
||||
}
|
||||
if (cpumask_equal(&offline_cpus, &system_monitor->offline_cpus))
|
||||
goto out;
|
||||
cpumask_copy(&system_monitor->offline_cpus, &offline_cpus);
|
||||
for_each_cpu(cpu, &system_monitor->offline_cpus) {
|
||||
if (cpu_online(cpu))
|
||||
cpu_down(cpu);
|
||||
@@ -384,12 +427,58 @@ static void rockchip_system_monitor_cpu_on_off(void)
|
||||
&system_monitor->offline_cpus);
|
||||
cpumask_xor(&online_cpus, cpu_online_mask, &online_cpus);
|
||||
if (cpumask_empty(&online_cpus))
|
||||
return;
|
||||
goto out;
|
||||
for_each_cpu(cpu, &online_cpus)
|
||||
cpu_up(cpu);
|
||||
|
||||
out:
|
||||
mutex_unlock(&cpu_on_off_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void rockchip_system_monitor_temp_cpu_on_off(int temp)
|
||||
{
|
||||
bool is_temp_offline;
|
||||
|
||||
if (cpumask_empty(&system_monitor->temp_offline_cpus))
|
||||
return;
|
||||
|
||||
if (temp > system_monitor->offline_cpus_temp)
|
||||
is_temp_offline = true;
|
||||
else if (temp < system_monitor->offline_cpus_temp -
|
||||
system_monitor->temp_hysteresis)
|
||||
is_temp_offline = false;
|
||||
else
|
||||
return;
|
||||
|
||||
if (system_monitor->is_temp_offline == is_temp_offline)
|
||||
return;
|
||||
system_monitor->is_temp_offline = is_temp_offline;
|
||||
rockchip_system_monitor_cpu_on_off();
|
||||
}
|
||||
|
||||
static void rockchip_system_monitor_thermal_update(void)
|
||||
{
|
||||
int temp, ret;
|
||||
|
||||
ret = thermal_zone_get_temp(system_monitor->tz, &temp);
|
||||
if (ret || temp == THERMAL_TEMP_INVALID)
|
||||
goto out;
|
||||
|
||||
dev_dbg(system_monitor->dev, "temperature=%d\n", temp);
|
||||
|
||||
rockchip_system_monitor_temp_cpu_on_off(temp);
|
||||
|
||||
out:
|
||||
mod_delayed_work(system_freezable_wq, &system_monitor->thermal_work,
|
||||
msecs_to_jiffies(system_monitor->delay));
|
||||
}
|
||||
|
||||
static void rockchip_system_monitor_thermal_check(struct work_struct *work)
|
||||
{
|
||||
rockchip_system_monitor_thermal_update();
|
||||
}
|
||||
|
||||
static void rockchip_system_status_cpu_on_off(unsigned long status)
|
||||
{
|
||||
struct cpumask offline_cpus;
|
||||
@@ -432,11 +521,17 @@ static int rockchip_system_monitor_probe(struct platform_device *pdev)
|
||||
if (sysfs_create_file(system_monitor->kobj, &status.attr))
|
||||
dev_err(dev, "failed to create system status sysfs\n");
|
||||
|
||||
cpumask_clear(&system_monitor->video_4k_offline_cpus);
|
||||
cpumask_clear(&system_monitor->status_offline_cpus);
|
||||
cpumask_clear(&system_monitor->offline_cpus);
|
||||
|
||||
rockchip_system_monitor_parse_dt(system_monitor);
|
||||
if (system_monitor->tz) {
|
||||
INIT_DELAYED_WORK(&system_monitor->thermal_work,
|
||||
rockchip_system_monitor_thermal_check);
|
||||
mod_delayed_work(system_freezable_wq,
|
||||
&system_monitor->thermal_work,
|
||||
msecs_to_jiffies(system_monitor->delay));
|
||||
}
|
||||
|
||||
system_monitor->status_nb.notifier_call =
|
||||
rockchip_system_status_notifier;
|
||||
|
||||
Reference in New Issue
Block a user