diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 0cd8eb76ad59..cacd1aeec699 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -121,6 +121,15 @@ config ARM_QCOM_CPUFREQ_KRYO 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 for Rockchip SoCs. + + If in doubt, say N. + config ARM_S3C_CPUFREQ bool help diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index c1ffeabe4ecf..f697feccc137 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.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 fe14c57de6ca..880777ee0aeb 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -68,18 +68,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", }, - { .compatible = "st-ericsson,u8500", }, { .compatible = "st-ericsson,u8540", }, { .compatible = "st-ericsson,u9500", }, @@ -119,6 +107,18 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "qcom,apq8096", }, { .compatible = "qcom,msm8996", }, + { .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", }, + { .compatible = "st,stih407", }, { .compatible = "st,stih410", }, diff --git a/drivers/cpufreq/rockchip-cpufreq.c b/drivers/cpufreq/rockchip-cpufreq.c index c206b7cf0205..73f6144dfb2f 100644 --- a/drivers/cpufreq/rockchip-cpufreq.c +++ b/drivers/cpufreq/rockchip-cpufreq.c @@ -30,12 +30,16 @@ #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; @@ -217,47 +221,6 @@ static struct cluster_info *rockchip_cluster_lookup_by_dev(struct device *dev) return NULL; } -int rockchip_cpufreq_get_scale(int cpu) -{ - struct cluster_info *cluster; - - cluster = rockchip_cluster_info_lookup(cpu); - if (!cluster) - return 0; - else - return cluster->scale; -} -EXPORT_SYMBOL_GPL(rockchip_cpufreq_get_scale); - -int rockchip_cpufreq_set_scale_rate(struct device *dev, unsigned long rate) -{ - struct cluster_info *cluster; - - cluster = rockchip_cluster_lookup_by_dev(dev); - if (!cluster) - return -EINVAL; - cluster->scale_rate = rate / 1000; - - return 0; -} -EXPORT_SYMBOL_GPL(rockchip_cpufreq_set_scale_rate); - -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); - static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster) { struct device_node *np; @@ -311,76 +274,76 @@ np_err: return ret; } -static int rockchip_cpufreq_set_opp_info(int cpu, struct cluster_info *cluster) +int rockchip_cpufreq_check_rate_volt(struct device *dev) { - struct device *dev = get_cpu_device(cpu); - - if (!dev) - return -ENODEV; - return rockchip_set_opp_info(dev, cluster->process, - cluster->volt_sel); -} - -static int rockchip_hotcpu_notifier(struct notifier_block *nb, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; struct cluster_info *cluster; - cpumask_t cpus; - int number, ret; - cluster = rockchip_cluster_info_lookup(cpu); + cluster = rockchip_cluster_lookup_by_dev(dev); if (!cluster) - return NOTIFY_OK; + return -EINVAL; + if (cluster->is_check_init) + return 0; + dev_pm_opp_check_rate_volt(dev, true); + cluster->is_check_init = true; - switch (action & ~CPU_TASKS_FROZEN) { - case CPU_ONLINE: - if (cluster->offline) { - ret = rockchip_cpufreq_set_opp_info(cpu, cluster); - if (ret) - pr_err("Failed to set cpu%d opp_info\n", cpu); - cluster->offline = false; - } - break; + return 0; +} +EXPORT_SYMBOL_GPL(rockchip_cpufreq_check_rate_volt); - case CPU_POST_DEAD: - cpumask_and(&cpus, &cluster->cpus, cpu_online_mask); - number = cpumask_weight(&cpus); - if (!number) - cluster->offline = true; - break; +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 NOTIFY_OK; + return 0; } +EXPORT_SYMBOL_GPL(rockchip_cpufreq_set_opp_info); -static struct notifier_block rockchip_hotcpu_nb = { - .notifier_call = rockchip_hotcpu_notifier, -}; - -static int rockchip_cpufreq_policy_notifier(struct notifier_block *nb, - unsigned long event, void *data) +void rockchip_cpufreq_put_opp_info(struct device *dev) { - struct cpufreq_policy *policy = data; struct cluster_info *cluster; - int cpu = policy->cpu; - if (event != CPUFREQ_ADJUST) - return NOTIFY_OK; - - cluster = rockchip_cluster_info_lookup(cpu); + cluster = rockchip_cluster_lookup_by_dev(dev); if (!cluster) - return NOTIFY_DONE; - - if (cluster->scale_rate && cluster->scale_rate < policy->max) - cpufreq_verify_within_limits(policy, 0, cluster->scale_rate); - - return NOTIFY_OK; + 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); -static struct notifier_block rockchip_cpufreq_policy_nb = { - .notifier_call = rockchip_cpufreq_policy_notifier, -}; +int rockchip_cpufreq_adjust_power_scale(struct device *dev) +{ + struct cluster_info *cluster; + + cluster = rockchip_cluster_lookup_by_dev(dev); + if (!cluster) + return -EINVAL; + rockchip_adjust_power_scale(dev, cluster->scale); + + return 0; +} +EXPORT_SYMBOL_GPL(rockchip_cpufreq_adjust_power_scale); + +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) { @@ -463,9 +426,9 @@ EXPORT_SYMBOL_GPL(rockchip_cpufreq_adjust_target); static int __init rockchip_cpufreq_driver_init(void) { - struct platform_device *pdev; struct cluster_info *cluster, *pos; - int cpu, first_cpu, ret, i = 0; + struct cpufreq_dt_platform_data pdata = {0}; + int cpu, ret, i = 0; for_each_possible_cpu(cpu) { cluster = rockchip_cluster_info_lookup(cpu); @@ -473,14 +436,17 @@ static int __init rockchip_cpufreq_driver_init(void) continue; cluster = kzalloc(sizeof(*cluster), GFP_KERNEL); - if (!cluster) - return -ENOMEM; + if (!cluster) { + ret = -ENOMEM; + goto release_cluster_info; + } ret = rockchip_cpufreq_cluster_init(cpu, cluster); if (ret) { if (ret != -ENOENT) { - pr_err("Failed to cpu%d parse_dt\n", cpu); - return ret; + pr_err("Failed to initialize dvfs info cpu%d\n", + cpu); + goto release_cluster_info; } /* @@ -494,32 +460,26 @@ static int __init rockchip_cpufreq_driver_init(void) list_for_each_entry(pos, &cluster_info_list, list_head) i++; if (i) - return ret; - /* - * If don't support operating-points-v2, there is no - * need to register notifiers. - */ + goto release_cluster_info; + list_add(&cluster->list_head, &cluster_info_list); goto next; } - - first_cpu = cpumask_first_and(&cluster->cpus, cpu_online_mask); - ret = rockchip_cpufreq_set_opp_info(first_cpu, cluster); - if (ret) { - pr_err("Failed to set cpu%d opp_info\n", first_cpu); - return ret; - } - list_add(&cluster->list_head, &cluster_info_list); } - register_hotcpu_notifier(&rockchip_hotcpu_nb); - cpufreq_register_notifier(&rockchip_cpufreq_policy_nb, - CPUFREQ_POLICY_NOTIFIER); - next: - pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0); + 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))); - return PTR_ERR_OR_ZERO(pdev); +release_cluster_info: + list_for_each_entry_safe(cluster, pos, &cluster_info_list, list_head) { + list_del(&cluster->list_head); + kfree(cluster); + } + return ret; } module_init(rockchip_cpufreq_driver_init); diff --git a/drivers/cpufreq/rockchip-cpufreq.h b/drivers/cpufreq/rockchip-cpufreq.h new file mode 100644 index 000000000000..9cd75d5f9b0f --- /dev/null +++ b/drivers/cpufreq/rockchip-cpufreq.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd + */ +#ifndef __ROCKCHIP_CPUFREQ_H +#define __ROCKCHIP_CPUFREQ_H + +#ifdef 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