Path: blob/master/arch/cris/arch-v32/mach-fs/cpufreq.c
15125 views
#include <linux/init.h>1#include <linux/module.h>2#include <linux/cpufreq.h>3#include <hwregs/reg_map.h>4#include <arch/hwregs/reg_rdwr.h>5#include <arch/hwregs/config_defs.h>6#include <arch/hwregs/bif_core_defs.h>78static int9cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,10void *data);1112static struct notifier_block cris_sdram_freq_notifier_block = {13.notifier_call = cris_sdram_freq_notifier14};1516static struct cpufreq_frequency_table cris_freq_table[] = {17{0x01, 6000},18{0x02, 200000},19{0, CPUFREQ_TABLE_END},20};2122static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)23{24reg_config_rw_clk_ctrl clk_ctrl;25clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);26return clk_ctrl.pll ? 200000 : 6000;27}2829static void cris_freq_set_cpu_state(unsigned int state)30{31int i;32struct cpufreq_freqs freqs;33reg_config_rw_clk_ctrl clk_ctrl;34clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);3536for_each_possible_cpu(i) {37freqs.old = cris_freq_get_cpu_frequency(i);38freqs.new = cris_freq_table[state].frequency;39freqs.cpu = i;40}4142cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);4344local_irq_disable();4546/* Even though we may be SMP they will share the same clock47* so all settings are made on CPU0. */48if (cris_freq_table[state].frequency == 200000)49clk_ctrl.pll = 1;50else51clk_ctrl.pll = 0;52REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl);5354local_irq_enable();5556cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);57};5859static int cris_freq_verify(struct cpufreq_policy *policy)60{61return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]);62}6364static int cris_freq_target(struct cpufreq_policy *policy,65unsigned int target_freq, unsigned int relation)66{67unsigned int newstate = 0;6869if (cpufreq_frequency_table_target70(policy, cris_freq_table, target_freq, relation, &newstate))71return -EINVAL;7273cris_freq_set_cpu_state(newstate);7475return 0;76}7778static int cris_freq_cpu_init(struct cpufreq_policy *policy)79{80int result;8182/* cpuinfo and default policy values */83policy->cpuinfo.transition_latency = 1000000; /* 1ms */84policy->cur = cris_freq_get_cpu_frequency(0);8586result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table);87if (result)88return (result);8990cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu);9192return 0;93}9495static int cris_freq_cpu_exit(struct cpufreq_policy *policy)96{97cpufreq_frequency_table_put_attr(policy->cpu);98return 0;99}100101static struct freq_attr *cris_freq_attr[] = {102&cpufreq_freq_attr_scaling_available_freqs,103NULL,104};105106static struct cpufreq_driver cris_freq_driver = {107.get = cris_freq_get_cpu_frequency,108.verify = cris_freq_verify,109.target = cris_freq_target,110.init = cris_freq_cpu_init,111.exit = cris_freq_cpu_exit,112.name = "cris_freq",113.owner = THIS_MODULE,114.attr = cris_freq_attr,115};116117static int __init cris_freq_init(void)118{119int ret;120ret = cpufreq_register_driver(&cris_freq_driver);121cpufreq_register_notifier(&cris_sdram_freq_notifier_block,122CPUFREQ_TRANSITION_NOTIFIER);123return ret;124}125126static int127cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,128void *data)129{130int i;131struct cpufreq_freqs *freqs = data;132if (val == CPUFREQ_PRECHANGE) {133reg_bif_core_rw_sdram_timing timing =134REG_RD(bif_core, regi_bif_core, rw_sdram_timing);135timing.cpd = (freqs->new == 200000 ? 0 : 1);136137if (freqs->new == 200000)138for (i = 0; i < 50000; i++) ;139REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing);140}141return 0;142}143144module_init(cris_freq_init);145146147