142099322SDeepak Sikri /* 242099322SDeepak Sikri * drivers/cpufreq/spear-cpufreq.c 342099322SDeepak Sikri * 442099322SDeepak Sikri * CPU Frequency Scaling for SPEAr platform 542099322SDeepak Sikri * 642099322SDeepak Sikri * Copyright (C) 2012 ST Microelectronics 742099322SDeepak Sikri * Deepak Sikri <deepak.sikri@st.com> 842099322SDeepak Sikri * 942099322SDeepak Sikri * This file is licensed under the terms of the GNU General Public 1042099322SDeepak Sikri * License version 2. This program is licensed "as is" without any 1142099322SDeepak Sikri * warranty of any kind, whether express or implied. 1242099322SDeepak Sikri */ 1342099322SDeepak Sikri 1442099322SDeepak Sikri #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1542099322SDeepak Sikri 1642099322SDeepak Sikri #include <linux/clk.h> 1742099322SDeepak Sikri #include <linux/cpufreq.h> 1842099322SDeepak Sikri #include <linux/err.h> 1942099322SDeepak Sikri #include <linux/init.h> 2042099322SDeepak Sikri #include <linux/module.h> 2142099322SDeepak Sikri #include <linux/of.h> 2242099322SDeepak Sikri #include <linux/slab.h> 2342099322SDeepak Sikri #include <linux/types.h> 2442099322SDeepak Sikri 2542099322SDeepak Sikri /* SPEAr CPUFreq driver data structure */ 2642099322SDeepak Sikri static struct { 2742099322SDeepak Sikri struct clk *clk; 2842099322SDeepak Sikri unsigned int transition_latency; 2942099322SDeepak Sikri struct cpufreq_frequency_table *freq_tbl; 3042099322SDeepak Sikri u32 cnt; 3142099322SDeepak Sikri } spear_cpufreq; 3242099322SDeepak Sikri 33f8517804SViresh Kumar static int spear_cpufreq_verify(struct cpufreq_policy *policy) 3442099322SDeepak Sikri { 3542099322SDeepak Sikri return cpufreq_frequency_table_verify(policy, spear_cpufreq.freq_tbl); 3642099322SDeepak Sikri } 3742099322SDeepak Sikri 3842099322SDeepak Sikri static unsigned int spear_cpufreq_get(unsigned int cpu) 3942099322SDeepak Sikri { 4042099322SDeepak Sikri return clk_get_rate(spear_cpufreq.clk) / 1000; 4142099322SDeepak Sikri } 4242099322SDeepak Sikri 4342099322SDeepak Sikri static struct clk *spear1340_cpu_get_possible_parent(unsigned long newfreq) 4442099322SDeepak Sikri { 4542099322SDeepak Sikri struct clk *sys_pclk; 4642099322SDeepak Sikri int pclk; 4742099322SDeepak Sikri /* 4842099322SDeepak Sikri * In SPEAr1340, cpu clk's parent sys clk can take input from 4942099322SDeepak Sikri * following sources 5042099322SDeepak Sikri */ 5142099322SDeepak Sikri const char *sys_clk_src[] = { 5242099322SDeepak Sikri "sys_syn_clk", 5342099322SDeepak Sikri "pll1_clk", 5442099322SDeepak Sikri "pll2_clk", 5542099322SDeepak Sikri "pll3_clk", 5642099322SDeepak Sikri }; 5742099322SDeepak Sikri 5842099322SDeepak Sikri /* 5942099322SDeepak Sikri * As sys clk can have multiple source with their own range 6042099322SDeepak Sikri * limitation so we choose possible sources accordingly 6142099322SDeepak Sikri */ 6242099322SDeepak Sikri if (newfreq <= 300000000) 6342099322SDeepak Sikri pclk = 0; /* src is sys_syn_clk */ 6442099322SDeepak Sikri else if (newfreq > 300000000 && newfreq <= 500000000) 6542099322SDeepak Sikri pclk = 3; /* src is pll3_clk */ 6642099322SDeepak Sikri else if (newfreq == 600000000) 6742099322SDeepak Sikri pclk = 1; /* src is pll1_clk */ 6842099322SDeepak Sikri else 6942099322SDeepak Sikri return ERR_PTR(-EINVAL); 7042099322SDeepak Sikri 7142099322SDeepak Sikri /* Get parent to sys clock */ 7242099322SDeepak Sikri sys_pclk = clk_get(NULL, sys_clk_src[pclk]); 7342099322SDeepak Sikri if (IS_ERR(sys_pclk)) 7442099322SDeepak Sikri pr_err("Failed to get %s clock\n", sys_clk_src[pclk]); 7542099322SDeepak Sikri 7642099322SDeepak Sikri return sys_pclk; 7742099322SDeepak Sikri } 7842099322SDeepak Sikri 7942099322SDeepak Sikri /* 8042099322SDeepak Sikri * In SPEAr1340, we cannot use newfreq directly because we need to actually 8142099322SDeepak Sikri * access a source clock (clk) which might not be ancestor of cpu at present. 8242099322SDeepak Sikri * Hence in SPEAr1340 we would operate on source clock directly before switching 8342099322SDeepak Sikri * cpu clock to it. 8442099322SDeepak Sikri */ 8542099322SDeepak Sikri static int spear1340_set_cpu_rate(struct clk *sys_pclk, unsigned long newfreq) 8642099322SDeepak Sikri { 8742099322SDeepak Sikri struct clk *sys_clk; 8842099322SDeepak Sikri int ret = 0; 8942099322SDeepak Sikri 9042099322SDeepak Sikri sys_clk = clk_get_parent(spear_cpufreq.clk); 9142099322SDeepak Sikri if (IS_ERR(sys_clk)) { 9242099322SDeepak Sikri pr_err("failed to get cpu's parent (sys) clock\n"); 9342099322SDeepak Sikri return PTR_ERR(sys_clk); 9442099322SDeepak Sikri } 9542099322SDeepak Sikri 9642099322SDeepak Sikri /* Set the rate of the source clock before changing the parent */ 9742099322SDeepak Sikri ret = clk_set_rate(sys_pclk, newfreq); 9842099322SDeepak Sikri if (ret) { 9942099322SDeepak Sikri pr_err("Failed to set sys clk rate to %lu\n", newfreq); 10042099322SDeepak Sikri return ret; 10142099322SDeepak Sikri } 10242099322SDeepak Sikri 10342099322SDeepak Sikri ret = clk_set_parent(sys_clk, sys_pclk); 10442099322SDeepak Sikri if (ret) { 10542099322SDeepak Sikri pr_err("Failed to set sys clk parent\n"); 10642099322SDeepak Sikri return ret; 10742099322SDeepak Sikri } 10842099322SDeepak Sikri 10942099322SDeepak Sikri return 0; 11042099322SDeepak Sikri } 11142099322SDeepak Sikri 11242099322SDeepak Sikri static int spear_cpufreq_target(struct cpufreq_policy *policy, 11342099322SDeepak Sikri unsigned int target_freq, unsigned int relation) 11442099322SDeepak Sikri { 11542099322SDeepak Sikri struct cpufreq_freqs freqs; 11642099322SDeepak Sikri unsigned long newfreq; 11742099322SDeepak Sikri struct clk *srcclk; 11842099322SDeepak Sikri int index, ret, mult = 1; 11942099322SDeepak Sikri 12042099322SDeepak Sikri if (cpufreq_frequency_table_target(policy, spear_cpufreq.freq_tbl, 12142099322SDeepak Sikri target_freq, relation, &index)) 12242099322SDeepak Sikri return -EINVAL; 12342099322SDeepak Sikri 12442099322SDeepak Sikri freqs.cpu = policy->cpu; 12542099322SDeepak Sikri freqs.old = spear_cpufreq_get(0); 12642099322SDeepak Sikri 12742099322SDeepak Sikri newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000; 12842099322SDeepak Sikri if (of_machine_is_compatible("st,spear1340")) { 12942099322SDeepak Sikri /* 13042099322SDeepak Sikri * SPEAr1340 is special in the sense that due to the possibility 13142099322SDeepak Sikri * of multiple clock sources for cpu clk's parent we can have 13242099322SDeepak Sikri * different clock source for different frequency of cpu clk. 13342099322SDeepak Sikri * Hence we need to choose one from amongst these possible clock 13442099322SDeepak Sikri * sources. 13542099322SDeepak Sikri */ 13642099322SDeepak Sikri srcclk = spear1340_cpu_get_possible_parent(newfreq); 13742099322SDeepak Sikri if (IS_ERR(srcclk)) { 13842099322SDeepak Sikri pr_err("Failed to get src clk\n"); 13942099322SDeepak Sikri return PTR_ERR(srcclk); 14042099322SDeepak Sikri } 14142099322SDeepak Sikri 14242099322SDeepak Sikri /* SPEAr1340: src clk is always 2 * intended cpu clk */ 14342099322SDeepak Sikri mult = 2; 14442099322SDeepak Sikri } else { 14542099322SDeepak Sikri /* 14642099322SDeepak Sikri * src clock to be altered is ancestor of cpu clock. Hence we 14742099322SDeepak Sikri * can directly work on cpu clk 14842099322SDeepak Sikri */ 14942099322SDeepak Sikri srcclk = spear_cpufreq.clk; 15042099322SDeepak Sikri } 15142099322SDeepak Sikri 15242099322SDeepak Sikri newfreq = clk_round_rate(srcclk, newfreq * mult); 15342099322SDeepak Sikri if (newfreq < 0) { 15442099322SDeepak Sikri pr_err("clk_round_rate failed for cpu src clock\n"); 15542099322SDeepak Sikri return newfreq; 15642099322SDeepak Sikri } 15742099322SDeepak Sikri 15842099322SDeepak Sikri freqs.new = newfreq / 1000; 15942099322SDeepak Sikri freqs.new /= mult; 1606f35a65fSViresh Kumar 1616f35a65fSViresh Kumar for_each_cpu(freqs.cpu, policy->cpus) 16242099322SDeepak Sikri cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 16342099322SDeepak Sikri 16442099322SDeepak Sikri if (mult == 2) 16542099322SDeepak Sikri ret = spear1340_set_cpu_rate(srcclk, newfreq); 16642099322SDeepak Sikri else 16742099322SDeepak Sikri ret = clk_set_rate(spear_cpufreq.clk, newfreq); 16842099322SDeepak Sikri 16942099322SDeepak Sikri /* Get current rate after clk_set_rate, in case of failure */ 17042099322SDeepak Sikri if (ret) { 17142099322SDeepak Sikri pr_err("CPU Freq: cpu clk_set_rate failed: %d\n", ret); 17242099322SDeepak Sikri freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000; 17342099322SDeepak Sikri } 17442099322SDeepak Sikri 1756f35a65fSViresh Kumar for_each_cpu(freqs.cpu, policy->cpus) 17642099322SDeepak Sikri cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 17742099322SDeepak Sikri return ret; 17842099322SDeepak Sikri } 17942099322SDeepak Sikri 18042099322SDeepak Sikri static int spear_cpufreq_init(struct cpufreq_policy *policy) 18142099322SDeepak Sikri { 18242099322SDeepak Sikri int ret; 18342099322SDeepak Sikri 18442099322SDeepak Sikri ret = cpufreq_frequency_table_cpuinfo(policy, spear_cpufreq.freq_tbl); 18542099322SDeepak Sikri if (ret) { 18642099322SDeepak Sikri pr_err("cpufreq_frequency_table_cpuinfo() failed"); 18742099322SDeepak Sikri return ret; 18842099322SDeepak Sikri } 18942099322SDeepak Sikri 19042099322SDeepak Sikri cpufreq_frequency_table_get_attr(spear_cpufreq.freq_tbl, policy->cpu); 19142099322SDeepak Sikri policy->cpuinfo.transition_latency = spear_cpufreq.transition_latency; 19242099322SDeepak Sikri policy->cur = spear_cpufreq_get(0); 19342099322SDeepak Sikri 1944c738d00SViresh Kumar cpumask_setall(policy->cpus); 19542099322SDeepak Sikri 19642099322SDeepak Sikri return 0; 19742099322SDeepak Sikri } 19842099322SDeepak Sikri 19942099322SDeepak Sikri static int spear_cpufreq_exit(struct cpufreq_policy *policy) 20042099322SDeepak Sikri { 20142099322SDeepak Sikri cpufreq_frequency_table_put_attr(policy->cpu); 20242099322SDeepak Sikri return 0; 20342099322SDeepak Sikri } 20442099322SDeepak Sikri 20542099322SDeepak Sikri static struct freq_attr *spear_cpufreq_attr[] = { 20642099322SDeepak Sikri &cpufreq_freq_attr_scaling_available_freqs, 20742099322SDeepak Sikri NULL, 20842099322SDeepak Sikri }; 20942099322SDeepak Sikri 21042099322SDeepak Sikri static struct cpufreq_driver spear_cpufreq_driver = { 21142099322SDeepak Sikri .name = "cpufreq-spear", 21242099322SDeepak Sikri .flags = CPUFREQ_STICKY, 21342099322SDeepak Sikri .verify = spear_cpufreq_verify, 21442099322SDeepak Sikri .target = spear_cpufreq_target, 21542099322SDeepak Sikri .get = spear_cpufreq_get, 21642099322SDeepak Sikri .init = spear_cpufreq_init, 21742099322SDeepak Sikri .exit = spear_cpufreq_exit, 21842099322SDeepak Sikri .attr = spear_cpufreq_attr, 21942099322SDeepak Sikri }; 22042099322SDeepak Sikri 22142099322SDeepak Sikri static int spear_cpufreq_driver_init(void) 22242099322SDeepak Sikri { 22342099322SDeepak Sikri struct device_node *np; 22442099322SDeepak Sikri const struct property *prop; 22542099322SDeepak Sikri struct cpufreq_frequency_table *freq_tbl; 22642099322SDeepak Sikri const __be32 *val; 22742099322SDeepak Sikri int cnt, i, ret; 22842099322SDeepak Sikri 22942099322SDeepak Sikri np = of_find_node_by_path("/cpus/cpu@0"); 23042099322SDeepak Sikri if (!np) { 23142099322SDeepak Sikri pr_err("No cpu node found"); 23242099322SDeepak Sikri return -ENODEV; 23342099322SDeepak Sikri } 23442099322SDeepak Sikri 23542099322SDeepak Sikri if (of_property_read_u32(np, "clock-latency", 23642099322SDeepak Sikri &spear_cpufreq.transition_latency)) 23742099322SDeepak Sikri spear_cpufreq.transition_latency = CPUFREQ_ETERNAL; 23842099322SDeepak Sikri 23942099322SDeepak Sikri prop = of_find_property(np, "cpufreq_tbl", NULL); 24042099322SDeepak Sikri if (!prop || !prop->value) { 24142099322SDeepak Sikri pr_err("Invalid cpufreq_tbl"); 24242099322SDeepak Sikri ret = -ENODEV; 24342099322SDeepak Sikri goto out_put_node; 24442099322SDeepak Sikri } 24542099322SDeepak Sikri 24642099322SDeepak Sikri cnt = prop->length / sizeof(u32); 24742099322SDeepak Sikri val = prop->value; 24842099322SDeepak Sikri 24942099322SDeepak Sikri freq_tbl = kmalloc(sizeof(*freq_tbl) * (cnt + 1), GFP_KERNEL); 25042099322SDeepak Sikri if (!freq_tbl) { 25142099322SDeepak Sikri ret = -ENOMEM; 25242099322SDeepak Sikri goto out_put_node; 25342099322SDeepak Sikri } 25442099322SDeepak Sikri 25542099322SDeepak Sikri for (i = 0; i < cnt; i++) { 25642099322SDeepak Sikri freq_tbl[i].index = i; 25742099322SDeepak Sikri freq_tbl[i].frequency = be32_to_cpup(val++); 25842099322SDeepak Sikri } 25942099322SDeepak Sikri 26042099322SDeepak Sikri freq_tbl[i].index = i; 26142099322SDeepak Sikri freq_tbl[i].frequency = CPUFREQ_TABLE_END; 26242099322SDeepak Sikri 26342099322SDeepak Sikri spear_cpufreq.freq_tbl = freq_tbl; 26442099322SDeepak Sikri 26542099322SDeepak Sikri of_node_put(np); 26642099322SDeepak Sikri 26742099322SDeepak Sikri spear_cpufreq.clk = clk_get(NULL, "cpu_clk"); 26842099322SDeepak Sikri if (IS_ERR(spear_cpufreq.clk)) { 26942099322SDeepak Sikri pr_err("Unable to get CPU clock\n"); 27042099322SDeepak Sikri ret = PTR_ERR(spear_cpufreq.clk); 27142099322SDeepak Sikri goto out_put_mem; 27242099322SDeepak Sikri } 27342099322SDeepak Sikri 27442099322SDeepak Sikri ret = cpufreq_register_driver(&spear_cpufreq_driver); 27542099322SDeepak Sikri if (!ret) 27642099322SDeepak Sikri return 0; 27742099322SDeepak Sikri 27842099322SDeepak Sikri pr_err("failed register driver: %d\n", ret); 27942099322SDeepak Sikri clk_put(spear_cpufreq.clk); 28042099322SDeepak Sikri 28142099322SDeepak Sikri out_put_mem: 28242099322SDeepak Sikri kfree(freq_tbl); 28342099322SDeepak Sikri return ret; 28442099322SDeepak Sikri 28542099322SDeepak Sikri out_put_node: 28642099322SDeepak Sikri of_node_put(np); 28742099322SDeepak Sikri return ret; 28842099322SDeepak Sikri } 28942099322SDeepak Sikri late_initcall(spear_cpufreq_driver_init); 29042099322SDeepak Sikri 29142099322SDeepak Sikri MODULE_AUTHOR("Deepak Sikri <deepak.sikri@st.com>"); 29242099322SDeepak Sikri MODULE_DESCRIPTION("SPEAr CPUFreq driver"); 29342099322SDeepak Sikri MODULE_LICENSE("GPL"); 294