1 /* us2e_cpufreq.c: UltraSPARC-IIe cpu frequency support
3 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
5 * Many thanks to Dominik Brodowski for fixing up the cpufreq
6 * infrastructure in order to make this driver easier to implement.
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/delay.h>
17 #include <linux/init.h>
20 #include <asm/timer.h>
22 static struct cpufreq_driver
*cpufreq_us2e_driver
;
24 struct us2e_freq_percpu_info
{
25 struct cpufreq_frequency_table table
[6];
28 /* Indexed by cpu number. */
29 static struct us2e_freq_percpu_info
*us2e_freq_table
;
31 #define HBIRD_MEM_CNTL0_ADDR 0x1fe0000f010UL
32 #define HBIRD_ESTAR_MODE_ADDR 0x1fe0000f080UL
34 /* UltraSPARC-IIe has five dividers: 1, 2, 4, 6, and 8. These are controlled
35 * in the ESTAR mode control register.
37 #define ESTAR_MODE_DIV_1 0x0000000000000000UL
38 #define ESTAR_MODE_DIV_2 0x0000000000000001UL
39 #define ESTAR_MODE_DIV_4 0x0000000000000003UL
40 #define ESTAR_MODE_DIV_6 0x0000000000000002UL
41 #define ESTAR_MODE_DIV_8 0x0000000000000004UL
42 #define ESTAR_MODE_DIV_MASK 0x0000000000000007UL
44 #define MCTRL0_SREFRESH_ENAB 0x0000000000010000UL
45 #define MCTRL0_REFR_COUNT_MASK 0x0000000000007f00UL
46 #define MCTRL0_REFR_COUNT_SHIFT 8
47 #define MCTRL0_REFR_INTERVAL 7800
48 #define MCTRL0_REFR_CLKS_P_CNT 64
50 static unsigned long read_hbreg(unsigned long addr
)
54 __asm__
__volatile__("ldxa [%1] %2, %0"
56 : "r" (addr
), "i" (ASI_PHYS_BYPASS_EC_E
));
60 static void write_hbreg(unsigned long addr
, unsigned long val
)
62 __asm__
__volatile__("stxa %0, [%1] %2\n\t"
65 : "r" (val
), "r" (addr
), "i" (ASI_PHYS_BYPASS_EC_E
)
67 if (addr
== HBIRD_ESTAR_MODE_ADDR
) {
68 /* Need to wait 16 clock cycles for the PLL to lock. */
73 static void self_refresh_ctl(int enable
)
75 unsigned long mctrl
= read_hbreg(HBIRD_MEM_CNTL0_ADDR
);
78 mctrl
|= MCTRL0_SREFRESH_ENAB
;
80 mctrl
&= ~MCTRL0_SREFRESH_ENAB
;
81 write_hbreg(HBIRD_MEM_CNTL0_ADDR
, mctrl
);
82 (void) read_hbreg(HBIRD_MEM_CNTL0_ADDR
);
85 static void frob_mem_refresh(int cpu_slowing_down
,
86 unsigned long clock_tick
,
87 unsigned long old_divisor
, unsigned long divisor
)
89 unsigned long old_refr_count
, refr_count
, mctrl
;
91 refr_count
= (clock_tick
* MCTRL0_REFR_INTERVAL
);
92 refr_count
/= (MCTRL0_REFR_CLKS_P_CNT
* divisor
* 1000000000UL);
94 mctrl
= read_hbreg(HBIRD_MEM_CNTL0_ADDR
);
95 old_refr_count
= (mctrl
& MCTRL0_REFR_COUNT_MASK
)
96 >> MCTRL0_REFR_COUNT_SHIFT
;
98 mctrl
&= ~MCTRL0_REFR_COUNT_MASK
;
99 mctrl
|= refr_count
<< MCTRL0_REFR_COUNT_SHIFT
;
100 write_hbreg(HBIRD_MEM_CNTL0_ADDR
, mctrl
);
101 mctrl
= read_hbreg(HBIRD_MEM_CNTL0_ADDR
);
103 if (cpu_slowing_down
&& !(mctrl
& MCTRL0_SREFRESH_ENAB
)) {
106 /* We have to wait for both refresh counts (old
107 * and new) to go to zero.
109 usecs
= (MCTRL0_REFR_CLKS_P_CNT
*
110 (refr_count
+ old_refr_count
) *
112 old_divisor
) / clock_tick
;
117 static void us2e_transition(unsigned long estar
, unsigned long new_bits
,
118 unsigned long clock_tick
,
119 unsigned long old_divisor
, unsigned long divisor
)
123 local_irq_save(flags
);
125 estar
&= ~ESTAR_MODE_DIV_MASK
;
127 /* This is based upon the state transition diagram in the IIe manual. */
128 if (old_divisor
== 2 && divisor
== 1) {
130 write_hbreg(HBIRD_ESTAR_MODE_ADDR
, estar
| new_bits
);
131 frob_mem_refresh(0, clock_tick
, old_divisor
, divisor
);
132 } else if (old_divisor
== 1 && divisor
== 2) {
133 frob_mem_refresh(1, clock_tick
, old_divisor
, divisor
);
134 write_hbreg(HBIRD_ESTAR_MODE_ADDR
, estar
| new_bits
);
136 } else if (old_divisor
== 1 && divisor
> 2) {
137 us2e_transition(estar
, ESTAR_MODE_DIV_2
, clock_tick
,
139 us2e_transition(estar
, new_bits
, clock_tick
,
141 } else if (old_divisor
> 2 && divisor
== 1) {
142 us2e_transition(estar
, ESTAR_MODE_DIV_2
, clock_tick
,
144 us2e_transition(estar
, new_bits
, clock_tick
,
146 } else if (old_divisor
< divisor
) {
147 frob_mem_refresh(0, clock_tick
, old_divisor
, divisor
);
148 write_hbreg(HBIRD_ESTAR_MODE_ADDR
, estar
| new_bits
);
149 } else if (old_divisor
> divisor
) {
150 write_hbreg(HBIRD_ESTAR_MODE_ADDR
, estar
| new_bits
);
151 frob_mem_refresh(1, clock_tick
, old_divisor
, divisor
);
156 local_irq_restore(flags
);
159 static unsigned long index_to_estar_mode(unsigned int index
)
163 return ESTAR_MODE_DIV_1
;
166 return ESTAR_MODE_DIV_2
;
169 return ESTAR_MODE_DIV_4
;
172 return ESTAR_MODE_DIV_6
;
175 return ESTAR_MODE_DIV_8
;
182 static unsigned long index_to_divisor(unsigned int index
)
205 static unsigned long estar_to_divisor(unsigned long estar
)
209 switch (estar
& ESTAR_MODE_DIV_MASK
) {
210 case ESTAR_MODE_DIV_1
:
213 case ESTAR_MODE_DIV_2
:
216 case ESTAR_MODE_DIV_4
:
219 case ESTAR_MODE_DIV_6
:
222 case ESTAR_MODE_DIV_8
:
232 static unsigned int us2e_freq_get(unsigned int cpu
)
234 cpumask_t cpus_allowed
;
235 unsigned long clock_tick
, estar
;
237 cpumask_copy(&cpus_allowed
, tsk_cpus_allowed(current
));
238 set_cpus_allowed_ptr(current
, cpumask_of(cpu
));
240 clock_tick
= sparc64_get_clock_tick(cpu
) / 1000;
241 estar
= read_hbreg(HBIRD_ESTAR_MODE_ADDR
);
243 set_cpus_allowed_ptr(current
, &cpus_allowed
);
245 return clock_tick
/ estar_to_divisor(estar
);
248 static void us2e_set_cpu_divider_index(struct cpufreq_policy
*policy
,
251 unsigned int cpu
= policy
->cpu
;
252 unsigned long new_bits
, new_freq
;
253 unsigned long clock_tick
, divisor
, old_divisor
, estar
;
254 cpumask_t cpus_allowed
;
255 struct cpufreq_freqs freqs
;
257 cpumask_copy(&cpus_allowed
, tsk_cpus_allowed(current
));
258 set_cpus_allowed_ptr(current
, cpumask_of(cpu
));
260 new_freq
= clock_tick
= sparc64_get_clock_tick(cpu
) / 1000;
261 new_bits
= index_to_estar_mode(index
);
262 divisor
= index_to_divisor(index
);
265 estar
= read_hbreg(HBIRD_ESTAR_MODE_ADDR
);
267 old_divisor
= estar_to_divisor(estar
);
269 freqs
.old
= clock_tick
/ old_divisor
;
270 freqs
.new = new_freq
;
271 cpufreq_notify_transition(policy
, &freqs
, CPUFREQ_PRECHANGE
);
273 if (old_divisor
!= divisor
)
274 us2e_transition(estar
, new_bits
, clock_tick
* 1000,
275 old_divisor
, divisor
);
277 cpufreq_notify_transition(policy
, &freqs
, CPUFREQ_POSTCHANGE
);
279 set_cpus_allowed_ptr(current
, &cpus_allowed
);
282 static int us2e_freq_target(struct cpufreq_policy
*policy
,
283 unsigned int target_freq
,
284 unsigned int relation
)
286 unsigned int new_index
= 0;
288 if (cpufreq_frequency_table_target(policy
,
289 &us2e_freq_table
[policy
->cpu
].table
[0],
290 target_freq
, relation
, &new_index
))
293 us2e_set_cpu_divider_index(policy
, new_index
);
298 static int us2e_freq_verify(struct cpufreq_policy
*policy
)
300 return cpufreq_frequency_table_verify(policy
,
301 &us2e_freq_table
[policy
->cpu
].table
[0]);
304 static int __init
us2e_freq_cpu_init(struct cpufreq_policy
*policy
)
306 unsigned int cpu
= policy
->cpu
;
307 unsigned long clock_tick
= sparc64_get_clock_tick(cpu
) / 1000;
308 struct cpufreq_frequency_table
*table
=
309 &us2e_freq_table
[cpu
].table
[0];
312 table
[0].frequency
= clock_tick
/ 1;
314 table
[1].frequency
= clock_tick
/ 2;
316 table
[2].frequency
= clock_tick
/ 4;
318 table
[2].frequency
= clock_tick
/ 6;
320 table
[2].frequency
= clock_tick
/ 8;
322 table
[3].frequency
= CPUFREQ_TABLE_END
;
324 policy
->cpuinfo
.transition_latency
= 0;
325 policy
->cur
= clock_tick
;
327 return cpufreq_frequency_table_cpuinfo(policy
, table
);
330 static int us2e_freq_cpu_exit(struct cpufreq_policy
*policy
)
332 if (cpufreq_us2e_driver
)
333 us2e_set_cpu_divider_index(policy
, 0);
338 static int __init
us2e_freq_init(void)
340 unsigned long manuf
, impl
, ver
;
343 if (tlb_type
!= spitfire
)
346 __asm__("rdpr %%ver, %0" : "=r" (ver
));
347 manuf
= ((ver
>> 48) & 0xffff);
348 impl
= ((ver
>> 32) & 0xffff);
350 if (manuf
== 0x17 && impl
== 0x13) {
351 struct cpufreq_driver
*driver
;
354 driver
= kzalloc(sizeof(struct cpufreq_driver
), GFP_KERNEL
);
358 us2e_freq_table
= kzalloc(
359 (NR_CPUS
* sizeof(struct us2e_freq_percpu_info
)),
361 if (!us2e_freq_table
)
364 driver
->init
= us2e_freq_cpu_init
;
365 driver
->verify
= us2e_freq_verify
;
366 driver
->target
= us2e_freq_target
;
367 driver
->get
= us2e_freq_get
;
368 driver
->exit
= us2e_freq_cpu_exit
;
369 driver
->owner
= THIS_MODULE
,
370 strcpy(driver
->name
, "UltraSPARC-IIe");
372 cpufreq_us2e_driver
= driver
;
373 ret
= cpufreq_register_driver(driver
);
382 cpufreq_us2e_driver
= NULL
;
384 kfree(us2e_freq_table
);
385 us2e_freq_table
= NULL
;
392 static void __exit
us2e_freq_exit(void)
394 if (cpufreq_us2e_driver
) {
395 cpufreq_unregister_driver(cpufreq_us2e_driver
);
396 kfree(cpufreq_us2e_driver
);
397 cpufreq_us2e_driver
= NULL
;
398 kfree(us2e_freq_table
);
399 us2e_freq_table
= NULL
;
403 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
404 MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-IIe");
405 MODULE_LICENSE("GPL");
407 module_init(us2e_freq_init
);
408 module_exit(us2e_freq_exit
);