Root/
1 | /* us3_cpufreq.c: UltraSPARC-III cpu frequency support |
2 | * |
3 | * Copyright (C) 2003 David S. Miller (davem@redhat.com) |
4 | * |
5 | * Many thanks to Dominik Brodowski for fixing up the cpufreq |
6 | * infrastructure in order to make this driver easier to implement. |
7 | */ |
8 | |
9 | #include <linux/kernel.h> |
10 | #include <linux/module.h> |
11 | #include <linux/sched.h> |
12 | #include <linux/smp.h> |
13 | #include <linux/cpufreq.h> |
14 | #include <linux/threads.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/init.h> |
17 | |
18 | #include <asm/head.h> |
19 | #include <asm/timer.h> |
20 | |
21 | static struct cpufreq_driver *cpufreq_us3_driver; |
22 | |
23 | struct us3_freq_percpu_info { |
24 | struct cpufreq_frequency_table table[4]; |
25 | }; |
26 | |
27 | /* Indexed by cpu number. */ |
28 | static struct us3_freq_percpu_info *us3_freq_table; |
29 | |
30 | /* UltraSPARC-III has three dividers: 1, 2, and 32. These are controlled |
31 | * in the Safari config register. |
32 | */ |
33 | #define SAFARI_CFG_DIV_1 0x0000000000000000UL |
34 | #define SAFARI_CFG_DIV_2 0x0000000040000000UL |
35 | #define SAFARI_CFG_DIV_32 0x0000000080000000UL |
36 | #define SAFARI_CFG_DIV_MASK 0x00000000C0000000UL |
37 | |
38 | static unsigned long read_safari_cfg(void) |
39 | { |
40 | unsigned long ret; |
41 | |
42 | __asm__ __volatile__("ldxa [%%g0] %1, %0" |
43 | : "=&r" (ret) |
44 | : "i" (ASI_SAFARI_CONFIG)); |
45 | return ret; |
46 | } |
47 | |
48 | static void write_safari_cfg(unsigned long val) |
49 | { |
50 | __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" |
51 | "membar #Sync" |
52 | : /* no outputs */ |
53 | : "r" (val), "i" (ASI_SAFARI_CONFIG) |
54 | : "memory"); |
55 | } |
56 | |
57 | static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg) |
58 | { |
59 | unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000; |
60 | unsigned long ret; |
61 | |
62 | switch (safari_cfg & SAFARI_CFG_DIV_MASK) { |
63 | case SAFARI_CFG_DIV_1: |
64 | ret = clock_tick / 1; |
65 | break; |
66 | case SAFARI_CFG_DIV_2: |
67 | ret = clock_tick / 2; |
68 | break; |
69 | case SAFARI_CFG_DIV_32: |
70 | ret = clock_tick / 32; |
71 | break; |
72 | default: |
73 | BUG(); |
74 | }; |
75 | |
76 | return ret; |
77 | } |
78 | |
79 | static unsigned int us3_freq_get(unsigned int cpu) |
80 | { |
81 | cpumask_t cpus_allowed; |
82 | unsigned long reg; |
83 | unsigned int ret; |
84 | |
85 | if (!cpu_online(cpu)) |
86 | return 0; |
87 | |
88 | cpus_allowed = current->cpus_allowed; |
89 | set_cpus_allowed_ptr(current, cpumask_of(cpu)); |
90 | |
91 | reg = read_safari_cfg(); |
92 | ret = get_current_freq(cpu, reg); |
93 | |
94 | set_cpus_allowed_ptr(current, &cpus_allowed); |
95 | |
96 | return ret; |
97 | } |
98 | |
99 | static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) |
100 | { |
101 | unsigned long new_bits, new_freq, reg; |
102 | cpumask_t cpus_allowed; |
103 | struct cpufreq_freqs freqs; |
104 | |
105 | if (!cpu_online(cpu)) |
106 | return; |
107 | |
108 | cpus_allowed = current->cpus_allowed; |
109 | set_cpus_allowed_ptr(current, cpumask_of(cpu)); |
110 | |
111 | new_freq = sparc64_get_clock_tick(cpu) / 1000; |
112 | switch (index) { |
113 | case 0: |
114 | new_bits = SAFARI_CFG_DIV_1; |
115 | new_freq /= 1; |
116 | break; |
117 | case 1: |
118 | new_bits = SAFARI_CFG_DIV_2; |
119 | new_freq /= 2; |
120 | break; |
121 | case 2: |
122 | new_bits = SAFARI_CFG_DIV_32; |
123 | new_freq /= 32; |
124 | break; |
125 | |
126 | default: |
127 | BUG(); |
128 | }; |
129 | |
130 | reg = read_safari_cfg(); |
131 | |
132 | freqs.old = get_current_freq(cpu, reg); |
133 | freqs.new = new_freq; |
134 | freqs.cpu = cpu; |
135 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); |
136 | |
137 | reg &= ~SAFARI_CFG_DIV_MASK; |
138 | reg |= new_bits; |
139 | write_safari_cfg(reg); |
140 | |
141 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); |
142 | |
143 | set_cpus_allowed_ptr(current, &cpus_allowed); |
144 | } |
145 | |
146 | static int us3_freq_target(struct cpufreq_policy *policy, |
147 | unsigned int target_freq, |
148 | unsigned int relation) |
149 | { |
150 | unsigned int new_index = 0; |
151 | |
152 | if (cpufreq_frequency_table_target(policy, |
153 | &us3_freq_table[policy->cpu].table[0], |
154 | target_freq, |
155 | relation, |
156 | &new_index)) |
157 | return -EINVAL; |
158 | |
159 | us3_set_cpu_divider_index(policy->cpu, new_index); |
160 | |
161 | return 0; |
162 | } |
163 | |
164 | static int us3_freq_verify(struct cpufreq_policy *policy) |
165 | { |
166 | return cpufreq_frequency_table_verify(policy, |
167 | &us3_freq_table[policy->cpu].table[0]); |
168 | } |
169 | |
170 | static int __init us3_freq_cpu_init(struct cpufreq_policy *policy) |
171 | { |
172 | unsigned int cpu = policy->cpu; |
173 | unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000; |
174 | struct cpufreq_frequency_table *table = |
175 | &us3_freq_table[cpu].table[0]; |
176 | |
177 | table[0].index = 0; |
178 | table[0].frequency = clock_tick / 1; |
179 | table[1].index = 1; |
180 | table[1].frequency = clock_tick / 2; |
181 | table[2].index = 2; |
182 | table[2].frequency = clock_tick / 32; |
183 | table[3].index = 0; |
184 | table[3].frequency = CPUFREQ_TABLE_END; |
185 | |
186 | policy->cpuinfo.transition_latency = 0; |
187 | policy->cur = clock_tick; |
188 | |
189 | return cpufreq_frequency_table_cpuinfo(policy, table); |
190 | } |
191 | |
192 | static int us3_freq_cpu_exit(struct cpufreq_policy *policy) |
193 | { |
194 | if (cpufreq_us3_driver) |
195 | us3_set_cpu_divider_index(policy->cpu, 0); |
196 | |
197 | return 0; |
198 | } |
199 | |
200 | static int __init us3_freq_init(void) |
201 | { |
202 | unsigned long manuf, impl, ver; |
203 | int ret; |
204 | |
205 | if (tlb_type != cheetah && tlb_type != cheetah_plus) |
206 | return -ENODEV; |
207 | |
208 | __asm__("rdpr %%ver, %0" : "=r" (ver)); |
209 | manuf = ((ver >> 48) & 0xffff); |
210 | impl = ((ver >> 32) & 0xffff); |
211 | |
212 | if (manuf == CHEETAH_MANUF && |
213 | (impl == CHEETAH_IMPL || |
214 | impl == CHEETAH_PLUS_IMPL || |
215 | impl == JAGUAR_IMPL || |
216 | impl == PANTHER_IMPL)) { |
217 | struct cpufreq_driver *driver; |
218 | |
219 | ret = -ENOMEM; |
220 | driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); |
221 | if (!driver) |
222 | goto err_out; |
223 | |
224 | us3_freq_table = kzalloc( |
225 | (NR_CPUS * sizeof(struct us3_freq_percpu_info)), |
226 | GFP_KERNEL); |
227 | if (!us3_freq_table) |
228 | goto err_out; |
229 | |
230 | driver->init = us3_freq_cpu_init; |
231 | driver->verify = us3_freq_verify; |
232 | driver->target = us3_freq_target; |
233 | driver->get = us3_freq_get; |
234 | driver->exit = us3_freq_cpu_exit; |
235 | driver->owner = THIS_MODULE, |
236 | strcpy(driver->name, "UltraSPARC-III"); |
237 | |
238 | cpufreq_us3_driver = driver; |
239 | ret = cpufreq_register_driver(driver); |
240 | if (ret) |
241 | goto err_out; |
242 | |
243 | return 0; |
244 | |
245 | err_out: |
246 | if (driver) { |
247 | kfree(driver); |
248 | cpufreq_us3_driver = NULL; |
249 | } |
250 | kfree(us3_freq_table); |
251 | us3_freq_table = NULL; |
252 | return ret; |
253 | } |
254 | |
255 | return -ENODEV; |
256 | } |
257 | |
258 | static void __exit us3_freq_exit(void) |
259 | { |
260 | if (cpufreq_us3_driver) { |
261 | cpufreq_unregister_driver(cpufreq_us3_driver); |
262 | kfree(cpufreq_us3_driver); |
263 | cpufreq_us3_driver = NULL; |
264 | kfree(us3_freq_table); |
265 | us3_freq_table = NULL; |
266 | } |
267 | } |
268 | |
269 | MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); |
270 | MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III"); |
271 | MODULE_LICENSE("GPL"); |
272 | |
273 | module_init(us3_freq_init); |
274 | module_exit(us3_freq_exit); |
275 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9