cpufreq: merge from mainline

PD#SWPL-15312

Change-Id: I1b354d551721e80f6b3052e9ed4c66437c0b5242
Signed-off-by: Lei Qian <lei.qian@amlogic.com>
This commit is contained in:
Lei Qian
2019-10-16 17:25:40 +08:00
committed by Luke Go
parent 85672bbe4d
commit fed4a57891
2 changed files with 175 additions and 18 deletions

View File

@@ -37,7 +37,7 @@
#include <linux/delay.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/driver.h>
#include <linux/amlogic/pm.h>
#include "../../regulator/internal.h"
#include <linux/amlogic/scpi_protocol.h>
#include "../../base/power/opp/opp.h"
@@ -131,7 +131,6 @@ static unsigned int meson_cpufreq_set_rate(struct cpufreq_policy *policy,
if (__clk_get_enable_count(high_freq_clk_p) >= 1)
clk_disable_unprepare(high_freq_clk_p);
}
if (!ret) {
/*
* FIXME: clk_set_rate hasn't returned an error here however it
@@ -270,6 +269,9 @@ static int meson_cpufreq_set_target(struct cpufreq_policy *policy,
}
}
freqs.old = freq_old / 1000;
freqs.new = freq_new / 1000;
cpufreq_freq_transition_begin(policy, &freqs);
/*scale clock frequency*/
ret = meson_cpufreq_set_rate(policy, cur_cluster,
freq_new / 1000);
@@ -283,6 +285,8 @@ static int meson_cpufreq_set_target(struct cpufreq_policy *policy,
}
return ret;
}
cpufreq_freq_transition_end(policy, &freqs, ret);
/*cpufreq down,change voltage after frequency*/
if (freq_new < freq_old) {
ret = meson_regulator_set_volate(cpu_reg, volt_old,
@@ -290,8 +294,14 @@ static int meson_cpufreq_set_target(struct cpufreq_policy *policy,
if (ret) {
pr_err("failed to scale volt %u %u down: %d\n",
volt_new, volt_tol, ret);
meson_cpufreq_set_rate(policy, cur_cluster,
freqs.old = freq_new / 1000;
freqs.new = freq_old / 1000;
cpufreq_freq_transition_begin(policy, &freqs);
ret = meson_cpufreq_set_rate(policy, cur_cluster,
freq_old / 1000);
cpufreq_freq_transition_end(policy,
&freqs, ret);
}
}
@@ -377,6 +387,77 @@ int choose_cpufreq_tables_index(const struct device_node *np, u32 cur_cluster)
return ret;
}
static int meson_cpufreq_transition_notifier(struct notifier_block *nb,
unsigned long val, void *data)
{
struct cpufreq_freqs *freq = data;
struct meson_cpufreq_driver_data *cpufreq_data =
to_meson_dvfs_cpu_nb(nb);
struct cpufreq_policy *policy = cpufreq_data->policy;
struct clk *dsu_clk = cpufreq_data->clk_dsu;
struct clk *dsu_cpu_parent = policy->clk;
struct clk *dsu_pre_parent = cpufreq_data->clk_dsu_pre;
int ret = 0;
unsigned int dsu_set_rate;
if (!dsu_clk || !dsu_cpu_parent || !dsu_pre_parent)
return 0;
pr_debug("%s:event %ld,old_rate =%u,new_rate =%u!\n",
__func__, val, freq->old, freq->new);
switch (val) {
case CPUFREQ_PRECHANGE:
if (freq->new > DSU_LOW_RATE) {
pr_debug("%s:dsu clk switch parent to dsu pre!\n",
__func__);
if (__clk_get_enable_count(dsu_pre_parent) == 0) {
ret = clk_prepare_enable(dsu_pre_parent);
if (ret) {
pr_err("%s: CPU%d gp1 pll enable failed,ret = %d\n",
__func__, policy->cpu, ret);
return ret;
}
}
if (freq->new > CPU_CMP_RATE)
dsu_set_rate = DSU_HIGH_RATE;
else
dsu_set_rate = DSU_LOW_RATE;
clk_set_rate(dsu_pre_parent, dsu_set_rate * 1000);
if (ret) {
pr_err("%s: GP1 clk setting %u MHz failed, ret = %d!\n",
__func__, dsu_set_rate, ret);
return ret;
}
pr_debug("%s:GP1 clk setting %u MHz!\n",
__func__, dsu_set_rate);
ret = clk_set_parent(dsu_clk, dsu_pre_parent);
}
return ret;
case CPUFREQ_POSTCHANGE:
if (freq->new <= DSU_LOW_RATE) {
pr_debug("%s:dsu clk switch parent to cpu!\n",
__func__);
ret = clk_set_parent(dsu_clk, dsu_cpu_parent);
if (__clk_get_enable_count(dsu_pre_parent) >= 1)
clk_disable_unprepare(dsu_pre_parent);
}
return ret;
default:
return 0;
}
return 0;
}
static struct notifier_block meson_cpufreq_notifier_block = {
.notifier_call = meson_cpufreq_transition_notifier,
};
/* CPU initialization */
static int meson_cpufreq_init(struct cpufreq_policy *policy)
{
@@ -386,6 +467,7 @@ static int meson_cpufreq_init(struct cpufreq_policy *policy)
struct regulator *cpu_reg = NULL;
struct meson_cpufreq_driver_data *cpufreq_data;
struct clk *low_freq_clk_p, *high_freq_clk_p = NULL;
struct clk *dsu_clk, *dsu_pre_parent;
unsigned int transition_latency = CPUFREQ_ETERNAL;
unsigned int volt_tol = 0;
unsigned long freq_hz = 0;
@@ -439,7 +521,7 @@ static int meson_cpufreq_init(struct cpufreq_policy *policy)
if (ret) {
pr_err("%s: error in setting low_freq_clk_p rate!\n",
__func__);
return ret;
goto free_clk;
}
high_freq_clk_p = of_clk_get_by_name(np, HIGH_FREQ_CLK_PARENT);
@@ -450,6 +532,18 @@ static int meson_cpufreq_init(struct cpufreq_policy *policy)
goto free_clk;
}
dsu_clk = of_clk_get_by_name(np, DSU_CLK);
if (IS_ERR(dsu_clk)) {
dsu_clk = NULL;
pr_info("%s: ignor dsu clk!\n", __func__);
}
dsu_pre_parent = of_clk_get_by_name(np, DSU_PRE_PARENT);
if (IS_ERR(dsu_pre_parent)) {
dsu_pre_parent = NULL;
pr_info("%s: ignor dsu pre parent clk!\n", __func__);
}
cpu_reg = devm_regulator_get(cpu_dev, CORE_SUPPLY);
if (IS_ERR(cpu_reg)) {
pr_err("%s:failed to get regulator, %ld\n", __func__,
@@ -462,6 +556,14 @@ static int meson_cpufreq_init(struct cpufreq_policy *policy)
volt_tol = DEF_VOLT_TOL;
pr_info("value of voltage_tolerance %u\n", volt_tol);
if (of_property_read_u32(np, "dynamic_gp1_clk",
&gp1_clk_target)) {
pr_err("%s:don't find the node <dynamic_gp1_clk>\n",
__func__);
gp1_clk_target = 0;
}
pr_info("value of gp1_clk_target %u\n", gp1_clk_target);
if (cur_cluster < MAX_CLUSTERS)
cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
@@ -506,12 +608,25 @@ static int meson_cpufreq_init(struct cpufreq_policy *policy)
if (of_property_read_u32(np, "clock-latency", &transition_latency))
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
if (cur_cluster == 0) {
cpufreq_data->freq_transition = meson_cpufreq_notifier_block;
ret = cpufreq_register_notifier(&cpufreq_data->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
if (ret) {
dev_err(cpu_dev, "failed to register cpufreq notifier!\n");
goto fail_cpufreq_unregister;
}
}
cpufreq_data->cpu_dev = cpu_dev;
cpufreq_data->low_freq_clk_p = low_freq_clk_p;
cpufreq_data->high_freq_clk_p = high_freq_clk_p;
cpufreq_data->clk_dsu = dsu_clk;
cpufreq_data->clk_dsu_pre = dsu_pre_parent;
cpufreq_data->reg = cpu_reg;
cpufreq_data->volt_tol = volt_tol;
cpufreq_data->policy = policy;
policy->driver_data = cpufreq_data;
policy->clk = clk[cur_cluster];
policy->cpuinfo.transition_latency = transition_latency;
@@ -532,6 +647,10 @@ static int meson_cpufreq_init(struct cpufreq_policy *policy)
dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu);
return ret;
fail_cpufreq_unregister:
if (cur_cluster == 0)
cpufreq_unregister_notifier(&cpufreq_data->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
free_opp_table:
if (policy->freq_table != NULL) {
dev_pm_opp_free_cpufreq_table(cpu_dev,
@@ -619,6 +738,9 @@ static int meson_cpufreq_exit(struct cpufreq_policy *policy)
policy->cpu);
return -ENODEV;
}
if (cur_cluster == 0)
cpufreq_unregister_notifier(&cpufreq_data->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
if (policy->freq_table != NULL) {
dev_pm_opp_free_cpufreq_table(cpu_dev,
@@ -633,8 +755,31 @@ static int meson_cpufreq_exit(struct cpufreq_policy *policy)
static int meson_cpufreq_suspend(struct cpufreq_policy *policy)
{
struct clk *dsu_pre_parent;
struct meson_cpufreq_driver_data *cpufreq_data;
int ret = 0;
return cpufreq_generic_suspend(policy);
cpufreq_data = policy->driver_data;
dsu_pre_parent = cpufreq_data->clk_dsu_pre;
if (is_pm_freeze_mode() && gp1_clk_target) {
ret = __cpufreq_driver_target(policy, gp1_clk_target
* 1000, CPUFREQ_RELATION_H);
if (__clk_get_enable_count(dsu_pre_parent) == 0) {
ret = clk_prepare_enable(dsu_pre_parent);
if (ret) {
pr_err("%s: CPU%d gp1 pll enable failed,ret = %d\n",
__func__, policy->cpu, ret);
return ret;
}
}
/*set gp1 pll to 1.2G*/
clk_set_rate(dsu_pre_parent, 1200 * 1000 * 1000);
pr_info("gp1 pll =%lu!\n", clk_get_rate(dsu_pre_parent));
return ret;
} else
return cpufreq_generic_suspend(policy);
return 0;
}
static int meson_cpufreq_resume(struct cpufreq_policy *policy)
@@ -647,7 +792,8 @@ static struct cpufreq_driver meson_cpufreq_driver = {
.name = "arm-big-little",
.flags = CPUFREQ_STICKY |
CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
CPUFREQ_NEED_INITIAL_FREQ_CHECK,
CPUFREQ_NEED_INITIAL_FREQ_CHECK |
CPUFREQ_ASYNC_NOTIFICATION,
.verify = cpufreq_generic_frequency_table_verify,
.target_index = meson_cpufreq_set_target,
.get = meson_cpufreq_get_rate,
@@ -658,8 +804,6 @@ static struct cpufreq_driver meson_cpufreq_driver = {
.resume = meson_cpufreq_resume,
};
static int meson_cpufreq_register_notifier(void) { return 0; }
static int meson_cpufreq_unregister_notifier(void) { return 0; }
static int meson_cpufreq_probe(struct platform_device *pdev)
{
struct device *cpu_dev;
@@ -711,14 +855,6 @@ static int meson_cpufreq_probe(struct platform_device *pdev)
if (ret) {
pr_err("%s: Failed registering platform driver, err: %d\n",
__func__, ret);
} else {
ret = meson_cpufreq_register_notifier();
if (ret) {
cpufreq_unregister_driver(&meson_cpufreq_driver);
} else {
pr_err("%s: Registered platform drive\n",
__func__);
}
}
return ret;
@@ -726,8 +862,6 @@ static int meson_cpufreq_probe(struct platform_device *pdev)
static int meson_cpufreq_remove(struct platform_device *pdev)
{
meson_cpufreq_unregister_notifier();
return cpufreq_unregister_driver(&meson_cpufreq_driver);
}

View File

@@ -27,6 +27,10 @@
#define CORE_CLK "core_clk"
#define LOW_FREQ_CLK_PARENT "low_freq_clk_parent"
#define HIGH_FREQ_CLK_PARENT "high_freq_clk_parent"
#define DSU_CLK "dsu_clk"
#define DSU_PRE_PARENT "dsu_pre_parent"
#define to_meson_dvfs_cpu_nb(_nb) container_of(_nb, \
struct meson_cpufreq_driver_data, freq_transition)
static struct clk *clk[MAX_CLUSTERS];
static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
@@ -38,7 +42,22 @@ static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
/*mid rate for set parent,Khz*/
static unsigned int mid_rate = (1000 * 1000);
static unsigned int gap_rate = (10 * 1000 * 1000);
static struct cpufreq_freqs freqs;
/*
* DSU_LOW_RATE:cpu clk less than DSU_LOW_RATE(1.2G)
* dsu clk swith to cpu clk
* DSU_HIGH_RATE:cpu clk between 1.2G to DSU_HIGH_RATE (1.8G)
* dsu clk set to DSU_LOW_RATE(1.2G)
* CPU_CMP_RATE: cpu clk greater than CPU_CMP_RATE(1.8G)
* dsu clk set to DSU_HIGH_RATE(1.5G)
*/
#define DSU_LOW_RATE (1200 * 1000)
#define DSU_HIGH_RATE (1500 * 1000)
#define CPU_CMP_RATE (1800 * 1000)
unsigned int gp1_clk_target;
/*whether use different tables or not*/
bool cpufreq_tables_supply;
static unsigned int hispeed_cpufreq_max;
@@ -53,10 +72,14 @@ enum cpufreq_index {
struct meson_cpufreq_driver_data {
struct device *cpu_dev;
struct regulator *reg;
struct cpufreq_policy *policy;
/* voltage tolerance in percentage */
unsigned int volt_tol;
struct clk *high_freq_clk_p;
struct clk *low_freq_clk_p;
struct clk *clk_dsu;
struct clk *clk_dsu_pre;
struct notifier_block freq_transition;
};
static struct mutex cluster_lock[MAX_CLUSTERS];