Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/cpufreq/loongson2_cpufreq.c
26278 views
1
/*
2
* Cpufreq driver for the loongson-2 processors
3
*
4
* The 2E revision of loongson processor not support this feature.
5
*
6
* Copyright (C) 2006 - 2008 Lemote Inc. & Institute of Computing Technology
7
* Author: Yanhua, [email protected]
8
*
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
11
* for more details.
12
*/
13
14
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
16
#include <linux/cpufreq.h>
17
#include <linux/module.h>
18
#include <linux/err.h>
19
#include <linux/delay.h>
20
#include <linux/platform_device.h>
21
22
#include <asm/idle.h>
23
24
#include <asm/mach-loongson2ef/loongson.h>
25
26
static uint nowait;
27
28
static void (*saved_cpu_wait) (void);
29
30
static int loongson2_cpu_freq_notifier(struct notifier_block *nb,
31
unsigned long val, void *data);
32
33
static struct notifier_block loongson2_cpufreq_notifier_block = {
34
.notifier_call = loongson2_cpu_freq_notifier
35
};
36
37
static int loongson2_cpu_freq_notifier(struct notifier_block *nb,
38
unsigned long val, void *data)
39
{
40
if (val == CPUFREQ_POSTCHANGE)
41
current_cpu_data.udelay_val = loops_per_jiffy;
42
43
return 0;
44
}
45
46
/*
47
* Here we notify other drivers of the proposed change and the final change.
48
*/
49
static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
50
unsigned int index)
51
{
52
unsigned int freq;
53
54
freq =
55
((cpu_clock_freq / 1000) *
56
loongson2_clockmod_table[index].driver_data) / 8;
57
58
/* setting the cpu frequency */
59
loongson2_cpu_set_rate(freq);
60
61
return 0;
62
}
63
64
static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
65
{
66
int i;
67
unsigned long rate;
68
int ret;
69
70
rate = cpu_clock_freq / 1000;
71
if (!rate)
72
return -EINVAL;
73
74
/* clock table init */
75
for (i = 2;
76
(loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END);
77
i++)
78
loongson2_clockmod_table[i].frequency = (rate * i) / 8;
79
80
ret = loongson2_cpu_set_rate(rate);
81
if (ret)
82
return ret;
83
84
cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0);
85
return 0;
86
}
87
88
static struct cpufreq_driver loongson2_cpufreq_driver = {
89
.name = "loongson2",
90
.init = loongson2_cpufreq_cpu_init,
91
.verify = cpufreq_generic_frequency_table_verify,
92
.target_index = loongson2_cpufreq_target,
93
.get = cpufreq_generic_get,
94
};
95
96
static const struct platform_device_id platform_device_ids[] = {
97
{
98
.name = "loongson2_cpufreq",
99
},
100
{}
101
};
102
103
MODULE_DEVICE_TABLE(platform, platform_device_ids);
104
105
static struct platform_driver platform_driver = {
106
.driver = {
107
.name = "loongson2_cpufreq",
108
},
109
.id_table = platform_device_ids,
110
};
111
112
/*
113
* This is the simple version of Loongson-2 wait, Maybe we need do this in
114
* interrupt disabled context.
115
*/
116
117
static DEFINE_SPINLOCK(loongson2_wait_lock);
118
119
static void loongson2_cpu_wait(void)
120
{
121
unsigned long flags;
122
u32 cpu_freq;
123
124
spin_lock_irqsave(&loongson2_wait_lock, flags);
125
cpu_freq = readl(LOONGSON_CHIPCFG);
126
/* Put CPU into wait mode */
127
writel(readl(LOONGSON_CHIPCFG) & ~0x7, LOONGSON_CHIPCFG);
128
/* Restore CPU state */
129
writel(cpu_freq, LOONGSON_CHIPCFG);
130
spin_unlock_irqrestore(&loongson2_wait_lock, flags);
131
local_irq_enable();
132
}
133
134
static int __init cpufreq_init(void)
135
{
136
int ret;
137
138
/* Register platform stuff */
139
ret = platform_driver_register(&platform_driver);
140
if (ret)
141
return ret;
142
143
pr_info("Loongson-2F CPU frequency driver\n");
144
145
cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,
146
CPUFREQ_TRANSITION_NOTIFIER);
147
148
ret = cpufreq_register_driver(&loongson2_cpufreq_driver);
149
150
if (ret) {
151
platform_driver_unregister(&platform_driver);
152
} else if (!nowait) {
153
saved_cpu_wait = cpu_wait;
154
cpu_wait = loongson2_cpu_wait;
155
}
156
157
return ret;
158
}
159
160
static void __exit cpufreq_exit(void)
161
{
162
if (!nowait && saved_cpu_wait)
163
cpu_wait = saved_cpu_wait;
164
cpufreq_unregister_driver(&loongson2_cpufreq_driver);
165
cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block,
166
CPUFREQ_TRANSITION_NOTIFIER);
167
168
platform_driver_unregister(&platform_driver);
169
}
170
171
module_init(cpufreq_init);
172
module_exit(cpufreq_exit);
173
174
module_param(nowait, uint, 0644);
175
MODULE_PARM_DESC(nowait, "Disable Loongson-2F specific wait");
176
177
MODULE_AUTHOR("Yanhua <[email protected]>");
178
MODULE_DESCRIPTION("cpufreq driver for Loongson2F");
179
MODULE_LICENSE("GPL");
180
181