]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/aim/mp_cpudep.c
sys/powerpc: further adoption of SPDX licensing ID tags.
[FreeBSD/FreeBSD.git] / sys / powerpc / aim / mp_cpudep.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2008 Marcel Moolenaar
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/bus.h>
36 #include <sys/pcpu.h>
37 #include <sys/proc.h>
38 #include <sys/smp.h>
39
40 #include <machine/bus.h>
41 #include <machine/cpu.h>
42 #include <machine/hid.h>
43 #include <machine/intr_machdep.h>
44 #include <machine/pcb.h>
45 #include <machine/psl.h>
46 #include <machine/smp.h>
47 #include <machine/spr.h>
48 #include <machine/trap.h>
49
50 #include <dev/ofw/openfirm.h>
51 #include <machine/ofw_machdep.h>
52
53 void *ap_pcpu;
54
55 static register_t bsp_state[8] __aligned(8);
56
57 static void cpudep_save_config(void *dummy);
58 SYSINIT(cpu_save_config, SI_SUB_CPU, SI_ORDER_ANY, cpudep_save_config, NULL);
59
60 void
61 cpudep_ap_early_bootstrap(void)
62 {
63 #ifndef __powerpc64__
64         register_t reg;
65 #endif
66
67         __asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu));
68         powerpc_sync();
69
70         switch (mfpvr() >> 16) {
71         case IBM970:
72         case IBM970FX:
73         case IBM970MP:
74                 /* Restore HID4 and HID5, which are necessary for the MMU */
75
76 #ifdef __powerpc64__
77                 mtspr(SPR_HID4, bsp_state[2]); powerpc_sync(); isync();
78                 mtspr(SPR_HID5, bsp_state[3]); powerpc_sync(); isync();
79 #else
80                 __asm __volatile("ld %0, 16(%2); sync; isync;   \
81                     mtspr %1, %0; sync; isync;"
82                     : "=r"(reg) : "K"(SPR_HID4), "b"(bsp_state));
83                 __asm __volatile("ld %0, 24(%2); sync; isync;   \
84                     mtspr %1, %0; sync; isync;"
85                     : "=r"(reg) : "K"(SPR_HID5), "b"(bsp_state));
86 #endif
87                 powerpc_sync();
88                 break;
89         }
90 }
91
92 uintptr_t
93 cpudep_ap_bootstrap(void)
94 {
95         register_t msr, sp;
96
97         msr = PSL_KERNSET & ~PSL_EE;
98         mtmsr(msr);
99
100         pcpup->pc_curthread = pcpup->pc_idlethread;
101 #ifdef __powerpc64__
102         __asm __volatile("mr 13,%0" :: "r"(pcpup->pc_curthread));
103 #else
104         __asm __volatile("mr 2,%0" :: "r"(pcpup->pc_curthread));
105 #endif
106         pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb;
107         sp = pcpup->pc_curpcb->pcb_sp;
108
109         return (sp);
110 }
111
112 static register_t
113 mpc74xx_l2_enable(register_t l2cr_config)
114 {
115         register_t ccr, bit;
116         uint16_t        vers;
117
118         vers = mfpvr() >> 16;
119         switch (vers) {
120         case MPC7400:
121         case MPC7410:
122                 bit = L2CR_L2IP;
123                 break;
124         default:
125                 bit = L2CR_L2I;
126                 break;
127         }
128
129         ccr = mfspr(SPR_L2CR);
130         if (ccr & L2CR_L2E)
131                 return (ccr);
132
133         /* Configure L2 cache. */
134         ccr = l2cr_config & ~L2CR_L2E;
135         mtspr(SPR_L2CR, ccr | L2CR_L2I);
136         do {
137                 ccr = mfspr(SPR_L2CR);
138         } while (ccr & bit);
139         powerpc_sync();
140         mtspr(SPR_L2CR, l2cr_config);
141         powerpc_sync();
142
143         return (l2cr_config);
144 }
145
146 static register_t
147 mpc745x_l3_enable(register_t l3cr_config)
148 {
149         register_t ccr;
150
151         ccr = mfspr(SPR_L3CR);
152         if (ccr & L3CR_L3E)
153                 return (ccr);
154
155         /* Configure L3 cache. */
156         ccr = l3cr_config & ~(L3CR_L3E | L3CR_L3I | L3CR_L3PE | L3CR_L3CLKEN);
157         mtspr(SPR_L3CR, ccr);
158         ccr |= 0x4000000;       /* Magic, but documented. */
159         mtspr(SPR_L3CR, ccr);
160         ccr |= L3CR_L3CLKEN;
161         mtspr(SPR_L3CR, ccr);
162         mtspr(SPR_L3CR, ccr | L3CR_L3I);
163         while (mfspr(SPR_L3CR) & L3CR_L3I)
164                 ;
165         mtspr(SPR_L3CR, ccr & ~L3CR_L3CLKEN);
166         powerpc_sync();
167         DELAY(100);
168         mtspr(SPR_L3CR, ccr);
169         powerpc_sync();
170         DELAY(100);
171         ccr |= L3CR_L3E;
172         mtspr(SPR_L3CR, ccr);
173         powerpc_sync();
174
175         return(ccr);
176 }
177
178 static register_t
179 mpc74xx_l1d_enable(void)
180 {
181         register_t hid;
182
183         hid = mfspr(SPR_HID0);
184         if (hid & HID0_DCE)
185                 return (hid);
186
187         /* Enable L1 D-cache */
188         hid |= HID0_DCE;
189         powerpc_sync();
190         mtspr(SPR_HID0, hid | HID0_DCFI);
191         powerpc_sync();
192
193         return (hid);
194 }
195
196 static register_t
197 mpc74xx_l1i_enable(void)
198 {
199         register_t hid;
200
201         hid = mfspr(SPR_HID0);
202         if (hid & HID0_ICE)
203                 return (hid);
204
205         /* Enable L1 I-cache */
206         hid |= HID0_ICE;
207         isync();
208         mtspr(SPR_HID0, hid | HID0_ICFI);
209         isync();
210
211         return (hid);
212 }
213
214 static void
215 cpudep_save_config(void *dummy)
216 {
217         uint16_t        vers;
218
219         vers = mfpvr() >> 16;
220
221         switch(vers) {
222         case IBM970:
223         case IBM970FX:
224         case IBM970MP:
225                 #ifdef __powerpc64__
226                 bsp_state[0] = mfspr(SPR_HID0);
227                 bsp_state[1] = mfspr(SPR_HID1);
228                 bsp_state[2] = mfspr(SPR_HID4);
229                 bsp_state[3] = mfspr(SPR_HID5);
230                 #else
231                 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
232                     : "=r" (bsp_state[0]),"=r" (bsp_state[1]) : "K" (SPR_HID0));
233                 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
234                     : "=r" (bsp_state[2]),"=r" (bsp_state[3]) : "K" (SPR_HID1));
235                 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
236                     : "=r" (bsp_state[4]),"=r" (bsp_state[5]) : "K" (SPR_HID4));
237                 __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
238                     : "=r" (bsp_state[6]),"=r" (bsp_state[7]) : "K" (SPR_HID5));
239                 #endif
240
241                 powerpc_sync();
242
243                 break;
244         case IBMCELLBE:
245                 #ifdef NOTYET /* Causes problems if in instruction stream on 970 */
246                 if (mfmsr() & PSL_HV) {
247                         bsp_state[0] = mfspr(SPR_HID0);
248                         bsp_state[1] = mfspr(SPR_HID1);
249                         bsp_state[2] = mfspr(SPR_HID4);
250                         bsp_state[3] = mfspr(SPR_HID6);
251
252                         bsp_state[4] = mfspr(SPR_CELL_TSCR);
253                 }
254                 #endif
255
256                 bsp_state[5] = mfspr(SPR_CELL_TSRL);
257
258                 break;
259         case MPC7450:
260         case MPC7455:
261         case MPC7457:
262                 /* Only MPC745x CPUs have an L3 cache. */
263                 bsp_state[3] = mfspr(SPR_L3CR);
264
265                 /* Fallthrough */
266         case MPC7400:
267         case MPC7410:
268         case MPC7447A:
269         case MPC7448:
270                 bsp_state[2] = mfspr(SPR_L2CR);
271                 bsp_state[1] = mfspr(SPR_HID1);
272                 bsp_state[0] = mfspr(SPR_HID0);
273                 break;
274         }
275 }
276
277 void
278 cpudep_ap_setup()
279
280         register_t      reg;
281         uint16_t        vers;
282
283         vers = mfpvr() >> 16;
284
285         /* The following is needed for restoring from sleep. */
286         platform_smp_timebase_sync(0, 1);
287
288         switch(vers) {
289         case IBM970:
290         case IBM970FX:
291         case IBM970MP:
292                 /* Set HIOR to 0 */
293                 __asm __volatile("mtspr 311,%0" :: "r"(0));
294                 powerpc_sync();
295
296                 /*
297                  * The 970 has strange rules about how to update HID registers.
298                  * See Table 2-3, 970MP manual
299                  *
300                  * Note: HID4 and HID5 restored already in
301                  * cpudep_ap_early_bootstrap()
302                  */
303
304                 __asm __volatile("mtasr %0; sync" :: "r"(0));
305         #ifdef __powerpc64__
306                 __asm __volatile(" \
307                         sync; isync;                                    \
308                         mtspr   %1, %0;                                 \
309                         mfspr   %0, %1; mfspr   %0, %1; mfspr   %0, %1; \
310                         mfspr   %0, %1; mfspr   %0, %1; mfspr   %0, %1; \
311                         sync; isync" 
312                     :: "r"(bsp_state[0]), "K"(SPR_HID0));
313                 __asm __volatile("sync; isync;  \
314                     mtspr %1, %0; mtspr %1, %0; sync; isync"
315                     :: "r"(bsp_state[1]), "K"(SPR_HID1));
316         #else
317                 __asm __volatile(" \
318                         ld      %0,0(%2);                               \
319                         sync; isync;                                    \
320                         mtspr   %1, %0;                                 \
321                         mfspr   %0, %1; mfspr   %0, %1; mfspr   %0, %1; \
322                         mfspr   %0, %1; mfspr   %0, %1; mfspr   %0, %1; \
323                         sync; isync" 
324                     : "=r"(reg) : "K"(SPR_HID0), "b"(bsp_state));
325                 __asm __volatile("ld %0, 8(%2); sync; isync;    \
326                     mtspr %1, %0; mtspr %1, %0; sync; isync"
327                     : "=r"(reg) : "K"(SPR_HID1), "b"(bsp_state));
328         #endif
329
330                 powerpc_sync();
331                 break;
332         case IBMCELLBE:
333                 #ifdef NOTYET /* Causes problems if in instruction stream on 970 */
334                 if (mfmsr() & PSL_HV) {
335                         mtspr(SPR_HID0, bsp_state[0]);
336                         mtspr(SPR_HID1, bsp_state[1]);
337                         mtspr(SPR_HID4, bsp_state[2]);
338                         mtspr(SPR_HID6, bsp_state[3]);
339
340                         mtspr(SPR_CELL_TSCR, bsp_state[4]);
341                 }
342                 #endif
343
344                 mtspr(SPR_CELL_TSRL, bsp_state[5]);
345
346                 break;
347         case MPC7400:
348         case MPC7410:
349         case MPC7447A:
350         case MPC7448:
351         case MPC7450:
352         case MPC7455:
353         case MPC7457:
354                 /* XXX: Program the CPU ID into PIR */
355                 __asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid)));
356
357                 powerpc_sync();
358                 isync();
359
360                 mtspr(SPR_HID0, bsp_state[0]); isync();
361                 mtspr(SPR_HID1, bsp_state[1]); isync();
362
363                 /* Now enable the L3 cache. */
364                 switch (vers) {
365                 case MPC7450:
366                 case MPC7455:
367                 case MPC7457:
368                         /* Only MPC745x CPUs have an L3 cache. */
369                         reg = mpc745x_l3_enable(bsp_state[3]);
370                 default:
371                         break;
372                 }
373                 
374                 reg = mpc74xx_l2_enable(bsp_state[2]);
375                 reg = mpc74xx_l1d_enable();
376                 reg = mpc74xx_l1i_enable();
377
378                 break;
379         case IBMPOWER7:
380         case IBMPOWER7PLUS:
381         case IBMPOWER8:
382         case IBMPOWER8E:
383 #ifdef __powerpc64__
384                 if (mfmsr() & PSL_HV)
385                         mtspr(SPR_LPCR, mfspr(SPR_LPCR) | LPCR_LPES);
386 #endif
387                 break;
388         default:
389 #ifdef __powerpc64__
390                 if (!(mfmsr() & PSL_HV)) /* Rely on HV to have set things up */
391                         break;
392 #endif
393                 printf("WARNING: Unknown CPU type. Cache performace may be "
394                     "suboptimal.\n");
395                 break;
396         }
397 }
398