diff options
Diffstat (limited to 'drivers/cpufreq')
40 files changed, 429 insertions, 588 deletions
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 3a88e33b0cfe..7f56fe5183f2 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -44,10 +44,11 @@ config ARM_DT_BL_CPUFREQ config ARM_SCPI_CPUFREQ tristate "SCPI based CPUfreq driver" - depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI + depends on ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI + depends on !CPU_THERMAL || THERMAL help - This adds the CPUfreq driver support for ARM big.LITTLE platforms - using SCPI protocol for CPU power management. + This adds the CPUfreq driver support for ARM platforms using SCPI + protocol for CPU power management. This driver uses SCPI Message Protocol driver to interact with the firmware providing the CPU DVFS functionality. @@ -238,6 +239,18 @@ config ARM_SA1100_CPUFREQ config ARM_SA1110_CPUFREQ bool +config ARM_SCMI_CPUFREQ + tristate "SCMI based CPUfreq driver" + depends on ARM_SCMI_PROTOCOL || COMPILE_TEST + depends on !CPU_THERMAL || THERMAL + select PM_OPP + help + This adds the CPUfreq driver support for ARM platforms using SCMI + protocol for CPU power management. + + This driver uses SCMI Message Protocol driver to interact with the + firmware providing the CPU DVFS functionality. + config ARM_SPEAR_CPUFREQ bool "SPEAr CPUFreq support" depends on PLAT_SPEAR diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index c60c1e141d9d..8d24ade3bd02 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o +obj-$(CONFIG_ARM_SCMI_CPUFREQ) += scmi-cpufreq.o obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o @@ -100,10 +101,7 @@ obj-$(CONFIG_POWERNV_CPUFREQ) += powernv-cpufreq.o ################################################################################## # Other platform drivers -obj-$(CONFIG_BFIN_CPU_FREQ) += blackfin-cpufreq.o obj-$(CONFIG_BMIPS_CPUFREQ) += bmips-cpufreq.o -obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o -obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o obj-$(CONFIG_LOONGSON1_CPUFREQ) += loongson1-cpufreq.o diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 3a2ca0f79daf..9449657d72f0 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -629,7 +629,7 @@ static int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c) if (c->x86_vendor == X86_VENDOR_INTEL) { if ((c->x86 == 15) && (c->x86_model == 6) && - (c->x86_mask == 8)) { + (c->x86_stepping == 8)) { pr_info("Intel(R) Xeon(R) 7100 Errata AL30, processors may lock up on frequency changes: disabling acpi-cpufreq\n"); return -ENODEV; } @@ -794,15 +794,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) valid_states++; } freq_table[valid_states].frequency = CPUFREQ_TABLE_END; + policy->freq_table = freq_table; perf->state = 0; - result = cpufreq_table_validate_and_show(policy, freq_table); - if (result) - goto err_freqfree; - - if (perf->states[0].core_frequency * 1000 != policy->cpuinfo.max_freq) - pr_warn(FW_WARN "P-state 0 is not max freq\n"); - switch (perf->control_register.space_id) { case ACPI_ADR_SPACE_SYSTEM_IO: /* @@ -842,8 +836,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) return result; -err_freqfree: - kfree(freq_table); err_unreg: acpi_processor_unregister_performance(cpu); err_free_mask: @@ -871,6 +863,15 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) return 0; } +static void acpi_cpufreq_cpu_ready(struct cpufreq_policy *policy) +{ + struct acpi_processor_performance *perf = per_cpu_ptr(acpi_perf_data, + policy->cpu); + + if (perf->states[0].core_frequency * 1000 != policy->cpuinfo.max_freq) + pr_warn(FW_WARN "P-state 0 is not max freq\n"); +} + static int acpi_cpufreq_resume(struct cpufreq_policy *policy) { struct acpi_cpufreq_data *data = policy->driver_data; @@ -898,6 +899,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = { .bios_limit = acpi_processor_get_bios_limit, .init = acpi_cpufreq_cpu_init, .exit = acpi_cpufreq_cpu_exit, + .ready = acpi_cpufreq_cpu_ready, .resume = acpi_cpufreq_resume, .name = "acpi-cpufreq", .attr = acpi_cpufreq_attr, diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index c56b57dcfda5..1d7ef5fc1977 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -483,14 +483,7 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) if (ret) return ret; - ret = cpufreq_table_validate_and_show(policy, freq_table[cur_cluster]); - if (ret) { - dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n", - policy->cpu, cur_cluster); - put_cluster_clk_and_freq_table(cpu_dev, policy->cpus); - return ret; - } - + policy->freq_table = freq_table[cur_cluster]; policy->cpuinfo.transition_latency = arm_bL_ops->get_transition_latency(cpu_dev); diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c deleted file mode 100644 index 12e97d8a9db0..000000000000 --- a/drivers/cpufreq/blackfin-cpufreq.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Blackfin core clock scaling - * - * Copyright 2008-2011 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/clk.h> -#include <linux/cpufreq.h> -#include <linux/fs.h> -#include <linux/delay.h> -#include <asm/blackfin.h> -#include <asm/time.h> -#include <asm/dpmc.h> - - -/* this is the table of CCLK frequencies, in Hz */ -/* .driver_data is the entry in the auxiliary dpm_state_table[] */ -static struct cpufreq_frequency_table bfin_freq_table[] = { - { - .frequency = CPUFREQ_TABLE_END, - .driver_data = 0, - }, - { - .frequency = CPUFREQ_TABLE_END, - .driver_data = 1, - }, - { - .frequency = CPUFREQ_TABLE_END, - .driver_data = 2, - }, - { - .frequency = CPUFREQ_TABLE_END, - .driver_data = 0, - }, -}; - -static struct bfin_dpm_state { - unsigned int csel; /* system clock divider */ - unsigned int tscale; /* change the divider on the core timer interrupt */ -} dpm_state_table[3]; - -#if defined(CONFIG_CYCLES_CLOCKSOURCE) -/* - * normalized to maximum frequency offset for CYCLES, - * used in time-ts cycles clock source, but could be used - * somewhere also. - */ -unsigned long long __bfin_cycles_off; -unsigned int __bfin_cycles_mod; -#endif - -/**************************************************************************/ -static void __init bfin_init_tables(unsigned long cclk, unsigned long sclk) -{ - - unsigned long csel, min_cclk; - int index; - - /* Anomaly 273 seems to still exist on non-BF54x w/dcache turned on */ -#if ANOMALY_05000273 || ANOMALY_05000274 || \ - (!(defined(CONFIG_BF54x) || defined(CONFIG_BF60x)) \ - && defined(CONFIG_BFIN_EXTMEM_DCACHEABLE)) - min_cclk = sclk * 2; -#else - min_cclk = sclk; -#endif - -#ifndef CONFIG_BF60x - csel = ((bfin_read_PLL_DIV() & CSEL) >> 4); -#else - csel = bfin_read32(CGU0_DIV) & 0x1F; -#endif - - for (index = 0; (cclk >> index) >= min_cclk && csel <= 3 && index < 3; index++, csel++) { - bfin_freq_table[index].frequency = cclk >> index; -#ifndef CONFIG_BF60x - dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */ -#else - dpm_state_table[index].csel = csel; -#endif - dpm_state_table[index].tscale = (TIME_SCALE >> index) - 1; - - pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d\n", - bfin_freq_table[index].frequency, - dpm_state_table[index].csel, - dpm_state_table[index].tscale); - } - return; -} - -static void bfin_adjust_core_timer(void *info) -{ - unsigned int tscale; - unsigned int index = *(unsigned int *)info; - - /* we have to adjust the core timer, because it is using cclk */ - tscale = dpm_state_table[index].tscale; - bfin_write_TSCALE(tscale); - return; -} - -static unsigned int bfin_getfreq_khz(unsigned int cpu) -{ - /* Both CoreA/B have the same core clock */ - return get_cclk() / 1000; -} - -#ifdef CONFIG_BF60x -static int cpu_set_cclk(int cpu, unsigned long new) -{ - struct clk *clk; - int ret; - - clk = clk_get(NULL, "CCLK"); - if (IS_ERR(clk)) - return -ENODEV; - - ret = clk_set_rate(clk, new); - clk_put(clk); - return ret; -} -#endif - -static int bfin_target(struct cpufreq_policy *policy, unsigned int index) -{ -#ifndef CONFIG_BF60x - unsigned int plldiv; -#endif - static unsigned long lpj_ref; - static unsigned int lpj_ref_freq; - unsigned int old_freq, new_freq; - int ret = 0; - -#if defined(CONFIG_CYCLES_CLOCKSOURCE) - cycles_t cycles; -#endif - - old_freq = bfin_getfreq_khz(0); - new_freq = bfin_freq_table[index].frequency; - -#ifndef CONFIG_BF60x - plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel; - bfin_write_PLL_DIV(plldiv); -#else - ret = cpu_set_cclk(policy->cpu, new_freq * 1000); - if (ret != 0) { - WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret); - return ret; - } -#endif - on_each_cpu(bfin_adjust_core_timer, &index, 1); -#if defined(CONFIG_CYCLES_CLOCKSOURCE) - cycles = get_cycles(); - SSYNC(); - cycles += 10; /* ~10 cycles we lose after get_cycles() */ - __bfin_cycles_off += (cycles << __bfin_cycles_mod) - (cycles << index); - __bfin_cycles_mod = index; -#endif - if (!lpj_ref_freq) { - lpj_ref = loops_per_jiffy; - lpj_ref_freq = old_freq; - } - if (new_freq != old_freq) { - loops_per_jiffy = cpufreq_scale(lpj_ref, - lpj_ref_freq, new_freq); - } - - return ret; -} - -static int __bfin_cpu_init(struct cpufreq_policy *policy) -{ - - unsigned long cclk, sclk; - - cclk = get_cclk() / 1000; - sclk = get_sclk() / 1000; - - if (policy->cpu == CPUFREQ_CPU) - bfin_init_tables(cclk, sclk); - - policy->cpuinfo.transition_latency = 50000; /* 50us assumed */ - - return cpufreq_table_validate_and_show(policy, bfin_freq_table); -} - -static struct cpufreq_driver bfin_driver = { - .verify = cpufreq_generic_frequency_table_verify, - .target_index = bfin_target, - .get = bfin_getfreq_khz, - .init = __bfin_cpu_init, - .name = "bfin cpufreq", - .attr = cpufreq_generic_attr, -}; - -static int __init bfin_cpu_init(void) -{ - return cpufreq_register_driver(&bfin_driver); -} - -static void __exit bfin_cpu_exit(void) -{ - cpufreq_unregister_driver(&bfin_driver); -} - -MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); -MODULE_DESCRIPTION("cpufreq driver for Blackfin"); -MODULE_LICENSE("GPL"); - -module_init(bfin_cpu_init); -module_exit(bfin_cpu_exit); diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c index 7281a2c19c36..6cdac1aaf23c 100644 --- a/drivers/cpufreq/brcmstb-avs-cpufreq.c +++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c @@ -902,11 +902,7 @@ static int brcm_avs_cpufreq_init(struct cpufreq_policy *policy) return ret; } - ret = cpufreq_table_validate_and_show(policy, freq_table); - if (ret) { - dev_err(dev, "invalid frequency table: %d\n", ret); - return ret; - } + policy->freq_table = freq_table; /* All cores share the same clock and thus the same policy. */ cpumask_setall(policy->cpus); diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index a1c3025f9df7..8300a9fcb80c 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -20,6 +20,7 @@ #include <linux/cpu.h> #include <linux/cpufreq.h> #include <linux/dmi.h> +#include <linux/time.h> #include <linux/vmalloc.h> #include <asm/unaligned.h> @@ -162,6 +163,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.max_freq = cppc_dmi_max_khz; policy->cpuinfo.transition_latency = cppc_get_transition_latency(cpu_num); + policy->transition_delay_us = cppc_get_transition_latency(cpu_num) / + NSEC_PER_USEC; policy->shared_type = cpu->shared_type; if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) @@ -230,8 +233,13 @@ static int __init cppc_cpufreq_init(void) return ret; out: - for_each_possible_cpu(i) - kfree(all_cpu_data[i]); + for_each_possible_cpu(i) { + cpu = all_cpu_data[i]; + if (!cpu) + break; + free_cpumask_var(cpu->shared_cpu_map); + kfree(cpu); + } kfree(all_cpu_data); return -ENODEV; diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index de3d104c25d7..190ea0dccb79 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -258,16 +258,10 @@ static int cpufreq_init(struct cpufreq_policy *policy) priv->cpu_dev = cpu_dev; policy->driver_data = priv; policy->clk = cpu_clk; + policy->freq_table = freq_table; policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; - ret = cpufreq_table_validate_and_show(policy, freq_table); - if (ret) { - dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, - ret); - goto out_free_cpufreq_table; - } - /* Support turbo/boost mode */ if (policy_has_boost_freq(policy)) { /* This gets disabled by core on driver unregister */ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index de33ebf008ad..075d18f6ba7a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -178,14 +178,7 @@ int cpufreq_generic_init(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table, unsigned int transition_latency) { - int ret; - - ret = cpufreq_table_validate_and_show(policy, table); - if (ret) { - pr_err("%s: invalid frequency table: %d\n", __func__, ret); - return ret; - } - + policy->freq_table = table; policy->cpuinfo.transition_latency = transition_latency; /* @@ -1219,6 +1212,10 @@ static int cpufreq_online(unsigned int cpu) goto out_free_policy; } + ret = cpufreq_table_validate_and_sort(policy); + if (ret) + goto out_exit_policy; + down_write(&policy->rwsem); if (new_policy) { @@ -1249,7 +1246,7 @@ static int cpufreq_online(unsigned int cpu) policy->cur = cpufreq_driver->get(policy->cpu); if (!policy->cur) { pr_err("%s: ->get() failed\n", __func__); - goto out_exit_policy; + goto out_destroy_policy; } } @@ -1296,7 +1293,7 @@ static int cpufreq_online(unsigned int cpu) if (new_policy) { ret = cpufreq_add_dev_interface(policy); if (ret) - goto out_exit_policy; + goto out_destroy_policy; cpufreq_stats_create_table(policy); @@ -1311,7 +1308,7 @@ static int cpufreq_online(unsigned int cpu) __func__, cpu, ret); /* cpufreq_policy_free() will notify based on this */ new_policy = false; - goto out_exit_policy; + goto out_destroy_policy; } up_write(&policy->rwsem); @@ -1326,15 +1323,16 @@ static int cpufreq_online(unsigned int cpu) return 0; -out_exit_policy: +out_destroy_policy: + for_each_cpu(j, policy->real_cpus) + remove_cpu_dev_symlink(policy, get_cpu_device(j)); + up_write(&policy->rwsem); +out_exit_policy: if (cpufreq_driver->exit) cpufreq_driver->exit(policy); - for_each_cpu(j, policy->real_cpus) - remove_cpu_dev_symlink(policy, get_cpu_device(j)); - out_free_policy: cpufreq_policy_free(policy); return ret; diff --git a/drivers/cpufreq/cris-artpec3-cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c deleted file mode 100644 index 455b4fb78cba..000000000000 --- a/drivers/cpufreq/cris-artpec3-cpufreq.c +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/init.h> -#include <linux/module.h> -#include <linux/cpufreq.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/clkgen_defs.h> -#include <hwregs/ddr2_defs.h> - -static int -cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val, - void *data); - -static struct notifier_block cris_sdram_freq_notifier_block = { - .notifier_call = cris_sdram_freq_notifier -}; - -static struct cpufreq_frequency_table cris_freq_table[] = { - {0, 0x01, 6000}, - {0, 0x02, 200000}, - {0, 0, CPUFREQ_TABLE_END}, -}; - -static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) -{ - reg_clkgen_rw_clk_ctrl clk_ctrl; - clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); - return clk_ctrl.pll ? 200000 : 6000; -} - -static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) -{ - reg_clkgen_rw_clk_ctrl clk_ctrl; - clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); - - local_irq_disable(); - - /* Even though we may be SMP they will share the same clock - * so all settings are made on CPU0. */ - if (cris_freq_table[state].frequency == 200000) - clk_ctrl.pll = 1; - else - clk_ctrl.pll = 0; - REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl); - - local_irq_enable(); - - return 0; -} - -static int cris_freq_cpu_init(struct cpufreq_policy *policy) -{ - return cpufreq_generic_init(policy, cris_freq_table, 1000000); -} - -static struct cpufreq_driver cris_freq_driver = { - .get = cris_freq_get_cpu_frequency, - .verify = cpufreq_generic_frequency_table_verify, - .target_index = cris_freq_target, - .init = cris_freq_cpu_init, - .name = "cris_freq", - .attr = cpufreq_generic_attr, -}; - -static int __init cris_freq_init(void) -{ - int ret; - ret = cpufreq_register_driver(&cris_freq_driver); - cpufreq_register_notifier(&cris_sdram_freq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - return ret; -} - -static int -cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val, - void *data) -{ - int i; - struct cpufreq_freqs *freqs = data; - if (val == CPUFREQ_PRECHANGE) { - reg_ddr2_rw_cfg cfg = - REG_RD(ddr2, regi_ddr2_ctrl, rw_cfg); - cfg.ref_interval = (freqs->new == 200000 ? 1560 : 46); - - if (freqs->new == 200000) - for (i = 0; i < 50000; i++); - REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing); - } - return 0; -} - - -module_init(cris_freq_init); diff --git a/drivers/cpufreq/cris-etraxfs-cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c deleted file mode 100644 index 4c4b5dd685e3..000000000000 --- a/drivers/cpufreq/cris-etraxfs-cpufreq.c +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/init.h> -#include <linux/module.h> -#include <linux/cpufreq.h> -#include <hwregs/reg_map.h> -#include <arch/hwregs/reg_rdwr.h> -#include <arch/hwregs/config_defs.h> -#include <arch/hwregs/bif_core_defs.h> - -static int -cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val, - void *data); - -static struct notifier_block cris_sdram_freq_notifier_block = { - .notifier_call = cris_sdram_freq_notifier -}; - -static struct cpufreq_frequency_table cris_freq_table[] = { - {0, 0x01, 6000}, - {0, 0x02, 200000}, - {0, 0, CPUFREQ_TABLE_END}, -}; - -static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) -{ - reg_config_rw_clk_ctrl clk_ctrl; - clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); - return clk_ctrl.pll ? 200000 : 6000; -} - -static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) -{ - reg_config_rw_clk_ctrl clk_ctrl; - clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); - - local_irq_disable(); - - /* Even though we may be SMP they will share the same clock - * so all settings are made on CPU0. */ - if (cris_freq_table[state].frequency == 200000) - clk_ctrl.pll = 1; - else - clk_ctrl.pll = 0; - REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl); - - local_irq_enable(); - - return 0; -} - -static int cris_freq_cpu_init(struct cpufreq_policy *policy) -{ - return cpufreq_generic_init(policy, cris_freq_table, 1000000); -} - -static struct cpufreq_driver cris_freq_driver = { - .get = cris_freq_get_cpu_frequency, - .verify = cpufreq_generic_frequency_table_verify, - .target_index = cris_freq_target, - .init = cris_freq_cpu_init, - .name = "cris_freq", - .attr = cpufreq_generic_attr, -}; - -static int __init cris_freq_init(void) -{ - int ret; - ret = cpufreq_register_driver(&cris_freq_driver); - cpufreq_register_notifier(&cris_sdram_freq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - return ret; -} - -static int -cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val, - void *data) -{ - int i; - struct cpufreq_freqs *freqs = data; - if (val == CPUFREQ_PRECHANGE) { - reg_bif_core_rw_sdram_timing timing = - REG_RD(bif_core, regi_bif_core, rw_sdram_timing); - timing.cpd = (freqs->new == 200000 ? 0 : 1); - - if (freqs->new == 200000) - for (i = 0; i < 50000; i++) ; - REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing); - } - return 0; -} - -module_init(cris_freq_init); diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index cdf097b29862..60bea302abbe 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c @@ -184,7 +184,6 @@ static int eps_cpu_init(struct cpufreq_policy *policy) struct cpuinfo_x86 *c = &cpu_data(0); struct cpufreq_frequency_table *f_table; int k, step, voltage; - int ret; int states; #if IS_ENABLED(CONFIG_ACPI_PROCESSOR) unsigned int limit; @@ -359,12 +358,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy) } policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */ - - ret = cpufreq_table_validate_and_show(policy, ¢aur->freq_table[0]); - if (ret) { - kfree(centaur); - return ret; - } + policy->freq_table = ¢aur->freq_table[0]; return 0; } diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c index 45e2ca62515e..03419f064752 100644 --- a/drivers/cpufreq/elanfreq.c +++ b/drivers/cpufreq/elanfreq.c @@ -165,7 +165,8 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy) if (pos->frequency > max_freq) pos->frequency = CPUFREQ_ENTRY_INVALID; - return cpufreq_table_validate_and_show(policy, elanfreq_table); + policy->freq_table = elanfreq_table; + return 0; } diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 6d007f824ca7..10e119ae66dd 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -362,10 +362,24 @@ int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, return ret; policy->freq_table = table; - return set_freq_table_sorted(policy); + return 0; } EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show); +int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy) +{ + int ret; + + if (!policy->freq_table) + return 0; + + ret = cpufreq_frequency_table_cpuinfo(policy, policy->freq_table); + if (ret) + return ret; + + return set_freq_table_sorted(policy); +} + MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); MODULE_DESCRIPTION("CPUfreq frequency table helpers"); MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index a757c0a1e7b5..7974a2fdb760 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -270,10 +270,7 @@ acpi_cpufreq_cpu_init ( } } - result = cpufreq_table_validate_and_show(policy, freq_table); - if (result) { - goto err_freqfree; - } + policy->freq_table = freq_table; /* notify BIOS that we exist */ acpi_processor_notify_smm(THIS_MODULE); @@ -296,8 +293,6 @@ acpi_cpufreq_cpu_init ( return (result); - err_freqfree: - kfree(freq_table); err_unreg: acpi_processor_unregister_performance(cpu); err_free: diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index ff67859948b3..83cf631fc9bc 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -52,6 +52,7 @@ static struct clk_bulk_data clks[] = { static struct device *cpu_dev; static bool free_opp; static struct cpufreq_frequency_table *freq_table; +static unsigned int max_freq; static unsigned int transition_latency; static u32 *imx6_soc_volt; @@ -196,7 +197,7 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy) policy->clk = clks[ARM].clk; ret = cpufreq_generic_init(policy, freq_table, transition_latency); - policy->suspend_freq = policy->max; + policy->suspend_freq = max_freq; return ret; } @@ -437,12 +438,12 @@ soc_opp_out: * freq_table initialised from OPP is therefore sorted in the * same order. */ + max_freq = freq_table[--num].frequency; opp = dev_pm_opp_find_freq_exact(cpu_dev, freq_table[0].frequency * 1000, true); min_volt = dev_pm_opp_get_voltage(opp); dev_pm_opp_put(opp); - opp = dev_pm_opp_find_freq_exact(cpu_dev, - freq_table[--num].frequency * 1000, true); + opp = dev_pm_opp_find_freq_exact(cpu_dev, max_freq * 1000, true); max_volt = dev_pm_opp_get_voltage(opp); dev_pm_opp_put(opp); diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 942632a27b50..61a4c5b08219 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -775,7 +775,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) break; case 7: - switch (c->x86_mask) { + switch (c->x86_stepping) { case 0: longhaul_version = TYPE_LONGHAUL_V1; cpu_model = CPU_SAMUEL2; @@ -787,7 +787,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) break; case 1 ... 15: longhaul_version = TYPE_LONGHAUL_V2; - if (c->x86_mask < 8) { + if (c->x86_stepping < 8) { cpu_model = CPU_SAMUEL2; cpuname = "C3 'Samuel 2' [C5B]"; } else { @@ -814,7 +814,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) numscales = 32; memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults)); memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr)); - switch (c->x86_mask) { + switch (c->x86_stepping) { case 0 ... 1: cpu_model = CPU_NEHEMIAH; cpuname = "C3 'Nehemiah A' [C5XLOE]"; @@ -895,8 +895,9 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) longhaul_setup_voltagescaling(); policy->transition_delay_us = 200000; /* usec */ + policy->freq_table = longhaul_table; - return cpufreq_table_validate_and_show(policy, longhaul_table); + return 0; } static struct cpufreq_driver longhaul_driver = { diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index 8c04dddd3c28..eb8920d39818 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -460,21 +460,12 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy) return ret; } - ret = cpufreq_table_validate_and_show(policy, freq_table); - if (ret) { - pr_err("%s: invalid frequency table: %d\n", __func__, ret); - goto out_free_cpufreq_table; - } - cpumask_copy(policy->cpus, &info->cpus); + policy->freq_table = freq_table; policy->driver_data = info; policy->clk = info->cpu_clk; return 0; - -out_free_cpufreq_table: - dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table); - return ret; } static int mtk_cpufreq_exit(struct cpufreq_policy *policy) @@ -578,7 +569,7 @@ static int __init mtk_cpufreq_driver_init(void) match = of_match_node(mtk_cpufreq_machines, np); of_node_put(np); if (!match) { - pr_warn("Machine is not compatible with mtk-cpufreq\n"); + pr_debug("Machine is not compatible with mtk-cpufreq\n"); return -ENODEV; } diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c index fd77812313f3..911206243050 100644 --- a/drivers/cpufreq/p4-clockmod.c +++ b/drivers/cpufreq/p4-clockmod.c @@ -168,7 +168,7 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) #endif /* Errata workaround */ - cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask; + cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_stepping; switch (cpuid) { case 0x0f07: case 0x0f0a: @@ -202,8 +202,9 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) /* the transition latency is set to be 1 higher than the maximum * transition latency of the ondemand governor */ policy->cpuinfo.transition_latency = 10000001; + policy->freq_table = &p4clockmod_table[0]; - return cpufreq_table_validate_and_show(policy, &p4clockmod_table[0]); + return 0; } diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c index dedd2568e852..8a8ea68611a8 100644 --- a/drivers/cpufreq/powernow-k6.c +++ b/drivers/cpufreq/powernow-k6.c @@ -214,8 +214,9 @@ have_busfreq: /* cpuinfo and default policy values */ policy->cpuinfo.transition_latency = 500000; + policy->freq_table = clock_ratio; - return cpufreq_table_validate_and_show(policy, clock_ratio); + return 0; } diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index 80ac313e6c59..d6cb052b0a75 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -131,7 +131,7 @@ static int check_powernow(void) return 0; } - if ((c->x86_model == 6) && (c->x86_mask == 0)) { + if ((c->x86_model == 6) && (c->x86_stepping == 0)) { pr_info("K7 660[A0] core detected, enabling errata workarounds\n"); have_a0 = 1; } @@ -639,8 +639,9 @@ static int powernow_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency); + policy->freq_table = powernow_table; - return cpufreq_table_validate_and_show(policy, powernow_table); + return 0; } static int powernow_cpu_exit(struct cpufreq_policy *policy) diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index b01e31db5f83..fb77b39a4ce3 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -122,14 +122,12 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data) static void count_off_irt(struct powernow_k8_data *data) { udelay((1 << data->irt) * 10); - return; } /* the voltage stabilization time */ static void count_off_vst(struct powernow_k8_data *data) { udelay(data->vstable * VST_UNITS_20US); - return; } /* need to init the control msr to a safe value (for each cpu) */ @@ -591,10 +589,8 @@ static int fill_powernow_table(struct powernow_k8_data *data, powernow_table = kzalloc((sizeof(*powernow_table) * (data->numps + 1)), GFP_KERNEL); - if (!powernow_table) { - pr_err("powernow_table memory alloc failure\n"); + if (!powernow_table) return -ENOMEM; - } for (j = 0; j < data->numps; j++) { int freq; @@ -760,10 +756,8 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) /* fill in data->powernow_table */ powernow_table = kzalloc((sizeof(*powernow_table) * (data->acpi_data.state_count + 1)), GFP_KERNEL); - if (!powernow_table) { - pr_debug("powernow_table memory alloc failure\n"); + if (!powernow_table) goto err_out; - } /* fill in data */ data->numps = data->acpi_data.state_count; @@ -1042,10 +1036,8 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) return -ENODEV; data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - pr_err("unable to alloc powernow_k8_data\n"); + if (!data) return -ENOMEM; - } data->cpu = pol->cpu; @@ -1084,15 +1076,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) cpumask_copy(pol->cpus, topology_core_cpumask(pol->cpu)); data->available_cores = pol->cpus; - - /* min/max the cpu is capable of */ - if (cpufreq_table_validate_and_show(pol, data->powernow_table)) { - pr_err(FW_BUG "invalid powernow_table\n"); - powernow_k8_cpu_exit_acpi(data); - kfree(data->powernow_table); - kfree(data); - return -EINVAL; - } + pol->freq_table = data->powernow_table; pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 29cdec198657..0591874856d3 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -812,7 +812,7 @@ gpstates_done: static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy) { - int base, i, ret; + int base, i; struct kernfs_node *kn; struct global_pstate_info *gpstates; @@ -848,15 +848,10 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy) gpstates->timer.expires = jiffies + msecs_to_jiffies(GPSTATE_TIMER_INTERVAL); spin_lock_init(&gpstates->gpstate_lock); - ret = cpufreq_table_validate_and_show(policy, powernv_freqs); - - if (ret < 0) { - kfree(policy->driver_data); - return ret; - } + policy->freq_table = powernv_freqs; policy->fast_switch_possible = true; - return ret; + return 0; } static int powernv_cpufreq_cpu_exit(struct cpufreq_policy *policy) diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c index 5a4c5a639f61..41a0f0be3f9f 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq.c @@ -121,9 +121,8 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); #endif - /* this ensures that policy->cpuinfo_min - * and policy->cpuinfo_max are set correctly */ - return cpufreq_table_validate_and_show(policy, cbe_freqs); + policy->freq_table = cbe_freqs; + return 0; } static int cbe_cpufreq_target(struct cpufreq_policy *policy, diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c index 06b024a3e474..46254e583982 100644 --- a/drivers/cpufreq/pxa2xx-cpufreq.c +++ b/drivers/cpufreq/pxa2xx-cpufreq.c @@ -292,10 +292,10 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy) pr_info("using %s frequency table\n", pxa255_turbo_table ? "turbo" : "run"); - cpufreq_table_validate_and_show(policy, pxa255_freq_table); + policy->freq_table = pxa255_freq_table; } else if (cpu_is_pxa27x()) { - cpufreq_table_validate_and_show(policy, pxa27x_freq_table); + policy->freq_table = pxa27x_freq_table; } pr_info("frequency change support initialized\n"); diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c index a01275900389..7acc7fa4536d 100644 --- a/drivers/cpufreq/pxa3xx-cpufreq.c +++ b/drivers/cpufreq/pxa3xx-cpufreq.c @@ -108,7 +108,9 @@ static int setup_freqs_table(struct cpufreq_policy *policy, pxa3xx_freqs_num = num; pxa3xx_freqs_table = table; - return cpufreq_table_validate_and_show(policy, table); + policy->freq_table = table; + + return 0; } static void __update_core_freq(struct pxa3xx_freq_info *info) diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c index 0562761a3dec..3d773f64b4df 100644 --- a/drivers/cpufreq/qoriq-cpufreq.c +++ b/drivers/cpufreq/qoriq-cpufreq.c @@ -165,7 +165,7 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table, static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) { struct device_node *np; - int i, count, ret; + int i, count; u32 freq; struct clk *clk; const struct clk_hw *hwclk; @@ -192,16 +192,12 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) count = clk_hw_get_num_parents(hwclk); data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL); - if (!data->pclk) { - pr_err("%s: no memory\n", __func__); + if (!data->pclk) goto err_nomem2; - } table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL); - if (!table) { - pr_err("%s: no memory\n", __func__); + if (!table) goto err_pclk; - } for (i = 0; i < count; i++) { clk = clk_hw_get_parent_by_index(hwclk, i)->clk; @@ -213,14 +209,7 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) freq_table_redup(table, count); freq_table_sort(table, count); table[i].frequency = CPUFREQ_TABLE_END; - - /* set the min and max frequency properly */ - ret = cpufreq_table_validate_and_show(policy, table); - if (ret) { - pr_err("invalid frequency table: %d\n", ret); - goto err_nomem1; - } - + policy->freq_table = table; data->table = table; /* update ->cpus if we have cluster, no harm if not */ @@ -236,8 +225,6 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) return 0; -err_nomem1: - kfree(table); err_pclk: kfree(data->pclk); err_nomem2: diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 7b596fa38ad2..909bd6e27639 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -351,7 +351,10 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) static int s3c_cpufreq_init(struct cpufreq_policy *policy) { policy->clk = clk_arm; - return cpufreq_generic_init(policy, ftab, cpu_cur.info->latency); + policy->cpuinfo.transition_latency = cpu_cur.info->latency; + policy->freq_table = ftab; + + return 0; } static int __init s3c_cpufreq_initclks(void) @@ -473,10 +476,8 @@ int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board) * initdata. */ ours = kzalloc(sizeof(*ours), GFP_KERNEL); - if (ours == NULL) { - pr_err("%s: no memory\n", __func__); + if (!ours) return -ENOMEM; - } *ours = *board; cpu_cur.board = ours; @@ -562,10 +563,8 @@ static int s3c_cpufreq_build_freq(void) size++; ftab = kzalloc(sizeof(*ftab) * size, GFP_KERNEL); - if (!ftab) { - pr_err("%s: no memory for tables\n", __func__); + if (!ftab) return -ENOMEM; - } ftab_size = size; diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c index 4225501a4b78..abaa75e86148 100644 --- a/drivers/cpufreq/sc520_freq.c +++ b/drivers/cpufreq/sc520_freq.c @@ -83,8 +83,9 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy) /* cpuinfo and default policy values */ policy->cpuinfo.transition_latency = 1000000; /* 1ms */ + policy->freq_table = sc520_freq_table; - return cpufreq_table_validate_and_show(policy, sc520_freq_table); + return 0; } diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c new file mode 100644 index 000000000000..959a1dbe3835 --- /dev/null +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System Control and Power Interface (SCMI) based CPUFreq Interface driver + * + * Copyright (C) 2018 ARM Ltd. + * Sudeep Holla <sudeep.holla@arm.com> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/cpu.h> +#include <linux/cpufreq.h> +#include <linux/cpumask.h> +#include <linux/cpu_cooling.h> +#include <linux/export.h> +#include <linux/module.h> +#include <linux/pm_opp.h> +#include <linux/slab.h> +#include <linux/scmi_protocol.h> +#include <linux/types.h> + +struct scmi_data { + int domain_id; + struct device *cpu_dev; + struct thermal_cooling_device *cdev; +}; + +static const struct scmi_handle *handle; + +static unsigned int scmi_cpufreq_get_rate(unsigned int cpu) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); + struct scmi_perf_ops *perf_ops = handle->perf_ops; + struct scmi_data *priv = policy->driver_data; + unsigned long rate; + int ret; + + ret = perf_ops->freq_get(handle, priv->domain_id, &rate, false); + if (ret) + return 0; + return rate / 1000; +} + +/* + * perf_ops->freq_set is not a synchronous, the actual OPP change will + * happen asynchronously and can get notified if the events are + * subscribed for by the SCMI firmware + */ +static int +scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) +{ + int ret; + struct scmi_data *priv = policy->driver_data; + struct scmi_perf_ops *perf_ops = handle->perf_ops; + u64 freq = policy->freq_table[index].frequency * 1000; + + ret = perf_ops->freq_set(handle, priv->domain_id, freq, false); + if (!ret) + arch_set_freq_scale(policy->related_cpus, freq, + policy->cpuinfo.max_freq); + return ret; +} + +static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + struct scmi_data *priv = policy->driver_data; + struct scmi_perf_ops *perf_ops = handle->perf_ops; + + if (!perf_ops->freq_set(handle, priv->domain_id, + target_freq * 1000, true)) { + arch_set_freq_scale(policy->related_cpus, target_freq, + policy->cpuinfo.max_freq); + return target_freq; + } + + return 0; +} + +static int +scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) +{ + int cpu, domain, tdomain; + struct device *tcpu_dev; + + domain = handle->perf_ops->device_domain_id(cpu_dev); + if (domain < 0) + return domain; + + for_each_possible_cpu(cpu) { + if (cpu == cpu_dev->id) + continue; + + tcpu_dev = get_cpu_device(cpu); + if (!tcpu_dev) + continue; + + tdomain = handle->perf_ops->device_domain_id(tcpu_dev); + if (tdomain == domain) + cpumask_set_cpu(cpu, cpumask); + } + + return 0; +} + +static int scmi_cpufreq_init(struct cpufreq_policy *policy) +{ + int ret; + unsigned int latency; + struct device *cpu_dev; + struct scmi_data *priv; + struct cpufreq_frequency_table *freq_table; + + cpu_dev = get_cpu_device(policy->cpu); + if (!cpu_dev) { + pr_err("failed to get cpu%d device\n", policy->cpu); + return -ENODEV; + } + + ret = handle->perf_ops->add_opps_to_device(handle, cpu_dev); + if (ret) { + dev_warn(cpu_dev, "failed to add opps to the device\n"); + return ret; + } + + ret = scmi_get_sharing_cpus(cpu_dev, policy->cpus); + if (ret) { + dev_warn(cpu_dev, "failed to get sharing cpumask\n"); + return ret; + } + + ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); + if (ret) { + dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", + __func__, ret); + return ret; + } + + ret = dev_pm_opp_get_opp_count(cpu_dev); + if (ret <= 0) { + dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); + ret = -EPROBE_DEFER; + goto out_free_opp; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out_free_opp; + } + + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); + if (ret) { + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); + goto out_free_priv; + } + + priv->cpu_dev = cpu_dev; + priv->domain_id = handle->perf_ops->device_domain_id(cpu_dev); + + policy->driver_data = priv; + + ret = cpufreq_table_validate_and_show(policy, freq_table); + if (ret) { + dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, + ret); + goto out_free_cpufreq_table; + } + + /* SCMI allows DVFS request for any domain from any CPU */ + policy->dvfs_possible_from_any_cpu = true; + + latency = handle->perf_ops->get_transition_latency(handle, cpu_dev); + if (!latency) + latency = CPUFREQ_ETERNAL; + + policy->cpuinfo.transition_latency = latency; + + policy->fast_switch_possible = true; + return 0; + +out_free_cpufreq_table: + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); +out_free_priv: + kfree(priv); +out_free_opp: + dev_pm_opp_cpumask_remove_table(policy->cpus); + + return ret; +} + +static int scmi_cpufreq_exit(struct cpufreq_policy *policy) +{ + struct scmi_data *priv = policy->driver_data; + + cpufreq_cooling_unregister(priv->cdev); + dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); + kfree(priv); + dev_pm_opp_cpumask_remove_table(policy->related_cpus); + + return 0; +} + +static void scmi_cpufreq_ready(struct cpufreq_policy *policy) +{ + struct scmi_data *priv = policy->driver_data; + + priv->cdev = of_cpufreq_cooling_register(policy); +} + +static struct cpufreq_driver scmi_cpufreq_driver = { + .name = "scmi", + .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | + CPUFREQ_NEED_INITIAL_FREQ_CHECK, + .verify = cpufreq_generic_frequency_table_verify, + .attr = cpufreq_generic_attr, + .target_index = scmi_cpufreq_set_target, + .fast_switch = scmi_cpufreq_fast_switch, + .get = scmi_cpufreq_get_rate, + .init = scmi_cpufreq_init, + .exit = scmi_cpufreq_exit, + .ready = scmi_cpufreq_ready, +}; + +static int scmi_cpufreq_probe(struct scmi_device *sdev) +{ + int ret; + + handle = sdev->handle; + + if (!handle || !handle->perf_ops) + return -ENODEV; + + ret = cpufreq_register_driver(&scmi_cpufreq_driver); + if (ret) { + dev_err(&sdev->dev, "%s: registering cpufreq failed, err: %d\n", + __func__, ret); + } + + return ret; +} + +static void scmi_cpufreq_remove(struct scmi_device *sdev) +{ + cpufreq_unregister_driver(&scmi_cpufreq_driver); +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_PERF }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_cpufreq_drv = { + .name = "scmi-cpufreq", + .probe = scmi_cpufreq_probe, + .remove = scmi_cpufreq_remove, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_cpufreq_drv); + +MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>"); +MODULE_DESCRIPTION("ARM SCMI CPUFreq interface driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c index c32a833e1b00..87a98ec77773 100644 --- a/drivers/cpufreq/scpi-cpufreq.c +++ b/drivers/cpufreq/scpi-cpufreq.c @@ -51,15 +51,23 @@ static unsigned int scpi_cpufreq_get_rate(unsigned int cpu) static int scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) { + unsigned long freq = policy->freq_table[index].frequency; struct scpi_data *priv = policy->driver_data; - u64 rate = policy->freq_table[index].frequency * 1000; + u64 rate = freq * 1000; int ret; ret = clk_set_rate(priv->clk, rate); - if (!ret && (clk_get_rate(priv->clk) != rate)) - ret = -EIO; - return ret; + if (ret) + return ret; + + if (clk_get_rate(priv->clk) != rate) + return -EIO; + + arch_set_freq_scale(policy->related_cpus, freq, + policy->cpuinfo.max_freq); + + return 0; } static int @@ -150,13 +158,7 @@ static int scpi_cpufreq_init(struct cpufreq_policy *policy) } policy->driver_data = priv; - - ret = cpufreq_table_validate_and_show(policy, freq_table); - if (ret) { - dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, - ret); - goto out_put_clk; - } + policy->freq_table = freq_table; /* scpi allows DVFS request for any domain from any CPU */ policy->dvfs_possible_from_any_cpu = true; @@ -170,8 +172,6 @@ static int scpi_cpufreq_init(struct cpufreq_policy *policy) policy->fast_switch_possible = false; return 0; -out_put_clk: - clk_put(priv->clk); out_free_cpufreq_table: dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); out_free_priv: diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c index 3779742f86e3..9767afe05da2 100644 --- a/drivers/cpufreq/sfi-cpufreq.c +++ b/drivers/cpufreq/sfi-cpufreq.c @@ -72,8 +72,9 @@ static int sfi_cpufreq_cpu_init(struct cpufreq_policy *policy) { policy->shared_type = CPUFREQ_SHARED_TYPE_HW; policy->cpuinfo.transition_latency = 100000; /* 100us */ + policy->freq_table = freq_table; - return cpufreq_table_validate_and_show(policy, freq_table); + return 0; } static struct cpufreq_driver sfi_cpufreq_driver = { diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c index 28893d435cf5..5096c0ab781b 100644 --- a/drivers/cpufreq/sh-cpufreq.c +++ b/drivers/cpufreq/sh-cpufreq.c @@ -122,11 +122,7 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL; if (freq_table) { - int result; - - result = cpufreq_table_validate_and_show(policy, freq_table); - if (result) - return result; + policy->freq_table = freq_table; } else { dev_notice(dev, "no frequency table found, falling back " "to rate rounding.\n"); @@ -137,11 +133,6 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; } - dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, " - "Maximum %u.%03u MHz.\n", - policy->min / 1000, policy->min % 1000, - policy->max / 1000, policy->max % 1000); - return 0; } @@ -155,6 +146,16 @@ static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy) return 0; } +static void sh_cpufreq_cpu_ready(struct cpufreq_policy *policy) +{ + struct device *dev = get_cpu_device(policy->cpu); + + dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, " + "Maximum %u.%03u MHz.\n", + policy->min / 1000, policy->min % 1000, + policy->max / 1000, policy->max % 1000); +} + static struct cpufreq_driver sh_cpufreq_driver = { .name = "sh", .flags = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING, @@ -163,6 +164,7 @@ static struct cpufreq_driver sh_cpufreq_driver = { .verify = sh_cpufreq_verify, .init = sh_cpufreq_cpu_init, .exit = sh_cpufreq_cpu_exit, + .ready = sh_cpufreq_cpu_ready, .attr = cpufreq_generic_attr, }; diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c index 90f33efee5fc..bbd1d1e166b8 100644 --- a/drivers/cpufreq/sparc-us2e-cpufreq.c +++ b/drivers/cpufreq/sparc-us2e-cpufreq.c @@ -292,8 +292,9 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = 0; policy->cur = clock_tick; + policy->freq_table = table; - return cpufreq_table_validate_and_show(policy, table); + return 0; } static int us2e_freq_cpu_exit(struct cpufreq_policy *policy) diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c index 30645b0118f9..51e3c6018e74 100644 --- a/drivers/cpufreq/sparc-us3-cpufreq.c +++ b/drivers/cpufreq/sparc-us3-cpufreq.c @@ -136,8 +136,9 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = 0; policy->cur = clock_tick; + policy->freq_table = table; - return cpufreq_table_validate_and_show(policy, table); + return 0; } static int us3_freq_cpu_exit(struct cpufreq_policy *policy) diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c index 41bc5397f4bb..a1fb735685db 100644 --- a/drivers/cpufreq/speedstep-centrino.c +++ b/drivers/cpufreq/speedstep-centrino.c @@ -37,7 +37,7 @@ struct cpu_id { __u8 x86; /* CPU family */ __u8 x86_model; /* model */ - __u8 x86_mask; /* stepping */ + __u8 x86_stepping; /* stepping */ }; enum { @@ -277,7 +277,7 @@ static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, { if ((c->x86 == x->x86) && (c->x86_model == x->x86_model) && - (c->x86_mask == x->x86_mask)) + (c->x86_stepping == x->x86_stepping)) return 1; return 0; } @@ -394,9 +394,9 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */ + policy->freq_table = per_cpu(centrino_model, policy->cpu)->op_points; - return cpufreq_table_validate_and_show(policy, - per_cpu(centrino_model, policy->cpu)->op_points); + return 0; } static int centrino_cpu_exit(struct cpufreq_policy *policy) diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c index 0412a246a785..fbbcb88db061 100644 --- a/drivers/cpufreq/speedstep-ich.c +++ b/drivers/cpufreq/speedstep-ich.c @@ -304,7 +304,9 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) if (gf.ret) return gf.ret; - return cpufreq_table_validate_and_show(policy, speedstep_freqs); + policy->freq_table = speedstep_freqs; + + return 0; } diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c index 8085ec9000d1..e3a9962ee410 100644 --- a/drivers/cpufreq/speedstep-lib.c +++ b/drivers/cpufreq/speedstep-lib.c @@ -272,9 +272,9 @@ unsigned int speedstep_detect_processor(void) ebx = cpuid_ebx(0x00000001); ebx &= 0x000000FF; - pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask); + pr_debug("ebx value is %x, x86_stepping is %x\n", ebx, c->x86_stepping); - switch (c->x86_mask) { + switch (c->x86_stepping) { case 4: /* * B-stepping [M-P4-M] @@ -361,7 +361,7 @@ unsigned int speedstep_detect_processor(void) msr_lo, msr_hi); if ((msr_hi & (1<<18)) && (relaxed_check ? 1 : (msr_hi & (3<<24)))) { - if (c->x86_mask == 0x01) { + if (c->x86_stepping == 0x01) { pr_debug("early PIII version\n"); return SPEEDSTEP_CPU_PIII_C_EARLY; } else diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c index d23f24ccff38..01fe70dae20b 100644 --- a/drivers/cpufreq/speedstep-smi.c +++ b/drivers/cpufreq/speedstep-smi.c @@ -266,7 +266,9 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) pr_debug("workaround worked.\n"); } - return cpufreq_table_validate_and_show(policy, speedstep_freqs); + policy->freq_table = speedstep_freqs; + + return 0; } static unsigned int speedstep_get(unsigned int cpu) diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c index fe7875311d62..1f59966573aa 100644 --- a/drivers/cpufreq/tegra186-cpufreq.c +++ b/drivers/cpufreq/tegra186-cpufreq.c @@ -78,7 +78,8 @@ static int tegra186_cpufreq_init(struct cpufreq_policy *policy) policy->driver_data = data->regs + info->offset + EDVD_CORE_VOLT_FREQ(core); - cpufreq_table_validate_and_show(policy, cluster->table); + policy->freq_table = cluster->table; + break; } policy->cpuinfo.transition_latency = 300 * 1000; |