cpufreq: rockchip: limit frequency when reboot
If i2c driver adds a shutdown callback function, the callback will be
executed before cpu's shutdown callback when reboot system, it will
fail to scale voltage like the following.
rk3x-i2c ff650000.i2c: Access denied - device already shutdown
rk3x-i2c ff650000.i2c: Access denied - device already shutdown
rk3x-i2c ff650000.i2c: Access denied - device already shutdown
rk3x-i2c ff650000.i2c: Access denied - device already shutdown
cpu cpu4: _set_opp_voltage: failed to set voltage
(950000 950000 1350000 mV):-5
So add a reboot notifier to limit frequency before i2c's shutdown callback,
and the cpu's shutdown callback will do nothing.
Change-Id: Ic5bb21b511c6f799dc62fd9db237d90522b7d4ee
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
This commit is contained in:
parent
cdcf4ffeab
commit
43310d2dde
1 changed files with 59 additions and 0 deletions
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -23,6 +24,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "../clk/rockchip/clk.h"
|
||||
|
|
@ -31,6 +33,8 @@
|
|||
#define LEAKAGE_TABLE_END ~1
|
||||
#define INVALID_VALUE 0xff
|
||||
|
||||
#define REBOOT_FREQ 816000 /* kHz */
|
||||
|
||||
struct leakage_table {
|
||||
int min;
|
||||
int max;
|
||||
|
|
@ -44,6 +48,8 @@ struct cluster_info {
|
|||
int lkg_volt_sel;
|
||||
int soc_version;
|
||||
bool set_opp;
|
||||
unsigned int reboot_freq;
|
||||
bool rebooting;
|
||||
};
|
||||
|
||||
static LIST_HEAD(cluster_info_list);
|
||||
|
|
@ -223,6 +229,9 @@ static int rockchip_cpufreq_of_parse_dt(int cpu, struct cluster_info *cluster)
|
|||
}
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "reboot-freq", &cluster->reboot_freq))
|
||||
cluster->reboot_freq = REBOOT_FREQ;
|
||||
|
||||
ret = rockchip_efuse_get_one_byte(np, "cpu_leakage", &cluster->leakage);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to get cpu_leakage\n");
|
||||
|
|
@ -336,6 +345,53 @@ 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);
|
||||
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_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct cpufreq_policy *policy = data;
|
||||
struct cluster_info *cluster;
|
||||
|
||||
if (event != CPUFREQ_ADJUST)
|
||||
return NOTIFY_OK;
|
||||
|
||||
list_for_each_entry(cluster, &cluster_info_list, list_head) {
|
||||
if (cluster->rebooting &&
|
||||
cpumask_test_cpu(policy->cpu, &cluster->cpus)) {
|
||||
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;
|
||||
}
|
||||
|
||||
static struct notifier_block rockchip_cpufreq_nb = {
|
||||
.notifier_call = rockchip_cpufreq_notifier,
|
||||
};
|
||||
|
||||
static int __init rockchip_cpufreq_driver_init(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
|
|
@ -388,6 +444,9 @@ 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_nb,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
|
||||
next:
|
||||
pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue