1 // SPDX-License-Identifier: GPL-2.0-only
2 /* us2e_cpufreq.c: UltraSPARC-IIe cpu frequency support
4 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
6 * Many thanks to Dominik Brodowski for fixing up the cpufreq
7 * infrastructure in order to make this driver easier to implement.
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/sched.h>
13 #include <linux/smp.h>
14 #include <linux/cpufreq.h>
15 #include <linux/threads.h>
16 #include <linux/slab.h>
17 #include <linux/delay.h>
18 #include <linux/init.h>
21 #include <asm/timer.h>
23 struct us2e_freq_percpu_info
{
24 struct cpufreq_frequency_table table
[6];
27 /* Indexed by cpu number. */
28 static struct us2e_freq_percpu_info
*us2e_freq_table
;
30 #define HBIRD_MEM_CNTL0_ADDR 0x1fe0000f010UL
31 #define HBIRD_ESTAR_MODE_ADDR 0x1fe0000f080UL
33 /* UltraSPARC-IIe has five dividers: 1, 2, 4, 6, and 8. These are controlled
34 * in the ESTAR mode control register.
36 #define ESTAR_MODE_DIV_1 0x0000000000000000UL
37 #define ESTAR_MODE_DIV_2 0x0000000000000001UL
38 #define ESTAR_MODE_DIV_4 0x0000000000000003UL
39 #define ESTAR_MODE_DIV_6 0x0000000000000002UL
40 #define ESTAR_MODE_DIV_8 0x0000000000000004UL
41 #define ESTAR_MODE_DIV_MASK 0x0000000000000007UL
43 #define MCTRL0_SREFRESH_ENAB 0x0000000000010000UL
44 #define MCTRL0_REFR_COUNT_MASK 0x0000000000007f00UL
45 #define MCTRL0_REFR_COUNT_SHIFT 8
46 #define MCTRL0_REFR_INTERVAL 7800
47 #define MCTRL0_REFR_CLKS_P_CNT 64
49 static unsigned long read_hbreg(unsigned long addr
)
53 __asm__
__volatile__("ldxa [%1] %2, %0"
55 : "r" (addr
), "i" (ASI_PHYS_BYPASS_EC_E
));
59 static void write_hbreg(unsigned long addr
, unsigned long val
)
61 __asm__
__volatile__("stxa %0, [%1] %2\n\t"
64 : "r" (val
), "r" (addr
), "i" (ASI_PHYS_BYPASS_EC_E
)
66 if (addr
== HBIRD_ESTAR_MODE_ADDR
) {
67 /* Need to wait 16 clock cycles for the PLL to lock. */
72 static void self_refresh_ctl(int enable
)
74 unsigned long mctrl
= read_hbreg(HBIRD_MEM_CNTL0_ADDR
);
77 mctrl
|= MCTRL0_SREFRESH_ENAB
;
79 mctrl
&= ~MCTRL0_SREFRESH_ENAB
;
80 write_hbreg(HBIRD_MEM_CNTL0_ADDR
, mctrl
);
81 (void) read_hbreg(HBIRD_MEM_CNTL0_ADDR
);
84 static void frob_mem_refresh(int cpu_slowing_down
,
85 unsigned long clock_tick
,
86 unsigned long old_divisor
, unsigned long divisor
)
88 unsigned long old_refr_count
, refr_count
, mctrl
;
90 refr_count
= (clock_tick
* MCTRL0_REFR_INTERVAL
);
91 refr_count
/= (MCTRL0_REFR_CLKS_P_CNT
* divisor
* 1000000000UL);
93 mctrl
= read_hbreg(HBIRD_MEM_CNTL0_ADDR
);
94 old_refr_count
= (mctrl
& MCTRL0_REFR_COUNT_MASK
)
95 >> MCTRL0_REFR_COUNT_SHIFT
;
97 mctrl
&= ~MCTRL0_REFR_COUNT_MASK
;
98 mctrl
|= refr_count
<< MCTRL0_REFR_COUNT_SHIFT
;
99 write_hbreg(HBIRD_MEM_CNTL0_ADDR
, mctrl
);
100 mctrl
= read_hbreg(HBIRD_MEM_CNTL0_ADDR
);
102 if (cpu_slowing_down
&& !(mctrl
& MCTRL0_SREFRESH_ENAB
)) {
105 /* We have to wait for both refresh counts (old
106 * and new) to go to zero.
108 usecs
= (MCTRL0_REFR_CLKS_P_CNT
*
109 (refr_count
+ old_refr_count
) *
111 old_divisor
) / clock_tick
;
116 static void us2e_transition(unsigned long estar
, unsigned long new_bits
,
117 unsigned long clock_tick
,
118 unsigned long old_divisor
, unsigned long divisor
)
120 estar
&= ~ESTAR_MODE_DIV_MASK
;
122 /* This is based upon the state transition diagram in the IIe manual. */
123 if (old_divisor
== 2 && divisor
== 1) {
125 write_hbreg(HBIRD_ESTAR_MODE_ADDR
, estar
| new_bits
);
126 frob_mem_refresh(0, clock_tick
, old_divisor
, divisor
);
127 } else if (old_divisor
== 1 && divisor
== 2) {
128 frob_mem_refresh(1, clock_tick
, old_divisor
, divisor
);
129 write_hbreg(HBIRD_ESTAR_MODE_ADDR
, estar
| new_bits
);
131 } else if (old_divisor
== 1 && divisor
> 2) {
132 us2e_transition(estar
, ESTAR_MODE_DIV_2
, clock_tick
,
134 us2e_transition(estar
, new_bits
, clock_tick
,
136 } else if (old_divisor
> 2 && divisor
== 1) {
137 us2e_transition(estar
, ESTAR_MODE_DIV_2
, clock_tick
,
139 us2e_transition(estar
, new_bits
, clock_tick
,
141 } else if (old_divisor
< divisor
) {
142 frob_mem_refresh(0, clock_tick
, old_divisor
, divisor
);
143 write_hbreg(HBIRD_ESTAR_MODE_ADDR
, estar
| new_bits
);
144 } else if (old_divisor
> divisor
) {
145 write_hbreg(HBIRD_ESTAR_MODE_ADDR
, estar
| new_bits
);
146 frob_mem_refresh(1, clock_tick
, old_divisor
, divisor
);
152 static unsigned long index_to_estar_mode(unsigned int index
)
156 return ESTAR_MODE_DIV_1
;
159 return ESTAR_MODE_DIV_2
;
162 return ESTAR_MODE_DIV_4
;
165 return ESTAR_MODE_DIV_6
;
168 return ESTAR_MODE_DIV_8
;
175 static unsigned long index_to_divisor(unsigned int index
)
198 static unsigned long estar_to_divisor(unsigned long estar
)
202 switch (estar
& ESTAR_MODE_DIV_MASK
) {
203 case ESTAR_MODE_DIV_1
:
206 case ESTAR_MODE_DIV_2
:
209 case ESTAR_MODE_DIV_4
:
212 case ESTAR_MODE_DIV_6
:
215 case ESTAR_MODE_DIV_8
:
225 static void __us2e_freq_get(void *arg
)
227 unsigned long *estar
= arg
;
229 *estar
= read_hbreg(HBIRD_ESTAR_MODE_ADDR
);
232 static unsigned int us2e_freq_get(unsigned int cpu
)
234 unsigned long clock_tick
, estar
;
236 clock_tick
= sparc64_get_clock_tick(cpu
) / 1000;
237 if (smp_call_function_single(cpu
, __us2e_freq_get
, &estar
, 1))
240 return clock_tick
/ estar_to_divisor(estar
);
243 static void __us2e_freq_target(void *arg
)
245 unsigned int cpu
= smp_processor_id();
246 unsigned int *index
= arg
;
247 unsigned long new_bits
, new_freq
;
248 unsigned long clock_tick
, divisor
, old_divisor
, estar
;
250 new_freq
= clock_tick
= sparc64_get_clock_tick(cpu
) / 1000;
251 new_bits
= index_to_estar_mode(*index
);
252 divisor
= index_to_divisor(*index
);
255 estar
= read_hbreg(HBIRD_ESTAR_MODE_ADDR
);
257 old_divisor
= estar_to_divisor(estar
);
259 if (old_divisor
!= divisor
) {
260 us2e_transition(estar
, new_bits
, clock_tick
* 1000,
261 old_divisor
, divisor
);
265 static int us2e_freq_target(struct cpufreq_policy
*policy
, unsigned int index
)
267 unsigned int cpu
= policy
->cpu
;
269 return smp_call_function_single(cpu
, __us2e_freq_target
, &index
, 1);
272 static int us2e_freq_cpu_init(struct cpufreq_policy
*policy
)
274 unsigned int cpu
= policy
->cpu
;
275 unsigned long clock_tick
= sparc64_get_clock_tick(cpu
) / 1000;
276 struct cpufreq_frequency_table
*table
=
277 &us2e_freq_table
[cpu
].table
[0];
279 table
[0].driver_data
= 0;
280 table
[0].frequency
= clock_tick
/ 1;
281 table
[1].driver_data
= 1;
282 table
[1].frequency
= clock_tick
/ 2;
283 table
[2].driver_data
= 2;
284 table
[2].frequency
= clock_tick
/ 4;
285 table
[2].driver_data
= 3;
286 table
[2].frequency
= clock_tick
/ 6;
287 table
[2].driver_data
= 4;
288 table
[2].frequency
= clock_tick
/ 8;
289 table
[2].driver_data
= 5;
290 table
[3].frequency
= CPUFREQ_TABLE_END
;
292 policy
->cpuinfo
.transition_latency
= 0;
293 policy
->cur
= clock_tick
;
294 policy
->freq_table
= table
;
299 static void us2e_freq_cpu_exit(struct cpufreq_policy
*policy
)
301 us2e_freq_target(policy
, 0);
304 static struct cpufreq_driver cpufreq_us2e_driver
= {
305 .name
= "UltraSPARC-IIe",
306 .init
= us2e_freq_cpu_init
,
307 .verify
= cpufreq_generic_frequency_table_verify
,
308 .target_index
= us2e_freq_target
,
309 .get
= us2e_freq_get
,
310 .exit
= us2e_freq_cpu_exit
,
313 static int __init
us2e_freq_init(void)
315 unsigned long manuf
, impl
, ver
;
318 if (tlb_type
!= spitfire
)
321 __asm__("rdpr %%ver, %0" : "=r" (ver
));
322 manuf
= ((ver
>> 48) & 0xffff);
323 impl
= ((ver
>> 32) & 0xffff);
325 if (manuf
== 0x17 && impl
== 0x13) {
326 us2e_freq_table
= kzalloc(NR_CPUS
* sizeof(*us2e_freq_table
),
328 if (!us2e_freq_table
)
331 ret
= cpufreq_register_driver(&cpufreq_us2e_driver
);
333 kfree(us2e_freq_table
);
341 static void __exit
us2e_freq_exit(void)
343 cpufreq_unregister_driver(&cpufreq_us2e_driver
);
344 kfree(us2e_freq_table
);
347 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
348 MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-IIe");
349 MODULE_LICENSE("GPL");
351 module_init(us2e_freq_init
);
352 module_exit(us2e_freq_exit
);