Skip to content

Commit

Permalink
ipq806x: cpufreq-dt: enhance l2 cache scaling
Browse files Browse the repository at this point in the history
Allow to set target cpu frequency to take decision on scaling l2 cache
up or down and corresponding voltages to be supplied per frequency.

Add correct L2 cpu frequency targets and voltages according to GPL
tarballs.

Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
  • Loading branch information
dissent1 committed Dec 26, 2017
1 parent 483e472 commit b2351d3
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 4 deletions.
Expand Up @@ -60,10 +60,10 @@
compatible = "cache";
cache-level = <2>;
qcom,saw = <&saw_l2>;
};

qcom,l2 {
qcom,l2-rates = <384000000 1000000000 1200000000>;
l2-rates = <384000000 1000000000 1200000000>;
l2-cpufreq = <384000000 600000000 1200000000>;
l2-volt = <1100000 1100000 1150000>;
l2-supply = <&smb208_s1a>;
};

idle-states {
Expand Down
Expand Up @@ -4,6 +4,12 @@
model = "Qualcomm IPQ8065";
compatible = "qcom,ipq8065", "qcom,ipq8064";

cpus {
L2: l2-cache {
l2-cpufreq = <384000000 600000000 1725000000>;
};
};

qcom,pvs {
qcom,pvs-format-a;
qcom,speed0-pvs0-bin-v0 =
Expand Down
@@ -0,0 +1,145 @@
From 9061c8a0799e27059e5fdf9b049ab8c7b83d58cf Mon Sep 17 00:00:00 2001
From: Pavel Kubelun <be.dissent@gmail.com>
Date: Tue, 26 Dec 2017 23:25:41 +0300
Subject: [PATCH] cpufreq-dt: enhance L2 cache freq scaling

Allow to set target cpu frequency to take decision on scaling l2 cache
up or down and corresponding voltages to be supplied per frequency.

Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
---
drivers/cpufreq/cpufreq-dt.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
include/linux/cpufreq.h | 2 ++
2 files changed, 55 insertions(+), 16 deletions(-)

diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index ac5d348..ec67a4b 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -37,6 +37,9 @@ struct private_data {
unsigned long opp_freq;
};

+static unsigned int voltage_tolerance; /* in percentage */
+static struct regulator *l2_regulator;
+
static struct freq_attr *cpufreq_dt_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL, /* Extra space for boost-attr if required */
@@ -50,23 +53,27 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index)
unsigned long target_freq = policy->freq_table[index].frequency * 1000;
struct clk *l2_clk = policy->l2_clk;
unsigned int l2_freq;
- unsigned long new_l2_freq = 0;
+ unsigned long new_l2_freq = 0, new_l2_volt = 0;

mutex_lock(&priv->lock);
ret = dev_pm_opp_set_rate(priv->cpu_dev, target_freq);

if (!ret) {
- if (!IS_ERR(l2_clk) && policy->l2_rate[0] && policy->l2_rate[1] &&
- policy->l2_rate[2]) {
+ if (!IS_ERR(l2_clk) && !IS_ERR(l2_regulator) && policy->l2_rate[0] &&
+ policy->l2_rate[1] && policy->l2_rate[2] && policy->l2_cpufreq[0] &&
+ policy->l2_cpufreq[1] && policy->l2_cpufreq[2] && policy->l2_volt[2] &&
+ policy->l2_volt[1] && policy->l2_volt[0]) {
static unsigned long krait_l2[CONFIG_NR_CPUS] = { };
- int cpu, ret = 0;
-
- if (target_freq >= policy->l2_rate[2])
- new_l2_freq = policy->l2_rate[2];
- else if (target_freq >= policy->l2_rate[1])
- new_l2_freq = policy->l2_rate[1];
- else
- new_l2_freq = policy->l2_rate[0];
+ int cpu, i, tol = 0, ret = 0;
+
+ for (i = 2; i >= 0; i--) {
+ if (target_freq >= policy->l2_cpufreq[i]) {
+ new_l2_freq = policy->l2_rate[i];
+ new_l2_volt = policy->l2_volt[i];
+ tol = policy->l2_volt[i] * voltage_tolerance / 100;
+ break;
+ }
+ }

krait_l2[policy->cpu] = new_l2_freq;
for_each_present_cpu(cpu)
@@ -74,9 +81,17 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index)

l2_freq = clk_get_rate(l2_clk);

- if (l2_freq != new_l2_freq) {
- /* scale l2 with the core */
+ if (l2_freq > new_l2_freq) {
+ /* scale l2 with the core, lower the frequency first */
ret = clk_set_rate(l2_clk, new_l2_freq);
+ if (!ret)
+ ret = regulator_set_voltage_tol(l2_regulator,new_l2_volt,tol);
+ }
+ if (l2_freq < new_l2_freq) {
+ /* scale l2 with the core, rise the voltage first */
+ ret = regulator_set_voltage_tol(l2_regulator,new_l2_volt,tol);
+ if (!ret)
+ ret = clk_set_rate(l2_clk, new_l2_freq);
}
}

@@ -231,6 +246,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
struct srcu_notifier_head *opp_srcu_head;
struct device_node *l2_np;
struct clk *l2_clk = NULL;
+ struct device_node *np, *cache;

cpu_dev = get_cpu_device(policy->cpu);
if (!cpu_dev) {
@@ -358,9 +374,30 @@ static int cpufreq_init(struct cpufreq_policy *policy)
l2_clk = clk_get(cpu_dev, "l2");
if (!IS_ERR(l2_clk))
policy->l2_clk = l2_clk;
- l2_np = of_find_node_by_name(NULL, "qcom,l2");
- if (l2_np)
- of_property_read_u32_array(l2_np, "qcom,l2-rates", policy->l2_rate, 3);
+
+ np = of_node_get(priv->cpu_dev->of_node);
+ if (np) {
+ of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
+ cache = of_find_next_cache_node(np);
+ }
+
+ if (cache) {
+ struct device_node *vdd;
+
+ of_property_read_u32_array(cache, "l2-rates", policy->l2_rate, 3);
+ of_property_read_u32_array(cache, "l2-cpufreq", policy->l2_cpufreq, 3);
+ of_property_read_u32_array(cache, "l2-volt", policy->l2_volt, 3);
+
+ vdd = of_parse_phandle(cache, "l2-supply", 0);
+ if (vdd) {
+ l2_regulator = regulator_get(NULL, vdd->name);
+ if (IS_ERR(l2_regulator)) {
+ pr_warn("failed to get l2 supply\n");
+ l2_regulator = NULL;
+ }
+ of_node_put(vdd);
+ }
+ }

ret = cpufreq_table_validate_and_show(policy, freq_table);
if (ret) {
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 9c0a4b5..ffa6942 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -75,6 +75,8 @@ struct cpufreq_policy {
struct clk *clk;
struct clk *l2_clk; /* L2 clock */
unsigned int l2_rate[3]; /* L2 bus clock rate thresholds */
+ unsigned int l2_cpufreq[3]; /* L2 target CPU frequency */
+ unsigned int l2_volt[3]; /* L2 voltage array */
struct cpufreq_cpuinfo cpuinfo;/* see above */

unsigned int min; /* in kHz */
--
Working Copy 3.0.6

0 comments on commit b2351d3

Please sign in to comment.