Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
[linux-2.6.git] / arch / powerpc / platforms / cell / cbe_cpufreq_pervasive.c
1 /*
2  * pervasive backend for the cbe_cpufreq driver
3  *
4  * This driver makes use of the pervasive unit to
5  * engage the desired frequency.
6  *
7  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
8  *
9  * Author: Christian Krafft <krafft@de.ibm.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2, or (at your option)
14  * any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #include <linux/io.h>
27 #include <linux/kernel.h>
28 #include <linux/time.h>
29 #include <asm/machdep.h>
30 #include <asm/hw_irq.h>
31 #include <asm/cell-regs.h>
32
33 #include "cbe_cpufreq.h"
34
35 /* to write to MIC register */
36 static u64 MIC_Slow_Fast_Timer_table[] = {
37         [0 ... 7] = 0x007fc00000000000ull,
38 };
39
40 /* more values for the MIC */
41 static u64 MIC_Slow_Next_Timer_table[] = {
42         0x0000240000000000ull,
43         0x0000268000000000ull,
44         0x000029C000000000ull,
45         0x00002D0000000000ull,
46         0x0000300000000000ull,
47         0x0000334000000000ull,
48         0x000039C000000000ull,
49         0x00003FC000000000ull,
50 };
51
52
53 int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode)
54 {
55         struct cbe_pmd_regs __iomem *pmd_regs;
56         struct cbe_mic_tm_regs __iomem *mic_tm_regs;
57         unsigned long flags;
58         u64 value;
59 #ifdef DEBUG
60         long time;
61 #endif
62
63         local_irq_save(flags);
64
65         mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
66         pmd_regs = cbe_get_cpu_pmd_regs(cpu);
67
68 #ifdef DEBUG
69         time = jiffies;
70 #endif
71
72         out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
73         out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
74
75         out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
76         out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
77
78         value = in_be64(&pmd_regs->pmcr);
79         /* set bits to zero */
80         value &= 0xFFFFFFFFFFFFFFF8ull;
81         /* set bits to next pmode */
82         value |= pmode;
83
84         out_be64(&pmd_regs->pmcr, value);
85
86 #ifdef DEBUG
87         /* wait until new pmode appears in status register */
88         value = in_be64(&pmd_regs->pmsr) & 0x07;
89         while (value != pmode) {
90                 cpu_relax();
91                 value = in_be64(&pmd_regs->pmsr) & 0x07;
92         }
93
94         time = jiffies  - time;
95         time = jiffies_to_msecs(time);
96         pr_debug("had to wait %lu ms for a transition using " \
97                  "pervasive unit\n", time);
98 #endif
99         local_irq_restore(flags);
100
101         return 0;
102 }
103
104
105 int cbe_cpufreq_get_pmode(int cpu)
106 {
107         int ret;
108         struct cbe_pmd_regs __iomem *pmd_regs;
109
110         pmd_regs = cbe_get_cpu_pmd_regs(cpu);
111         ret = in_be64(&pmd_regs->pmsr) & 0x07;
112
113         return ret;
114 }
115