9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/sched.h>
15 #include <linux/slab.h>
20 #include <asm/timer.h>
31 #define HBIRD_MEM_CNTL0_ADDR 0x1fe0000f010UL
32 #define HBIRD_ESTAR_MODE_ADDR 0x1fe0000f080UL
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"
60 static void write_hbreg(
unsigned long addr,
unsigned long val)
62 __asm__ __volatile__(
"stxa %0, [%1] %2\n\t"
73 static void self_refresh_ctl(
int enable)
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;
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)
128 if (old_divisor == 2 && divisor == 1) {
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);
136 }
else if (old_divisor == 1 && divisor > 2) {
139 us2e_transition(estar, new_bits, clock_tick,
141 }
else if (old_divisor > 2 && divisor == 1) {
144 us2e_transition(estar, new_bits, clock_tick,
146 }
else if (old_divisor < divisor) {
147 frob_mem_refresh(0, clock_tick, old_divisor, divisor);
149 }
else if (old_divisor > divisor) {
151 frob_mem_refresh(1, clock_tick, old_divisor, divisor);
159 static unsigned long index_to_estar_mode(
unsigned int index)
182 static unsigned long index_to_divisor(
unsigned int index)
205 static unsigned long estar_to_divisor(
unsigned long estar)
232 static unsigned int us2e_freq_get(
unsigned int cpu)
235 unsigned long clock_tick, estar;
246 set_cpus_allowed_ptr(
current, &cpus_allowed);
248 return clock_tick / estar_to_divisor(estar);
251 static void us2e_set_cpu_divider_index(
unsigned int cpu,
unsigned int index)
253 unsigned long new_bits, new_freq;
254 unsigned long clock_tick,
divisor, old_divisor, estar;
265 new_bits = index_to_estar_mode(index);
266 divisor = index_to_divisor(index);
271 old_divisor = estar_to_divisor(estar);
273 freqs.old = clock_tick / old_divisor;
274 freqs.new = new_freq;
278 if (old_divisor != divisor)
279 us2e_transition(estar, new_bits, clock_tick * 1000,
280 old_divisor, divisor);
284 set_cpus_allowed_ptr(
current, &cpus_allowed);
288 unsigned int target_freq,
289 unsigned int relation)
291 unsigned int new_index = 0;
294 &us2e_freq_table[policy->
cpu].
table[0],
295 target_freq, relation, &new_index))
298 us2e_set_cpu_divider_index(policy->
cpu, new_index);
306 &us2e_freq_table[policy->
cpu].
table[0]);
311 unsigned int cpu = policy->
cpu;
329 policy->
cpuinfo.transition_latency = 0;
330 policy->
cur = clock_tick;
337 if (cpufreq_us2e_driver)
338 us2e_set_cpu_divider_index(policy->
cpu, 0);
343 static int __init us2e_freq_init(
void)
345 unsigned long manuf, impl,
ver;
351 __asm__(
"rdpr %%ver, %0" :
"=r" (ver));
352 manuf = ((ver >> 48) & 0xffff);
353 impl = ((ver >> 32) & 0xffff);
355 if (manuf == 0x17 && impl == 0x13) {
363 us2e_freq_table = kzalloc(
366 if (!us2e_freq_table)
369 driver->
init = us2e_freq_cpu_init;
370 driver->
verify = us2e_freq_verify;
371 driver->
target = us2e_freq_target;
372 driver->
get = us2e_freq_get;
373 driver->
exit = us2e_freq_cpu_exit;
377 cpufreq_us2e_driver =
driver;
387 cpufreq_us2e_driver =
NULL;
389 kfree(us2e_freq_table);
390 us2e_freq_table =
NULL;
397 static void __exit us2e_freq_exit(
void)
399 if (cpufreq_us2e_driver) {
401 kfree(cpufreq_us2e_driver);
402 cpufreq_us2e_driver =
NULL;
403 kfree(us2e_freq_table);
404 us2e_freq_table =
NULL;