diff options
author | Anson Huang <Anson.Huang@nxp.com> | 2017-03-29 00:07:57 +0800 |
---|---|---|
committer | Leonard Crestez <leonard.crestez@nxp.com> | 2018-08-24 12:41:33 +0300 |
commit | 3f9937b275357f014b26d622654824a78de750cb (patch) | |
tree | 558b7ec2ed4203c3acaa809ecbe0c930d463d28e /drivers/cpufreq | |
parent | e229a4c2bdd750326457f9a0f99a997cb7f10316 (diff) |
MLK-14534-1 cpufreq: imx8: add cpu-freq support
Add multi-clusters cpu-freq driver support for i.MX8,
only support cpu-freq get now.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r-- | drivers/cpufreq/Kconfig.arm | 8 | ||||
-rw-r--r-- | drivers/cpufreq/Makefile | 1 | ||||
-rw-r--r-- | drivers/cpufreq/imx8-cpufreq.c | 183 |
3 files changed, 192 insertions, 0 deletions
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 0fc6ad87a1b2..1a4a1db1d37a 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -76,6 +76,14 @@ config ARM_IMX7ULP_CPUFREQ If in doubt, say N. +config ARM_IMX8_CPUFREQ + tristate "NXP i.MX8 cpufreq support" + select PM_OPP + help + This adds cpufreq driver support for NXP i.MX8 series SoCs. + + If in doubt, say N. + config ARM_INTEGRATOR tristate "CPUfreq driver for ARM Integrator CPUs" depends on ARCH_INTEGRATOR diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 4fc9f547ae6e..198592f0f869 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o obj-$(CONFIG_ARM_IMX7D_CPUFREQ) += imx7-cpufreq.o obj-$(CONFIG_ARM_IMX7ULP_CPUFREQ) += imx7ulp-cpufreq.o +obj-$(CONFIG_ARM_IMX8_CPUFREQ) += imx8-cpufreq.o obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o obj-$(CONFIG_ARM_MT8173_CPUFREQ) += mt8173-cpufreq.o diff --git a/drivers/cpufreq/imx8-cpufreq.c b/drivers/cpufreq/imx8-cpufreq.c new file mode 100644 index 000000000000..46f18009d09d --- /dev/null +++ b/drivers/cpufreq/imx8-cpufreq.c @@ -0,0 +1,183 @@ +/* + * Copyright 2017 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/cpu.h> +#include <linux/cpufreq.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pm_opp.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> + +#define MAX_CLUSTER_NUM 2 + +struct imx8_cpufreq { + struct clk *cpu_clk; +}; + +struct imx8_cpufreq cluster_freq[MAX_CLUSTER_NUM]; +static struct cpufreq_frequency_table *freq_table[MAX_CLUSTER_NUM]; +static unsigned int transition_latency[MAX_CLUSTER_NUM]; + +static int imx8_set_target(struct cpufreq_policy *policy, unsigned int index) +{ + return 0; +} + +static int imx8_cpufreq_init(struct cpufreq_policy *policy) +{ + int cluster_id = topology_physical_package_id(policy->cpu); + int ret = 0; + + policy->clk = cluster_freq[cluster_id].cpu_clk; + policy->cur = clk_get_rate(cluster_freq[cluster_id].cpu_clk) / 1000; + + pr_info("%s: cluster %d running at freq %d MHz\n", + __func__, cluster_id, policy->cur / 1000); + /* + * The driver only supports the SMP configuartion where all processors + * share the clock and voltage and clock. + */ + cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); + + ret = cpufreq_table_validate_and_show(policy, freq_table[cluster_id]); + if (ret) { + pr_err("%s: invalid frequency table: %d\n", __func__, ret); + return ret; + } + + policy->cpuinfo.transition_latency = transition_latency[cluster_id]; + + return ret; +} + +static struct cpufreq_driver imx8_cpufreq_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = imx8_set_target, + .get = cpufreq_generic_get, + .init = imx8_cpufreq_init, + .name = "imx8-cpufreq", + .attr = cpufreq_generic_attr, +}; + +static int imx8_cpufreq_probe(struct platform_device *pdev) +{ + struct device_node *np; + struct device *cpu_dev; + int ret = 0; + int i, cluster_id; + + cpu_dev = get_cpu_device(0); + + if (!cpu_dev) { + pr_err("failed to get cpu device 0\n"); + return -ENODEV; + } + + np = of_node_get(cpu_dev->of_node); + if (!np) { + pr_warn("failed to find cpu 0 node\n"); + return -ENODEV; + } + + ret = dev_pm_opp_of_add_table(cpu_dev); + if (ret < 0) { + dev_err(cpu_dev, "failed to init OPP table: %d\n", ret); + goto put_node; + } + + cluster_id = topology_physical_package_id(0); + cluster_freq[cluster_id].cpu_clk = devm_clk_get(cpu_dev, NULL); + if (IS_ERR(cluster_freq[cluster_id].cpu_clk)) { + dev_err(cpu_dev, "failed to get cluster %d clock\n", cluster_id); + ret = -ENOENT; + goto put_node; + } + + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster_id]); + if (ret) { + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); + goto put_node; + } + + if (of_property_read_u32(np, "clock-latency", &transition_latency[cluster_id])) + transition_latency[cluster_id] = CPUFREQ_ETERNAL; + + /* init next cluster if there is */ + for (i = 1; i < num_online_cpus(); i++) { + if (topology_physical_package_id(i) == topology_physical_package_id(0)) + continue; + cpu_dev = get_cpu_device(i); + if (!cpu_dev) { + pr_err("failed to get cpu device %d\n", i); + return -ENODEV; + } + + np = of_node_get(cpu_dev->of_node); + if (!np) { + pr_warn("failed to find cpu %d node\n", i); + ret = -ENODEV; + goto put_node; + } + + ret = dev_pm_opp_of_add_table(cpu_dev); + if (ret < 0) { + dev_err(cpu_dev, "failed to add OPP table for cpu %d\n", i); + goto put_node; + } + + cluster_id = topology_physical_package_id(i); + cluster_freq[cluster_id].cpu_clk = devm_clk_get(cpu_dev, NULL); + if (IS_ERR(cluster_freq[cluster_id].cpu_clk)) { + dev_err(cpu_dev, "failed to get cluster %d clock\n", cluster_id); + ret = -ENOENT; + goto put_node; + } + + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster_id]); + if (ret) { + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); + goto put_node; + } + + if (of_property_read_u32(np, "clock-latency", &transition_latency[cluster_id])) + transition_latency[cluster_id] = CPUFREQ_ETERNAL; + break; + } + + ret = cpufreq_register_driver(&imx8_cpufreq_driver); + if (ret) + dev_err(cpu_dev, "failed register driver: %d\n", ret); + +put_node: + of_node_put(np); + return ret; +} + +static int imx8_cpufreq_remove(struct platform_device *pdev) +{ + cpufreq_unregister_driver(&imx8_cpufreq_driver); + + return 0; +} + +static struct platform_driver imx8_cpufreq_platdrv = { + .driver = { + .name = "imx8-cpufreq", + }, + .probe = imx8_cpufreq_probe, + .remove = imx8_cpufreq_remove, +}; +module_platform_driver(imx8_cpufreq_platdrv); + +MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>"); +MODULE_DESCRIPTION("NXP i.MX8 cpufreq driver"); +MODULE_LICENSE("GPL"); |