soc: rockchip: system_monitor: Add reboot notifier

Change-Id: Ic788ca9ba353c7d7c64e3e323698d8c23303eaa0
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
This commit is contained in:
Finley Xiao
2019-04-03 11:52:32 +08:00
committed by Tao Huang
parent 8077a32db9
commit 72b246bef0
4 changed files with 77 additions and 78 deletions

View File

@@ -24,7 +24,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/reboot.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/soc/rockchip/pvtm.h>
@@ -35,7 +34,6 @@
#include "../clk/rockchip/clk.h"
#define LEAKAGE_INVALID 0xff
#define REBOOT_FREQ 816000 /* kHz */
struct cluster_info {
struct list_head list_head;
@@ -48,7 +46,6 @@ struct cluster_info {
int scale;
int process;
bool offline;
bool rebooting;
bool freq_limit;
bool is_check_init;
};
@@ -300,9 +297,6 @@ static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
goto np_err;
}
if (of_property_read_u32(np, "rockchip,reboot-freq",
&cluster->reboot_freq))
cluster->reboot_freq = REBOOT_FREQ;
of_property_read_u32(np, "rockchip,threshold-freq",
&cluster->threshold_freq);
cluster->freq_limit = of_property_read_bool(np, "rockchip,freq-limit");
@@ -364,27 +358,6 @@ static struct notifier_block rockchip_hotcpu_nb = {
.notifier_call = rockchip_hotcpu_notifier,
};
static int rockchip_reboot_notifier(struct notifier_block *nb,
unsigned long action, void *ptr)
{
int cpu;
struct cluster_info *cluster;
list_for_each_entry(cluster, &cluster_info_list, list_head) {
cpu = cpumask_first_and(&cluster->cpus, cpu_online_mask);
if (cpu >= nr_cpu_ids)
continue;
cluster->rebooting = true;
cpufreq_update_policy(cpu);
}
return NOTIFY_OK;
}
static struct notifier_block rockchip_reboot_nb = {
.notifier_call = rockchip_reboot_notifier,
};
static int rockchip_cpufreq_policy_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
@@ -399,20 +372,8 @@ static int rockchip_cpufreq_policy_notifier(struct notifier_block *nb,
if (!cluster)
return NOTIFY_DONE;
if (cluster->scale_rate) {
if (cluster->scale_rate < policy->max)
policy->max = cluster->scale_rate;
}
if (cluster->rebooting) {
if (cluster->reboot_freq < policy->max)
policy->max = cluster->reboot_freq;
policy->min = policy->max;
pr_info("cpu%d limit freq=%d min=%d max=%d\n",
policy->cpu, cluster->reboot_freq,
policy->min, policy->max);
return NOTIFY_OK;
}
if (cluster->scale_rate && cluster->scale_rate < policy->max)
cpufreq_verify_within_limits(policy, 0, cluster->scale_rate);
return NOTIFY_OK;
}
@@ -552,7 +513,6 @@ static int __init rockchip_cpufreq_driver_init(void)
}
register_hotcpu_notifier(&rockchip_hotcpu_nb);
register_reboot_notifier(&rockchip_reboot_nb);
cpufreq_register_notifier(&rockchip_cpufreq_policy_nb,
CPUFREQ_POLICY_NOTIFIER);

View File

