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