From 05a8a9418a75854265738b2d6eee9a371d43d9f6 Mon Sep 17 00:00:00 2001 From: Hong Guo Date: Wed, 30 May 2018 10:07:33 +0800 Subject: [PATCH] CPUFREQ: modify cpufreq driver. PD#165090: cpufreq: modify cpufreq driver. Change-Id: I8583acfd74a52629e40b39d5e53ea8b30a6b28e1 Signed-off-by: Hong Guo --- arch/arm64/boot/dts/amlogic/mesong12b.dtsi | 41 -- drivers/cpufreq/meson-cpufreq.c | 664 +++++------------------------ 2 files changed, 107 insertions(+), 598 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/mesong12b.dtsi b/arch/arm64/boot/dts/amlogic/mesong12b.dtsi index 1746e07..fd476a3 100644 --- a/arch/arm64/boot/dts/amlogic/mesong12b.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesong12b.dtsi @@ -84,16 +84,6 @@ reg = <0x0 0x1>; enable-method = "psci"; sched-energy-costs = <&CPU_COST_A53 &CLUSTER_COST_A53>; - clocks = <&clkc CLKID_CPU_CLK>, - <&clkc CLKID_CPU_FCLK_P>, - <&clkc CLKID_SYS1_PLL>; - clock-names = "core_clk", - "low_freq_clk_parent", - "high_freq_clk_parent"; - operating-points-v2 = <&cpu_opp_table0>; - cpu-supply = <&vddcpu0>; - voltage-tolerance = <0>; - clock-latency = <50000>; }; CPU2:cpu@100 { @@ -123,17 +113,6 @@ enable-method = "psci"; //cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; sched-energy-costs = <&CPU_COST_A73 &CLUSTER_COST_A73>; - clocks = <&clkc CLKID_CPUB_CLK>, - <&clkc CLKID_CPUB_FCLK_P>, - <&clkc CLKID_SYS_PLL>; - clock-names = "core_clk", - "low_freq_clk_parent", - "high_freq_clk_parent"; - operating-points-v2 = <&cpu_opp_table1>; - cpu-supply = <&vddcpu1>; - voltage-tolerance = <0>; - clock-latency = <50000>; - }; CPU4:cpu@102 { @@ -143,16 +122,6 @@ enable-method = "psci"; //cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; sched-energy-costs = <&CPU_COST_A73 &CLUSTER_COST_A73>; - clocks = <&clkc CLKID_CPUB_CLK>, - <&clkc CLKID_CPUB_FCLK_P>, - <&clkc CLKID_SYS_PLL>; - clock-names = "core_clk", - "low_freq_clk_parent", - "high_freq_clk_parent"; - operating-points-v2 = <&cpu_opp_table1>; - cpu-supply = <&vddcpu1>; - voltage-tolerance = <0>; - clock-latency = <50000>; }; CPU5:cpu@103 { @@ -162,16 +131,6 @@ enable-method = "psci"; //cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; sched-energy-costs = <&CPU_COST_A73 &CLUSTER_COST_A73>; - clocks = <&clkc CLKID_CPUB_CLK>, - <&clkc CLKID_CPUB_FCLK_P>, - <&clkc CLKID_SYS_PLL>; - clock-names = "core_clk", - "low_freq_clk_parent", - "high_freq_clk_parent"; - operating-points-v2 = <&cpu_opp_table1>; - cpu-supply = <&vddcpu1>; - voltage-tolerance = <0>; - clock-latency = <50000>; }; idle-states { diff --git a/drivers/cpufreq/meson-cpufreq.c b/drivers/cpufreq/meson-cpufreq.c index c1304e0..5b94f99 100644 --- a/drivers/cpufreq/meson-cpufreq.c +++ b/drivers/cpufreq/meson-cpufreq.c @@ -44,26 +44,8 @@ #include "../regulator/internal.h" /* Currently we support only two clusters */ -#define A15_CLUSTER 0 -#define A7_CLUSTER 1 #define MAX_CLUSTERS 2 -#ifdef CONFIG_BL_SWITCHER -#include -static bool bL_switching_enabled; -#define is_bL_switching_enabled() bL_switching_enabled -#define set_switching_enabled(x) (bL_switching_enabled = (x)) -#else -#define is_bL_switching_enabled() false -#define set_switching_enabled(x) do { } while (0) -#define bL_switch_request(...) do { } while (0) -#define bL_switcher_put_enabled() do { } while (0) -#define bL_switcher_get_enabled() do { } while (0) -#endif - -#define ACTUAL_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq << 1 : freq) -#define VIRT_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq >> 1 : freq) - /*core power supply*/ #define CORE_SUPPLY "cpu" @@ -73,13 +55,8 @@ static bool bL_switching_enabled; #define HIGH_FREQ_CLK_PARENT "high_freq_clk_parent" static struct thermal_cooling_device *cdev[MAX_CLUSTERS]; -static struct cpufreq_arm_bL_ops *arm_bL_ops; static struct clk *clk[MAX_CLUSTERS]; static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; -static atomic_t cluster_usage[MAX_CLUSTERS + 1]; - -static unsigned int clk_big_min; /* (Big) clock frequencies */ -static unsigned int clk_little_max; /* Maximum clock frequency (Little) */ /* Default voltage_tolerance */ #define DEF_VOLT_TOL 0 @@ -99,121 +76,39 @@ struct meson_cpufreq_driver_data { static DEFINE_PER_CPU(unsigned int, physical_cluster); -static DEFINE_PER_CPU(unsigned int, cpu_last_req_freq); static struct mutex cluster_lock[MAX_CLUSTERS]; -static inline int raw_cpu_to_cluster(int cpu) -{ - return topology_physical_package_id(cpu); -} - -static inline int cpu_to_cluster(int cpu) +static unsigned int meson_cpufreq_get_rate(unsigned int cpu) { - return is_bL_switching_enabled() ? - MAX_CLUSTERS : raw_cpu_to_cluster(cpu); -} -static int dt_get_transition_latency(struct device *cpu_dev) -{ - struct device_node *np; - u32 transition_latency = CPUFREQ_ETERNAL; - - np = of_node_get(cpu_dev->of_node); - if (!np) { - pr_info("Failed to find cpu node. Use CPUFREQ_ETERNAL transition latency\n"); - return CPUFREQ_ETERNAL; - } - - of_property_read_u32(np, "clock-latency", &transition_latency); - of_node_put(np); - - pr_debug("%s: clock-latency: %d\n", __func__, transition_latency); - return transition_latency; -} - -static unsigned int find_cluster_maxfreq(int cluster) -{ - int j; - u32 max_freq = 0, cpu_freq; - - for_each_online_cpu(j) { - cpu_freq = per_cpu(cpu_last_req_freq, j); - - if ((cluster == per_cpu(physical_cluster, j)) && - (max_freq < cpu_freq)) - max_freq = cpu_freq; - } - - pr_debug("%s: cluster: %d, max freq: %d\n", __func__, cluster, - max_freq); - - return max_freq; -} - -static unsigned int clk_get_cpu_rate(unsigned int cpu) -{ - u32 cur_cluster = per_cpu(physical_cluster, cpu); + u32 cur_cluster = topology_physical_package_id(cpu); u32 rate = clk_get_rate(clk[cur_cluster]) / 1000; - /* For switcher we use virtual A7 clock rates */ - if (is_bL_switching_enabled()) - rate = VIRT_FREQ(cur_cluster, rate); - pr_debug("%s: cpu: %d, cluster: %d, freq: %u\n", __func__, cpu, cur_cluster, rate); return rate; } -static unsigned int meson_bL_cpufreq_get_rate(unsigned int cpu) -{ - if (is_bL_switching_enabled()) { - pr_debug("%s: freq: %d\n", __func__, per_cpu(cpu_last_req_freq, - cpu)); - - return per_cpu(cpu_last_req_freq, cpu); - } else { - return clk_get_cpu_rate(cpu); - } -} - -static unsigned int meson_bL_cpufreq_set_rate(struct cpufreq_policy *policy, - u32 old_cluster, u32 new_cluster, u32 rate) +static unsigned int meson_cpufreq_set_rate(struct cpufreq_policy *policy, + u32 cur_cluster, u32 rate) { struct clk *low_freq_clk_p, *high_freq_clk_p; struct meson_cpufreq_driver_data *cpufreq_data; - u32 new_rate, prev_rate; + u32 new_rate; int ret, cpu = 0; - bool bLs = is_bL_switching_enabled(); cpu = policy->cpu; cpufreq_data = policy->driver_data; high_freq_clk_p = cpufreq_data->high_freq_clk_p; low_freq_clk_p = cpufreq_data->low_freq_clk_p; -#ifdef CONFIG_AMLOGIC_COMMON_CLK_SCPI - /* MARK: cluster0 and cluster share the same scpi lock, - * and don't send scpi command at the same time - */ - mutex_lock(&cluster_lock[0]); -#else - mutex_lock(&cluster_lock[new_cluster]); -#endif - - if (bLs) { - prev_rate = per_cpu(cpu_last_req_freq, cpu); - per_cpu(cpu_last_req_freq, cpu) = rate; - per_cpu(physical_cluster, cpu) = new_cluster; - - new_rate = find_cluster_maxfreq(new_cluster); - new_rate = ACTUAL_FREQ(new_cluster, new_rate); - } else { - new_rate = rate; - } + mutex_lock(&cluster_lock[cur_cluster]); + new_rate = rate; - pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d, freq: %d\n", - __func__, cpu, old_cluster, new_cluster, new_rate); + pr_debug("%s: cpu: %d, new cluster: %d, freq: %d\n", + __func__, cpu, cur_cluster, new_rate); if (new_rate > mid_rate) { if (__clk_get_enable_count(high_freq_clk_p) == 0) { @@ -225,7 +120,7 @@ static unsigned int meson_bL_cpufreq_set_rate(struct cpufreq_policy *policy, } } - ret = clk_set_parent(clk[new_cluster], low_freq_clk_p); + ret = clk_set_parent(clk[cur_cluster], low_freq_clk_p); if (ret) { pr_err("%s: error in setting low_freq_clk_p as parent\n", __func__); @@ -234,12 +129,12 @@ static unsigned int meson_bL_cpufreq_set_rate(struct cpufreq_policy *policy, ret = clk_set_rate(high_freq_clk_p, new_rate * 1000); if (ret) { - pr_err("%s: error in setting low_freq_clk_p rate!\n", + pr_err("%s: error in setting high_freq_clk_p rate!\n", __func__); return ret; } - ret = clk_set_parent(clk[new_cluster], high_freq_clk_p); + ret = clk_set_parent(clk[cur_cluster], high_freq_clk_p); if (ret) { pr_err("%s: error in setting high_freq_clk_p as parent\n", __func__); @@ -253,7 +148,7 @@ static unsigned int meson_bL_cpufreq_set_rate(struct cpufreq_policy *policy, return ret; } - ret = clk_set_parent(clk[new_cluster], low_freq_clk_p); + ret = clk_set_parent(clk[cur_cluster], low_freq_clk_p); if (ret) { pr_err("%s: error in setting low_freq_clk_p rate!\n", __func__); @@ -273,67 +168,19 @@ static unsigned int meson_bL_cpufreq_set_rate(struct cpufreq_policy *policy, * problem we will read back the clock rate and check it is * correct. This needs to be removed once clk core is fixed. */ - if (abs(clk_get_rate(clk[new_cluster]) - new_rate * 1000) + if (abs(clk_get_rate(clk[cur_cluster]) - new_rate * 1000) > gap_rate) ret = -EIO; } if (WARN_ON(ret)) { pr_err("clk_set_rate failed: %d, new cluster: %d\n", ret, - new_cluster); - if (bLs) { - per_cpu(cpu_last_req_freq, cpu) = prev_rate; - per_cpu(physical_cluster, cpu) = old_cluster; - } - -#ifdef CONFIG_AMLOGIC_COMMON_CLK_SCPI - mutex_unlock(&cluster_lock[0]); -#else - mutex_unlock(&cluster_lock[new_cluster]); -#endif - + cur_cluster); + mutex_unlock(&cluster_lock[cur_cluster]); return ret; } -#ifdef CONFIG_AMLOGIC_COMMON_CLK_SCPI - mutex_unlock(&cluster_lock[0]); -#else - mutex_unlock(&cluster_lock[new_cluster]); -#endif - - /* Recalc freq for old cluster when switching clusters */ - if (old_cluster != new_cluster) { - pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d\n", - __func__, cpu, old_cluster, new_cluster); - - /* Switch cluster */ - bL_switch_request(cpu, new_cluster); - -#ifdef CONFIG_AMLOGIC_COMMON_CLK_SCPI - mutex_lock(&cluster_lock[0]); -#else - mutex_lock(&cluster_lock[new_cluster]); -#endif - - /* Set freq of old cluster if there are cpus left on it */ - new_rate = find_cluster_maxfreq(old_cluster); - new_rate = ACTUAL_FREQ(old_cluster, new_rate); - - if (new_rate) { - pr_debug("%s: Updating rate of old cluster: %d, to freq: %d\n", - __func__, old_cluster, new_rate); - - if (clk_set_rate(clk[old_cluster], new_rate * 1000)) - pr_err("%s: clk_set_rate failed: %d, old cluster: %d\n", - __func__, ret, old_cluster); - } -#ifdef CONFIG_AMLOGIC_COMMON_CLK_SCPI - mutex_unlock(&cluster_lock[0]); -#else - mutex_unlock(&cluster_lock[new_cluster]); -#endif - } - + mutex_unlock(&cluster_lock[cur_cluster]); return 0; } @@ -388,11 +235,11 @@ static int meson_regulator_set_volate(struct regulator *regulator, int old_uv, } /* Set clock frequency */ -static int meson_bL_cpufreq_set_target(struct cpufreq_policy *policy, +static int meson_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) { struct dev_pm_opp *opp; - u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster; + u32 cpu, cur_cluster; unsigned long int freq_new, freq_old; unsigned int volt_new = 0, volt_old = 0, volt_tol = 0; struct meson_cpufreq_driver_data *cpufreq_data; @@ -404,11 +251,12 @@ static int meson_bL_cpufreq_set_target(struct cpufreq_policy *policy, pr_err("invalid policy, returning\n"); return -ENODEV; } + + cpu = policy->cpu; cpufreq_data = policy->driver_data; cpu_dev = cpufreq_data->cpu_dev; cpu_reg = cpufreq_data->reg; - cur_cluster = cpu_to_cluster(cpu); - new_cluster = actual_cluster = per_cpu(physical_cluster, cpu); + cur_cluster = topology_physical_package_id(cpu); pr_debug("setting target for cpu %d, index =%d\n", policy->cpu, index); @@ -430,25 +278,13 @@ static int meson_bL_cpufreq_set_target(struct cpufreq_policy *policy, pr_debug("Found OPP: %lu kHz, %u, tolerance: %u\n", freq_new / 1000, volt_new, volt_tol); } - - if (is_bL_switching_enabled()) { - per_cpu(cpu_last_req_freq, policy->cpu) = - clk_get_cpu_rate(policy->cpu); - if ((actual_cluster == A15_CLUSTER) && - (freq_new < clk_big_min)) { - new_cluster = A7_CLUSTER; - } else if ((actual_cluster == A7_CLUSTER) && - (freq_new > clk_little_max)) { - new_cluster = A15_CLUSTER; - } - } else - freq_old = clk_get_rate(clk[cur_cluster]); + freq_old = clk_get_rate(clk[cur_cluster]); pr_debug("Scalling from %lu MHz, %u mV,cur_cluster_id:%u, --> %lu MHz, %u mV,new_cluster_id:%u\n", freq_old / 1000000, (volt_old > 0) ? volt_old / 1000 : -1, cur_cluster, freq_new / 1000000, volt_new ? volt_new / 1000 : -1, - new_cluster); + cur_cluster); /*cpufreq up,change voltage before frequency*/ if (freq_new > freq_old) { @@ -462,7 +298,7 @@ static int meson_bL_cpufreq_set_target(struct cpufreq_policy *policy, } /*scale clock frequency*/ - ret = meson_bL_cpufreq_set_rate(policy, actual_cluster, new_cluster, + ret = meson_cpufreq_set_rate(policy, cur_cluster, freq_new / 1000); if (ret) { pr_err("failed to set clock %luMhz rate: %d\n", @@ -481,8 +317,8 @@ static int meson_bL_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_bL_cpufreq_set_rate(policy, actual_cluster, - actual_cluster, freq_old / 1000); + meson_cpufreq_set_rate(policy, cur_cluster, + freq_old / 1000); } } @@ -492,29 +328,6 @@ static int meson_bL_cpufreq_set_target(struct cpufreq_policy *policy, return ret; } - -static inline u32 get_table_count(struct cpufreq_frequency_table *table) -{ - int count; - - for (count = 0; table[count].frequency != CPUFREQ_TABLE_END; count++) - ; - - return count; -} - -/* get the minimum frequency in the cpufreq_frequency_table */ -static inline u32 get_table_min(struct cpufreq_frequency_table *table) -{ - struct cpufreq_frequency_table *pos; - uint32_t min_freq = ~0; - - cpufreq_for_each_entry(pos, table) - if (pos->frequency < min_freq) - min_freq = pos->frequency; - return min_freq; -} - /* get the maximum frequency in the cpufreq_frequency_table */ static inline u32 get_table_max(struct cpufreq_frequency_table *table) { @@ -527,205 +340,17 @@ static inline u32 get_table_max(struct cpufreq_frequency_table *table) return max_freq; } -static int merge_cluster_tables(void) -{ - int i, j, k = 0, count = 1; - struct cpufreq_frequency_table *table; - - for (i = 0; i < MAX_CLUSTERS; i++) - count += get_table_count(freq_table[i]); - - table = kcalloc(count, sizeof(*table), GFP_KERNEL); - if (!table) - return -ENOMEM; - - freq_table[MAX_CLUSTERS] = table; - - /* Add in reverse order to get freqs in increasing order */ - for (i = MAX_CLUSTERS - 1; i >= 0; i--) { - for (j = 0; freq_table[i][j].frequency != CPUFREQ_TABLE_END; - j++) { - table[k].frequency = VIRT_FREQ(i, - freq_table[i][j].frequency); - pr_debug("%s: index: %d, freq: %d\n", __func__, k, - table[k].frequency); - k++; - } - } - - table[k].driver_data = k; - table[k].frequency = CPUFREQ_TABLE_END; - - pr_debug("%s: End, table: %p, count: %d\n", __func__, table, k); - - return 0; -} - -static void _put_cluster_clk_and_freq_table(struct device *cpu_dev, - const struct cpumask *cpumask) -{ - u32 cluster = raw_cpu_to_cluster(cpu_dev->id); - - if (!freq_table[cluster]) - return; - - clk_put(clk[cluster]); - dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); - if (arm_bL_ops->free_opp_table) - arm_bL_ops->free_opp_table(cpumask); - dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster); -} - -static void put_cluster_clk_and_freq_table(struct device *cpu_dev, - const struct cpumask *cpumask) -{ - u32 cluster = cpu_to_cluster(cpu_dev->id); - int i; - - if (atomic_dec_return(&cluster_usage[cluster])) - return; - - if (cluster < MAX_CLUSTERS) - return _put_cluster_clk_and_freq_table(cpu_dev, cpumask); - - for_each_present_cpu(i) { - struct device *cdev = get_cpu_device(i); - - if (!cdev) { - pr_err("%s: failed to get cpu%d device\n", __func__, i); - return; - } - - _put_cluster_clk_and_freq_table(cdev, cpumask); - } - - /* free virtual table */ - kfree(freq_table[cluster]); -} - - -static int _get_cluster_clk_and_freq_table(struct device *cpu_dev, - const struct cpumask *cpumask) +/* CPU initialization */ +static int meson_cpufreq_init(struct cpufreq_policy *policy) { - u32 cluster = raw_cpu_to_cluster(cpu_dev->id); - int ret; - - if (freq_table[cluster]) - return 0; - - ret = arm_bL_ops->init_opp_table(cpumask); - if (ret) { - dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n", - __func__, cpu_dev->id, ret); - goto out; - } - - ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]); - if (ret) { - dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n", - __func__, cpu_dev->id, ret); - goto free_opp_table; - } - - clk[cluster] = of_clk_get_by_name(of_node_get(cpu_dev->of_node), - CORE_CLK); - if (!IS_ERR(clk[cluster])) { - dev_dbg(cpu_dev, "%s: clk: %p & freq table: %p, cluster: %d\n", - __func__, clk[cluster], freq_table[cluster], - cluster); - return 0; - } - - dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d, cluster: %d\n", - __func__, cpu_dev->id, cluster); - - ret = PTR_ERR(clk[cluster]); - dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); - -free_opp_table: - if (arm_bL_ops->free_opp_table) - arm_bL_ops->free_opp_table(cpumask); -out: - dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__, - cluster); - return ret; -} - -static int get_cluster_clk_and_freq_table(struct device *cpu_dev, - const struct cpumask *cpumask) -{ - u32 cluster = cpu_to_cluster(cpu_dev->id); - int i, ret; - - if (atomic_inc_return(&cluster_usage[cluster]) != 1) - return 0; - - if (cluster < MAX_CLUSTERS) { - ret = _get_cluster_clk_and_freq_table(cpu_dev, cpumask); - if (ret) - atomic_dec(&cluster_usage[cluster]); - return ret; - } - - /* - * Get data for all clusters and fill virtual cluster with a merge of - * both - */ - - for_each_present_cpu(i) { - struct device *cdev = get_cpu_device(i); - - if (!cdev) { - pr_err("%s: failed to get cpu%d device\n", __func__, i); - return -ENODEV; - } - - ret = _get_cluster_clk_and_freq_table(cdev, cpumask); - if (ret) - goto put_clusters; - } - - ret = merge_cluster_tables(); - if (ret) - goto put_clusters; - - /* Assuming 2 cluster, set clk_big_min and clk_little_max */ - clk_big_min = get_table_min(freq_table[0]); - clk_little_max = VIRT_FREQ(1, get_table_max(freq_table[1])); - - pr_debug("%s: cluster: %d, clk_big_min: %d, clk_little_max: %d\n", - __func__, cluster, clk_big_min, clk_little_max); - - return 0; - -put_clusters: - for_each_present_cpu(i) { - struct device *cdev = get_cpu_device(i); - - if (!cdev) { - pr_err("%s: failed to get cpu%d device\n", __func__, i); - return -ENODEV; - } - - _put_cluster_clk_and_freq_table(cdev, cpumask); - } - - atomic_dec(&cluster_usage[cluster]); - - return ret; -} - - -/* Per-CPU initialization */ -static int meson_bL_cpufreq_init(struct cpufreq_policy *policy) -{ - u32 cur_cluster = cpu_to_cluster(policy->cpu); + u32 cur_cluster; struct dev_pm_opp *opp; struct device *cpu_dev; struct device_node *np; struct regulator *cpu_reg = NULL; struct meson_cpufreq_driver_data *cpufreq_data; struct clk *low_freq_clk_p, *high_freq_clk_p = NULL; + unsigned int transition_latency = CPUFREQ_ETERNAL; unsigned int volt_new = 0, volt_old = 0, volt_tol = 0; unsigned long freq_hz = 0; int cpu = 0; @@ -736,6 +361,7 @@ static int meson_bL_cpufreq_init(struct cpufreq_policy *policy) return -ENODEV; } + cur_cluster = topology_physical_package_id(policy->cpu); cpu = policy->cpu; cpu_dev = get_cpu_device(cpu); if (IS_ERR(cpu_dev)) { @@ -753,14 +379,23 @@ static int meson_bL_cpufreq_init(struct cpufreq_policy *policy) cpufreq_data = kzalloc(sizeof(*cpufreq_data), GFP_KERNEL); if (IS_ERR(cpufreq_data)) { pr_err("%s: failed to alloc cpufreq data!\n", __func__); - return -ENOMEM; + ret = -ENOMEM; goto free_np; } + clk[cur_cluster] = of_clk_get_by_name(np, CORE_CLK); + if (IS_ERR(clk[cur_cluster])) { + pr_err("failed to get cpu clock, %ld\n", + PTR_ERR(clk[cur_cluster])); + ret = PTR_ERR(clk[cur_cluster]); + goto free_mem; + } + low_freq_clk_p = of_clk_get_by_name(np, LOW_FREQ_CLK_PARENT); if (IS_ERR(low_freq_clk_p)) { pr_err("%s: Failed to get low parent for cpu: %d, cluster: %d\n", __func__, cpu_dev->id, cur_cluster); + ret = PTR_ERR(low_freq_clk_p); goto free_clk; } @@ -768,7 +403,8 @@ static int meson_bL_cpufreq_init(struct cpufreq_policy *policy) if (IS_ERR(high_freq_clk_p)) { pr_err("%s: Failed to get high parent for cpu: %d,cluster: %d\n", __func__, cpu_dev->id, cur_cluster); - goto free_mem; + ret = PTR_ERR(high_freq_clk_p); + goto free_clk; } cpu_reg = devm_regulator_get(cpu_dev, CORE_SUPPLY); @@ -789,28 +425,30 @@ static int meson_bL_cpufreq_init(struct cpufreq_policy *policy) cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); for_each_cpu(cpu, policy->cpus) per_cpu(physical_cluster, cpu) = cur_cluster; - } else { - /* Assumption: during init, we are always running on A15 */ - per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER; } - ret = get_cluster_clk_and_freq_table(cpu_dev, policy->cpus); + ret = dev_pm_opp_of_add_table(cpu_dev); + if (ret) { + pr_err("%s: init_opp_table failed, cpu: %d, cluster: %d, err: %d\n", + __func__, cpu_dev->id, cur_cluster, ret); + goto free_reg; + } - if (ret) - return ret; + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cur_cluster]); + if (ret) { + dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n", + __func__, cpu_dev->id, ret); + goto free_reg; + } ret = cpufreq_table_validate_and_show(policy, freq_table[cur_cluster]); if (ret) { dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n", policy->cpu, cur_cluster); - put_cluster_clk_and_freq_table(cpu_dev, policy->cpus); - return ret; + goto free_opp_table; } - if (arm_bL_ops->get_transition_latency) - policy->cpuinfo.transition_latency = - arm_bL_ops->get_transition_latency(cpu_dev); - else + if (of_property_read_u32(np, "clock-latency", &transition_latency)) policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; cpufreq_data->cpu_dev = cpu_dev; @@ -819,13 +457,10 @@ static int meson_bL_cpufreq_init(struct cpufreq_policy *policy) cpufreq_data->reg = cpu_reg; cpufreq_data->volt_tol = volt_tol; policy->driver_data = cpufreq_data; + policy->clk = clk[cur_cluster]; + policy->cpuinfo.transition_latency = transition_latency; policy->suspend_freq = get_table_max(freq_table[0]); - - if (is_bL_switching_enabled()) - per_cpu(cpu_last_req_freq, policy->cpu) = - clk_get_cpu_rate(policy->cpu); - else - policy->cur = clk_get_rate(clk[cur_cluster]) / 1000; + policy->cur = clk_get_rate(clk[cur_cluster]) / 1000; /* * if uboot default cpufreq larger than freq_table's max, @@ -843,27 +478,34 @@ static int meson_bL_cpufreq_init(struct cpufreq_policy *policy) ret = meson_regulator_set_volate(cpu_reg, volt_old, volt_new, volt_tol); dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu); - - goto free_np; - + return ret; +free_opp_table: + if (policy->freq_table != NULL) + dev_pm_opp_free_cpufreq_table(cpu_dev, + &freq_table[cur_cluster]); +free_reg: + if (!IS_ERR(cpu_reg)) + devm_regulator_put(cpu_reg); free_clk: - if (!IS_ERR(low_freq_clk_p)) - clk_put(low_freq_clk_p); - if (!IS_ERR(high_freq_clk_p)) - clk_put(high_freq_clk_p); + if (!IS_ERR(clk[cur_cluster])) + clk_put(clk[cur_cluster]); + if (!IS_ERR(low_freq_clk_p)) + clk_put(low_freq_clk_p); + if (!IS_ERR(high_freq_clk_p)) + clk_put(high_freq_clk_p); free_mem: - kfree(cpufreq_data); + kfree(cpufreq_data); free_np: - if (!np) + if (np) of_node_put(np); return ret; } -static int meson_bL_cpufreq_exit(struct cpufreq_policy *policy) +static int meson_cpufreq_exit(struct cpufreq_policy *policy) { struct device *cpu_dev; struct sprd_cpufreq_driver_data *cpufreq_data; - int cur_cluster = cpu_to_cluster(policy->cpu); + int cur_cluster = topology_physical_package_id(policy->cpu); cpufreq_data = policy->driver_data; if (cpufreq_data == NULL) @@ -881,7 +523,7 @@ static int meson_bL_cpufreq_exit(struct cpufreq_policy *policy) return -ENODEV; } - put_cluster_clk_and_freq_table(cpu_dev, policy->related_cpus); + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cur_cluster]); dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu); kfree(cpufreq_data); @@ -906,129 +548,17 @@ static struct cpufreq_driver meson_cpufreq_driver = { CPUFREQ_HAVE_GOVERNOR_PER_POLICY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, - .target_index = meson_bL_cpufreq_set_target, - .get = meson_bL_cpufreq_get_rate, - .init = meson_bL_cpufreq_init, - .exit = meson_bL_cpufreq_exit, + .target_index = meson_cpufreq_set_target, + .get = meson_cpufreq_get_rate, + .init = meson_cpufreq_init, + .exit = meson_cpufreq_exit, .attr = cpufreq_generic_attr, .suspend = meson_cpufreq_suspend, .resume = meson_cpufreq_resume, }; -#ifdef CONFIG_BL_SWITCHER -static int bL_cpufreq_switcher_notifier(struct notifier_block *nfb, - unsigned long action, void *_arg) -{ - pr_debug("%s: action: %ld\n", __func__, action); - - switch (action) { - case BL_NOTIFY_PRE_ENABLE: - case BL_NOTIFY_PRE_DISABLE: - cpufreq_unregister_driver(&bL_cpufreq_driver); - break; - - case BL_NOTIFY_POST_ENABLE: - set_switching_enabled(true); - cpufreq_register_driver(&bL_cpufreq_driver); - break; - - case BL_NOTIFY_POST_DISABLE: - set_switching_enabled(false); - cpufreq_register_driver(&bL_cpufreq_driver); - break; - - default: - return NOTIFY_DONE; - } - - return NOTIFY_OK; -} - -static struct notifier_block bL_switcher_notifier = { - .notifier_call = bL_cpufreq_switcher_notifier, -}; - -static int meson_cpufreq_register_notifier(void) -{ - return bL_switcher_register_notifier(&bL_switcher_notifier); -} - -static int meson_cpufreq_unregister_notifier(void) -{ - return bL_switcher_unregister_notifier(&bL_switcher_notifier); -} -#else static int meson_cpufreq_register_notifier(void) { return 0; } static int meson_cpufreq_unregister_notifier(void) { return 0; } -#endif - -int meson_cpufreq_register(struct cpufreq_arm_bL_ops *ops) -{ - int ret, i; - - if (arm_bL_ops) { - pr_debug("%s: Already registered: %s, exiting\n", __func__, - arm_bL_ops->name); - return -EBUSY; - } - - if (!ops || !strlen(ops->name) || !ops->init_opp_table) { - pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__); - return -ENODEV; - } - - arm_bL_ops = ops; - set_switching_enabled(bL_switcher_get_enabled()); - - for (i = 0; i < MAX_CLUSTERS; i++) - mutex_init(&cluster_lock[i]); - - ret = cpufreq_register_driver(&meson_cpufreq_driver); - if (ret) { - pr_err("%s: Failed registering platform driver: %s, err: %d\n", - __func__, ops->name, ret); - arm_bL_ops = NULL; - } else { - ret = meson_cpufreq_register_notifier(); - if (ret) { - cpufreq_unregister_driver(&meson_cpufreq_driver); - arm_bL_ops = NULL; - } else { - pr_err("%s: Registered platform driver: %s\n", - __func__, ops->name); - } - } - - bL_switcher_put_enabled(); - return ret; -} -EXPORT_SYMBOL_GPL(meson_cpufreq_register); - -void meson_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops) -{ - if (arm_bL_ops != ops) { - pr_err("%s: Registered with: %s, can't unregister, exiting\n", - __func__, arm_bL_ops->name); - return; - } - - bL_switcher_get_enabled(); - meson_cpufreq_unregister_notifier(); - cpufreq_unregister_driver(&meson_cpufreq_driver); - bL_switcher_put_enabled(); - pr_info("%s: Un-registered platform driver: %s\n", __func__, - arm_bL_ops->name); - arm_bL_ops = NULL; -} -EXPORT_SYMBOL_GPL(meson_cpufreq_unregister); - - -static struct cpufreq_arm_bL_ops meson_dt_bL_ops = { - .name = "meson_dt-bl", - .get_transition_latency = dt_get_transition_latency, - .init_opp_table = dev_pm_opp_of_cpumask_add_table, - .free_opp_table = dev_pm_opp_of_cpumask_remove_table, -}; static int meson_cpufreq_probe(struct platform_device *pdev) { @@ -1036,6 +566,10 @@ static int meson_cpufreq_probe(struct platform_device *pdev) struct device_node *np; struct regulator *cpu_reg = NULL; unsigned int cpu = 0; + int ret, i; + + for (i = 0; i < MAX_CLUSTERS; i++) + mutex_init(&cluster_lock[i]); cpu_dev = get_cpu_device(cpu); if (!cpu_dev) { @@ -1058,13 +592,29 @@ static int meson_cpufreq_probe(struct platform_device *pdev) return PTR_ERR(cpu_reg); } - return meson_cpufreq_register(&meson_dt_bL_ops); + + ret = cpufreq_register_driver(&meson_cpufreq_driver); + 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; } static int meson_cpufreq_remove(struct platform_device *pdev) { - meson_cpufreq_unregister(&meson_dt_bL_ops); - return 0; + meson_cpufreq_unregister_notifier(); + + return cpufreq_unregister_driver(&meson_cpufreq_driver); } static const struct of_device_id amlogic_cpufreq_meson_dt_match[] = { -- 2.7.4