mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 12:57:06 +09:00
cpufreq: merge from mainline
PD#SWPL-15312 Change-Id: I1b354d551721e80f6b3052e9ed4c66437c0b5242 Signed-off-by: Lei Qian <lei.qian@amlogic.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user