Commit | Line | Data |
---|---|---|
c902be71 AB |
1 | /* |
2 | * CBE Pervasive Monitor and Debug | |
3 | * | |
4 | * (C) Copyright IBM Corporation 2005 | |
5 | * | |
6 | * Authors: Maximino Aguilar (maguilar@us.ibm.com) | |
7 | * Michael N. Day (mnday@us.ibm.com) | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2, or (at your option) | |
12 | * any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 | */ | |
23 | ||
24 | #undef DEBUG | |
25 | ||
c902be71 AB |
26 | #include <linux/interrupt.h> |
27 | #include <linux/irq.h> | |
28 | #include <linux/percpu.h> | |
29 | #include <linux/types.h> | |
30 | #include <linux/kallsyms.h> | |
31 | ||
32 | #include <asm/io.h> | |
33 | #include <asm/machdep.h> | |
34 | #include <asm/prom.h> | |
35 | #include <asm/pgtable.h> | |
36 | #include <asm/reg.h> | |
37 | ||
38 | #include "pervasive.h" | |
acf7d768 | 39 | #include "cbe_regs.h" |
c902be71 | 40 | |
3addf55c AB |
41 | static int sysreset_hack; |
42 | ||
302eca18 | 43 | static void cbe_power_save(void) |
c902be71 | 44 | { |
302eca18 | 45 | unsigned long ctrl, thread_switch_control; |
5850dd8f BH |
46 | |
47 | /* | |
e1fa2e13 BH |
48 | * We need to hard disable interrupts, the local_irq_enable() done by |
49 | * our caller upon return will hard re-enable. | |
5850dd8f BH |
50 | */ |
51 | hard_irq_disable(); | |
5850dd8f | 52 | |
302eca18 | 53 | ctrl = mfspr(SPRN_CTRLF); |
c902be71 AB |
54 | |
55 | /* Enable DEC and EE interrupt request */ | |
56 | thread_switch_control = mfspr(SPRN_TSC_CELL); | |
57 | thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST; | |
58 | ||
302eca18 | 59 | switch (ctrl & CTRL_CT) { |
c902be71 AB |
60 | case CTRL_CT0: |
61 | thread_switch_control |= TSC_CELL_DEC_ENABLE_0; | |
c902be71 AB |
62 | break; |
63 | case CTRL_CT1: | |
64 | thread_switch_control |= TSC_CELL_DEC_ENABLE_1; | |
c902be71 AB |
65 | break; |
66 | default: | |
67 | printk(KERN_WARNING "%s: unknown configuration\n", | |
68 | __FUNCTION__); | |
c902be71 AB |
69 | break; |
70 | } | |
c902be71 AB |
71 | mtspr(SPRN_TSC_CELL, thread_switch_control); |
72 | ||
302eca18 | 73 | /* |
74 | * go into low thread priority, medium priority will be | |
75 | * restored for us after wake-up. | |
acf7d768 | 76 | */ |
302eca18 | 77 | HMT_low(); |
c902be71 | 78 | |
302eca18 | 79 | /* |
80 | * atomically disable thread execution and runlatch. | |
81 | * External and Decrementer exceptions are still handled when the | |
82 | * thread is disabled but now enter in cbe_system_reset_exception() | |
83 | */ | |
84 | ctrl &= ~(CTRL_RUNLATCH | CTRL_TE); | |
85 | mtspr(SPRN_CTRLT, ctrl); | |
c902be71 AB |
86 | } |
87 | ||
8fce10a3 | 88 | static int cbe_system_reset_exception(struct pt_regs *regs) |
c902be71 | 89 | { |
3addf55c AB |
90 | int cpu; |
91 | struct cbe_pmd_regs __iomem *pmd; | |
92 | ||
c902be71 AB |
93 | switch (regs->msr & SRR1_WAKEMASK) { |
94 | case SRR1_WAKEEE: | |
95 | do_IRQ(regs); | |
96 | break; | |
97 | case SRR1_WAKEDEC: | |
98 | timer_interrupt(regs); | |
99 | break; | |
100 | case SRR1_WAKEMT: | |
3addf55c AB |
101 | /* |
102 | * The BMC can inject user triggered system reset exceptions, | |
103 | * but cannot set the system reset reason in srr1, | |
104 | * so check an extra register here. | |
105 | */ | |
106 | if (sysreset_hack && (cpu = smp_processor_id()) == 0) { | |
107 | pmd = cbe_get_cpu_pmd_regs(cpu); | |
108 | if (in_be64(&pmd->ras_esc_0) & 0xffff) { | |
109 | out_be64(&pmd->ras_esc_0, 0); | |
110 | return 0; | |
111 | } | |
112 | } | |
c902be71 | 113 | break; |
acf7d768 BH |
114 | #ifdef CONFIG_CBE_RAS |
115 | case SRR1_WAKESYSERR: | |
116 | cbe_system_error_exception(regs); | |
117 | break; | |
118 | case SRR1_WAKETHERM: | |
119 | cbe_thermal_exception(regs); | |
120 | break; | |
121 | #endif /* CONFIG_CBE_RAS */ | |
c902be71 AB |
122 | default: |
123 | /* do system reset */ | |
124 | return 0; | |
125 | } | |
126 | /* everything handled */ | |
127 | return 1; | |
128 | } | |
129 | ||
acf7d768 | 130 | void __init cbe_pervasive_init(void) |
c902be71 | 131 | { |
302eca18 | 132 | int cpu; |
3addf55c | 133 | |
c902be71 AB |
134 | if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) |
135 | return; | |
136 | ||
3addf55c AB |
137 | sysreset_hack = machine_is_compatible("IBM,CBPLUS-1.0"); |
138 | ||
302eca18 | 139 | for_each_possible_cpu(cpu) { |
140 | struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu); | |
141 | if (!regs) | |
142 | continue; | |
143 | ||
144 | /* Enable Pause(0) control bit */ | |
145 | out_be64(®s->pmcr, in_be64(®s->pmcr) | | |
146 | CBE_PMD_PAUSE_ZERO_CONTROL); | |
3addf55c AB |
147 | |
148 | /* Enable JTAG system-reset hack */ | |
149 | if (sysreset_hack) | |
150 | out_be32(®s->fir_mode_reg, | |
151 | in_be32(®s->fir_mode_reg) | | |
152 | CBE_PMD_FIR_MODE_M8); | |
302eca18 | 153 | } |
154 | ||
155 | ppc_md.power_save = cbe_power_save; | |
c902be71 AB |
156 | ppc_md.system_reset_exception = cbe_system_reset_exception; |
157 | } |