]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/powerpc/aim/mp_cpudep.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / powerpc / aim / mp_cpudep.c
1 /*-
2  * Copyright (c) 2008 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <sys/pcpu.h>
35 #include <sys/proc.h>
36 #include <sys/smp.h>
37
38 #include <machine/bus.h>
39 #include <machine/cpu.h>
40 #include <machine/hid.h>
41 #include <machine/intr_machdep.h>
42 #include <machine/pcb.h>
43 #include <machine/psl.h>
44 #include <machine/smp.h>
45 #include <machine/spr.h>
46 #include <machine/trap_aim.h>
47
48 #include <dev/ofw/openfirm.h>
49 #include <machine/ofw_machdep.h>
50
51 void *ap_pcpu;
52
53 static register_t bsp_state[8] __aligned(8);
54
55 static void cpudep_save_config(void *dummy);
56 SYSINIT(cpu_save_config, SI_SUB_CPU, SI_ORDER_ANY, cpudep_save_config, NULL);
57
58 uintptr_t
59 cpudep_ap_bootstrap(void)
60 {
61         register_t msr, sp;
62
63         msr = PSL_KERNSET & ~PSL_EE;
64         mtmsr(msr);
65         isync();
66
67         __asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu));
68         powerpc_sync();
69
70         pcpup->pc_curthread = pcpup->pc_idlethread;
71         pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb;
72         sp = pcpup->pc_curpcb->pcb_sp;
73
74         return (sp);
75 }
76
77 static register_t
78 mpc745x_l2_enable(register_t l2cr_config)
79 {
80         register_t ccr;
81
82         ccr = mfspr(SPR_L2CR);
83         if (ccr & L2CR_L2E)
84                 return (ccr);
85
86         /* Configure L2 cache. */
87         ccr = l2cr_config & ~L2CR_L2E;
88         mtspr(SPR_L2CR, ccr | L2CR_L2I);
89         do {
90                 ccr = mfspr(SPR_L2CR);
91         } while (ccr & L2CR_L2I);
92         powerpc_sync();
93         mtspr(SPR_L2CR, l2cr_config);
94         powerpc_sync();
95
96         return (l2cr_config);
97 }
98
99 static register_t
100 mpc745x_l3_enable(register_t l3cr_config)
101 {
102         register_t ccr;
103
104         ccr = mfspr(SPR_L3CR);
105         if (ccr & L3CR_L3E)
106                 return (ccr);
107
108         /* Configure L3 cache. */
109         ccr = l3cr_config & ~(L3CR_L3E | L3CR_L3I | L3CR_L3PE | L3CR_L3CLKEN);
110         mtspr(SPR_L3CR, ccr);
111         ccr |= 0x4000000;       /* Magic, but documented. */
112         mtspr(SPR_L3CR, ccr);
113         ccr |= L3CR_L3CLKEN;
114         mtspr(SPR_L3CR, ccr);
115         mtspr(SPR_L3CR, ccr | L3CR_L3I);
116         while (mfspr(SPR_L3CR) & L3CR_L3I)
117                 ;
118         mtspr(SPR_L3CR, ccr & ~L3CR_L3CLKEN);
119         powerpc_sync();
120         DELAY(100);
121         mtspr(SPR_L3CR, ccr);
122         powerpc_sync();
123         DELAY(100);
124         ccr |= L3CR_L3E;
125         mtspr(SPR_L3CR, ccr);
126         powerpc_sync();
127
128         return(ccr);
129 }
130
131 static register_t
132 mpc745x_l1d_enable(void)
133 {
134         register_t hid;
135
136         hid = mfspr(SPR_HID0);
137         if (hid & HID0_DCE)
138                 return (hid);
139
140         /* Enable L1 D-cache */
141         hid |= HID0_DCE;
142         powerpc_sync();
143         mtspr(SPR_HID0, hid | HID0_DCFI);
144         powerpc_sync();
145
146         return (hid);
147 }
148
149 static register_t
150 mpc745x_l1i_enable(void)
151 {
152         register_t hid;
153
154         hid = mfspr(SPR_HID0);
155         if (hid & HID0_ICE)
156                 return (hid);
157
158         /* Enable L1 I-cache */
159         hid |= HID0_ICE;
160         isync();
161         mtspr(SPR_HID0, hid | HID0_ICFI);
162         isync();
163
164         return (hid);
165 }
166
167 static void
168 cpudep_save_config(void *dummy)
169 {
170         uint16_t        vers;
171
172         vers = mfpvr() >> 16;
173
174         switch(vers) {
175         case IBM970:
176         case IBM970FX:
177         case IBM970MP:
178                 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
179                     : "=r" (bsp_state[0]),"=r" (bsp_state[1]) : "K" (SPR_HID0));
180                 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
181                     : "=r" (bsp_state[2]),"=r" (bsp_state[3]) : "K" (SPR_HID1));
182                 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
183                     : "=r" (bsp_state[4]),"=r" (bsp_state[5]) : "K" (SPR_HID4));
184                 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
185                     : "=r" (bsp_state[6]),"=r" (bsp_state[7]) : "K" (SPR_HID5));
186
187                 powerpc_sync();
188
189                 break;
190         case MPC7450:
191         case MPC7455:
192         case MPC7457:
193                 /* Only MPC745x CPUs have an L3 cache. */
194                 bsp_state[3] = mfspr(SPR_L3CR);
195
196                 /* Fallthrough */
197         case MPC7400:
198         case MPC7410:
199         case MPC7447A:
200         case MPC7448:
201                 bsp_state[2] = mfspr(SPR_L2CR);
202                 bsp_state[1] = mfspr(SPR_HID1);
203                 bsp_state[0] = mfspr(SPR_HID0);
204                 break;
205         }
206 }
207
208 void
209 cpudep_ap_setup()
210
211         register_t      reg;
212         uint16_t        vers;
213
214         vers = mfpvr() >> 16;
215
216         switch(vers) {
217         case IBM970:
218         case IBM970FX:
219         case IBM970MP:
220                 /* Set HIOR to 0 */
221                 __asm __volatile("mtspr 311,%0" :: "r"(0));
222                 powerpc_sync();
223
224                 /*
225                  * The 970 has strange rules about how to update HID registers.
226                  * See Table 2-3, 970MP manual
227                  */
228
229                 __asm __volatile("mtasr %0; sync" :: "r"(0));
230                 __asm __volatile(" \
231                         ld      %0,0(%2);                               \
232                         sync; isync;                                    \
233                         mtspr   %1, %0;                                 \
234                         mfspr   %0, %1; mfspr   %0, %1; mfspr   %0, %1; \
235                         mfspr   %0, %1; mfspr   %0, %1; mfspr   %0, %1; \
236                         sync; isync" 
237                     : "=r"(reg) : "K"(SPR_HID0), "r"(bsp_state));
238                 __asm __volatile("ld %0, 8(%2); sync; isync;    \
239                     mtspr %1, %0; mtspr %1, %0; sync; isync"
240                     : "=r"(reg) : "K"(SPR_HID1), "r"(bsp_state));
241                 __asm __volatile("ld %0, 16(%2); sync; isync;   \
242                     mtspr %1, %0; sync; isync;"
243                     : "=r"(reg) : "K"(SPR_HID4), "r"(bsp_state));
244                 __asm __volatile("ld %0, 24(%2); sync; isync;   \
245                     mtspr %1, %0; sync; isync;"
246                     : "=r"(reg) : "K"(SPR_HID5), "r"(bsp_state));
247
248                 powerpc_sync();
249                 break;
250         case MPC7450:
251         case MPC7455:
252         case MPC7457:
253                 /* Only MPC745x CPUs have an L3 cache. */
254                 reg = mpc745x_l3_enable(bsp_state[3]);
255                 
256                 /* Fallthrough */
257         case MPC7400:
258         case MPC7410:
259         case MPC7447A:
260         case MPC7448:
261                 /* XXX: Program the CPU ID into PIR */
262                 __asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid)));
263
264                 powerpc_sync();
265                 isync();
266
267                 mtspr(SPR_HID0, bsp_state[0]); isync();
268                 mtspr(SPR_HID1, bsp_state[1]); isync();
269
270                 reg = mpc745x_l2_enable(bsp_state[2]);
271                 reg = mpc745x_l1d_enable();
272                 reg = mpc745x_l1i_enable();
273
274                 break;
275         default:
276                 printf("WARNING: Unknown CPU type. Cache performace may be "
277                     "suboptimal.\n");
278                 break;
279         }
280 }
281