Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[linux-2.6-microblaze.git] / drivers / cpufreq / sparc-us2e-cpufreq.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* us2e_cpufreq.c: UltraSPARC-IIe cpu frequency support
3  *
4  * Copyright (C) 2003 David S. Miller (davem@redhat.com)
5  *
6  * Many thanks to Dominik Brodowski for fixing up the cpufreq
7  * infrastructure in order to make this driver easier to implement.
8  */
9
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>
19
20 #include <asm/asi.h>
21 #include <asm/timer.h>
22
23 static struct cpufreq_driver *cpufreq_us2e_driver;
24
25 struct us2e_freq_percpu_info {
26         struct cpufreq_frequency_table table[6];
27 };
28
29 /* Indexed by cpu number. */
30 static struct us2e_freq_percpu_info *us2e_freq_table;
31
32 #define HBIRD_MEM_CNTL0_ADDR    0x1fe0000f010UL
33 #define HBIRD_ESTAR_MODE_ADDR   0x1fe0000f080UL
34
35 /* UltraSPARC-IIe has five dividers: 1, 2, 4, 6, and 8.  These are controlled
36  * in the ESTAR mode control register.
37  */
38 #define ESTAR_MODE_DIV_1        0x0000000000000000UL
39 #define ESTAR_MODE_DIV_2        0x0000000000000001UL
40 #define ESTAR_MODE_DIV_4        0x0000000000000003UL
41 #define ESTAR_MODE_DIV_6        0x0000000000000002UL
42 #define ESTAR_MODE_DIV_8        0x0000000000000004UL
43 #define ESTAR_MODE_DIV_MASK     0x0000000000000007UL
44
45 #define MCTRL0_SREFRESH_ENAB    0x0000000000010000UL
46 #define MCTRL0_REFR_COUNT_MASK  0x0000000000007f00UL
47 #define MCTRL0_REFR_COUNT_SHIFT 8
48 #define MCTRL0_REFR_INTERVAL    7800
49 #define MCTRL0_REFR_CLKS_P_CNT  64
50
51 static unsigned long read_hbreg(unsigned long addr)
52 {
53         unsigned long ret;
54
55         __asm__ __volatile__("ldxa      [%1] %2, %0"
56                              : "=&r" (ret)
57                              : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
58         return ret;
59 }
60
61 static void write_hbreg(unsigned long addr, unsigned long val)
62 {
63         __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
64                              "membar    #Sync"
65                              : /* no outputs */
66                              : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E)
67                              : "memory");
68         if (addr == HBIRD_ESTAR_MODE_ADDR) {
69                 /* Need to wait 16 clock cycles for the PLL to lock.  */
70                 udelay(1);
71         }
72 }
73
74 static void self_refresh_ctl(int enable)
75 {
76         unsigned long mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
77
78         if (enable)
79                 mctrl |= MCTRL0_SREFRESH_ENAB;
80         else
81                 mctrl &= ~MCTRL0_SREFRESH_ENAB;
82         write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl);
83         (void) read_hbreg(HBIRD_MEM_CNTL0_ADDR);
84 }
85
86 static void frob_mem_refresh(int cpu_slowing_down,
87                              unsigned long clock_tick,
88                              unsigned long old_divisor, unsigned long divisor)
89 {
90         unsigned long old_refr_count, refr_count, mctrl;
91
92         refr_count  = (clock_tick * MCTRL0_REFR_INTERVAL);
93         refr_count /= (MCTRL0_REFR_CLKS_P_CNT * divisor * 1000000000UL);
94
95         mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
96         old_refr_count = (mctrl & MCTRL0_REFR_COUNT_MASK)
97                 >> MCTRL0_REFR_COUNT_SHIFT;
98
99         mctrl &= ~MCTRL0_REFR_COUNT_MASK;
100         mctrl |= refr_count << MCTRL0_REFR_COUNT_SHIFT;
101         write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl);
102         mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
103
104         if (cpu_slowing_down && !(mctrl & MCTRL0_SREFRESH_ENAB)) {
105                 unsigned long usecs;
106
107                 /* We have to wait for both refresh counts (old
108                  * and new) to go to zero.
109                  */
110                 usecs = (MCTRL0_REFR_CLKS_P_CNT *
111                          (refr_count + old_refr_count) *
112                          1000000UL *
113                          old_divisor) / clock_tick;
114                 udelay(usecs + 1UL);
115         }
116 }
117
118 static void us2e_transition(unsigned long estar, unsigned long new_bits,
119                             unsigned long clock_tick,
120                             unsigned long old_divisor, unsigned long divisor)
121 {
122         estar &= ~ESTAR_MODE_DIV_MASK;
123
124         /* This is based upon the state transition diagram in the IIe manual.  */
125         if (old_divisor == 2 && divisor == 1) {
126                 self_refresh_ctl(0);
127                 write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
128                 frob_mem_refresh(0, clock_tick, old_divisor, divisor);
129         } else if (old_divisor == 1 && divisor == 2) {
130                 frob_mem_refresh(1, clock_tick, old_divisor, divisor);
131                 write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
132                 self_refresh_ctl(1);
133         } else if (old_divisor == 1 && divisor > 2) {
134                 us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick,
135                                 1, 2);
136                 us2e_transition(estar, new_bits, clock_tick,
137                                 2, divisor);
138         } else if (old_divisor > 2 && divisor == 1) {
139                 us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick,
140                                 old_divisor, 2);
141                 us2e_transition(estar, new_bits, clock_tick,
142                                 2, divisor);
143         } else if (old_divisor < divisor) {
144                 frob_mem_refresh(0, clock_tick, old_divisor, divisor);
145                 write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
146         } else if (old_divisor > divisor) {
147                 write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
148                 frob_mem_refresh(1, clock_tick, old_divisor, divisor);
149         } else {
150                 BUG();
151         }
152 }
153
154 static unsigned long index_to_estar_mode(unsigned int index)
155 {
156         switch (index) {
157         case 0:
158                 return ESTAR_MODE_DIV_1;
159
160         case 1:
161                 return ESTAR_MODE_DIV_2;
162
163         case 2:
164                 return ESTAR_MODE_DIV_4;
165
166         case 3:
167                 return ESTAR_MODE_DIV_6;
168
169         case 4:
170                 return ESTAR_MODE_DIV_8;
171
172         default:
173                 BUG();
174         }
175 }
176
177 static unsigned long index_to_divisor(unsigned int index)
178 {
179         switch (index) {
180         case 0:
181                 return 1;
182
183         case 1:
184                 return 2;
185
186         case 2:
187                 return 4;
188
189         case 3:
190                 return 6;
191
192         case 4:
193                 return 8;
194
195         default:
196                 BUG();
197         }
198 }
199
200 static unsigned long estar_to_divisor(unsigned long estar)
201 {
202         unsigned long ret;
203
204         switch (estar & ESTAR_MODE_DIV_MASK) {
205         case ESTAR_MODE_DIV_1:
206                 ret = 1;
207                 break;
208         case ESTAR_MODE_DIV_2:
209                 ret = 2;
210                 break;
211         case ESTAR_MODE_DIV_4:
212                 ret = 4;
213                 break;
214         case ESTAR_MODE_DIV_6:
215                 ret = 6;
216                 break;
217         case ESTAR_MODE_DIV_8:
218                 ret = 8;
219                 break;
220         default:
221                 BUG();
222         }
223
224         return ret;
225 }
226
227 static void __us2e_freq_get(void *arg)
228 {
229         unsigned long *estar = arg;
230
231         *estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR);
232 }
233
234 static unsigned int us2e_freq_get(unsigned int cpu)
235 {
236         unsigned long clock_tick, estar;
237
238         clock_tick = sparc64_get_clock_tick(cpu) / 1000;
239         if (smp_call_function_single(cpu, __us2e_freq_get, &estar, 1))
240                 return 0;
241
242         return clock_tick / estar_to_divisor(estar);
243 }
244
245 static void __us2e_freq_target(void *arg)
246 {
247         unsigned int cpu = smp_processor_id();
248         unsigned int *index = arg;
249         unsigned long new_bits, new_freq;
250         unsigned long clock_tick, divisor, old_divisor, estar;
251
252         new_freq = clock_tick = sparc64_get_clock_tick(cpu) / 1000;
253         new_bits = index_to_estar_mode(*index);
254         divisor = index_to_divisor(*index);
255         new_freq /= divisor;
256
257         estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR);
258
259         old_divisor = estar_to_divisor(estar);
260
261         if (old_divisor != divisor) {
262                 us2e_transition(estar, new_bits, clock_tick * 1000,
263                                 old_divisor, divisor);
264         }
265 }
266
267 static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index)
268 {
269         unsigned int cpu = policy->cpu;
270
271         return smp_call_function_single(cpu, __us2e_freq_target, &index, 1);
272 }
273
274 static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
275 {
276         unsigned int cpu = policy->cpu;
277         unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000;
278         struct cpufreq_frequency_table *table =
279                 &us2e_freq_table[cpu].table[0];
280
281         table[0].driver_data = 0;
282         table[0].frequency = clock_tick / 1;
283         table[1].driver_data = 1;
284         table[1].frequency = clock_tick / 2;
285         table[2].driver_data = 2;
286         table[2].frequency = clock_tick / 4;
287         table[2].driver_data = 3;
288         table[2].frequency = clock_tick / 6;
289         table[2].driver_data = 4;
290         table[2].frequency = clock_tick / 8;
291         table[2].driver_data = 5;
292         table[3].frequency = CPUFREQ_TABLE_END;
293
294         policy->cpuinfo.transition_latency = 0;
295         policy->cur = clock_tick;
296         policy->freq_table = table;
297
298         return 0;
299 }
300
301 static int us2e_freq_cpu_exit(struct cpufreq_policy *policy)
302 {
303         if (cpufreq_us2e_driver)
304                 us2e_freq_target(policy, 0);
305
306         return 0;
307 }
308
309 static int __init us2e_freq_init(void)
310 {
311         unsigned long manuf, impl, ver;
312         int ret;
313
314         if (tlb_type != spitfire)
315                 return -ENODEV;
316
317         __asm__("rdpr %%ver, %0" : "=r" (ver));
318         manuf = ((ver >> 48) & 0xffff);
319         impl  = ((ver >> 32) & 0xffff);
320
321         if (manuf == 0x17 && impl == 0x13) {
322                 struct cpufreq_driver *driver;
323
324                 ret = -ENOMEM;
325                 driver = kzalloc(sizeof(*driver), GFP_KERNEL);
326                 if (!driver)
327                         goto err_out;
328
329                 us2e_freq_table = kzalloc((NR_CPUS * sizeof(*us2e_freq_table)),
330                         GFP_KERNEL);
331                 if (!us2e_freq_table)
332                         goto err_out;
333
334                 driver->init = us2e_freq_cpu_init;
335                 driver->verify = cpufreq_generic_frequency_table_verify;
336                 driver->target_index = us2e_freq_target;
337                 driver->get = us2e_freq_get;
338                 driver->exit = us2e_freq_cpu_exit;
339                 strcpy(driver->name, "UltraSPARC-IIe");
340
341                 cpufreq_us2e_driver = driver;
342                 ret = cpufreq_register_driver(driver);
343                 if (ret)
344                         goto err_out;
345
346                 return 0;
347
348 err_out:
349                 if (driver) {
350                         kfree(driver);
351                         cpufreq_us2e_driver = NULL;
352                 }
353                 kfree(us2e_freq_table);
354                 us2e_freq_table = NULL;
355                 return ret;
356         }
357
358         return -ENODEV;
359 }
360
361 static void __exit us2e_freq_exit(void)
362 {
363         if (cpufreq_us2e_driver) {
364                 cpufreq_unregister_driver(cpufreq_us2e_driver);
365                 kfree(cpufreq_us2e_driver);
366                 cpufreq_us2e_driver = NULL;
367                 kfree(us2e_freq_table);
368                 us2e_freq_table = NULL;
369         }
370 }
371
372 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
373 MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-IIe");
374 MODULE_LICENSE("GPL");
375
376 module_init(us2e_freq_init);
377 module_exit(us2e_freq_exit);