Commit | Line | Data |
---|---|---|
de6cc651 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
74889e41 CK |
2 | /* |
3 | * pervasive backend for the cbe_cpufreq driver | |
4 | * | |
5 | * This driver makes use of the pervasive unit to | |
6 | * engage the desired frequency. | |
7 | * | |
8 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 | |
9 | * | |
10 | * Author: Christian Krafft <krafft@de.ibm.com> | |
74889e41 CK |
11 | */ |
12 | ||
13 | #include <linux/io.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/time.h> | |
16 | #include <asm/machdep.h> | |
17 | #include <asm/hw_irq.h> | |
eef686a0 | 18 | #include <asm/cell-regs.h> |
74889e41 | 19 | |
6eb1c377 | 20 | #include "ppc_cbe_cpufreq.h" |
74889e41 CK |
21 | |
22 | /* to write to MIC register */ | |
23 | static u64 MIC_Slow_Fast_Timer_table[] = { | |
24 | [0 ... 7] = 0x007fc00000000000ull, | |
25 | }; | |
26 | ||
27 | /* more values for the MIC */ | |
28 | static u64 MIC_Slow_Next_Timer_table[] = { | |
29 | 0x0000240000000000ull, | |
30 | 0x0000268000000000ull, | |
31 | 0x000029C000000000ull, | |
32 | 0x00002D0000000000ull, | |
33 | 0x0000300000000000ull, | |
34 | 0x0000334000000000ull, | |
35 | 0x000039C000000000ull, | |
36 | 0x00003FC000000000ull, | |
37 | }; | |
38 | ||
39 | ||
40 | int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode) | |
41 | { | |
42 | struct cbe_pmd_regs __iomem *pmd_regs; | |
43 | struct cbe_mic_tm_regs __iomem *mic_tm_regs; | |
54cfd0d5 | 44 | unsigned long flags; |
74889e41 CK |
45 | u64 value; |
46 | #ifdef DEBUG | |
47 | long time; | |
48 | #endif | |
49 | ||
50 | local_irq_save(flags); | |
51 | ||
52 | mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu); | |
53 | pmd_regs = cbe_get_cpu_pmd_regs(cpu); | |
54 | ||
55 | #ifdef DEBUG | |
56 | time = jiffies; | |
57 | #endif | |
58 | ||
59 | out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]); | |
60 | out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]); | |
61 | ||
62 | out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]); | |
63 | out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]); | |
64 | ||
65 | value = in_be64(&pmd_regs->pmcr); | |
66 | /* set bits to zero */ | |
67 | value &= 0xFFFFFFFFFFFFFFF8ull; | |
68 | /* set bits to next pmode */ | |
69 | value |= pmode; | |
70 | ||
71 | out_be64(&pmd_regs->pmcr, value); | |
72 | ||
73 | #ifdef DEBUG | |
74 | /* wait until new pmode appears in status register */ | |
75 | value = in_be64(&pmd_regs->pmsr) & 0x07; | |
76 | while (value != pmode) { | |
77 | cpu_relax(); | |
78 | value = in_be64(&pmd_regs->pmsr) & 0x07; | |
79 | } | |
80 | ||
81 | time = jiffies - time; | |
82 | time = jiffies_to_msecs(time); | |
83 | pr_debug("had to wait %lu ms for a transition using " \ | |
84 | "pervasive unit\n", time); | |
85 | #endif | |
86 | local_irq_restore(flags); | |
87 | ||
88 | return 0; | |
89 | } | |
90 | ||
91 | ||
92 | int cbe_cpufreq_get_pmode(int cpu) | |
93 | { | |
94 | int ret; | |
95 | struct cbe_pmd_regs __iomem *pmd_regs; | |
96 | ||
97 | pmd_regs = cbe_get_cpu_pmd_regs(cpu); | |
98 | ret = in_be64(&pmd_regs->pmsr) & 0x07; | |
99 | ||
100 | return ret; | |
101 | } | |
102 |