From a724f211e7b17e7d04f81d1385f5414acf1976f6 Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Wed, 23 Jun 2021 18:51:29 +0800 Subject: [PATCH] cpufreq: Add runtime initialised driver for rockchip platforms The driver reads OTP value from SoC to provide the OPP framework with required information. This is used to determine the voltage and frequency value for each OPP of operating-points-v2 table when it is parsed by the OPP framework. Change-Id: Iec5a4ff05a4829fdbc3535f94e92759d4238623d Signed-off-by: Finley Xiao --- drivers/cpufreq/Kconfig.arm | 10 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/cpufreq-dt-platdev.c | 38 +++-- drivers/cpufreq/rockchip-cpufreq.c | 230 +++------------------------ drivers/cpufreq/rockchip-cpufreq.h | 31 ---- 5 files changed, 58 insertions(+), 252 deletions(-) diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 1f73fa75b1a0..0faef5fc6df3 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -158,6 +158,16 @@ config ARM_RASPBERRYPI_CPUFREQ If in doubt, say N. +config ARM_ROCKCHIP_CPUFREQ + tristate "Rockchip CPUfreq driver" + depends on ARCH_ROCKCHIP && CPUFREQ_DT + select PM_OPP + help + This adds the CPUFreq driver support for Rockchip SoCs, + based on cpufreq-dt. + + If in doubt, say N. + config ARM_S3C_CPUFREQ bool help diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index b2f4531105fb..d7c9cbc9eded 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o +obj-$(CONFIG_ARM_ROCKCHIP_CPUFREQ) += rockchip-cpufreq.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 1c192a42f11e..cccdfbc844aa 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -66,21 +66,6 @@ static const struct of_device_id whitelist[] __initconst = { { .compatible = "renesas,r8a7794", }, { .compatible = "renesas,sh73a0", }, - { .compatible = "rockchip,rk2928", }, - { .compatible = "rockchip,rk3036", }, - { .compatible = "rockchip,rk3066a", }, - { .compatible = "rockchip,rk3066b", }, - { .compatible = "rockchip,rk3188", }, - { .compatible = "rockchip,rk3228", }, - { .compatible = "rockchip,rk3288", }, - { .compatible = "rockchip,rk3328", }, - { .compatible = "rockchip,rk3366", }, - { .compatible = "rockchip,rk3368", }, - { .compatible = "rockchip,rk3399", - .data = &(struct cpufreq_dt_platform_data) - { .have_governor_per_policy = true, }, - }, - { .compatible = "st-ericsson,u8500", }, { .compatible = "st-ericsson,u8540", }, { .compatible = "st-ericsson,u9500", }, @@ -137,6 +122,29 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "qcom,sc7180", }, { .compatible = "qcom,sdm845", }, + { .compatible = "rockchip,px30", }, + { .compatible = "rockchip,rk2928", }, + { .compatible = "rockchip,rk3036", }, + { .compatible = "rockchip,rk3066a", }, + { .compatible = "rockchip,rk3066b", }, + { .compatible = "rockchip,rk3126", }, + { .compatible = "rockchip,rk3128", }, + { .compatible = "rockchip,rk3188", }, + { .compatible = "rockchip,rk3228", }, + { .compatible = "rockchip,rk3229", }, + { .compatible = "rockchip,rk3288", }, + { .compatible = "rockchip,rk3288w", }, + { .compatible = "rockchip,rk3326", }, + { .compatible = "rockchip,rk3328", }, + { .compatible = "rockchip,rk3366", }, + { .compatible = "rockchip,rk3368", }, + { .compatible = "rockchip,rk3399", }, + { .compatible = "rockchip,rk3399pro", }, + { .compatible = "rockchip,rk3566", }, + { .compatible = "rockchip,rk3568", }, + { .compatible = "rockchip,rv1109", }, + { .compatible = "rockchip,rv1126", }, + { .compatible = "st,stih407", }, { .compatible = "st,stih410", }, { .compatible = "st,stih418", }, diff --git a/drivers/cpufreq/rockchip-cpufreq.c b/drivers/cpufreq/rockchip-cpufreq.c index 173da325ce6d..7a91701546f1 100644 --- a/drivers/cpufreq/rockchip-cpufreq.c +++ b/drivers/cpufreq/rockchip-cpufreq.c @@ -24,31 +24,19 @@ #include #include #include -#include #include -#include -#include #include #include #include #include "cpufreq-dt.h" #include "rockchip-cpufreq.h" -#include "../clk/rockchip/clk.h" - -#define LEAKAGE_INVALID 0xff struct cluster_info { struct opp_table *opp_table; struct list_head list_head; cpumask_t cpus; - unsigned int reboot_freq; - unsigned int threshold_freq; - unsigned int scale_rate; - unsigned int temp_limit_rate; - int volt_sel; int scale; - int process; bool offline; bool freq_limit; bool is_check_init; @@ -255,51 +243,27 @@ static struct cluster_info *rockchip_cluster_info_lookup(int cpu) return NULL; } -static struct cluster_info *rockchip_cluster_lookup_by_dev(struct device *dev) -{ - struct cluster_info *cluster; - struct device *cpu_dev; - int cpu; - - list_for_each_entry(cluster, &cluster_info_list, list_head) { - for_each_cpu(cpu, &cluster->cpus) { - cpu_dev = get_cpu_device(cpu); - if (!cpu_dev) - continue; - if (cpu_dev == dev) - return cluster; - } - } - - return NULL; -} - static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster) { + struct opp_table *opp_table; struct device_node *np; - struct property *pp; struct device *dev; char *reg_name = NULL; - int ret = 0, bin = -EINVAL; - - cluster->process = -EINVAL; - cluster->volt_sel = -EINVAL; - cluster->scale = 0; + int bin = -EINVAL; + int process = -EINVAL; + int volt_sel = -EINVAL; + int ret = 0; dev = get_cpu_device(cpu); if (!dev) return -ENODEV; - pp = of_find_property(dev->of_node, "cpu-supply", NULL); - if (pp) { + if (of_find_property(dev->of_node, "cpu-supply", NULL)) reg_name = "cpu"; - } else { - pp = of_find_property(dev->of_node, "cpu0-supply", NULL); - if (pp) - reg_name = "cpu0"; - else - return -ENOENT; - } + else if (of_find_property(dev->of_node, "cpu0-supply", NULL)) + reg_name = "cpu0"; + else + return -ENOENT; np = of_parse_phandle(dev->of_node, "operating-points-v2", 0); if (!np) { @@ -313,72 +277,23 @@ static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster) goto np_err; } - of_property_read_u32(np, "rockchip,threshold-freq", - &cluster->threshold_freq); - cluster->freq_limit = of_property_read_bool(np, "rockchip,freq-limit"); - - rockchip_get_soc_info(dev, rockchip_cpufreq_of_match, - &bin, &cluster->process); - rockchip_get_scale_volt_sel(dev, "cpu_leakage", reg_name, - bin, cluster->process, - &cluster->scale, &cluster->volt_sel); + rockchip_get_soc_info(dev, rockchip_cpufreq_of_match, &bin, &process); + rockchip_get_scale_volt_sel(dev, "cpu_leakage", reg_name, bin, process, + &cluster->scale, &volt_sel); + opp_table = rockchip_set_opp_prop_name(dev, process, volt_sel); + if (IS_ERR(opp_table)) + ret = PTR_ERR(opp_table); np_err: of_node_put(np); + return ret; } -int rockchip_cpufreq_check_rate_volt(struct device *dev) -{ - struct cluster_info *cluster; - - cluster = rockchip_cluster_lookup_by_dev(dev); - if (!cluster) - return -EINVAL; - if (cluster->is_check_init) - return 0; - dev_pm_opp_check_rate_volt(dev, true); - cluster->is_check_init = true; - - return 0; -} -EXPORT_SYMBOL_GPL(rockchip_cpufreq_check_rate_volt); - -int rockchip_cpufreq_set_opp_info(struct device *dev) -{ - struct cluster_info *cluster; - - cluster = rockchip_cluster_lookup_by_dev(dev); - if (!cluster) - return -EINVAL; - cluster->opp_table = rockchip_set_opp_prop_name(dev, - cluster->process, - cluster->volt_sel); - if (IS_ERR(cluster->opp_table)) { - dev_err(dev, "Failed to set prop name\n"); - return PTR_ERR(cluster->opp_table); - } - - return 0; -} -EXPORT_SYMBOL_GPL(rockchip_cpufreq_set_opp_info); - -void rockchip_cpufreq_put_opp_info(struct device *dev) -{ - struct cluster_info *cluster; - - cluster = rockchip_cluster_lookup_by_dev(dev); - if (!cluster) - return; - if (!IS_ERR_OR_NULL(cluster->opp_table)) - dev_pm_opp_put_prop_name(cluster->opp_table); -} -EXPORT_SYMBOL_GPL(rockchip_cpufreq_put_opp_info); - int rockchip_cpufreq_adjust_power_scale(struct device *dev) { struct cluster_info *cluster; - cluster = rockchip_cluster_lookup_by_dev(dev); + cluster = rockchip_cluster_info_lookup(dev->id); if (!cluster) return -EINVAL; rockchip_adjust_power_scale(dev, cluster->scale); @@ -387,101 +302,22 @@ int rockchip_cpufreq_adjust_power_scale(struct device *dev) } EXPORT_SYMBOL_GPL(rockchip_cpufreq_adjust_power_scale); -int rockchip_cpufreq_suspend(struct cpufreq_policy *policy) +static int rockchip_cpufreq_suspend(struct cpufreq_policy *policy) { int ret = 0; ret = cpufreq_generic_suspend(policy); if (!ret) rockchip_monitor_suspend_low_temp_adjust(policy->cpu); + return ret; } -EXPORT_SYMBOL_GPL(rockchip_cpufreq_suspend); - -static struct cpufreq_policy *rockchip_get_policy(struct cluster_info *cluster) -{ - int first_cpu; - - first_cpu = cpumask_first_and(&cluster->cpus, cpu_online_mask); - if (first_cpu >= nr_cpu_ids) - return NULL; - - return cpufreq_cpu_get(first_cpu); -} - -/** - * rockchip_cpufreq_adjust_target() - Adjust cpu target frequency - * @cpu: CPU number - * @freq: Expected target frequency - * - * This adjusts cpu target frequency for reducing power consumption. - * Only one cluster can eanble frequency limit, and the cluster's - * maximum frequency will be limited to its threshold frequency, if the - * other cluster's frequency is geater than or equal to its threshold - * frequency. - */ -unsigned int rockchip_cpufreq_adjust_target(int cpu, unsigned int freq) -{ - struct cpufreq_policy *policy; - struct cluster_info *cluster, *temp; - - cluster = rockchip_cluster_info_lookup(cpu); - if (!cluster || !cluster->threshold_freq) - goto adjust_out; - - if (cluster->freq_limit) { - if (freq <= cluster->threshold_freq) - goto adjust_out; - - list_for_each_entry(temp, &cluster_info_list, list_head) { - if (temp->freq_limit || temp == cluster || - temp->offline) - continue; - - policy = rockchip_get_policy(temp); - if (!policy) - continue; - - if (temp->threshold_freq && - temp->threshold_freq <= policy->cur) { - cpufreq_cpu_put(policy); - return cluster->threshold_freq; - } - cpufreq_cpu_put(policy); - } - } else { - if (freq < cluster->threshold_freq) - goto adjust_out; - - list_for_each_entry(temp, &cluster_info_list, list_head) { - if (!temp->freq_limit || temp == cluster || - temp->offline) - continue; - - policy = rockchip_get_policy(temp); - if (!policy) - continue; - - if (temp->threshold_freq && - temp->threshold_freq < policy->cur) - cpufreq_driver_target(policy, - temp->threshold_freq, - CPUFREQ_RELATION_H); - cpufreq_cpu_put(policy); - } - } - -adjust_out: - - return freq; -} -EXPORT_SYMBOL_GPL(rockchip_cpufreq_adjust_target); static int __init rockchip_cpufreq_driver_init(void) { struct cluster_info *cluster, *pos; struct cpufreq_dt_platform_data pdata = {0}; - int cpu, ret, i = 0; + int cpu, ret; for_each_possible_cpu(cpu) { cluster = rockchip_cluster_info_lookup(cpu); @@ -496,33 +332,15 @@ static int __init rockchip_cpufreq_driver_init(void) ret = rockchip_cpufreq_cluster_init(cpu, cluster); if (ret) { - if (ret != -ENOENT) { - pr_err("Failed to initialize dvfs info cpu%d\n", - cpu); - goto release_cluster_info; - } - - /* - * As the OPP document said, only one OPP binding - * should be used per device. - * And if there are multiple clusters on rockchip - * platforms, we should use operating-points-v2. - * So if don't support operating-points-v2, there must - * be only one cluster, the list shuold be null. - */ - list_for_each_entry(pos, &cluster_info_list, list_head) - i++; - if (i) - goto release_cluster_info; - list_add(&cluster->list_head, &cluster_info_list); - goto next; + pr_err("Failed to initialize dvfs info cpu%d\n", cpu); + goto release_cluster_info; } list_add(&cluster->list_head, &cluster_info_list); } -next: pdata.have_governor_per_policy = true; pdata.suspend = rockchip_cpufreq_suspend; + return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "cpufreq-dt", -1, (void *)&pdata, sizeof(struct cpufreq_dt_platform_data))); diff --git a/drivers/cpufreq/rockchip-cpufreq.h b/drivers/cpufreq/rockchip-cpufreq.h index b1509c07f8bc..43015c079a1f 100644 --- a/drivers/cpufreq/rockchip-cpufreq.h +++ b/drivers/cpufreq/rockchip-cpufreq.h @@ -6,43 +6,12 @@ #define __ROCKCHIP_CPUFREQ_H #if IS_ENABLED(CONFIG_ARM_ROCKCHIP_CPUFREQ) -unsigned int rockchip_cpufreq_adjust_target(int cpu, unsigned int freq); -int rockchip_cpufreq_check_rate_volt(struct device *dev); -int rockchip_cpufreq_set_opp_info(struct device *dev); -void rockchip_cpufreq_put_opp_info(struct device *dev); int rockchip_cpufreq_adjust_power_scale(struct device *dev); -int rockchip_cpufreq_suspend(struct cpufreq_policy *policy); #else -static inline unsigned int rockchip_cpufreq_adjust_target(int cpu, - unsigned int freq) -{ - return freq; -} - -static inline int rockchip_cpufreq_check_rate_volt(struct device *dev) -{ - return -ENOTSUPP; -} - -static inline int rockchip_cpufreq_set_opp_info(struct device *dev) -{ - return -ENOTSUPP; -} - -static inline void rockchip_cpufreq_put_opp_info(struct device *dev) -{ -} - static inline int rockchip_cpufreq_adjust_power_scale(struct device *dev) { return -ENOTSUPP; } - -static inline int rockchip_cpufreq_suspend(struct cpufreq_policy *policy) -{ - return -ENOTSUPP; -} - #endif /* CONFIG_ARM_ROCKCHIP_CPUFREQ */ #endif