@@ -36,7 +36,6 @@
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/pm_qos.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/rockchip/rockchip_sip.h>
@@ -1117,7 +1116,6 @@ struct rockchip_dmcfreq {
struct dram_timing *timing;
struct regulator *vdd_center;
struct notifier_block status_nb;
struct notifier_block reboot_nb;
struct notifier_block fb_nb;
struct list_head video_info_list;
struct freq_map_table *vop_bw_tbl;
@@ -2780,6 +2778,7 @@ static int rockchip_dmcfreq_system_status_notifier(struct notifier_block *nb,
}
if (dmcfreq->reboot_rate && (status & SYS_STATUS_REBOOT)) {
devfreq_monitor_stop(dmcfreq->devfreq);
target_rate = dmcfreq->reboot_rate;
goto next;
}
@@ -2831,17 +2830,6 @@ next:
return NOTIFY_OK;
}
static int rockchip_dmcfreq_reboot_notifier(struct notifier_block *nb,
unsigned long action, void *ptr)
{
struct rockchip_dmcfreq *dmcfreq = reboot_to_dmcfreq(nb);
devfreq_monitor_stop(dmcfreq->devfreq);
rockchip_set_system_status(SYS_STATUS_REBOOT);
return NOTIFY_OK;
}
static int rockchip_dmcfreq_fb_notifier(struct notifier_block *nb,
unsigned long action, void *ptr)
{
@@ -3423,11 +3411,6 @@ static void rockchip_dmcfreq_register_notifier(struct rockchip_dmcfreq *dmcfreq)
if (ret)
dev_err(dmcfreq->dev, "failed to register system_status nb\n");
dmcfreq->reboot_nb.notifier_call = rockchip_dmcfreq_reboot_notifier;
ret = register_reboot_notifier(&dmcfreq->reboot_nb);
if (ret)
dev_err(dmcfreq->dev, "failed to register reboot nb\n");
dmcfreq->fb_nb.notifier_call = rockchip_dmcfreq_fb_notifier;
ret = fb_register_client(&dmcfreq->fb_nb);
if (ret)

View File

@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/uaccess.h>
#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/thermal.h>
@@ -25,6 +26,7 @@
#include "../../base/power/opp/opp.h"
#include "../../devfreq/governor.h"
#define CPU_REBOOT_FREQ 816000 /* kHz */
#define VIDEO_1080P_SIZE (1920 * 1080)
#define THERMAL_POLLING_DELAY 200 /* milliseconds */
@@ -585,6 +587,19 @@ err:
return ret;
}
static int monitor_device_parse_status_config(struct device_node *np,
struct monitor_dev_info *info)
{
int ret;
ret = of_property_read_u32(np, "rockchip,video-4k-freq",
&info->video_4k_freq);
ret &= of_property_read_u32(np, "rockchip,reboot-freq",
&info->reboot_freq);
return ret;
}
static int rockchip_get_temp_freq_table(struct device_node *np,
char *porp_name,
struct temp_freq_table **freq_table)
@@ -629,7 +644,7 @@ static int monitor_device_parse_dt(struct device *dev,
struct device_node *np;
int ret = 0;
bool is_wide_temp_en = false;
bool is_4k_limit_en = false;
bool is_status_limit_en = false;
bool is_temp_freq_en = false;
np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
@@ -638,13 +653,12 @@ static int monitor_device_parse_dt(struct device *dev,
if (!monitor_device_parse_wide_temp_config(np, info))
is_wide_temp_en = true;
if (!of_property_read_u32(np, "rockchip,video-4k-freq",
&info->video_4k_freq))
is_4k_limit_en = true;
if (!monitor_device_parse_status_config(np, info))
is_status_limit_en = true;
if (!rockchip_get_temp_freq_table(np, "rockchip,temp-freq-table",
&info->temp_freq_table))
is_temp_freq_en = true;
if (is_wide_temp_en || is_4k_limit_en || is_temp_freq_en)
if (is_wide_temp_en || is_status_limit_en || is_temp_freq_en)
ret = 0;
else
ret = -EINVAL;
@@ -1203,24 +1217,42 @@ static void rockchip_system_monitor_thermal_check(struct work_struct *work)
rockchip_system_monitor_thermal_update();
}
static void rockchip_system_status_cpu_limit_freq(struct monitor_dev_info *info,
unsigned long status)
{
unsigned int target_freq = 0;
bool is_freq_fixed = false;
int cpu;
if (status & SYS_STATUS_REBOOT) {
if (!info->reboot_freq)
info->reboot_freq = CPU_REBOOT_FREQ;
info->status_min_limit = info->reboot_freq;
info->status_max_limit = info->reboot_freq;
info->is_status_freq_fixed = true;
goto next;
}
if (info->video_4k_freq && (status & SYS_STATUS_VIDEO_4K))
target_freq = info->video_4k_freq;
if (target_freq == info->status_max_limit &&
info->is_status_freq_fixed == is_freq_fixed)
return;
info->status_max_limit = target_freq;
info->is_status_freq_fixed = is_freq_fixed;
next:
cpu = cpumask_any(&info->devp->allowed_cpus);
cpufreq_update_policy(cpu);
}
static void rockchip_system_status_limit_freq(unsigned long status)
{
struct monitor_dev_info *info;
unsigned int target_freq, cpu;
down_read(&mdev_list_sem);
list_for_each_entry(info, &monitor_dev_list, node) {
if (info->devp->type != MONITOR_TPYE_CPU)
continue;
if (status & SYS_STATUS_VIDEO_4K)
target_freq = info->video_4k_freq;
else
target_freq = 0;
if (target_freq != info->status_max_limit) {
info->status_max_limit = target_freq;
cpu = cpumask_any(&info->devp->allowed_cpus);
cpufreq_update_policy(cpu);
}
if (info->devp->type == MONITOR_TPYE_CPU)
rockchip_system_status_cpu_limit_freq(info, status);
}
up_read(&mdev_list_sem);
}
@@ -1306,8 +1338,14 @@ static int rockchip_monitor_cpufreq_policy_notifier(struct notifier_block *nb,
limit_freq > info->status_max_limit)
limit_freq = info->status_max_limit;
if (limit_freq < policy->max)
if (info->is_status_freq_fixed) {
cpufreq_verify_within_limits(policy, limit_freq,
limit_freq);
dev_info(info->dev, "min=%u, max=%u\n", policy->min,
policy->max);
} else if (limit_freq < policy->max) {
cpufreq_verify_within_limits(policy, 0, limit_freq);
}
}
up_read(&mdev_list_sem);
@@ -1318,6 +1356,18 @@ static struct notifier_block rockchip_monitor_cpufreq_policy_nb = {
.notifier_call = rockchip_monitor_cpufreq_policy_notifier,
};
static int rockchip_monitor_reboot_notifier(struct notifier_block *nb,
unsigned long action, void *ptr)
{
rockchip_set_system_status(SYS_STATUS_REBOOT);
return NOTIFY_OK;
}
static struct notifier_block rockchip_monitor_reboot_nb = {
.notifier_call = rockchip_monitor_reboot_notifier,
};
static int rockchip_system_monitor_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1356,6 +1406,8 @@ static int rockchip_system_monitor_probe(struct platform_device *pdev)
cpufreq_register_notifier(&rockchip_monitor_cpufreq_policy_nb,
CPUFREQ_POLICY_NOTIFIER);
register_reboot_notifier(&rockchip_monitor_reboot_nb);
dev_info(dev, "system monitor probe\n");
return 0;

