2 * Cpufreq driver for the loongson-2 processors
4 * The 2E revision of loongson processor not support this feature.
6 * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology
7 * Author: Yanhua, yanh@lemote.com
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive
13 #include <linux/cpufreq.h>
14 #include <linux/module.h>
15 #include <linux/err.h>
16 #include <linux/sched.h> /* set_cpus_allowed() */
17 #include <linux/delay.h>
18 #include <linux/platform_device.h>
20 #include <asm/clock.h>
23 #include <asm/mach-loongson/loongson.h>
27 static void (*saved_cpu_wait
) (void);
29 static int loongson2_cpu_freq_notifier(struct notifier_block
*nb
,
30 unsigned long val
, void *data
);
32 static struct notifier_block loongson2_cpufreq_notifier_block
= {
33 .notifier_call
= loongson2_cpu_freq_notifier
36 static int loongson2_cpu_freq_notifier(struct notifier_block
*nb
,
37 unsigned long val
, void *data
)
39 if (val
== CPUFREQ_POSTCHANGE
)
40 current_cpu_data
.udelay_val
= loops_per_jiffy
;
46 * Here we notify other drivers of the proposed change and the final change.
48 static int loongson2_cpufreq_target(struct cpufreq_policy
*policy
,
51 unsigned int cpu
= policy
->cpu
;
52 cpumask_t cpus_allowed
;
55 cpus_allowed
= current
->cpus_allowed
;
56 set_cpus_allowed_ptr(current
, cpumask_of(cpu
));
59 ((cpu_clock_freq
/ 1000) *
60 loongson2_clockmod_table
[index
].driver_data
) / 8;
62 set_cpus_allowed_ptr(current
, &cpus_allowed
);
64 /* setting the cpu frequency */
65 clk_set_rate(policy
->clk
, freq
);
70 static int loongson2_cpufreq_cpu_init(struct cpufreq_policy
*policy
)
77 cpuclk
= clk_get(NULL
, "cpu_clk");
79 printk(KERN_ERR
"cpufreq: couldn't get CPU clk\n");
80 return PTR_ERR(cpuclk
);
83 rate
= cpu_clock_freq
/ 1000;
89 /* clock table init */
91 (loongson2_clockmod_table
[i
].frequency
!= CPUFREQ_TABLE_END
);
93 loongson2_clockmod_table
[i
].frequency
= (rate
* i
) / 8;
95 ret
= clk_set_rate(cpuclk
, rate
);
101 policy
->clk
= cpuclk
;
102 return cpufreq_generic_init(policy
, &loongson2_clockmod_table
[0], 0);
105 static int loongson2_cpufreq_exit(struct cpufreq_policy
*policy
)
107 clk_put(policy
->clk
);
111 static struct cpufreq_driver loongson2_cpufreq_driver
= {
113 .init
= loongson2_cpufreq_cpu_init
,
114 .verify
= cpufreq_generic_frequency_table_verify
,
115 .target_index
= loongson2_cpufreq_target
,
116 .get
= cpufreq_generic_get
,
117 .exit
= loongson2_cpufreq_exit
,
118 .attr
= cpufreq_generic_attr
,
121 static struct platform_device_id platform_device_ids
[] = {
123 .name
= "loongson2_cpufreq",
128 MODULE_DEVICE_TABLE(platform
, platform_device_ids
);
130 static struct platform_driver platform_driver
= {
132 .name
= "loongson2_cpufreq",
133 .owner
= THIS_MODULE
,
135 .id_table
= platform_device_ids
,
139 * This is the simple version of Loongson-2 wait, Maybe we need do this in
140 * interrupt disabled context.
143 static DEFINE_SPINLOCK(loongson2_wait_lock
);
145 static void loongson2_cpu_wait(void)
150 spin_lock_irqsave(&loongson2_wait_lock
, flags
);
151 cpu_freq
= LOONGSON_CHIPCFG0
;
152 LOONGSON_CHIPCFG0
&= ~0x7; /* Put CPU into wait mode */
153 LOONGSON_CHIPCFG0
= cpu_freq
; /* Restore CPU state */
154 spin_unlock_irqrestore(&loongson2_wait_lock
, flags
);
158 static int __init
cpufreq_init(void)
162 /* Register platform stuff */
163 ret
= platform_driver_register(&platform_driver
);
167 pr_info("cpufreq: Loongson-2F CPU frequency driver.\n");
169 cpufreq_register_notifier(&loongson2_cpufreq_notifier_block
,
170 CPUFREQ_TRANSITION_NOTIFIER
);
172 ret
= cpufreq_register_driver(&loongson2_cpufreq_driver
);
174 if (!ret
&& !nowait
) {
175 saved_cpu_wait
= cpu_wait
;
176 cpu_wait
= loongson2_cpu_wait
;
182 static void __exit
cpufreq_exit(void)
184 if (!nowait
&& saved_cpu_wait
)
185 cpu_wait
= saved_cpu_wait
;
186 cpufreq_unregister_driver(&loongson2_cpufreq_driver
);
187 cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block
,
188 CPUFREQ_TRANSITION_NOTIFIER
);
190 platform_driver_unregister(&platform_driver
);
193 module_init(cpufreq_init
);
194 module_exit(cpufreq_exit
);
196 module_param(nowait
, uint
, 0644);
197 MODULE_PARM_DESC(nowait
, "Disable Loongson-2F specific wait");
199 MODULE_AUTHOR("Yanhua <yanh@lemote.com>");
200 MODULE_DESCRIPTION("cpufreq driver for Loongson2F");
201 MODULE_LICENSE("GPL");