0ee3533dec351a49c024fb39f0d80a4c6f2ae3e7
[openwrt.git] / target / linux / pxa / patches-2.6.21 / 010-bkpxa-pxa-cpufreq.patch
1 Status: WORKS
2 PXA CPU frequency change support
3 added mods from Stefan Eletzhofer and Lothar Weissmann
4
5 #
6 # Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
7 #
8
9 Index: linux-2.6.21.7/arch/arm/Kconfig
10 ===================================================================
11 --- linux-2.6.21.7.orig/arch/arm/Kconfig
12 +++ linux-2.6.21.7/arch/arm/Kconfig
13 @@ -800,7 +800,7 @@ config KEXEC
14  
15  endmenu
16  
17 -if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX )
18 +if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA )
19  
20  menu "CPU Frequency scaling"
21  
22 @@ -838,6 +838,12 @@ config CPU_FREQ_IMX
23  
24  endmenu
25  
26 +config CPU_FREQ_PXA
27 +       bool
28 +       depends on CPU_FREQ && ARCH_PXA
29 +       default y
30 +       select CPU_FREQ_DEFAULT_GOV_USERSPACE
31 +
32  endif
33  
34  menu "Floating point emulation"
35 Index: linux-2.6.21.7/arch/arm/mach-pxa/Makefile
36 ===================================================================
37 --- linux-2.6.21.7.orig/arch/arm/mach-pxa/Makefile
38 +++ linux-2.6.21.7/arch/arm/mach-pxa/Makefile
39 @@ -32,6 +32,7 @@ obj-$(CONFIG_LEDS) += $(led-y)
40  # Misc features
41  obj-$(CONFIG_PM) += pm.o sleep.o
42  obj-$(CONFIG_PXA_SSP) += ssp.o
43 +obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o
44  
45  ifeq ($(CONFIG_PXA27x),y)
46  obj-$(CONFIG_PM) += standby.o
47 Index: linux-2.6.21.7/arch/arm/mach-pxa/cpu-pxa.c
48 ===================================================================
49 --- /dev/null
50 +++ linux-2.6.21.7/arch/arm/mach-pxa/cpu-pxa.c
51 @@ -0,0 +1,321 @@
52 +/*
53 + *  linux/arch/arm/mach-pxa/cpu-pxa.c
54 + *
55 + *  Copyright (C) 2002,2003 Intrinsyc Software
56 + *
57 + * This program is free software; you can redistribute it and/or modify
58 + * it under the terms of the GNU General Public License as published by
59 + * the Free Software Foundation; either version 2 of the License, or
60 + * (at your option) any later version.
61 + *
62 + * This program is distributed in the hope that it will be useful,
63 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
64 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
65 + * GNU General Public License for more details.
66 + * 
67 + * You should have received a copy of the GNU General Public License
68 + * along with this program; if not, write to the Free Software
69 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
70 + *
71 + * History:
72 + *   31-Jul-2002 : Initial version [FB]
73 + *   29-Jan-2003 : added PXA255 support [FB]
74 + *   20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.)
75 + * 
76 + * Note:
77 + *   This driver may change the memory bus clock rate, but will not do any
78 + *   platform specific access timing changes... for example if you have flash
79 + *   memory connected to CS0, you will need to register a platform specific
80 + *   notifier which will adjust the memory access strobes to maintain a 
81 + *   minimum strobe width.
82 + *
83 + */
84 +
85 +#include <linux/kernel.h>
86 +#include <linux/module.h>
87 +#include <linux/sched.h>
88 +#include <linux/init.h>
89 +#include <linux/cpufreq.h>
90 +
91 +#include <asm/hardware.h>
92 +#include <asm/arch/pxa-regs.h>
93 +
94 +#define DEBUG  0
95 +
96 +#ifdef DEBUG
97 +  static unsigned int freq_debug = DEBUG;
98 +  MODULE_PARM(freq_debug, "i");
99 +  MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0");
100 +#else
101 +  #define freq_debug  0
102 +#endif  
103 +
104 +typedef struct
105 +{
106 +    unsigned int khz;
107 +    unsigned int membus;
108 +    unsigned int cccr;
109 +    unsigned int div2;
110 +} pxa_freqs_t;
111 +
112 +/* Define the refresh period in mSec for the SDRAM and the number of rows */
113 +#define SDRAM_TREF          64      /* standard 64ms SDRAM */
114 +#define SDRAM_ROWS          4096    /* 64MB=8192 32MB=4096 */ 
115 +#define MDREFR_DRI(x)       ((x*SDRAM_TREF)/(SDRAM_ROWS*32))
116 +
117 +#define CCLKCFG_TURBO       0x1
118 +#define CCLKCFG_FCS         0x2
119 +#define PXA25x_MIN_FREQ     99500
120 +#define PXA25x_MAX_FREQ     398100
121 +#define MDREFR_DB2_MASK     (MDREFR_K2DB2 | MDREFR_K1DB2)
122 +#define MDREFR_DRI_MASK     0xFFF
123 +
124 +
125 +/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */
126 +static pxa_freqs_t pxa255_run_freqs[] =
127 +{
128 +    /* CPU   MEMBUS  CCCR  DIV2*/
129 +    { 99500,  99500, 0x121, 1}, /* run= 99, turbo= 99, PXbus=50,  SDRAM=50 */
130 +    {132700, 132700, 0x123, 1}, /* run=133, turbo=133, PXbus=66,  SDRAM=66 */
131 +    {199100,  99500, 0x141, 0}, /* run=199, turbo=199, PXbus=99,  SDRAM=99 */
132 +    {265400, 132700, 0x143, 1}, /* run=265, turbo=265, PXbus=133, SDRAM=66 */
133 +    {331800, 165900, 0x145, 1}, /* run=331, turbo=331, PXbus=166, SDRAM=83 */
134 +    {398100,  99500, 0x161, 0}, /* run=398, turbo=398, PXbus=196, SDRAM=99 */
135 +    {0,}
136 +};
137 +#define NUM_RUN_FREQS (sizeof(pxa255_run_freqs)/sizeof(pxa_freqs_t))
138 +
139 +static struct cpufreq_frequency_table pxa255_run_freq_table[NUM_RUN_FREQS+1];
140 +
141 +/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
142 +static pxa_freqs_t pxa255_turbo_freqs[] =
143 +{
144 +    /* CPU   MEMBUS  CCCR  DIV2*/
145 +    { 99500, 99500,  0x121, 1}, /* run=99,  turbo= 99, PXbus=50, SDRAM=50 */
146 +    {199100, 99500,  0x221, 0}, /* run=99,  turbo=199, PXbus=50, SDRAM=99 */
147 +    {298500, 99500,  0x321, 0}, /* run=99,  turbo=287, PXbus=50, SDRAM=99 */
148 +    {298600, 99500,  0x1c1, 0}, /* run=199, turbo=287, PXbus=99, SDRAM=99 */
149 +    {398100, 99500,  0x241, 0}, /* run=199, turbo=398, PXbus=99, SDRAM=99 */
150 +    {0,}
151 +};
152 +#define NUM_TURBO_FREQS (sizeof(pxa255_turbo_freqs)/sizeof(pxa_freqs_t))
153 +
154 +static struct cpufreq_frequency_table pxa255_turbo_freq_table[NUM_TURBO_FREQS+1];
155 +
156 +extern unsigned get_clk_frequency_khz(int info);
157 +
158 +/* find a valid frequency point */
159 +static int pxa_verify_policy(struct cpufreq_policy *policy)
160 +{
161 +    int ret;
162 +    struct cpufreq_frequency_table *pxa_freqs_table;
163 +
164 +    if(policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
165 +        pxa_freqs_table = pxa255_run_freq_table;
166 +    } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
167 +        pxa_freqs_table = pxa255_turbo_freq_table;
168 +    } else {
169 +        printk("CPU PXA: Unknown policy found. "
170 +               "Using CPUFREQ_POLICY_PERFORMANCE\n");
171 +        pxa_freqs_table = pxa255_run_freq_table;
172 +    } 
173 +       ret=cpufreq_frequency_table_verify(policy, pxa_freqs_table);
174 +    
175 +    if(freq_debug) {
176 +        printk("Verified CPU policy: %dKhz min to %dKhz max\n",
177 +            policy->min, policy->max);
178 +    }
179 +
180 +    return ret;
181 +}
182 +
183 +static int pxa_set_target(struct cpufreq_policy *policy,
184 +                 unsigned int target_freq,
185 +                 unsigned int relation)
186 +{
187 +    int idx;
188 +    unsigned long cpus_allowed;
189 +    int cpu = policy->cpu;
190 +    struct cpufreq_freqs freqs;
191 +    pxa_freqs_t *pxa_freq_settings;
192 +    struct cpufreq_frequency_table *pxa_freqs_table;
193 +    unsigned long flags;
194 +    unsigned int unused;
195 +    unsigned int preset_mdrefr, postset_mdrefr;
196 +
197 +    /*
198 +     * Save this threads cpus_allowed mask.
199 +     */
200 +    cpus_allowed = current->cpus_allowed;
201 +
202 +    /*
203 +     * Bind to the specified CPU.  When this call returns,
204 +     * we should be running on the right CPU.
205 +     */
206 +    set_cpus_allowed(current, 1 << cpu);
207 +    BUG_ON(cpu != smp_processor_id());
208 +
209 +    /* Get the current policy */
210 +    if(policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
211 +        pxa_freq_settings = pxa255_run_freqs;
212 +        pxa_freqs_table   = pxa255_run_freq_table;
213 +    }else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
214 +        pxa_freq_settings = pxa255_turbo_freqs;
215 +        pxa_freqs_table   = pxa255_turbo_freq_table;
216 +    }else {
217 +        printk("CPU PXA: Unknown policy found. "
218 +               "Using CPUFREQ_POLICY_PERFORMANCE\n");
219 +        pxa_freq_settings = pxa255_run_freqs;
220 +        pxa_freqs_table   = pxa255_run_freq_table;
221 +    } 
222 +
223 +    /* Lookup the next frequency */
224 +       if (cpufreq_frequency_table_target(policy, pxa_freqs_table, 
225 +                                          target_freq, relation, &idx)) {
226 +               return -EINVAL;
227 +    }
228 +
229 +    freqs.old = policy->cur;
230 +    freqs.new = pxa_freq_settings[idx].khz;
231 +    freqs.cpu = policy->cpu;  
232 +    if(freq_debug) {
233 +        printk(KERN_INFO "Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", 
234 +            freqs.new/1000, (pxa_freq_settings[idx].div2) ? 
235 +            (pxa_freq_settings[idx].membus/2000) : 
236 +            (pxa_freq_settings[idx].membus/1000));
237 +    }
238 +
239 +    void *ramstart = phys_to_virt(0xa0000000);
240 +
241 +    /* 
242 +     * Tell everyone what we're about to do... 
243 +     * you should add a notify client with any platform specific 
244 +     * Vcc changing capability
245 +     */
246 +    cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
247 +
248 +    /* Calculate the next MDREFR.  If we're slowing down the SDRAM clock
249 +     * we need to preset the smaller DRI before the change.  If we're speeding
250 +     * up we need to set the larger DRI value after the change.  
251 +     */
252 +    preset_mdrefr = postset_mdrefr = MDREFR;
253 +    if((MDREFR & MDREFR_DRI_MASK) > MDREFR_DRI(pxa_freq_settings[idx].membus)) {    
254 +        preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK) | 
255 +                        MDREFR_DRI(pxa_freq_settings[idx].membus);
256 +    }
257 +    postset_mdrefr = (postset_mdrefr & ~MDREFR_DRI_MASK) | 
258 +                    MDREFR_DRI(pxa_freq_settings[idx].membus);
259 +    
260 +    /* If we're dividing the memory clock by two for the SDRAM clock, this
261 +     * must be set prior to the change.  Clearing the divide must be done
262 +     * after the change.
263 +     */
264 +    if(pxa_freq_settings[idx].div2) { 
265 +        preset_mdrefr  |= MDREFR_DB2_MASK;
266 +        postset_mdrefr |= MDREFR_DB2_MASK;
267 +    } else { 
268 +        postset_mdrefr &= ~MDREFR_DB2_MASK; 
269 +    }
270 +    
271 +    local_irq_save(flags);
272 +    
273 +    /* Set new the CCCR */
274 +    CCCR = pxa_freq_settings[idx].cccr;
275 +
276 +    __asm__ __volatile__("                                  \
277 +        ldr r4, [%1] ;  /* load MDREFR */                   \
278 +        b   2f ;                                            \
279 +        .align  5 ;                                         \
280 +1:                                                          \
281 +        str %4, [%1] ;          /* preset the MDREFR */     \
282 +        mcr p14, 0, %2, c6, c0, 0 ; /* set CCLKCFG[FCS] */  \
283 +        str %5, [%1] ;          /* postset the MDREFR */    \
284 +                                                            \
285 +        b   3f       ;                                      \
286 +2:      b   1b       ;                                      \
287 +3:      nop          ;                                      \
288 +        "                                                                            
289 +        : "=&r" (unused)                                                             
290 +        : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart), \
291 +          "r" (preset_mdrefr), "r" (postset_mdrefr)             
292 +        : "r4", "r5");
293 +    local_irq_restore(flags);
294 +
295 +    /*
296 +     * Restore the CPUs allowed mask.
297 +     */
298 +    set_cpus_allowed(current, cpus_allowed);
299 +
300 +    /* 
301 +     * Tell everyone what we've just done... 
302 +     * you should add a notify client with any platform specific 
303 +     * SDRAM refresh timer adjustments
304 +     */
305 +    cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
306 +
307 +    return 0;
308 +}
309 +
310 +static int pxa_cpufreq_init(struct cpufreq_policy *policy)
311 +{
312 +    unsigned long cpus_allowed;
313 +    unsigned int cpu = policy->cpu;
314 +    int i;
315 +
316 +       cpus_allowed = current->cpus_allowed;
317 +
318 +       set_cpus_allowed(current, 1 << cpu);
319 +       BUG_ON(cpu != smp_processor_id());
320 +
321 +    /* set default policy and cpuinfo */
322 +    policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
323 +    policy->policy = CPUFREQ_POLICY_PERFORMANCE;
324 +    policy->cpuinfo.max_freq = PXA25x_MAX_FREQ;
325 +    policy->cpuinfo.min_freq = PXA25x_MIN_FREQ;
326 +    policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
327 +    policy->cur = get_clk_frequency_khz(0); /* current freq */
328 +    policy->min = policy->max = policy->cur;
329 +
330 +    /* Generate the run cpufreq_frequency_table struct */
331 +    for(i=0;i<NUM_RUN_FREQS;i++) {
332 +        pxa255_run_freq_table[i].frequency = pxa255_run_freqs[i].khz;
333 +        pxa255_run_freq_table[i].index = i;    
334 +    }
335 +    pxa255_run_freq_table[i].frequency = CPUFREQ_TABLE_END;
336 +    /* Generate the turbo cpufreq_frequency_table struct */
337 +    for(i=0;i<NUM_TURBO_FREQS;i++) {
338 +        pxa255_turbo_freq_table[i].frequency = pxa255_turbo_freqs[i].khz;
339 +        pxa255_turbo_freq_table[i].index = i;    
340 +    }
341 +    pxa255_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END;
342 +    
343 +    set_cpus_allowed(current, cpus_allowed);
344 +    printk(KERN_INFO "PXA CPU frequency change support initialized\n");
345 +
346 +    return 0;
347 +}
348 +
349 +static struct cpufreq_driver pxa_cpufreq_driver = {
350 +    .verify     = pxa_verify_policy,
351 +    .target     = pxa_set_target,
352 +    .init       = pxa_cpufreq_init,
353 +    .name       = "PXA25x",
354 +};
355 +
356 +static int __init pxa_cpu_init(void)
357 +{
358 +    return cpufreq_register_driver(&pxa_cpufreq_driver);
359 +}
360 +
361 +static void __exit pxa_cpu_exit(void)
362 +{
363 +    cpufreq_unregister_driver(&pxa_cpufreq_driver);
364 +}
365 +
366 +
367 +MODULE_AUTHOR ("Intrinsyc Software Inc.");
368 +MODULE_DESCRIPTION ("CPU frequency changing driver for the PXA architecture");
369 +MODULE_LICENSE("GPL");
370 +module_init(pxa_cpu_init);
371 +module_exit(pxa_cpu_exit);
372 +
373 Index: linux-2.6.21.7/Documentation/cpu-freq/user-guide.txt
374 ===================================================================
375 --- linux-2.6.21.7.orig/Documentation/cpu-freq/user-guide.txt
376 +++ linux-2.6.21.7/Documentation/cpu-freq/user-guide.txt
377 @@ -18,7 +18,7 @@
378  Contents:
379  ---------
380  1. Supported Architectures and Processors
381 -1.1 ARM
382 +1.1 ARM, PXA
383  1.2 x86
384  1.3 sparc64
385  1.4 ppc
386 @@ -37,14 +37,15 @@ Contents:
387  1. Supported Architectures and Processors
388  =========================================
389  
390 -1.1 ARM
391 --------
392 +1.1 ARM, PXA
393 +------------
394  
395  The following ARM processors are supported by cpufreq:
396  
397  ARM Integrator
398  ARM-SA1100
399  ARM-SA1110
400 +Intel PXA
401  
402  
403  1.2 x86