View File

@@ -56,6 +56,7 @@ struct temp_opp_table {
* @wide_temp_limit: Target maximum frequency when low or high temperature,
* in Hz
* @video_4k_freq: Maximum frequency when paly 4k video, in KHz
* @reboot_freq: Limit maximum and minimum frequency when reboot, in KHz
* @status_min_limit: Minimum frequency of some status frequency, in KHz
* @status_max_limit: Minimum frequency of all status frequency, in KHz
* @freq_table: Optional list of frequencies in descending order
@@ -67,6 +68,7 @@ struct temp_opp_table {
* @is_high_temp: True if current temperature greater than high_temp
* @is_low_temp_enabled: True if device node contains low temperature
* configuration
* @is_status_freq_fixed: True if enter into some status
*/
struct monitor_dev_info {
struct device *dev;
@@ -83,6 +85,7 @@ struct monitor_dev_info {
unsigned long high_temp_max_volt;
unsigned long wide_temp_limit;
unsigned int video_4k_freq;
unsigned int reboot_freq;
unsigned int status_min_limit;
unsigned int status_max_limit;
unsigned long *freq_table;
@@ -93,6 +96,7 @@ struct monitor_dev_info {
bool is_low_temp;
bool is_high_temp;
bool is_low_temp_enabled;
bool is_status_freq_fixed;
};
struct monitor_dev_profile {