From: Finley Xiao Date: Tue, 16 May 2017 09:00:04 +0000 (+0800) Subject: cpufreq: rockchip: limit frequency when reboot X-Git-Tag: release-20171130_firefly~4^2~553 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=43310d2ddec79da73c313937e304b1e784c184a2;p=firefly-linux-kernel-4.4.55.git 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 --- diff --git a/drivers/cpufreq/rockchip-cpufreq.c b/drivers/cpufreq/rockchip-cpufreq.c index 24010498730f..52ac81e2202b 100644 --- a/drivers/cpufreq/rockchip-cpufreq.c +++ b/drivers/cpufreq/rockchip-cpufreq.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include #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);