Path: blob/master/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
10820 views
/*1* Cpufreq driver for the loongson-2 processors2*3* The 2E revision of loongson processor not support this feature.4*5* Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology6* Author: Yanhua, [email protected]7*8* This file is subject to the terms and conditions of the GNU General Public9* License. See the file "COPYING" in the main directory of this archive10* for more details.11*/12#include <linux/cpufreq.h>13#include <linux/module.h>14#include <linux/err.h>15#include <linux/sched.h> /* set_cpus_allowed() */16#include <linux/delay.h>17#include <linux/platform_device.h>1819#include <asm/clock.h>2021#include <loongson.h>2223static uint nowait;2425static struct clk *cpuclk;2627static void (*saved_cpu_wait) (void);2829static int loongson2_cpu_freq_notifier(struct notifier_block *nb,30unsigned long val, void *data);3132static struct notifier_block loongson2_cpufreq_notifier_block = {33.notifier_call = loongson2_cpu_freq_notifier34};3536static int loongson2_cpu_freq_notifier(struct notifier_block *nb,37unsigned long val, void *data)38{39if (val == CPUFREQ_POSTCHANGE)40current_cpu_data.udelay_val = loops_per_jiffy;4142return 0;43}4445static unsigned int loongson2_cpufreq_get(unsigned int cpu)46{47return clk_get_rate(cpuclk);48}4950/*51* Here we notify other drivers of the proposed change and the final change.52*/53static int loongson2_cpufreq_target(struct cpufreq_policy *policy,54unsigned int target_freq,55unsigned int relation)56{57unsigned int cpu = policy->cpu;58unsigned int newstate = 0;59cpumask_t cpus_allowed;60struct cpufreq_freqs freqs;61unsigned int freq;6263if (!cpu_online(cpu))64return -ENODEV;6566cpus_allowed = current->cpus_allowed;67set_cpus_allowed_ptr(current, cpumask_of(cpu));6869if (cpufreq_frequency_table_target70(policy, &loongson2_clockmod_table[0], target_freq, relation,71&newstate))72return -EINVAL;7374freq =75((cpu_clock_freq / 1000) *76loongson2_clockmod_table[newstate].index) / 8;77if (freq < policy->min || freq > policy->max)78return -EINVAL;7980pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);8182freqs.cpu = cpu;83freqs.old = loongson2_cpufreq_get(cpu);84freqs.new = freq;85freqs.flags = 0;8687if (freqs.new == freqs.old)88return 0;8990/* notifiers */91cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);9293set_cpus_allowed_ptr(current, &cpus_allowed);9495/* setting the cpu frequency */96clk_set_rate(cpuclk, freq);9798/* notifiers */99cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);100101pr_debug("cpufreq: set frequency %u kHz\n", freq);102103return 0;104}105106static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)107{108int i;109110if (!cpu_online(policy->cpu))111return -ENODEV;112113cpuclk = clk_get(NULL, "cpu_clk");114if (IS_ERR(cpuclk)) {115printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");116return PTR_ERR(cpuclk);117}118119cpuclk->rate = cpu_clock_freq / 1000;120if (!cpuclk->rate)121return -EINVAL;122123/* clock table init */124for (i = 2;125(loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END);126i++)127loongson2_clockmod_table[i].frequency = (cpuclk->rate * i) / 8;128129policy->cur = loongson2_cpufreq_get(policy->cpu);130131cpufreq_frequency_table_get_attr(&loongson2_clockmod_table[0],132policy->cpu);133134return cpufreq_frequency_table_cpuinfo(policy,135&loongson2_clockmod_table[0]);136}137138static int loongson2_cpufreq_verify(struct cpufreq_policy *policy)139{140return cpufreq_frequency_table_verify(policy,141&loongson2_clockmod_table[0]);142}143144static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)145{146clk_put(cpuclk);147return 0;148}149150static struct freq_attr *loongson2_table_attr[] = {151&cpufreq_freq_attr_scaling_available_freqs,152NULL,153};154155static struct cpufreq_driver loongson2_cpufreq_driver = {156.owner = THIS_MODULE,157.name = "loongson2",158.init = loongson2_cpufreq_cpu_init,159.verify = loongson2_cpufreq_verify,160.target = loongson2_cpufreq_target,161.get = loongson2_cpufreq_get,162.exit = loongson2_cpufreq_exit,163.attr = loongson2_table_attr,164};165166static struct platform_device_id platform_device_ids[] = {167{168.name = "loongson2_cpufreq",169},170{}171};172173MODULE_DEVICE_TABLE(platform, platform_device_ids);174175static struct platform_driver platform_driver = {176.driver = {177.name = "loongson2_cpufreq",178.owner = THIS_MODULE,179},180.id_table = platform_device_ids,181};182183static int __init cpufreq_init(void)184{185int ret;186187/* Register platform stuff */188ret = platform_driver_register(&platform_driver);189if (ret)190return ret;191192pr_info("cpufreq: Loongson-2F CPU frequency driver.\n");193194cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,195CPUFREQ_TRANSITION_NOTIFIER);196197ret = cpufreq_register_driver(&loongson2_cpufreq_driver);198199if (!ret && !nowait) {200saved_cpu_wait = cpu_wait;201cpu_wait = loongson2_cpu_wait;202}203204return ret;205}206207static void __exit cpufreq_exit(void)208{209if (!nowait && saved_cpu_wait)210cpu_wait = saved_cpu_wait;211cpufreq_unregister_driver(&loongson2_cpufreq_driver);212cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block,213CPUFREQ_TRANSITION_NOTIFIER);214215platform_driver_unregister(&platform_driver);216}217218module_init(cpufreq_init);219module_exit(cpufreq_exit);220221module_param(nowait, uint, 0644);222MODULE_PARM_DESC(nowait, "Disable Loongson-2F specific wait");223224MODULE_AUTHOR("Yanhua <[email protected]>");225MODULE_DESCRIPTION("cpufreq driver for Loongson2F");226MODULE_LICENSE("GPL");227228229